@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
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P2P 工具调用模块
|
|
3
|
+
* 支持文件和本地信息的 P2P 传递
|
|
4
|
+
*/
|
|
5
|
+
// 工具类型枚举
|
|
6
|
+
export var P2PToolType;
|
|
7
|
+
(function (P2PToolType) {
|
|
8
|
+
P2PToolType["FILE_TRANSFER"] = "file_transfer";
|
|
9
|
+
P2PToolType["LOCAL_INFO"] = "local_info";
|
|
10
|
+
P2PToolType["SYSTEM_INFO"] = "system_info";
|
|
11
|
+
P2PToolType["FILE_LIST"] = "file_list";
|
|
12
|
+
})(P2PToolType || (P2PToolType = {}));
|
|
13
|
+
// 文件传输
|
|
14
|
+
export async function transferFile(targetDid, fileInfo, messageId) {
|
|
15
|
+
try {
|
|
16
|
+
const payload = {
|
|
17
|
+
type: 'file',
|
|
18
|
+
tool: P2PToolType.FILE_TRANSFER,
|
|
19
|
+
data: {
|
|
20
|
+
name: fileInfo.name,
|
|
21
|
+
size: fileInfo.size,
|
|
22
|
+
mimeType: fileInfo.mimeType,
|
|
23
|
+
content: fileInfo.content
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const res = await fetch('/api/message-p2p', {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
targetDid,
|
|
31
|
+
content: JSON.stringify(payload),
|
|
32
|
+
type: 'file'
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
if (res.ok) {
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
messageId: data.messageId || messageId
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return { success: false, error: '文件传输失败' };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return { success: false, error: e.message };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 本地信息查询
|
|
51
|
+
export async function queryLocalInfo(targetDid, query) {
|
|
52
|
+
try {
|
|
53
|
+
const payload = {
|
|
54
|
+
type: 'info_query',
|
|
55
|
+
tool: P2PToolType.LOCAL_INFO,
|
|
56
|
+
query: query
|
|
57
|
+
};
|
|
58
|
+
const res = await fetch('/api/message-p2p', {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json' },
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
targetDid,
|
|
63
|
+
content: JSON.stringify(payload),
|
|
64
|
+
type: 'ai-dialogue'
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
if (res.ok) {
|
|
68
|
+
const data = await res.json();
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
data: data.response,
|
|
72
|
+
messageId: data.messageId
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return { success: false, error: '信息查询失败' };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return { success: false, error: e.message };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// 系统信息请求
|
|
84
|
+
export async function getSystemInfo(targetDid) {
|
|
85
|
+
try {
|
|
86
|
+
const payload = {
|
|
87
|
+
type: 'system_info_request',
|
|
88
|
+
tool: P2PToolType.SYSTEM_INFO
|
|
89
|
+
};
|
|
90
|
+
const res = await fetch('/api/message-p2p', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: { 'Content-Type': 'application/json' },
|
|
93
|
+
body: JSON.stringify({
|
|
94
|
+
targetDid,
|
|
95
|
+
content: JSON.stringify(payload),
|
|
96
|
+
type: 'ai-dialogue'
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
if (res.ok) {
|
|
100
|
+
const data = await res.json();
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
data: data.response,
|
|
104
|
+
messageId: data.messageId
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return { success: false, error: '系统信息获取失败' };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
return { success: false, error: e.message };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 文件列表请求
|
|
116
|
+
export async function listFiles(targetDid, path = '/') {
|
|
117
|
+
try {
|
|
118
|
+
const payload = {
|
|
119
|
+
type: 'file_list_request',
|
|
120
|
+
tool: P2PToolType.FILE_LIST,
|
|
121
|
+
path: path
|
|
122
|
+
};
|
|
123
|
+
const res = await fetch('/api/message-p2p', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: { 'Content-Type': 'application/json' },
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
targetDid,
|
|
128
|
+
content: JSON.stringify(payload),
|
|
129
|
+
type: 'ai-dialogue'
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
if (res.ok) {
|
|
133
|
+
const data = await res.json();
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
data: data.response,
|
|
137
|
+
messageId: data.messageId
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
return { success: false, error: '文件列表获取失败' };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
return { success: false, error: e.message };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// 工具调用入口
|
|
149
|
+
export async function executeP2PTool(request) {
|
|
150
|
+
const { toolName, payload, targetDid } = request;
|
|
151
|
+
if (!targetDid) {
|
|
152
|
+
return { success: false, error: '未指定目标节点' };
|
|
153
|
+
}
|
|
154
|
+
switch (toolName) {
|
|
155
|
+
case P2PToolType.FILE_TRANSFER:
|
|
156
|
+
return transferFile(targetDid, payload.data);
|
|
157
|
+
case P2PToolType.LOCAL_INFO:
|
|
158
|
+
return queryLocalInfo(targetDid, payload.data);
|
|
159
|
+
case P2PToolType.SYSTEM_INFO:
|
|
160
|
+
return getSystemInfo(targetDid);
|
|
161
|
+
case P2PToolType.FILE_LIST:
|
|
162
|
+
return listFiles(targetDid, payload.data?.path || '/');
|
|
163
|
+
default:
|
|
164
|
+
return { success: false, error: `未知工具: ${toolName}` };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// 本地系统信息获取 (用于响应来自远程的请求)
|
|
168
|
+
export function getLocalSystemInfo() {
|
|
169
|
+
const memUsage = process.memoryUsage();
|
|
170
|
+
const cpuCores = require('os').cpus();
|
|
171
|
+
return {
|
|
172
|
+
platform: process.platform,
|
|
173
|
+
arch: process.arch,
|
|
174
|
+
nodeVersion: process.version,
|
|
175
|
+
memory: {
|
|
176
|
+
total: memUsage.heapTotal,
|
|
177
|
+
free: memUsage.heapTotal - memUsage.heapUsed,
|
|
178
|
+
used: memUsage.heapUsed
|
|
179
|
+
},
|
|
180
|
+
cpu: {
|
|
181
|
+
cores: cpuCores.length,
|
|
182
|
+
model: cpuCores[0]?.model || 'Unknown'
|
|
183
|
+
},
|
|
184
|
+
uptime: process.uptime()
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// 本地文件列表 (用于响应来自远程的请求)
|
|
188
|
+
export function getLocalFileList(dirPath) {
|
|
189
|
+
try {
|
|
190
|
+
// Dynamic import for ESM compatibility
|
|
191
|
+
const pathModule = require('path');
|
|
192
|
+
const fs = require('fs');
|
|
193
|
+
const fullPath = pathModule.resolve(dirPath);
|
|
194
|
+
const files = fs.readdirSync(fullPath);
|
|
195
|
+
const fileList = files.map((name) => {
|
|
196
|
+
const fullFilePath = pathModule.join(fullPath, name);
|
|
197
|
+
let stat;
|
|
198
|
+
try {
|
|
199
|
+
stat = fs.statSync(fullFilePath);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
name: name,
|
|
206
|
+
size: stat.size,
|
|
207
|
+
isDirectory: stat.isDirectory(),
|
|
208
|
+
modified: stat.mtime.toISOString()
|
|
209
|
+
};
|
|
210
|
+
}).filter(Boolean);
|
|
211
|
+
return {
|
|
212
|
+
success: true,
|
|
213
|
+
path: fullPath,
|
|
214
|
+
files: fileList
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
return {
|
|
219
|
+
success: false,
|
|
220
|
+
path: dirPath,
|
|
221
|
+
error: e.message
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 导出工具名称列表
|
|
226
|
+
export const P2P_TOOLS = [
|
|
227
|
+
{
|
|
228
|
+
name: P2PToolType.FILE_TRANSFER,
|
|
229
|
+
description: '传输文件到远程节点',
|
|
230
|
+
parameters: ['targetDid', 'fileInfo']
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: P2PToolType.LOCAL_INFO,
|
|
234
|
+
description: '查询远程节点本地信息',
|
|
235
|
+
parameters: ['targetDid', 'query']
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: P2PToolType.SYSTEM_INFO,
|
|
239
|
+
description: '获取远程节点系统信息',
|
|
240
|
+
parameters: ['targetDid']
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: P2PToolType.FILE_LIST,
|
|
244
|
+
description: '列出远程节点目录文件',
|
|
245
|
+
parameters: ['targetDid', 'path']
|
|
246
|
+
}
|
|
247
|
+
];
|
|
248
|
+
console.log('[P2P Tools] 工具模块已加载');
|
package/dist/web/index.html
CHANGED
|
@@ -205,21 +205,39 @@
|
|
|
205
205
|
<input type="text" id="judgment-reason" placeholder="例: 信任 Bolloon 的判断存储">
|
|
206
206
|
</div>
|
|
207
207
|
<div class="form-group judgment-form-row">
|
|
208
|
-
<label
|
|
209
|
-
<
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<
|
|
221
|
-
<
|
|
222
|
-
|
|
208
|
+
<label>分类</label>
|
|
209
|
+
<div class="judgment-polarity-toggle" id="judgment-polarity-toggle">
|
|
210
|
+
<label class="polarity-opt active" data-polarity="positive">
|
|
211
|
+
<input type="radio" name="judgment-polarity" value="positive" checked>
|
|
212
|
+
<span>▲ 正向 <small>采纳</small></span>
|
|
213
|
+
</label>
|
|
214
|
+
<label class="polarity-opt" data-polarity="negative">
|
|
215
|
+
<input type="radio" name="judgment-polarity" value="negative">
|
|
216
|
+
<span>▼ 负向 <small>否决/避免</small></span>
|
|
217
|
+
</label>
|
|
218
|
+
</div>
|
|
219
|
+
<details class="judgment-advanced-fold" style="margin-left:auto;">
|
|
220
|
+
<summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">高级 (领域/风险)</summary>
|
|
221
|
+
<div style="display:flex;gap:10px;padding:6px 0 0;flex-wrap:wrap;font-size:11px;">
|
|
222
|
+
<label>领域
|
|
223
|
+
<select id="judgment-domain">
|
|
224
|
+
<option value="general">general</option>
|
|
225
|
+
<option value="code">code</option>
|
|
226
|
+
<option value="architecture">architecture</option>
|
|
227
|
+
<option value="security">security</option>
|
|
228
|
+
<option value="testing">testing</option>
|
|
229
|
+
</select>
|
|
230
|
+
</label>
|
|
231
|
+
<label>风险
|
|
232
|
+
<select id="judgment-stakes">
|
|
233
|
+
<option value="medium">medium</option>
|
|
234
|
+
<option value="low">low</option>
|
|
235
|
+
<option value="high">high</option>
|
|
236
|
+
<option value="critical">critical</option>
|
|
237
|
+
</select>
|
|
238
|
+
</label>
|
|
239
|
+
</div>
|
|
240
|
+
</details>
|
|
223
241
|
</div>
|
|
224
242
|
<div class="btn-group">
|
|
225
243
|
<button id="judgment-submit-btn" class="btn-primary">记录</button>
|
|
@@ -235,15 +253,21 @@
|
|
|
235
253
|
</button>
|
|
236
254
|
<button class="judgment-tab" data-tab="global">全局</button>
|
|
237
255
|
</div>
|
|
238
|
-
<!--
|
|
256
|
+
<!-- 2026-07-22 简化: 正向 / 负向 两个主分类 (替换原 6 个 status tab)
|
|
257
|
+
正向 = 采纳类 (approve/modify/escalate), 会注入 prompt 复用
|
|
258
|
+
负向 = 否决/被推翻 (reject/rejected/superseded), 负向回收为避免清单
|
|
259
|
+
高级分析 (违规/自适应/因果) 折叠保留, 数据/API 不删 -->
|
|
239
260
|
<div id="judgments-status-filter" class="judgment-status-bar">
|
|
240
|
-
<
|
|
241
|
-
<button class="judgment-
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
261
|
+
<button class="judgment-polarity-tab active" data-polarity="positive" title="采纳类: approve/modify/escalate, 会注入 prompt 复用">▲ 正向</button>
|
|
262
|
+
<button class="judgment-polarity-tab" data-polarity="negative" title="否决/被推翻: reject/rejected/superseded, 负向回收为避免清单">▼ 负向</button>
|
|
263
|
+
<details class="judgment-advanced-fold" style="margin-left:auto;">
|
|
264
|
+
<summary style="font-size:11px;color:#6b7280;cursor:pointer;list-style:none;">⋯ 高级分析</summary>
|
|
265
|
+
<div style="display:flex;gap:4px;padding:6px 0 0;flex-wrap:wrap;">
|
|
266
|
+
<button class="judgment-status-tab" data-status="violations" style="font-size:11px;">违规记录</button>
|
|
267
|
+
<button class="judgment-status-tab" data-status="adaptive" style="font-size:11px;">📊 自适应</button>
|
|
268
|
+
<button class="judgment-status-tab" data-status="causal" style="font-size:11px;">🔍 因果分析</button>
|
|
269
|
+
</div>
|
|
270
|
+
</details>
|
|
247
271
|
</div>
|
|
248
272
|
<h3 class="judgment-list-header">
|
|
249
273
|
<span id="judgments-list-title">本 channel 的判断力</span>
|
|
@@ -36,15 +36,21 @@ export function registerJudgmentsRoutes(app) {
|
|
|
36
36
|
// 极简版: 只记录 decision + reason; 其它字段可选
|
|
37
37
|
app.post('/api/judgments', async (req, res) => {
|
|
38
38
|
try {
|
|
39
|
-
const { decision, reason, context } = req.body;
|
|
39
|
+
const { decision, reason, context, decision_type } = req.body;
|
|
40
40
|
if (!decision || typeof decision !== 'string' || !decision.trim()) {
|
|
41
41
|
return res.status(400).json({ error: 'decision required' });
|
|
42
42
|
}
|
|
43
|
+
// 2026-07-22: 接受前端 polarity toggle 传来的 decision_type (正=approve / 负=reject)
|
|
44
|
+
// 不传或非法 → 默认 approve (向后兼容)
|
|
45
|
+
const allowedTypes = ['approve', 'reject', 'modify', 'escalate'];
|
|
46
|
+
const finalType = decision_type && allowedTypes.includes(decision_type)
|
|
47
|
+
? decision_type
|
|
48
|
+
: 'approve';
|
|
43
49
|
const { storeHumanJudgment, initializeValueStore } = await import('../pi-ecosystem-judgment/human-value-store.js');
|
|
44
50
|
await initializeValueStore();
|
|
45
51
|
const j = await storeHumanJudgment({
|
|
46
52
|
decision: decision.trim(),
|
|
47
|
-
decision_type:
|
|
53
|
+
decision_type: finalType,
|
|
48
54
|
reasons: reason ? [reason.trim()] : [],
|
|
49
55
|
values_derived: [],
|
|
50
56
|
context: {
|
package/dist/web/server.js
CHANGED
|
@@ -4484,6 +4484,17 @@ ${goalDesc}
|
|
|
4484
4484
|
}
|
|
4485
4485
|
});
|
|
4486
4486
|
// 获取 iroh 节点信息
|
|
4487
|
+
// 2026-07-22 设计 C: 引擎背压 API (涡轮增压表, 隐式可观测 — 废气内容不暴露, 只展示压力等级)
|
|
4488
|
+
app.get('/api/engine/backpressure', async (_req, res) => {
|
|
4489
|
+
try {
|
|
4490
|
+
const { getBackpressure } = await import('../bootstrap/exhaust-scrubber.js');
|
|
4491
|
+
const snap = getBackpressure();
|
|
4492
|
+
res.json({ ok: true, ...snap });
|
|
4493
|
+
}
|
|
4494
|
+
catch (err) {
|
|
4495
|
+
res.status(500).json({ error: err.message });
|
|
4496
|
+
}
|
|
4497
|
+
});
|
|
4487
4498
|
app.get('/api/iroh/info', async (_req, res) => {
|
|
4488
4499
|
if (!irohInitialized || !irohNodeInfo) {
|
|
4489
4500
|
res.json({ initialized: false });
|
package/dist/web/style.css
CHANGED
|
@@ -1795,6 +1795,36 @@ body {
|
|
|
1795
1795
|
background: var(--accent);
|
|
1796
1796
|
color: var(--bg);
|
|
1797
1797
|
}
|
|
1798
|
+
|
|
1799
|
+
/* 2026-07-22 设计 A: 正向/负向主分类 tab + 表单 toggle */
|
|
1800
|
+
.judgment-polarity-tab {
|
|
1801
|
+
background: var(--bg-hover);
|
|
1802
|
+
color: var(--text-secondary);
|
|
1803
|
+
border: none;
|
|
1804
|
+
padding: 4px 14px;
|
|
1805
|
+
border-radius: 4px;
|
|
1806
|
+
cursor: pointer;
|
|
1807
|
+
font-size: 12px;
|
|
1808
|
+
font-weight: 600;
|
|
1809
|
+
transition: var(--transition);
|
|
1810
|
+
}
|
|
1811
|
+
.judgment-polarity-tab:hover { background: var(--bg-active); color: var(--text-primary); }
|
|
1812
|
+
.judgment-polarity-tab[data-polarity="positive"].active { background: #059669; color: #fff; }
|
|
1813
|
+
.judgment-polarity-tab[data-polarity="negative"].active { background: #dc2626; color: #fff; }
|
|
1814
|
+
.judgment-advanced-fold > summary::-webkit-details-marker { display: none; }
|
|
1815
|
+
|
|
1816
|
+
.judgment-polarity-toggle { display: flex; gap: 4px; }
|
|
1817
|
+
.polarity-opt {
|
|
1818
|
+
display: flex; align-items: center; gap: 4px;
|
|
1819
|
+
padding: 3px 10px; border-radius: 4px; cursor: pointer;
|
|
1820
|
+
font-size: 12px; background: var(--bg-hover); color: var(--text-secondary);
|
|
1821
|
+
border: 1px solid transparent; transition: var(--transition);
|
|
1822
|
+
}
|
|
1823
|
+
.polarity-opt input { display: none; }
|
|
1824
|
+
.polarity-opt small { color: var(--text-muted); font-weight: 400; }
|
|
1825
|
+
.polarity-opt.active[data-polarity="positive"] { background: #ecfdf5; color: #047857; border-color: #6ee7b7; }
|
|
1826
|
+
.polarity-opt.active[data-polarity="negative"] { background: #fef2f2; color: #b91c1c; border-color: #fca5a5; }
|
|
1827
|
+
|
|
1798
1828
|
.judgment-form-row {
|
|
1799
1829
|
display: flex;
|
|
1800
1830
|
gap: 8px;
|