feat: 巡检增强 / 拓扑大屏 / 远程 HTTP / portable 绿色打包
Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled

巡检模块:巡检调度器改为轮询驱动,新增每日报告存储、告警规则独立
Store、设备 Store 解耦,_executeSnapshot 补齐 DEBUG 声明,巡检中心
与告警中心页增强。

拓扑大屏:MonitoringTopologyView 扩展分组/布局控制,
useMonitoringData 重构数据流。

远程 HTTP:新增 electron/remoteHttpServer.cjs,preload/api.cjs 暴露
IPC,registerBridges 注册 netcatty:http:open 桥。

portable 绿色打包:
- electron-builder.config.cjs 恢复原始白名单(61MB app.asar),
  收集器自动追踪运行时依赖;
- portableData.cjs 重写为 .portable 标记检测;
- scripts/migratePortableLocalStorage.cjs 离线脚本把 Local Storage
  的 http://localhost:5173 origin 批量迁移为 app://netcatty;
- scripts/scanWorkspaceDeps.cjs 扫描 workspace 运行时依赖。
This commit is contained in:
2026-10-19 21:11:57 +08:00
committed by trae-solo-agent
parent 336c3afd47
commit 2e71e03d71
34 changed files with 3012 additions and 230 deletions

View File

@@ -33,7 +33,8 @@ class InspectionScheduler {
* @param {function} options.readFn - 读取存储 (key) => string
* @param {function} options.writeFn - 写入存储 (key, value) => void
* @param {function} options.getConnectionFn - 获取 SSH 连接 (hostId) => connection 或 null
* @param {function} options.execFn - 执行命令 (hostId, command) => Promise<string>
* @param {function} options.execFn - 执行单条命令 (hostId, command) => Promise<string>
* @param {function} [options.execCommandsFn] - 批量执行多条命令 (hostId, commands) => Promise<{ results, stdout }>
* @param {function} [options.onResult] - 单设备巡检完成回调
* @param {number} [options.pollIntervalMs] - 轮询间隔
* @param {number} [options.concurrency] - 并发数
@@ -44,6 +45,7 @@ class InspectionScheduler {
this.writeFn = options.writeFn;
this.getConnectionFn = options.getConnectionFn;
this.execFn = options.execFn;
this.execCommandsFn = options.execCommandsFn;
this.onResult = options.onResult || (() => {});
this.onAlertChanged = options.onAlertChanged || (() => {});
this.pollIntervalMs = options.pollIntervalMs || DEFAULT_POLL_INTERVAL_MS;
@@ -93,6 +95,13 @@ class InspectionScheduler {
if (!this._running) return;
try {
// 全局自动巡检开关(一键启用/停止)
const autoEnabledRaw = this.readFn("inspection-auto-enabled");
const autoEnabled = autoEnabledRaw !== "false"; // 默认 true
if (!autoEnabled) {
return; // 全局停止 —— 跳过本次 tick
}
// 1. 获取所有启用巡检的设备
const devices = deviceStore.getEnabledDevices(this.readFn);
@@ -149,6 +158,8 @@ class InspectionScheduler {
}
// 2. 创建采集器
// connectionInfo 只传 { host: hostId } 作为标识——adapter 的 execCommands 会被 options.execCommands 覆盖,
// 真正的 SSH 凭据由主进程 execCommandsFn 从 _hostConfigs 读取(和 execFn 同理)
const adapter = adapterRegistry.createAdapter(
catalog.adapter_class,
{ host: hostId },
@@ -157,6 +168,11 @@ class InspectionScheduler {
if (!this.execFn) throw new Error("execFn 未配置");
return this.execFn(hostId, cmd);
},
execCommands: this.execCommandsFn
? async (commands, options) => {
return this.execCommandsFn(hostId, commands, options);
}
: undefined,
timeoutMs: this.timeoutMs,
}
);
@@ -281,10 +297,8 @@ class InspectionScheduler {
console.log(`[InspectionScheduler] 告警评估 device=${deviceName}(${deviceExt.host_id}) online=${metrics.online} 规则数=${rules.length}`);
for (const rule of rules) {
// 特殊处理:online 指标
if (rule.metric === "online") {
const isOnline = metrics.online !== false;
// threshold 为 "false" 表示离线时告警
const shouldAlert = rule.threshold === "false" ? !isOnline : isOnline;
console.log(`[InspectionScheduler] 离线规则: name=${rule.name} enabled=${rule.enabled} threshold=${rule.threshold} isOnline=${isOnline} shouldAlert=${shouldAlert}`);
const alertResult = alertRecordStore.processAlert(
@@ -308,8 +322,8 @@ class InspectionScheduler {
const isTriggered = alertRuleStore.evaluateRule(value, rule.operator, rule.threshold);
const hostInfo = this._hostInfo[deviceExt.host_id] || {};
const deviceName = hostInfo.label || hostInfo.hostname || deviceExt.host_id;
// 注意:hostInfo / deviceName 在函数顶部 L285-286 已声明,此处直接复用,
// 避免同名 const 重复声明导致 TDZ(Cannot access 'deviceName' before initialization)
const alertResult = alertRecordStore.processAlert(
this.readFn,
this.writeFn,