arona-agent 1.1.7 → 1.2.0

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/gui/main.cjs CHANGED
@@ -1,9 +1,20 @@
1
1
  // ARONA GUI Electron 主进程:单窗口,与 Node 后端父进程经 stdin/stdout JSON lines 通信
2
2
  // (协议行前缀 ###GUI### 过滤 Electron 日志;与桌宠桥同模式)。
3
- const { app, BrowserWindow, ipcMain, nativeImage } = require("electron");
3
+ const { app, BrowserWindow, Menu, ipcMain, nativeImage } = require("electron");
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
6
 
7
+ // Windows:GUI 是纯 HTML/CSS(无 WebGL),默认硬件加速下页面加载/脚本均正常但不 paint(白屏,
8
+ // 无 did-fail-load / render-process-gone / renderer 报错)——本机硬件 GPU 合成路径有问题,禁 GPU 走
9
+ // 软件渲染(桌宠同款已验证配置)。ARONA_GUI_GPU=1 可强制恢复硬件加速用于排障对比。
10
+ if (process.platform === "win32" && process.env.ARONA_GUI_GPU !== "1") {
11
+ app.commandLine.appendSwitch("disable-gpu");
12
+ }
13
+ // 桌宠(pet/main.cjs)与本 GUI 是两个 Electron 进程,默认共用 userData(%APPDATA%/arona-agent)会
14
+ // 竞争磁盘缓存锁(日志表现:Unable to move the cache 0x5 / Gpu Cache Creation failed / DIPS SQLite
15
+ // 初始化失败),ready 前按进程隔离。
16
+ app.setPath("userData", path.join(app.getPath("appData"), "arona-agent-gui"));
17
+
7
18
  const APP_TITLE = "Arona Agent";
8
19
  const ICON_PATH = path.join(__dirname, "renderer", "assets", "icon.png");
9
20
 
@@ -26,33 +37,44 @@ const pending = [];
26
37
 
27
38
  function forward(msg) {
28
39
  if (win && !win.isDestroyed() && rendererReady) {
40
+ if (VERBOSE) console.error("[gui:verbose] forward", msg.type);
29
41
  win.webContents.send("gui-event", msg);
30
42
  } else {
43
+ if (VERBOSE) console.error("[gui:verbose] buffer", msg.type, "(rendererReady=" + rendererReady + ")");
31
44
  pending.push(msg);
32
45
  }
33
46
  }
34
47
 
35
48
  function flushPending() {
36
49
  if (!win || win.isDestroyed()) return;
50
+ if (VERBOSE && pending.length) console.error("[gui:verbose] flush " + pending.length + " buffered events");
37
51
  while (pending.length) {
38
52
  win.webContents.send("gui-event", pending.shift());
39
53
  }
40
54
  }
41
55
 
