@aiscene/aiserver 1.0.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/dist/api/callback.d.ts +7 -0
- package/dist/api/callback.d.ts.map +1 -0
- package/dist/api/callback.js +116 -0
- package/dist/api/callback.js.map +1 -0
- package/dist/api/device-api.d.ts +13 -0
- package/dist/api/device-api.d.ts.map +1 -0
- package/dist/api/device-api.js +98 -0
- package/dist/api/device-api.js.map +1 -0
- package/dist/api/task-api.d.ts +9 -0
- package/dist/api/task-api.d.ts.map +1 -0
- package/dist/api/task-api.js +47 -0
- package/dist/api/task-api.js.map +1 -0
- package/dist/config/cli.d.ts +30 -0
- package/dist/config/cli.d.ts.map +1 -0
- package/dist/config/cli.js +129 -0
- package/dist/config/cli.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +142 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +66 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +2 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/event-bus.d.ts +14 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +33 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/logger.d.ts +24 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +52 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/types.d.ts +134 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/debug/dump-manager.d.ts +10 -0
- package/dist/debug/dump-manager.d.ts.map +1 -0
- package/dist/debug/dump-manager.js +52 -0
- package/dist/debug/dump-manager.js.map +1 -0
- package/dist/debug/screencast.d.ts +11 -0
- package/dist/debug/screencast.d.ts.map +1 -0
- package/dist/debug/screencast.js +88 -0
- package/dist/debug/screencast.js.map +1 -0
- package/dist/debug/session-manager.d.ts +14 -0
- package/dist/debug/session-manager.d.ts.map +1 -0
- package/dist/debug/session-manager.js +76 -0
- package/dist/debug/session-manager.js.map +1 -0
- package/dist/debug/types.d.ts +76 -0
- package/dist/debug/types.d.ts.map +1 -0
- package/dist/debug/types.js +2 -0
- package/dist/debug/types.js.map +1 -0
- package/dist/debug/web-screencast.d.ts +60 -0
- package/dist/debug/web-screencast.d.ts.map +1 -0
- package/dist/debug/web-screencast.js +146 -0
- package/dist/debug/web-screencast.js.map +1 -0
- package/dist/debug/websocket-server.d.ts +27 -0
- package/dist/debug/websocket-server.d.ts.map +1 -0
- package/dist/debug/websocket-server.js +681 -0
- package/dist/debug/websocket-server.js.map +1 -0
- package/dist/device/detector.d.ts +10 -0
- package/dist/device/detector.d.ts.map +1 -0
- package/dist/device/detector.js +100 -0
- package/dist/device/detector.js.map +1 -0
- package/dist/device/heartbeat.d.ts +26 -0
- package/dist/device/heartbeat.d.ts.map +1 -0
- package/dist/device/heartbeat.js +225 -0
- package/dist/device/heartbeat.js.map +1 -0
- package/dist/device/status-manager.d.ts +15 -0
- package/dist/device/status-manager.d.ts.map +1 -0
- package/dist/device/status-manager.js +58 -0
- package/dist/device/status-manager.js.map +1 -0
- package/dist/device/types.d.ts +30 -0
- package/dist/device/types.d.ts.map +1 -0
- package/dist/device/types.js +2 -0
- package/dist/device/types.js.map +1 -0
- package/dist/executor/action-executor.d.ts +25 -0
- package/dist/executor/action-executor.d.ts.map +1 -0
- package/dist/executor/action-executor.js +261 -0
- package/dist/executor/action-executor.js.map +1 -0
- package/dist/executor/android-executor.d.ts +12 -0
- package/dist/executor/android-executor.d.ts.map +1 -0
- package/dist/executor/android-executor.js +127 -0
- package/dist/executor/android-executor.js.map +1 -0
- package/dist/executor/base.d.ts +20 -0
- package/dist/executor/base.d.ts.map +1 -0
- package/dist/executor/base.js +91 -0
- package/dist/executor/base.js.map +1 -0
- package/dist/executor/cli-executor.d.ts +12 -0
- package/dist/executor/cli-executor.d.ts.map +1 -0
- package/dist/executor/cli-executor.js +94 -0
- package/dist/executor/cli-executor.js.map +1 -0
- package/dist/executor/code-executor.d.ts +13 -0
- package/dist/executor/code-executor.d.ts.map +1 -0
- package/dist/executor/code-executor.js +52 -0
- package/dist/executor/code-executor.js.map +1 -0
- package/dist/executor/code-instrument.d.ts +12 -0
- package/dist/executor/code-instrument.d.ts.map +1 -0
- package/dist/executor/code-instrument.js +116 -0
- package/dist/executor/code-instrument.js.map +1 -0
- package/dist/executor/executor-factory.d.ts +7 -0
- package/dist/executor/executor-factory.d.ts.map +1 -0
- package/dist/executor/executor-factory.js +24 -0
- package/dist/executor/executor-factory.js.map +1 -0
- package/dist/executor/ios-executor.d.ts +10 -0
- package/dist/executor/ios-executor.d.ts.map +1 -0
- package/dist/executor/ios-executor.js +91 -0
- package/dist/executor/ios-executor.js.map +1 -0
- package/dist/executor/types.d.ts +14 -0
- package/dist/executor/types.d.ts.map +1 -0
- package/dist/executor/types.js +2 -0
- package/dist/executor/types.js.map +1 -0
- package/dist/executor/worker-entry.d.ts +2 -0
- package/dist/executor/worker-entry.d.ts.map +1 -0
- package/dist/executor/worker-entry.js +61 -0
- package/dist/executor/worker-entry.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -0
- package/dist/node/service.d.ts +21 -0
- package/dist/node/service.d.ts.map +1 -0
- package/dist/node/service.js +178 -0
- package/dist/node/service.js.map +1 -0
- package/dist/node/types.d.ts +45 -0
- package/dist/node/types.d.ts.map +1 -0
- package/dist/node/types.js +3 -0
- package/dist/node/types.js.map +1 -0
- package/dist/storage/database.d.ts +6 -0
- package/dist/storage/database.d.ts.map +1 -0
- package/dist/storage/database.js +154 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/repositories/debug-log-repo.d.ts +29 -0
- package/dist/storage/repositories/debug-log-repo.d.ts.map +1 -0
- package/dist/storage/repositories/debug-log-repo.js +90 -0
- package/dist/storage/repositories/debug-log-repo.js.map +1 -0
- package/dist/storage/repositories/device-repo.d.ts +12 -0
- package/dist/storage/repositories/device-repo.d.ts.map +1 -0
- package/dist/storage/repositories/device-repo.js +87 -0
- package/dist/storage/repositories/device-repo.js.map +1 -0
- package/dist/storage/repositories/execution-log-repo.d.ts +9 -0
- package/dist/storage/repositories/execution-log-repo.d.ts.map +1 -0
- package/dist/storage/repositories/execution-log-repo.js +49 -0
- package/dist/storage/repositories/execution-log-repo.js.map +1 -0
- package/dist/storage/repositories/task-repo.d.ts +13 -0
- package/dist/storage/repositories/task-repo.d.ts.map +1 -0
- package/dist/storage/repositories/task-repo.js +109 -0
- package/dist/storage/repositories/task-repo.js.map +1 -0
- package/dist/task/poller.d.ts +25 -0
- package/dist/task/poller.d.ts.map +1 -0
- package/dist/task/poller.js +153 -0
- package/dist/task/poller.js.map +1 -0
- package/dist/task/queue.d.ts +13 -0
- package/dist/task/queue.d.ts.map +1 -0
- package/dist/task/queue.js +38 -0
- package/dist/task/queue.js.map +1 -0
- package/dist/task/scheduler.d.ts +25 -0
- package/dist/task/scheduler.d.ts.map +1 -0
- package/dist/task/scheduler.js +274 -0
- package/dist/task/scheduler.js.map +1 -0
- package/dist/task/types.d.ts +31 -0
- package/dist/task/types.d.ts.map +1 -0
- package/dist/task/types.js +37 -0
- package/dist/task/types.js.map +1 -0
- package/dist/web/server.d.ts +14 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +478 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createLogger } from '../core/logger.js';
|
|
4
|
+
import { deviceRepo } from '../storage/repositories/device-repo.js';
|
|
5
|
+
import { taskRepo } from '../storage/repositories/task-repo.js';
|
|
6
|
+
import { debugLogRepo } from '../storage/repositories/debug-log-repo.js';
|
|
7
|
+
import { executionLogRepo } from '../storage/repositories/execution-log-repo.js';
|
|
8
|
+
const logger = createLogger('WebServer');
|
|
9
|
+
export class WebServer {
|
|
10
|
+
app;
|
|
11
|
+
config;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.app = express();
|
|
14
|
+
this.setupMiddleware();
|
|
15
|
+
this.setupApiRoutes();
|
|
16
|
+
this.setupStaticFiles();
|
|
17
|
+
}
|
|
18
|
+
setupMiddleware() {
|
|
19
|
+
this.app.use(express.json());
|
|
20
|
+
this.app.use((_, res, next) => {
|
|
21
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
22
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
23
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
24
|
+
next();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
setupApiRoutes() {
|
|
28
|
+
const api = express.Router();
|
|
29
|
+
// ===== Dashboard =====
|
|
30
|
+
api.get('/dashboard', (_, res) => {
|
|
31
|
+
const devices = deviceRepo.getAll();
|
|
32
|
+
const onlineDevices = devices.filter(d => d.status === 'online').length;
|
|
33
|
+
const recentTasks = taskRepo.getAll(10);
|
|
34
|
+
const runningTasks = taskRepo.getRunningTasks().length;
|
|
35
|
+
const debugSessions = debugLogRepo.getAllSessions(20);
|
|
36
|
+
res.json({
|
|
37
|
+
devices: { total: devices.length, online: onlineDevices, list: devices },
|
|
38
|
+
tasks: {
|
|
39
|
+
running: runningTasks,
|
|
40
|
+
total: taskRepo.count(),
|
|
41
|
+
recent: recentTasks,
|
|
42
|
+
},
|
|
43
|
+
debugSessions,
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
// ===== Devices =====
|
|
47
|
+
api.get('/devices', (_, res) => {
|
|
48
|
+
res.json(deviceRepo.getAll());
|
|
49
|
+
});
|
|
50
|
+
api.get('/devices/online', (_, res) => {
|
|
51
|
+
res.json(deviceRepo.getOnline());
|
|
52
|
+
});
|
|
53
|
+
// ===== Tasks =====
|
|
54
|
+
api.get('/tasks', (req, res) => {
|
|
55
|
+
const limit = parseInt(req.query.limit) || 100;
|
|
56
|
+
const offset = parseInt(req.query.offset) || 0;
|
|
57
|
+
const status = req.query.status;
|
|
58
|
+
if (status) {
|
|
59
|
+
res.json(taskRepo.getByStatus(status));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
res.json(taskRepo.getAll(limit, offset));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
api.get('/tasks/count', (_, res) => {
|
|
66
|
+
res.json({ count: taskRepo.count() });
|
|
67
|
+
});
|
|
68
|
+
api.get('/tasks/:taskId', (req, res) => {
|
|
69
|
+
const task = taskRepo.getById(req.params.taskId);
|
|
70
|
+
if (task) {
|
|
71
|
+
res.json(task);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
res.status(404).json({ error: 'Task not found' });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
api.get('/tasks/:taskId/logs', (req, res) => {
|
|
78
|
+
const limit = parseInt(req.query.limit) || 1000;
|
|
79
|
+
res.json(executionLogRepo.getByTaskId(req.params.taskId, limit));
|
|
80
|
+
});
|
|
81
|
+
// ===== Debug Sessions =====
|
|
82
|
+
api.get('/debug/sessions', (_, res) => {
|
|
83
|
+
res.json(debugLogRepo.getAllSessions());
|
|
84
|
+
});
|
|
85
|
+
api.get('/debug/sessions/:sessionId', (req, res) => {
|
|
86
|
+
const session = debugLogRepo.getSession(req.params.sessionId);
|
|
87
|
+
if (session) {
|
|
88
|
+
res.json(session);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
res.status(404).json({ error: 'Session not found' });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
api.get('/debug/sessions/:sessionId/logs', (req, res) => {
|
|
95
|
+
const limit = parseInt(req.query.limit) || 1000;
|
|
96
|
+
res.json(debugLogRepo.getLogsBySession(req.params.sessionId, limit));
|
|
97
|
+
});
|
|
98
|
+
this.app.use('/api', api);
|
|
99
|
+
}
|
|
100
|
+
setupStaticFiles() {
|
|
101
|
+
const distPath = path.resolve(import.meta.dirname, 'dist');
|
|
102
|
+
this.app.use(express.static(distPath));
|
|
103
|
+
this.app.get('*', (_, res) => {
|
|
104
|
+
res.sendFile(path.join(distPath, 'index.html'), (err) => {
|
|
105
|
+
if (err) {
|
|
106
|
+
res.status(200).send(this.getFallbackHtml());
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
getFallbackHtml() {
|
|
112
|
+
return `<!DOCTYPE html>
|
|
113
|
+
<html lang="zh-CN">
|
|
114
|
+
<head>
|
|
115
|
+
<meta charset="UTF-8">
|
|
116
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
117
|
+
<title>AIServer Dashboard</title>
|
|
118
|
+
<style>
|
|
119
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
120
|
+
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0f172a;color:#e2e8f0;min-height:100vh}
|
|
121
|
+
.container{max-width:1400px;margin:0 auto;padding:20px}
|
|
122
|
+
.header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}
|
|
123
|
+
.header h1{font-size:24px;color:#38bdf8}
|
|
124
|
+
.tabs{display:flex;gap:4px;background:#1e293b;border-radius:8px;padding:4px;margin-bottom:24px}
|
|
125
|
+
.tab{padding:8px 20px;border-radius:6px;cursor:pointer;font-size:14px;font-weight:500;color:#94a3b8;border:none;background:none;transition:all .2s}
|
|
126
|
+
.tab.active{background:#38bdf8;color:#0f172a}
|
|
127
|
+
.tab:hover:not(.active){color:#e2e8f0}
|
|
128
|
+
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin-bottom:24px}
|
|
129
|
+
.card{background:#1e293b;border-radius:8px;padding:20px;border:1px solid #334155}
|
|
130
|
+
.card h3{font-size:13px;color:#94a3b8;margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}
|
|
131
|
+
.card .value{font-size:32px;font-weight:700;color:#38bdf8}
|
|
132
|
+
.card .sub{font-size:12px;color:#64748b;margin-top:4px}
|
|
133
|
+
table{width:100%;border-collapse:collapse;margin-top:8px}
|
|
134
|
+
th,td{text-align:left;padding:10px 14px;border-bottom:1px solid #1e293b;font-size:13px}
|
|
135
|
+
th{color:#94a3b8;font-size:11px;text-transform:uppercase;letter-spacing:.5px;background:#0f172a;position:sticky;top:0}
|
|
136
|
+
tr:hover{background:#1e293b}
|
|
137
|
+
.badge{display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600}
|
|
138
|
+
.b-online{background:#166534;color:#22c55e}
|
|
139
|
+
.b-offline{background:#7f1d1d;color:#ef4444}
|
|
140
|
+
.b-running{background:#713f12;color:#f59e0b}
|
|
141
|
+
.b-completed{background:#166534;color:#22c55e}
|
|
142
|
+
.b-failed{background:#7f1d1d;color:#ef4444}
|
|
143
|
+
.b-pending{background:#1e3a5f;color:#38bdf8}
|
|
144
|
+
.b-idle{background:#334155;color:#94a3b8}
|
|
145
|
+
.b-stopped{background:#334155;color:#94a3b8}
|
|
146
|
+
.btn{padding:6px 14px;border-radius:6px;border:none;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s}
|
|
147
|
+
.btn-primary{background:#38bdf8;color:#0f172a}
|
|
148
|
+
.btn-primary:hover{background:#7dd3fc}
|
|
149
|
+
.btn-sm{padding:4px 10px;font-size:11px}
|
|
150
|
+
.section-title{font-size:16px;font-weight:600;color:#e2e8f0;margin:20px 0 12px;display:flex;align-items:center;gap:8px}
|
|
151
|
+
.mono{font-family:'SF Mono',Monaco,Consolas,monospace;font-size:12px}
|
|
152
|
+
.log-viewer{background:#0c0f1a;border:1px solid #334155;border-radius:8px;padding:16px;max-height:600px;overflow-y:auto;font-family:'SF Mono',Monaco,Consolas,monospace;font-size:12px;line-height:1.6}
|
|
153
|
+
.log-viewer .log-line{padding:2px 0;border-bottom:1px solid #1e293b20}
|
|
154
|
+
.log-viewer .log-line:hover{background:#1e293b40}
|
|
155
|
+
.log-time{color:#64748b;margin-right:8px}
|
|
156
|
+
.log-level-info{color:#38bdf8}
|
|
157
|
+
.log-level-warn{color:#f59e0b}
|
|
158
|
+
.log-level-error{color:#ef4444}
|
|
159
|
+
.log-level-debug{color:#94a3b8}
|
|
160
|
+
.log-content{color:#cbd5e1}
|
|
161
|
+
.detail-panel{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;margin-top:16px}
|
|
162
|
+
.detail-row{display:flex;padding:8px 0;border-bottom:1px solid #33415520}
|
|
163
|
+
.detail-label{width:140px;color:#94a3b8;font-size:13px;flex-shrink:0}
|
|
164
|
+
.detail-value{color:#e2e8f0;font-size:13px;word-break:break-all}
|
|
165
|
+
.empty-state{text-align:center;padding:60px 20px;color:#64748b}
|
|
166
|
+
.empty-state .icon{font-size:48px;margin-bottom:16px}
|
|
167
|
+
.refresh-bar{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
168
|
+
.refresh-bar .auto{font-size:12px;color:#64748b}
|
|
169
|
+
.refresh-bar .auto.on{color:#22c55e}
|
|
170
|
+
.search{background:#1e293b;border:1px solid #334155;border-radius:6px;padding:8px 14px;color:#e2e8f0;font-size:13px;width:220px}
|
|
171
|
+
.search:focus{outline:none;border-color:#38bdf8}
|
|
172
|
+
.collapsed{display:none}
|
|
173
|
+
</style>
|
|
174
|
+
</head>
|
|
175
|
+
<body>
|
|
176
|
+
<div class="container">
|
|
177
|
+
<div class="header">
|
|
178
|
+
<h1>AIServer Dashboard</h1>
|
|
179
|
+
<div class="refresh-bar">
|
|
180
|
+
<span class="auto" id="autoLabel">Auto-refresh: ON</span>
|
|
181
|
+
<button class="btn btn-primary" onclick="refresh()">Refresh</button>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
<div class="tabs">
|
|
185
|
+
<button class="tab active" onclick="switchTab('dashboard')">Dashboard</button>
|
|
186
|
+
<button class="tab" onclick="switchTab('devices')">Devices</button>
|
|
187
|
+
<button class="tab" onclick="switchTab('tasks')">Tasks</button>
|
|
188
|
+
<button class="tab" onclick="switchTab('debug')">Debug Sessions</button>
|
|
189
|
+
</div>
|
|
190
|
+
<div id="page-dashboard"></div>
|
|
191
|
+
<div id="page-devices" class="collapsed"></div>
|
|
192
|
+
<div id="page-tasks" class="collapsed"></div>
|
|
193
|
+
<div id="page-debug" class="collapsed"></div>
|
|
194
|
+
</div>
|
|
195
|
+
<script>
|
|
196
|
+
let currentTab='dashboard';
|
|
197
|
+
let autoRefresh=true;
|
|
198
|
+
let refreshTimer=null;
|
|
199
|
+
let detailOpen=false; // track if a detail panel is open
|
|
200
|
+
|
|
201
|
+
function switchTab(tab){
|
|
202
|
+
currentTab=tab;
|
|
203
|
+
detailOpen=false;
|
|
204
|
+
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));
|
|
205
|
+
document.querySelectorAll('.tab').forEach(t=>{if(t.textContent.toLowerCase().includes(tab==='debug'?'debug':tab))t.classList.add('active')});
|
|
206
|
+
document.querySelectorAll('[id^="page-"]').forEach(p=>p.classList.add('collapsed'));
|
|
207
|
+
document.getElementById('page-'+tab).classList.remove('collapsed');
|
|
208
|
+
refresh();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function badge(s){
|
|
212
|
+
const cls='b-'+(s||'unknown');
|
|
213
|
+
return '<span class="badge '+cls+'">'+s+'</span>';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function esc(s){return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
217
|
+
|
|
218
|
+
function timeAgo(d){
|
|
219
|
+
if(!d)return '-';
|
|
220
|
+
const diff=(Date.now()-new Date(d).getTime())/1000;
|
|
221
|
+
if(diff<60)return Math.floor(diff)+'s ago';
|
|
222
|
+
if(diff<3600)return Math.floor(diff/60)+'m ago';
|
|
223
|
+
if(diff<86400)return Math.floor(diff/3600)+'h ago';
|
|
224
|
+
return Math.floor(diff/86400)+'d ago';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function fmtTime(d){return d?new Date(d).toLocaleString():'-'}
|
|
228
|
+
|
|
229
|
+
async function api(path){
|
|
230
|
+
try{return await(await fetch('/api'+path)).json()}catch(e){return null}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function refresh(){
|
|
234
|
+
if(currentTab==='dashboard')await loadDashboard();
|
|
235
|
+
else if(currentTab==='devices')await loadDevices();
|
|
236
|
+
else if(currentTab==='tasks')await loadTasks();
|
|
237
|
+
else if(currentTab==='debug')await loadDebug();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ===== Dashboard =====
|
|
241
|
+
async function loadDashboard(){
|
|
242
|
+
const d=await api('/dashboard');
|
|
243
|
+
if(!d)return;
|
|
244
|
+
const p=document.getElementById('page-dashboard');
|
|
245
|
+
let h='<div class="grid">';
|
|
246
|
+
h+='<div class="card"><h3>Devices Online</h3><div class="value">'+d.devices.online+'/'+d.devices.total+'</div><div class="sub">Connected devices</div></div>';
|
|
247
|
+
h+='<div class="card"><h3>Running Tasks</h3><div class="value">'+d.tasks.running+'</div><div class="sub">Total: '+d.tasks.total+'</div></div>';
|
|
248
|
+
h+='<div class="card"><h3>Debug Sessions</h3><div class="value">'+d.debugSessions.length+'</div><div class="sub">Recent sessions</div></div>';
|
|
249
|
+
h+='</div>';
|
|
250
|
+
|
|
251
|
+
// Devices overview
|
|
252
|
+
if(d.devices.list&&d.devices.list.length>0){
|
|
253
|
+
h+='<div class="section-title">Devices</div><table><tr><th>Serial Number</th><th>Model</th><th>Brand</th><th>Platform</th><th>Status</th><th>Last Heartbeat</th></tr>';
|
|
254
|
+
d.devices.list.forEach(dev=>{
|
|
255
|
+
h+='<tr><td class="mono">'+esc(dev.serialNumber)+'</td><td>'+esc(dev.model||'-')+'</td><td>'+esc(dev.brand||'-')+'</td><td>'+esc(dev.platform)+'</td><td>'+badge(dev.status)+'</td><td>'+timeAgo(dev.lastHeartbeatAt)+'</td></tr>';
|
|
256
|
+
});
|
|
257
|
+
h+='</table>';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Recent tasks
|
|
261
|
+
if(d.tasks.recent&&d.tasks.recent.length>0){
|
|
262
|
+
h+='<div class="section-title">Recent Tasks</div><table><tr><th>Task ID</th><th>Type</th><th>Status</th><th>Started</th><th>Completed</th><th>Actions</th></tr>';
|
|
263
|
+
d.tasks.recent.forEach(t=>{
|
|
264
|
+
h+='<tr><td class="mono">'+esc(t.taskId)+'</td><td>'+esc(t.type)+'</td><td>'+badge(t.status)+'</td><td>'+fmtTime(t.startedAt)+'</td><td>'+fmtTime(t.completedAt)+'</td><td><button class="btn btn-primary btn-sm" onclick="showTaskLogs(\\''+esc(t.taskId)+'\\')">Logs</button></td></tr>';
|
|
265
|
+
});
|
|
266
|
+
h+='</table>';
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Recent debug sessions
|
|
270
|
+
if(d.debugSessions&&d.debugSessions.length>0){
|
|
271
|
+
h+='<div class="section-title">Recent Debug Sessions</div><table><tr><th>Session ID</th><th>Device</th><th>Platform</th><th>Status</th><th>Started</th><th>Actions</th></tr>';
|
|
272
|
+
d.debugSessions.slice(0,10).forEach(s=>{
|
|
273
|
+
h+='<tr><td class="mono">'+esc(s.sessionId.substring(0,24))+'...</td><td>'+esc(s.deviceId||'-')+'</td><td>'+esc(s.platform||'-')+'</td><td>'+badge(s.status)+'</td><td>'+fmtTime(s.startedAt)+'</td><td><button class="btn btn-primary btn-sm" onclick="showDebugLogs(\\''+esc(s.sessionId)+'\\')">Logs</button></td></tr>';
|
|
274
|
+
});
|
|
275
|
+
h+='</table>';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
h+='<div id="detail-panel"></div>';
|
|
279
|
+
p.innerHTML=h;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ===== Devices =====
|
|
283
|
+
async function loadDevices(){
|
|
284
|
+
const devs=await api('/devices');
|
|
285
|
+
if(!devs)return;
|
|
286
|
+
const p=document.getElementById('page-devices');
|
|
287
|
+
const online=devs.filter(d=>d.status==='online').length;
|
|
288
|
+
let h='<div class="grid">';
|
|
289
|
+
h+='<div class="card"><h3>Total Devices</h3><div class="value">'+devs.length+'</div></div>';
|
|
290
|
+
h+='<div class="card"><h3>Online</h3><div class="value">'+online+'</div></div>';
|
|
291
|
+
h+='<div class="card"><h3>Offline</h3><div class="value">'+(devs.length-online)+'</div></div>';
|
|
292
|
+
h+='</div>';
|
|
293
|
+
|
|
294
|
+
if(devs.length>0){
|
|
295
|
+
h+='<div class="section-title">All Devices</div><table><tr><th>Serial Number</th><th>Model</th><th>Brand</th><th>Platform</th><th>Status</th><th>Last Heartbeat</th><th>Created</th></tr>';
|
|
296
|
+
devs.forEach(d=>{
|
|
297
|
+
h+='<tr><td class="mono">'+esc(d.serialNumber)+'</td><td>'+esc(d.model||'-')+'</td><td>'+esc(d.brand||'-')+'</td><td>'+esc(d.platform)+'</td><td>'+badge(d.status)+'</td><td>'+timeAgo(d.lastHeartbeatAt)+'</td><td>'+fmtTime(d.createdAt)+'</td></tr>';
|
|
298
|
+
});
|
|
299
|
+
h+='</table>';
|
|
300
|
+
}else{
|
|
301
|
+
h+='<div class="empty-state"><div class="icon">📱</div><p>No devices detected</p></div>';
|
|
302
|
+
}
|
|
303
|
+
p.innerHTML=h;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ===== Tasks =====
|
|
307
|
+
async function loadTasks(){
|
|
308
|
+
const tasks=await api('/tasks?limit=50');
|
|
309
|
+
if(!tasks)return;
|
|
310
|
+
const p=document.getElementById('page-tasks');
|
|
311
|
+
const running=tasks.filter(t=>t.status==='running').length;
|
|
312
|
+
const completed=tasks.filter(t=>t.status==='completed').length;
|
|
313
|
+
const failed=tasks.filter(t=>t.status==='failed').length;
|
|
314
|
+
|
|
315
|
+
let h='<div class="grid">';
|
|
316
|
+
h+='<div class="card"><h3>Total Tasks</h3><div class="value">'+tasks.length+'</div></div>';
|
|
317
|
+
h+='<div class="card"><h3>Running</h3><div class="value">'+running+'</div></div>';
|
|
318
|
+
h+='<div class="card"><h3>Completed</h3><div class="value">'+completed+'</div></div>';
|
|
319
|
+
h+='<div class="card"><h3>Failed</h3><div class="value">'+failed+'</div></div>';
|
|
320
|
+
h+='</div>';
|
|
321
|
+
|
|
322
|
+
if(tasks.length>0){
|
|
323
|
+
h+='<div class="section-title">All Tasks</div><table><tr><th>Task ID</th><th>Execution ID</th><th>Type</th><th>Status</th><th>Priority</th><th>Started</th><th>Completed</th><th>Error</th><th>Actions</th></tr>';
|
|
324
|
+
tasks.forEach(t=>{
|
|
325
|
+
const err=t.errorMessage?(t.errorMessage.length>50?esc(t.errorMessage.substring(0,50))+'...':esc(t.errorMessage)):'-';
|
|
326
|
+
h+='<tr><td class="mono">'+esc(t.taskId)+'</td><td class="mono">'+esc(t.executionId||'-')+'</td><td>'+esc(t.type)+'</td><td>'+badge(t.status)+'</td><td>'+t.priority+'</td><td>'+fmtTime(t.startedAt)+'</td><td>'+fmtTime(t.completedAt)+'</td><td style="color:#ef4444;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+err+'</td><td><button class="btn btn-primary btn-sm" onclick="showTaskDetail(\\''+esc(t.taskId)+'\\')">Detail</button></td></tr>';
|
|
327
|
+
});
|
|
328
|
+
h+='</table>';
|
|
329
|
+
}else{
|
|
330
|
+
h+='<div class="empty-state"><div class="icon">📋</div><p>No tasks found</p></div>';
|
|
331
|
+
}
|
|
332
|
+
h+='<div id="task-detail"></div>';
|
|
333
|
+
p.innerHTML=h;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async function showTaskDetail(taskId){
|
|
337
|
+
detailOpen=true;
|
|
338
|
+
const task=await api('/tasks/'+encodeURIComponent(taskId));
|
|
339
|
+
const logs=await api('/tasks/'+encodeURIComponent(taskId)+'/logs');
|
|
340
|
+
const panel=document.getElementById('task-detail');
|
|
341
|
+
if(!task){panel.innerHTML='<p style="color:#ef4444">Task not found</p>';detailOpen=false;return}
|
|
342
|
+
|
|
343
|
+
let h='<div class="detail-panel"><div class="section-title">Task Detail: '+esc(task.taskId)+' <button class="btn btn-sm" style="background:#334155;color:#94a3b8;margin-left:12px" onclick="closeTaskDetail()">Close</button></div>';
|
|
344
|
+
h+='<div class="detail-row"><div class="detail-label">Task ID</div><div class="detail-value mono">'+esc(task.taskId)+'</div></div>';
|
|
345
|
+
h+='<div class="detail-row"><div class="detail-label">Execution ID</div><div class="detail-value mono">'+esc(task.executionId||'-')+'</div></div>';
|
|
346
|
+
h+='<div class="detail-row"><div class="detail-label">Type</div><div class="detail-value">'+esc(task.type)+'</div></div>';
|
|
347
|
+
h+='<div class="detail-row"><div class="detail-label">Status</div><div class="detail-value">'+badge(task.status)+'</div></div>';
|
|
348
|
+
h+='<div class="detail-row"><div class="detail-label">Priority</div><div class="detail-value">'+task.priority+'</div></div>';
|
|
349
|
+
h+='<div class="detail-row"><div class="detail-label">Started At</div><div class="detail-value">'+fmtTime(task.startedAt)+'</div></div>';
|
|
350
|
+
h+='<div class="detail-row"><div class="detail-label">Completed At</div><div class="detail-value">'+fmtTime(task.completedAt)+'</div></div>';
|
|
351
|
+
h+='<div class="detail-row"><div class="detail-label">Created At</div><div class="detail-value">'+fmtTime(task.createdAt)+'</div></div>';
|
|
352
|
+
if(task.errorMessage)h+='<div class="detail-row"><div class="detail-label">Error</div><div class="detail-value" style="color:#ef4444">'+esc(task.errorMessage)+'</div></div>';
|
|
353
|
+
if(task.config){
|
|
354
|
+
h+='<div class="detail-row"><div class="detail-label">Config</div><div class="detail-value mono" style="white-space:pre-wrap;font-size:11px">'+esc(typeof task.config==='object'?JSON.stringify(task.config,null,2):task.config)+'</div></div>';
|
|
355
|
+
}
|
|
356
|
+
if(task.result){
|
|
357
|
+
h+='<div class="detail-row"><div class="detail-label">Result</div><div class="detail-value mono" style="white-space:pre-wrap;font-size:11px">'+esc(typeof task.result==='object'?JSON.stringify(task.result,null,2):task.result)+'</div></div>';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Execution logs
|
|
361
|
+
if(logs&&logs.length>0){
|
|
362
|
+
h+='<div class="section-title" style="margin-top:20px">Execution Logs ('+logs.length+')</div>';
|
|
363
|
+
h+='<div class="log-viewer">';
|
|
364
|
+
logs.forEach(l=>{
|
|
365
|
+
const lvl='log-level-'+esc(l.level||'info');
|
|
366
|
+
h+='<div class="log-line"><span class="log-time">'+fmtTime(l.createdAt)+'</span><span class="'+lvl+'">['+esc(l.level||'info').toUpperCase()+']</span> <span class="log-content">'+esc(l.content)+'</span></div>';
|
|
367
|
+
});
|
|
368
|
+
h+='</div>';
|
|
369
|
+
}else{
|
|
370
|
+
h+='<div class="section-title" style="margin-top:20px">Execution Logs</div><p style="color:#64748b">No logs available</p>';
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
h+='</div>';
|
|
374
|
+
panel.innerHTML=h;
|
|
375
|
+
panel.scrollIntoView({behavior:'smooth'});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function showTaskLogs(taskId){
|
|
379
|
+
if(currentTab!=='tasks'){switchTab('tasks');setTimeout(()=>showTaskDetail(taskId),500);return}
|
|
380
|
+
showTaskDetail(taskId);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ===== Debug Sessions =====
|
|
384
|
+
async function loadDebug(){
|
|
385
|
+
const sessions=await api('/debug/sessions');
|
|
386
|
+
if(!sessions)return;
|
|
387
|
+
const p=document.getElementById('page-debug');
|
|
388
|
+
const running=sessions.filter(s=>s.status==='running').length;
|
|
389
|
+
|
|
390
|
+
let h='<div class="grid">';
|
|
391
|
+
h+='<div class="card"><h3>Total Sessions</h3><div class="value">'+sessions.length+'</div></div>';
|
|
392
|
+
h+='<div class="card"><h3>Running</h3><div class="value">'+running+'</div></div>';
|
|
393
|
+
h+='</div>';
|
|
394
|
+
|
|
395
|
+
if(sessions.length>0){
|
|
396
|
+
h+='<div class="section-title">All Debug Sessions</div><table><tr><th>Session ID</th><th>Task ID</th><th>Device</th><th>Platform</th><th>Status</th><th>Started</th><th>Completed</th><th>Actions</th></tr>';
|
|
397
|
+
sessions.forEach(s=>{
|
|
398
|
+
h+='<tr><td class="mono">'+esc(s.sessionId.substring(0,28))+'...</td><td class="mono">'+esc(s.taskId||'-')+'</td><td>'+esc(s.deviceId||'-')+'</td><td>'+esc(s.platform||'-')+'</td><td>'+badge(s.status)+'</td><td>'+fmtTime(s.startedAt)+'</td><td>'+fmtTime(s.completedAt)+'</td><td><button class="btn btn-primary btn-sm" onclick="showDebugDetail(\\''+esc(s.sessionId)+'\\')">Detail</button></td></tr>';
|
|
399
|
+
});
|
|
400
|
+
h+='</table>';
|
|
401
|
+
}else{
|
|
402
|
+
h+='<div class="empty-state"><div class="icon">🐛</div><p>No debug sessions</p></div>';
|
|
403
|
+
}
|
|
404
|
+
h+='<div id="debug-detail"></div>';
|
|
405
|
+
p.innerHTML=h;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function showDebugDetail(sessionId){
|
|
409
|
+
detailOpen=true;
|
|
410
|
+
const session=await api('/debug/sessions/'+encodeURIComponent(sessionId));
|
|
411
|
+
const logs=await api('/debug/sessions/'+encodeURIComponent(sessionId)+'/logs');
|
|
412
|
+
const panel=document.getElementById('debug-detail');
|
|
413
|
+
if(!session){panel.innerHTML='<p style="color:#ef4444">Session not found</p>';detailOpen=false;return}
|
|
414
|
+
|
|
415
|
+
let h='<div class="detail-panel"><div class="section-title">Debug Session: '+esc(sessionId)+' <button class="btn btn-sm" style="background:#334155;color:#94a3b8;margin-left:12px" onclick="closeDebugDetail()">Close</button></div>';
|
|
416
|
+
h+='<div class="detail-row"><div class="detail-label">Session ID</div><div class="detail-value mono">'+esc(session.sessionId)+'</div></div>';
|
|
417
|
+
h+='<div class="detail-row"><div class="detail-label">Task ID</div><div class="detail-value mono">'+esc(session.taskId||'-')+'</div></div>';
|
|
418
|
+
h+='<div class="detail-row"><div class="detail-label">Device</div><div class="detail-value mono">'+esc(session.deviceId||'-')+'</div></div>';
|
|
419
|
+
h+='<div class="detail-row"><div class="detail-label">Platform</div><div class="detail-value">'+esc(session.platform||'-')+'</div></div>';
|
|
420
|
+
h+='<div class="detail-row"><div class="detail-label">Status</div><div class="detail-value">'+badge(session.status)+'</div></div>';
|
|
421
|
+
h+='<div class="detail-row"><div class="detail-label">Started At</div><div class="detail-value">'+fmtTime(session.startedAt)+'</div></div>';
|
|
422
|
+
h+='<div class="detail-row"><div class="detail-label">Completed At</div><div class="detail-value">'+fmtTime(session.completedAt)+'</div></div>';
|
|
423
|
+
h+='</div>';
|
|
424
|
+
|
|
425
|
+
// Session logs
|
|
426
|
+
if(logs&&logs.length>0){
|
|
427
|
+
h+='<div class="detail-panel" style="margin-top:16px"><div class="section-title">Session Logs ('+logs.length+')</div>';
|
|
428
|
+
h+='<div class="log-viewer">';
|
|
429
|
+
logs.forEach(l=>{
|
|
430
|
+
const lvl='log-level-'+esc(l.type==='log_output'?'info':l.type==='error'?'error':'info');
|
|
431
|
+
const content=l.content||'';
|
|
432
|
+
h+='<div class="log-line"><span class="log-time">'+fmtTime(l.createdAt)+'</span> <span class="log-content">'+esc(content)+'</span></div>';
|
|
433
|
+
});
|
|
434
|
+
h+='</div></div>';
|
|
435
|
+
}else{
|
|
436
|
+
h+='<div class="detail-panel" style="margin-top:16px"><div class="section-title">Session Logs</div><p style="color:#64748b">No logs available</p></div>';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
panel.innerHTML=h;
|
|
440
|
+
panel.scrollIntoView({behavior:'smooth'});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function showDebugLogs(sessionId){
|
|
444
|
+
if(currentTab!=='debug'){switchTab('debug');setTimeout(()=>showDebugDetail(sessionId),500);return}
|
|
445
|
+
showDebugDetail(sessionId);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function closeTaskDetail(){
|
|
449
|
+
const panel=document.getElementById('task-detail');
|
|
450
|
+
if(panel)panel.innerHTML='';
|
|
451
|
+
detailOpen=false;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function closeDebugDetail(){
|
|
455
|
+
const panel=document.getElementById('debug-detail');
|
|
456
|
+
if(panel)panel.innerHTML='';
|
|
457
|
+
detailOpen=false;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ===== Init =====
|
|
461
|
+
refresh();
|
|
462
|
+
refreshTimer=setInterval(()=>{if(autoRefresh&&!detailOpen)refresh()},5000);
|
|
463
|
+
</script>
|
|
464
|
+
</body>
|
|
465
|
+
</html>`;
|
|
466
|
+
}
|
|
467
|
+
start(config) {
|
|
468
|
+
this.config = config;
|
|
469
|
+
this.app.listen(config.webPort, config.host, () => {
|
|
470
|
+
logger.info(`Web server started on http://${config.host}:${config.webPort}`);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
close() {
|
|
474
|
+
logger.info('Web server closed');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
export const webServer = new WebServer();
|
|
478
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aiscene/aiserver",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI automation server with device management, task scheduling, and debug capabilities",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"aiserver": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"dev": "tsx watch src/index.ts",
|
|
17
|
+
"lint": "eslint src/",
|
|
18
|
+
"format": "prettier --write src/"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@aiscene/android": "^8.1.4",
|
|
22
|
+
"@midscene/ios": "^1.6.0",
|
|
23
|
+
"@midscene/web": "^1.6.0",
|
|
24
|
+
"@playwright/test": "^1.59.1",
|
|
25
|
+
"acorn": "^8.16.0",
|
|
26
|
+
"axios": "^1.7.9",
|
|
27
|
+
"better-sqlite3": "^11.7.0",
|
|
28
|
+
"dotenv": "^16.4.7",
|
|
29
|
+
"eventemitter3": "^5.0.1",
|
|
30
|
+
"express": "^4.21.2",
|
|
31
|
+
"form-data": "^4.0.1",
|
|
32
|
+
"jsonpath": "^1.3.0",
|
|
33
|
+
"playwright": "^1.49.1",
|
|
34
|
+
"ws": "^8.18.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/acorn": "^4.0.6",
|
|
38
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
39
|
+
"@types/express": "^5.0.0",
|
|
40
|
+
"@types/node": "^22.10.0",
|
|
41
|
+
"@types/ws": "^8.5.13",
|
|
42
|
+
"tsx": "^4.19.0",
|
|
43
|
+
"typescript": "^5.7.0"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT"
|
|
49
|
+
}
|