@yxzpro/agent-acta 2.14.4
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/LICENSE +21 -0
- package/LOGFORMATS.md +960 -0
- package/README.md +238 -0
- package/REFERENCE.md +1428 -0
- package/agent-acta-page.html +1998 -0
- package/agent-acta-server.mjs +1066 -0
- package/agent-acta-widget.html +724 -0
- package/archive.mjs +335 -0
- package/core/log.mjs +20 -0
- package/core/service.mjs +4285 -0
- package/hooks/cursor-usage-hook.mjs +89 -0
- package/mcp-server.mjs +372 -0
- package/package.json +68 -0
- package/page/dialog-add-agent.js +65 -0
- package/page/dialog-alert.js +159 -0
- package/page/dialog-archive.js +342 -0
- package/page/dialog-compare.js +238 -0
- package/page/dialog-ctxw.js +101 -0
- package/page/dialog-diag.js +72 -0
- package/page/dialog-heatmap.js +215 -0
- package/page/dialog-selftest.js +202 -0
- package/page/dialog-sess-timeline.js +108 -0
- package/page/dialog-stats.js +694 -0
- package/page/dialog-usage.js +158 -0
- package/page/log-card.js +277 -0
- package/page/log-view.js +273 -0
- package/page/sess-view.js +382 -0
- package/page/shared.js +408 -0
- package/page/sidebar.js +129 -0
- package/page/style.css +973 -0
- package/page/topbar.js +61 -0
- package/parsers/atomcode.mjs +321 -0
- package/parsers/buddy.mjs +272 -0
- package/parsers/buddyext.mjs +582 -0
- package/parsers/claude.mjs +496 -0
- package/parsers/cline.mjs +468 -0
- package/parsers/codearts.mjs +96 -0
- package/parsers/codex.mjs +188 -0
- package/parsers/comate.mjs +195 -0
- package/parsers/copilot.mjs +308 -0
- package/parsers/cursor.mjs +493 -0
- package/parsers/devindb.mjs +358 -0
- package/parsers/discovery.mjs +1230 -0
- package/parsers/doubao.mjs +406 -0
- package/parsers/dsh.mjs +377 -0
- package/parsers/gemini.mjs +267 -0
- package/parsers/generic.mjs +494 -0
- package/parsers/hermes.mjs +398 -0
- package/parsers/kilo.mjs +42 -0
- package/parsers/kimi.mjs +249 -0
- package/parsers/mimocode.mjs +531 -0
- package/parsers/minimax.mjs +503 -0
- package/parsers/openclaw.mjs +490 -0
- package/parsers/opencode.mjs +465 -0
- package/parsers/shared.mjs +418 -0
- package/parsers/trace.mjs +66 -0
- package/parsers/tracecode.mjs +348 -0
- package/parsers/traedb.mjs +528 -0
- package/parsers/zcode.mjs +356 -0
- package/plugin/client.js +51 -0
- package/plugin/cordis.patch.yml +5 -0
- package/plugin/plugin.mjs +220 -0
- package/search.mjs +554 -0
- package/tools/grab-trae-key.ps1 +265 -0
- package/vendor/element-plus-icons.js +3 -0
- package/vendor/element-plus.css +1 -0
- package/vendor/element-plus.dark.css +1 -0
- package/vendor/element-plus.full.min.js +65 -0
- package/vendor/element-plus.zh-cn.js +2 -0
- package/vendor/svg/antgroup-color.svg +1 -0
- package/vendor/svg/bytedance-color.svg +1 -0
- package/vendor/svg/chatglm-color.svg +1 -0
- package/vendor/svg/claude-color.svg +1 -0
- package/vendor/svg/claudecode-color.svg +1 -0
- package/vendor/svg/cline.svg +1 -0
- package/vendor/svg/codebuddy-color.svg +1 -0
- package/vendor/svg/codebuddy.svg +1 -0
- package/vendor/svg/codex-color.svg +1 -0
- package/vendor/svg/copilot.svg +1 -0
- package/vendor/svg/cursor.svg +1 -0
- package/vendor/svg/deepseek-color.svg +1 -0
- package/vendor/svg/deepseek-harness-whale.svg +8 -0
- package/vendor/svg/doubao-color.svg +1 -0
- package/vendor/svg/gemini-color.svg +1 -0
- package/vendor/svg/glmv-color.svg +1 -0
- package/vendor/svg/grok.svg +1 -0
- package/vendor/svg/hermesagent.svg +1 -0
- package/vendor/svg/huawei-color.svg +1 -0
- package/vendor/svg/hunyuan-color.svg +1 -0
- package/vendor/svg/kilocode-avatar.svg +1 -0
- package/vendor/svg/kilocode.svg +1 -0
- package/vendor/svg/kimi-color.svg +1 -0
- package/vendor/svg/kimi.svg +1 -0
- package/vendor/svg/logo-AtomGit-G-red.svg +3 -0
- package/vendor/svg/logo-AtomGit-dark.svg +4 -0
- package/vendor/svg/logo-AtomGit-light.svg +4 -0
- package/vendor/svg/meta-color.svg +1 -0
- package/vendor/svg/mimo.svg +66 -0
- package/vendor/svg/minimax-code-logo.svg +8 -0
- package/vendor/svg/minimax-color.svg +1 -0
- package/vendor/svg/moonshot.svg +1 -0
- package/vendor/svg/nex-color.svg +1 -0
- package/vendor/svg/nex.svg +1 -0
- package/vendor/svg/nvidia-color.svg +1 -0
- package/vendor/svg/openai.svg +1 -0
- package/vendor/svg/openclaw-color.svg +1 -0
- package/vendor/svg/openclaw.svg +1 -0
- package/vendor/svg/opencode.svg +1 -0
- package/vendor/svg/openrouter-color.svg +1 -0
- package/vendor/svg/qoder-color.svg +1 -0
- package/vendor/svg/qwen-color.svg +1 -0
- package/vendor/svg/sensenova-color.svg +1 -0
- package/vendor/svg/stepfun.svg +1 -0
- package/vendor/svg/trae-color.svg +1 -0
- package/vendor/svg/traework-v2.svg +1 -0
- package/vendor/svg/wenxin-color.svg +1 -0
- package/vendor/svg/windsurf.svg +1 -0
- package/vendor/svg/workbuddy-color.svg +29 -0
- package/vendor/svg/xiaomimimo.svg +1 -0
- package/vendor/svg/yuanbao-color.svg +1 -0
- package/vendor/svg/yuanbao.svg +1 -0
- package/vendor/svg/zai.svg +1 -0
- package/vendor/svg/zhipu-color.svg +1 -0
- package/vendor/vue.global.prod.js +9 -0
- package/widget/main.js +202 -0
- package/widget/package.json +7 -0
- package/widget/preload.js +11 -0
package/widget/main.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// AgentActa 悬浮卡片壳:一个无边框、透明、置顶的窗口,里面加载 agent-acta 服务的 /widget?float=1。
|
|
2
|
+
// 壳只管窗口形态(悬浮层皮),数据与页面逻辑全在服务端 agent-acta-widget.html —— 升级页面不用动壳。
|
|
3
|
+
// 由 `agentacta --client` 拉起(Electron 运行时首次使用时下载到 数据目录/widget-runtime/,不进包)。
|
|
4
|
+
const { app, BrowserWindow, ipcMain, screen, shell } = require('electron');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
const PORT = Number(process.env.AGENT_LOG_PORT || 14570);
|
|
10
|
+
const URL_WIDGET = `http://127.0.0.1:${PORT}/widget?float=1`;
|
|
11
|
+
const URL_PANEL = `http://127.0.0.1:${PORT}/`;
|
|
12
|
+
|
|
13
|
+
// 状态落在数据目录而不是包目录:全局安装的包目录不该被运行时写(只读部署/权限都说得通),
|
|
14
|
+
// 且升级包时状态天然留住。写坏了删掉这个文件,壳用默认值重来。
|
|
15
|
+
const DATA_DIR = process.env.AGENT_ACTA_DATA_DIR || path.join(os.homedir(), '.agent-acta');
|
|
16
|
+
const STATE_FILE = path.join(DATA_DIR, 'widget-state.json');
|
|
17
|
+
function loadState() {
|
|
18
|
+
try { return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')); } catch { return {}; }
|
|
19
|
+
}
|
|
20
|
+
const state = loadState();
|
|
21
|
+
|
|
22
|
+
// 单实例:重复 `agentacta --client` / 面板「悬浮卡片」按钮 = 聚焦已有窗口,不开第二个。
|
|
23
|
+
// 卡片关掉(✕)只是 hide:壳还在,这里把它 show 回来即可,不重建 —— 用户模型里卡片就是这个进程的
|
|
24
|
+
// 常驻形态,只有 --stop 才让壳退出(2026-09-21)。窗口真销毁过(历史路径)才走 create 兜底。
|
|
25
|
+
const gotLock = app.requestSingleInstanceLock();
|
|
26
|
+
if (!gotLock) app.quit();
|
|
27
|
+
else app.on('second-instance', () => {
|
|
28
|
+
if (!win || win.isDestroyed()) { create(); return; }
|
|
29
|
+
if (win.isMinimized()) win.restore();
|
|
30
|
+
win.show(); win.focus();
|
|
31
|
+
if (panel && !panel.isDestroyed()) { panel.show(); panel.focus(); }
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
let win = null;
|
|
35
|
+
// 水球模式的窗口尺寸 = 页面 CSS 的 --bs(球本体直径,现 88px)+ 24(四周各 12px 透明边给 CSS 圆形阴影落脚)。
|
|
36
|
+
// ⚠️ 两处必须一起改:只改页面的 --bs,窗口还是这个数,多出来的一圈透明区照样吞鼠标点击(透明区不穿透),
|
|
37
|
+
// 球看着偏在窗口中间、四周点不动。改这里要 npm pack + 全局重装才生效(跑的是全局那份拷贝,不是源码目录)。
|
|
38
|
+
const BALL_SIZE = 112;
|
|
39
|
+
|
|
40
|
+
// 把记住的位置夹回「现在还连着的屏」里。原来 create() 直接用 state.bounds 的 x/y、不夹 ——
|
|
41
|
+
// 拔一块屏或改过排列之后,窗口会开在谁都看不见的坐标上,而唯一的「✕」就在那个窗口里,等于自锁
|
|
42
|
+
// (本机实测:卡片位记成 x=-918,那是左边那块屏)。
|
|
43
|
+
// 两道判断:先按所有工作区的**并集外接矩形**夹一遍,再验「中心是否真落在某块屏上」—— 两屏高度不等时
|
|
44
|
+
// 并集的外接矩形会包含两屏之间那段空隙,只夹边界能夹出「在并集内、却不在任何屏上」的坐标。
|
|
45
|
+
function placeWithin(x, y, w, h) {
|
|
46
|
+
const areas = screen.getAllDisplays().map(d => d.workArea);
|
|
47
|
+
if (!areas.length) return { x, y };
|
|
48
|
+
const l = Math.min(...areas.map(a => a.x)), t = Math.min(...areas.map(a => a.y));
|
|
49
|
+
const r = Math.max(...areas.map(a => a.x + a.width)), bo = Math.max(...areas.map(a => a.y + a.height));
|
|
50
|
+
let nx = Math.max(l, Math.min(x, r - w)), ny = Math.max(t, Math.min(y, bo - h));
|
|
51
|
+
const cx = nx + w / 2, cy = ny + h / 2;
|
|
52
|
+
const onSome = areas.some(a => cx >= a.x && cx < a.x + a.width && cy >= a.y && cy < a.y + a.height);
|
|
53
|
+
if (!onSome) { // 落进空隙(或窗口比任何一块屏都大)→ 退回主屏右下角,也就是本来的开机位
|
|
54
|
+
const p = screen.getPrimaryDisplay().workArea;
|
|
55
|
+
nx = p.x + p.width - w - 24; ny = p.y + p.height - h - 24;
|
|
56
|
+
}
|
|
57
|
+
return { x: Math.round(nx), y: Math.round(ny) };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function create() {
|
|
61
|
+
const wa = screen.getPrimaryDisplay().workArea; // 避开任务栏
|
|
62
|
+
const b = state.bounds;
|
|
63
|
+
// 开机固定 324×404:对齐预览卡 300×380(窗口 = 内容 + 四周各 12px 透明留白),落主屏右下角。
|
|
64
|
+
// 尺寸不读存档(用户要求:运行中可以拖拉,重启一律回到这个宽高),只记住位置。
|
|
65
|
+
const defW = 324, defH = 404;
|
|
66
|
+
const cw = defW, ch = defH;
|
|
67
|
+
// 开机**一律开卡片**(2026-09-24 用户点名:`--client` 要打开的是悬浮卡片,不是水球)——
|
|
68
|
+
// 上次会话里随手点的那个 ○ 不该决定这次起来是什么形态。会话内的收放照旧(float-mode 那条 ipc)。
|
|
69
|
+
const pos = (b && b.x != null && b.y != null)
|
|
70
|
+
? placeWithin(b.x, b.y, cw, ch)
|
|
71
|
+
: { x: wa.x + wa.width - cw - 24, y: wa.y + wa.height - ch - 24 };
|
|
72
|
+
win = new BrowserWindow({
|
|
73
|
+
width: cw, height: ch,
|
|
74
|
+
x: pos.x, y: pos.y,
|
|
75
|
+
minWidth: 230, minHeight: 160, maxWidth: 640, maxHeight: 1200,
|
|
76
|
+
frame: false, // 无边框:标题栏消失,拖动由页面 header 的 app-region 负责
|
|
77
|
+
transparent: true, // 透明背景:圆角与阴影由页面 CSS 画
|
|
78
|
+
hasShadow: false, // ⚠️ 必须显式关:Win10 的 DWM 给透明窗画阴影按**窗口矩形**画,
|
|
79
|
+
// 水球底下会冒出一个正方形影子(2026-09-20 实测)——阴影让 CSS 自己画
|
|
80
|
+
resizable: true, minimizable: false, // 透明无边框窗没有系统拉边框,缩放走页面右下角的拖拽柄(float-resize)。
|
|
81
|
+
// 「缩小」= 收成水球(页面的 ○ 按钮),不做真最小化:
|
|
82
|
+
// skipTaskbar 的窗口最小化后没有入口能叫回来(本机踩过,2026-09-20)
|
|
83
|
+
alwaysOnTop: true, // 悬浮窗的本体
|
|
84
|
+
skipTaskbar: true, // 不占任务栏(托盘也不做 —— 关掉就是关掉)
|
|
85
|
+
backgroundColor: '#00000000',
|
|
86
|
+
webPreferences: {
|
|
87
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
88
|
+
contextIsolation: true,
|
|
89
|
+
nodeIntegration: false,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
win.setAlwaysOnTop(true, 'screen-saver'); // 层级拉高一点,压过普通置顶窗口
|
|
93
|
+
win.loadURL(URL_WIDGET); // 不带 &mode=ball:开机形态恒为卡片(球只是会话内的收放)
|
|
94
|
+
if (state.zoom) win.webContents.on('did-finish-load', () => win.webContents.setZoomFactor(state.zoom));
|
|
95
|
+
|
|
96
|
+
win.on('close', () => {
|
|
97
|
+
try {
|
|
98
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
99
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify({
|
|
100
|
+
bounds: win.getBounds(), zoom: win.webContents.getZoomFactor() || 1,
|
|
101
|
+
cardBounds: state.cardBounds || null,
|
|
102
|
+
}, null, 1));
|
|
103
|
+
} catch { /* 落盘失败下次用默认,不挡关窗 */ }
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 卡片 ⇄ 水球:窗口尺寸切换由壳做(页面拿不到窗口),位置锚定右下角 —— 用户把它摆在角落,
|
|
108
|
+
// 收放不该让角跑掉。卡片尺寸在切走前记住,切回来时还原。
|
|
109
|
+
ipcMain.on('float-mode', (e, mode) => {
|
|
110
|
+
if (!win) return;
|
|
111
|
+
const b = win.getBounds();
|
|
112
|
+
if (win.isVisible()) { // 切模式锚定右下角:藏在后台时别动它,show 回来还是原位
|
|
113
|
+
if (mode === 'ball') {
|
|
114
|
+
state.cardBounds = { width: b.width, height: b.height };
|
|
115
|
+
// 先降最小尺寸再缩窗:setBounds 会被 minWidth/minHeight 夹住(球比卡片下限小),
|
|
116
|
+
// 顺序反了球会飘在一个大一圈的透明窗里,那圈透明边照样挡下层的点击。
|
|
117
|
+
win.setMinimumSize(BALL_SIZE, BALL_SIZE);
|
|
118
|
+
// 卡片能被拖成右下角探出屏外(用户故意的「停半个在角落」):锚右下角收球会把球
|
|
119
|
+
// 直接放进屏外,再也点不到(2026-09-28 用户撞上)。收球同样夹回工作区 —— 卡片在屏内时
|
|
120
|
+
// placeWithin 是恒等,不影响「缩回卡片那个角」的落点。
|
|
121
|
+
const p = placeWithin(b.x + b.width - BALL_SIZE, b.y + b.height - BALL_SIZE, BALL_SIZE, BALL_SIZE);
|
|
122
|
+
win.setBounds({ x: p.x, y: p.y, width: BALL_SIZE, height: BALL_SIZE });
|
|
123
|
+
} else {
|
|
124
|
+
const c = state.cardBounds || { width: 324, height: 404 };
|
|
125
|
+
// 球能被拖到屏幕顶边/左边:锚右下角还原会让卡片顶(= 唯一拖柄所在的顶栏)探出屏外,
|
|
126
|
+
// 卡片就此拖不回来(2026-09-28 用户撞上:球贴顶边展开,卡片上半截在屏外)。
|
|
127
|
+
// 夹回工作区;球在屏内时 placeWithin 是恒等,不动「从球的位置长回来」的落点。
|
|
128
|
+
const p = placeWithin(b.x + b.width - c.width, b.y + b.height - c.height, c.width, c.height);
|
|
129
|
+
win.setBounds({ x: p.x, y: p.y, width: c.width, height: c.height });
|
|
130
|
+
win.setMinimumSize(230, 160); // 还原卡片模式的下限
|
|
131
|
+
}
|
|
132
|
+
} else if (mode === 'card') win.setMinimumSize(230, 160);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
ipcMain.on('float-hide', () => { if (win && !win.isDestroyed()) win.hide(); }); // 关卡片 = 隐藏,不销毁(再开只是 show)
|
|
136
|
+
ipcMain.on('float-close', () => { if (win) win.close(); });
|
|
137
|
+
// 注意:没有 float-minimize。skipTaskbar 的窗口真最小化 = 永远叫不回来;「缩小」就是收球(float-mode)
|
|
138
|
+
// 页面拖拽柄报的是「目标尺寸」(页面从拖动起点自己算好增量),这里只负责夹紧再 setSize
|
|
139
|
+
ipcMain.on('float-resize', (e, w, h) => {
|
|
140
|
+
if (!win) return;
|
|
141
|
+
w = Math.max(230, Math.min(640, Math.round(w)));
|
|
142
|
+
h = Math.max(160, Math.min(1200, Math.round(h)));
|
|
143
|
+
win.setSize(w, h);
|
|
144
|
+
});
|
|
145
|
+
// 水球拖动:球不设系统拖区(app-region:drag 在 Windows 会吞掉 click),页面按 pointer 增量报过来。
|
|
146
|
+
// 起点位置在 begin 时记一次 —— 直接每帧读 cursor 位置的另一条路要轮询,增量方案没有竞态。
|
|
147
|
+
let dragOrigin = null;
|
|
148
|
+
ipcMain.on('float-drag-begin', () => { if (win) dragOrigin = win.getBounds(); });
|
|
149
|
+
ipcMain.on('float-drag-by', (e, dx, dy) => {
|
|
150
|
+
if (win && dragOrigin) win.setPosition(dragOrigin.x + Math.round(dx), dragOrigin.y + Math.round(dy));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Ctrl+滚轮的内容缩放,clamp 在壳里 —— 页面只管报方向。
|
|
154
|
+
// 基准读 webContents 的实际值而不是本地变量:Chromium 会按 origin 自动记忆缩放(Preferences),
|
|
155
|
+
// 重启后实际值可能不是 1,本地变量从 1 起算会跟真实值错开一档。
|
|
156
|
+
ipcMain.on('float-zoom', (e, dir) => {
|
|
157
|
+
if (!win) return;
|
|
158
|
+
const cur = win.webContents.getZoomFactor() || 1;
|
|
159
|
+
const next = Math.max(0.6, Math.min(1.5, Math.round((cur + dir) * 10) / 10));
|
|
160
|
+
win.webContents.setZoomFactor(next);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// 完整面板:悬浮窗里点「面板 ↗」/球上的 ↗,开成**正经有框大窗**(1280×820 内自适应屏幕),
|
|
164
|
+
// 不是浏览器、也不是 Electron 默认那个 500×400 的憋屈弹窗。单例:再点就是聚焦,不开第二个。
|
|
165
|
+
let panel = null;
|
|
166
|
+
function openPanel() {
|
|
167
|
+
if (panel && !panel.isDestroyed()) { panel.show(); panel.focus(); return; }
|
|
168
|
+
const wa = screen.getPrimaryDisplay().workArea;
|
|
169
|
+
const w = Math.min(1280, wa.width - 80), h = Math.min(820, wa.height - 60);
|
|
170
|
+
panel = new BrowserWindow({
|
|
171
|
+
width: w, height: h,
|
|
172
|
+
x: wa.x + ((wa.width - w) >> 1), y: wa.y + ((wa.height - h) >> 1),
|
|
173
|
+
autoHideMenuBar: true, title: 'Agent 请求日志', backgroundColor: '#ffffff',
|
|
174
|
+
webPreferences: { contextIsolation: true, nodeIntegration: false }, // 无 preload:面板页不需要任何壳能力
|
|
175
|
+
});
|
|
176
|
+
panel.loadURL(URL_PANEL);
|
|
177
|
+
// setWindowOpenHandler 的 deny 还没返回就建窗,Chromium 的 popup 流程没收尾,
|
|
178
|
+
// 新窗可能停在不可见态(2026-09-21 实测:第一次点击后窗口存在但 vis=False)。创建路径上补一次显式 show/focus。
|
|
179
|
+
panel.show(); panel.focus();
|
|
180
|
+
panel.on('closed', () => { panel = null; });
|
|
181
|
+
}
|
|
182
|
+
// 页面里的 target=_blank / window.open 一律由壳接管:本服务的链接开成面板窗,外部链接去系统浏览器。
|
|
183
|
+
// 不拦的话 Electron 默认开一个又小又没菜单栏的弹窗(2026-09-20 用户撞上:面板挤得展不开)。
|
|
184
|
+
// ⚠️ 建窗动作必须 setImmediate 推迟到 handler 返回之后(Electron 文档口径,见 openPanel 里那条实测)。
|
|
185
|
+
app.on('web-contents-created', (e, wc) => {
|
|
186
|
+
wc.setWindowOpenHandler(({ url }) => {
|
|
187
|
+
if (url.startsWith('http://127.0.0.1:' + PORT) || url.startsWith('http://localhost:' + PORT)) setImmediate(openPanel);
|
|
188
|
+
else if (/^https?:/.test(url)) shell.openExternal(url);
|
|
189
|
+
return { action: 'deny' };
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// CDP 调试口:默认关。要量「真卡片」(读 computed style、看层叠到底落在哪一版皮肤)时显式开:
|
|
194
|
+
// AGENT_ACTA_WIDGET_DEBUG=9333 agentacta --client
|
|
195
|
+
// curl http://127.0.0.1:9333/json/list → 拿 webSocketDebuggerUrl(页面标题就是「Agent 实况」)
|
|
196
|
+
// 为什么不默认开:这个口能驱动页面,而页面能打到本地服务(/api/agents 写配置、/api/shutdown 停服务)——
|
|
197
|
+
// 只绑 127.0.0.1 也不是零风险。做成显式开关,随壳一起退出,不留常驻后门。
|
|
198
|
+
const DEBUG_PORT = Number(process.env.AGENT_ACTA_WIDGET_DEBUG) || 0;
|
|
199
|
+
if (DEBUG_PORT > 1024 && DEBUG_PORT < 65536) app.commandLine.appendSwitch('remote-debugging-port', String(DEBUG_PORT));
|
|
200
|
+
|
|
201
|
+
app.whenReady().then(create);
|
|
202
|
+
app.on('window-all-closed', () => app.quit());
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// 只暴露窗口动作给页面,页面拿不到任何 Node 能力
|
|
2
|
+
const { contextBridge, ipcRenderer } = require('electron');
|
|
3
|
+
contextBridge.exposeInMainWorld('floatApi', {
|
|
4
|
+
close: () => ipcRenderer.send('float-close'),
|
|
5
|
+
hide: () => ipcRenderer.send('float-hide'), // 关卡片 = 隐藏窗口(壳不退,位置/模式都保着)
|
|
6
|
+
resize: (w, h) => ipcRenderer.send('float-resize', w, h), // 右下角拖拽柄:目标尺寸
|
|
7
|
+
zoom: dir => ipcRenderer.send('float-zoom', dir), // Ctrl+滚轮:+0.1 / -0.1
|
|
8
|
+
setMode: mode => ipcRenderer.send('float-mode', mode), // 卡片 ⇄ 水球:窗口尺寸切换在壳里做
|
|
9
|
+
dragBegin: () => ipcRenderer.send('float-drag-begin'), // 水球拖动起点(壳记下当前位置)
|
|
10
|
+
dragBy: (dx, dy) => ipcRenderer.send('float-drag-by', dx, dy),
|
|
11
|
+
});
|