42
- // ARONA_GUI_SMOKE=1:loadFile + flush 后探测 DOM(页面可见性 / preload / 渲染层脚本),
43
- // 结果打 SMOKE_RESULT 行后退出——冒烟验证 mode 事件不丢(无需人工看窗口)。
44
- // 另起 SMOKE_UI 探测(8s 后,等 startMain 就绪):欢迎页 LOGO / 浅色背景 / 斜杠菜单过滤 / 工具行样式。
45
- function smokeProbe(skipQuit) {
56
+ // ARONA_GUI_SMOKE=1:loadFile 后周期探测 DOM(每 2s,最长 30s)——页面可见性 / preload / 渲染层脚本,
57
+ // 结果打 SMOKE_RESULT 行;一旦有页面揭示(或超时)打 SMOKE_UI 详情后退出。
58
+ // 周期重试的原因:后端 startMain(initAgent 等)可能远超 8s,单次探测会把"启动慢"误判成"事件未送达"。
59
+ function smokeProbe() {
46
60
  const js = '(function(){var p=document.querySelectorAll(".page:not(.hidden)");'
47
61
  + 'return JSON.stringify({visible:p.length?p[0].id:null,'
48
62
  + 'api:!!(window.guiAPI&&window.guiAPI.send&&window.guiAPI.on),'
49
63
  + 'setup:!!(window.SetupUI&&window.SetupUI.handle)});})()';
50
- setTimeout(() => {
64
+ const started = Date.now();
65
+ const timer = setInterval(() => {
66
+ if (!win || win.isDestroyed()) { clearInterval(timer); return; }
51
67
  win.webContents.executeJavaScript(js)
52
68
  // stderr 会被 backend 转发到终端(stdout 被 ###GUI### 协议解析占用)
53
- .then((r) => { console.error("SMOKE_RESULT " + r); if (!skipQuit) app.quit(); })
54
- .catch((e) => { console.error("SMOKE_ERROR " + e); if (!skipQuit) app.quit(); });
55
- }, 300);
69
+ .then((r) => {
70
+ console.error("SMOKE_RESULT " + r);
71
+ if (JSON.parse(r).visible || Date.now() - started >= 30000) {
72
+ clearInterval(timer);
73
+ smokeProbeUI();
74
+ }
75
+ })
76
+ .catch((e) => { console.error("SMOKE_ERROR " + e); clearInterval(timer); smokeProbeUI(); });
77
+ }, 2000);
56
78
  }
57
79
 
58
80
  function smokeProbeUI() {
@@ -226,8 +248,10 @@ function createWindow() {
226
248
  minHeight: 480,
227
249
  title: APP_TITLE,
228
250
  backgroundColor: "#f6f7f9",
229
- titleBarStyle: "hiddenInset",
230
- trafficLightPosition: { x: 16, y: 16 },
251
+ // hiddenInset/trafficLightPosition 是 macOS 专用(Windows 忽略 titleBarStyle,标准边框 + 无菜单)
252
+ ...(process.platform === "darwin"
253
+ ? { titleBarStyle: "hiddenInset", trafficLightPosition: { x: 16, y: 16 } }
254
+ : {}),
231
255
  icon: ICON_PATH,
232
256
  webPreferences: {
233
257
  preload: path.join(__dirname, "preload.cjs"),
@@ -238,8 +262,9 @@ function createWindow() {
238
262
  // 先挂监听再 loadFile:避免加载完成事件在挂监听前触发导致 rendererReady 永不置位
239
263
  win.webContents.once("did-finish-load", () => {
240
264
  rendererReady = true;
265
+ if (VERBOSE) console.error("[gui:verbose] did-finish-load, pending=" + pending.length);
241
266
  flushPending();
242
- if (process.env.ARONA_GUI_SMOKE === "1") { smokeProbe(true); smokeProbeUI(); }
267
+ if (process.env.ARONA_GUI_SMOKE === "1") smokeProbe();
243
268
  if (process.env.ARONA_GUI_DEMO === "1") setTimeout(demoScenario, 2000);
244
269
  });
245
270
  win.loadFile(path.join(__dirname, "renderer", "index.html"));
@@ -247,6 +272,16 @@ function createWindow() {
247
272
  win.webContents.on("did-fail-load", (_e, code, desc, url) => {
248
273
  console.error(`[gui] did-fail-load ${code} ${desc} ${url}`);
249
274
  });
275
+ // renderer console → stderr:GUI 白屏等"进程活着但无画面"问题时可见。error 级无条件转发,
276
+ // 其余仅 VERBOSE(Electron 43 规范签名为单事件对象 event.{message,level,lineNumber},与桌宠同)
277
+ win.webContents.on("console-message", (event) => {
278
+ const msg = typeof event.message === "string" ? event.message : "";
279
+ if (!msg) return;
280
+ if (VERBOSE || event.level === 3) {
281
+ const line = event.lineNumber ? `:${event.lineNumber}` : "";
282
+ console.error(`[gui:render:${event.level ?? "?"}]${line} ${msg}`);
283
+ }
284
+ });
250
285
  if (VERBOSE) win.webContents.openDevTools({ mode: "detach" });
251
286
  }
252
287
 
@@ -279,11 +314,23 @@ app.on("window-all-closed", () => {
279
314
  });
280
315
 
281
316
  app.whenReady().then(() => {
317
+ // Windows 上默认应用菜单(File/Edit/View/Window)画进窗口顶部,GUI 用不到 → 移除
318
+ //(须在 ready 后调用;Ctrl+C/V 等编辑快捷键是原生行为不受影响,仅去掉 Reload/DevTools 默认键)
319
+ if (process.platform === "win32") Menu.setApplicationMenu(null);
282
320
  // macOS 开发模式下 Dock 图标默认是 Electron 图标,用 LOGO 替换(打包后由应用 bundle 提供)
283
321
  if (process.platform === "darwin" && app.dock) {
284
322
  const icon = nativeImage.createFromPath(ICON_PATH);
285
323
  if (!icon.isEmpty()) app.dock.setIcon(icon);
286
324
  }
325
+ if (VERBOSE) {
326
+ // GPU 功能状态:Windows 白屏排查关键(disable-gpu 下预期 gpu_compositing=disabled_software 且可正常上屏)
327
+ try {
328
+ console.error("[gui:verbose] GPU feature status:", JSON.stringify(app.getGPUFeatureStatus()));
329
+ } catch (e) {
330
+ console.error("[gui:verbose] getGPUFeatureStatus failed:", e.message);
331
+ }
332
+ console.error("[gui:verbose] platform:", process.platform, "electron:", process.versions.electron, "chrome:", process.versions.chrome);
333
+ }
287
334
  createWindow();
288
335
  });
289
336
 
@@ -1,5 +1,15 @@
1
1
  // ARONA GUI 渲染层主逻辑:###GUI### 协议 → DOM(侧栏会话列表 / 斜杠菜单 / 消息流 / 麦克风 / 弹窗)
2
+ // 全局错误陷阱:未捕获异常打进 console.error(经 main.cjs 以 [gui:render:3] 转发终端)——
3
+ // 定位"页面加载正常但 .page 保持 hidden → 白屏"时 app.js 中途崩溃的情况
4
+ window.addEventListener("error", (e) => {
5
+ console.error("[app.js] window error:", e.message, e.filename + ":" + e.lineno);
6
+ });
7
+ window.addEventListener("unhandledrejection", (e) => {
8
+ console.error("[app.js] unhandled rejection:", e.reason);
9
+ });
10
+
2
11
  (function () {
12
+ console.log("[app.js] boot");
3
13
  const $ = (sel) => document.querySelector(sel);
4
14
  const api = window.guiAPI;
5
15
  const chat = $("#chat");
@@ -1166,6 +1176,7 @@
1166
1176
 
1167
1177
  // ── 协议分发 ──────────────────────────────────
1168
1178
  api.on((msg) => {
1179
+ if (msg.type === "mode") console.log("[app.js] mode ->", msg.mode); // 白屏排查:确认事件到达渲染层
1169
1180
  switch (msg.type) {
1170
1181
  case "mode":
1171
1182
  $("#main-page").classList.toggle("hidden", msg.mode !== "main");
@@ -1227,4 +1238,5 @@
1227
1238
  });
1228
1239
 
1229
1240
  updateSendState(); // 初始为空输入:发送按钮置灰
1241
+ console.log("[app.js] listener ready"); // 白屏排查:走到此处 = app.js 完整执行、api.on 已注册
1230
1242
  })();
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "arona-agent",
3
- "version": "1.1.7",
3
+ "version": "1.2.0",
4
4
  "description": "Terminal AI Agent with desktop pet Arona — eye-tracking pupils, voice cloning, Computer Use, TTS/STT, MCP.",
5
- "keywords": ["voice-clone", "Blue Archive", "blue-archive", "ai-agent", "arona", "computer-use", "desktop-pet"],
5
+ "keywords": [
6
+ "voice-clone",
7
+ "Blue Archive",
8
+ "blue-archive",
9
+ "ai-agent",
10
+ "arona",
11
+ "computer-use",
12
+ "desktop-pet"
13
+ ],
6
14
  "license": "MIT",
7
15
  "type": "module",
8
16
  "bin": {
package/pet/main.cjs CHANGED
@@ -8,6 +8,11 @@ const fs = require("fs");
8
8
  const os = require("os");
9
9
  const { AGENTS } = require("./agents.cjs");
10
10
 
11
+ // 与 GUI(gui/main.cjs)是两个 Electron 进程:默认共用 userData(%APPDATA%/arona-agent)会竞争磁盘
12
+ // 缓存锁(Windows 日志表现:Unable to move the cache 0x5 / Gpu Cache Creation failed / DIPS SQLite
13
+ // 初始化失败),ready 前按进程隔离。
14
+ app.setPath("userData", path.join(app.getPath("appData"), "arona-agent-pet"));
15
+
11
16
  // Windows 透明无边框窗口在部分显卡驱动下会触发渲染进程崩溃;禁 GPU 硬件加速(须在 app ready 前调用)。
12
17
  // 注意:不能用 app.disableHardwareAcceleration()——Electron 43 里它会顺带 --disable-software-rasterizer,
13
18
  // 把软件 WebGL 一并堵死(实测 getGPUFeatureStatus().webgl === "disabled_off",Spine 直接白屏)。
package/src/gui/index.ts CHANGED
@@ -23,6 +23,7 @@ class GuiBridge {
23
23
  private exited = false;
24
24
 
25
25
  emit(ev: GuiEvent): void {
26
+ if (verbose) console.error(chalk.gray("[gui:verbose]"), "emit", ev.type); // 白屏排查:后端→GUI 事件流向
26
27
  if (!this.proc || this.proc.killed) return;
27
28
  try {
28
29
  this.proc.stdin.write(formatGuiLine(ev));
@@ -41,7 +42,14 @@ class GuiBridge {
41
42
  const env: NodeJS.ProcessEnv = { ...process.env, ARONA_GUI: "1" };
42
43
  delete env.ELECTRON_RUN_AS_NODE;
43
44
  const args = ["--no-sandbox"];
44
- if (verbose) args.push("--enable-logging");
45
+ if (verbose) {
46
+ // --enable-logging:渲染进程 console(GPU 初始化失败等)原样打进 stderr,白屏根因不传则完全不可见;
47
+ // ARONA_GUI_VERBOSE:接通 gui/main.cjs 的 VERBOSE 分支(GPU feature status / renderer console
48
+ // 全量转发 / devtools 自动打开)——此前未接线,--verbose 下这些诊断从未生效过。
49
+ args.push("--enable-logging");
50
+ env.ARONA_GUI_VERBOSE = "1";
51
+ console.error(chalk.gray("[gui:verbose]"), "spawn", electronPath, args.concat(join(GUI_DIR, "main.cjs")).join(" "));
52
+ }
45
53
 
46
54
  this.proc = spawn(electronPath, args.concat(join(GUI_DIR, "main.cjs")), {
47
55
  env,