agent-window 1.0.3 → 1.0.5
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/package.json +1 -1
- package/src/api/routes/instances.js +85 -4
- package/src/api/routes/operations.js +34 -3
- package/src/api/websocket/logs.js +8 -3
- package/src/core/instance/manager.js +112 -0
- package/web/dist/assets/{Dashboard-ezbZMSpZ.css → Dashboard---si3Smb.css} +1 -1
- package/web/dist/assets/Dashboard-CLdsgY13.js +1 -0
- package/web/dist/assets/{InstanceDetail-C_Ddtrog.js → InstanceDetail-srqsvZOw.js} +1 -1
- package/web/dist/assets/{Instances-_u2__M83.js → Instances-DBBB5E3g.js} +1 -1
- package/web/dist/assets/{Settings-CIa9MX7m.js → Settings-Auj5u5IH.js} +1 -1
- package/web/dist/assets/{element-plus-Jr6qTeY5.js → element-plus-CSm40ime.js} +1 -1
- package/web/dist/assets/{main-D3cdXAiV.js → main-CMa467nG.js} +4 -4
- package/web/dist/index.html +2 -2
- package/web/dist/assets/Dashboard-C1smB9Nj.js +0 -1
package/package.json
CHANGED
|
@@ -14,7 +14,9 @@ import {
|
|
|
14
14
|
getInstance,
|
|
15
15
|
addInstance,
|
|
16
16
|
removeInstance,
|
|
17
|
-
updateInstance
|
|
17
|
+
updateInstance,
|
|
18
|
+
discoverInstances,
|
|
19
|
+
importInstance
|
|
18
20
|
} from '../../core/instance/manager.js';
|
|
19
21
|
import {
|
|
20
22
|
getStatus,
|
|
@@ -208,8 +210,19 @@ export async function registerInstanceRoutes(fastify) {
|
|
|
208
210
|
}, async (request, reply) => {
|
|
209
211
|
try {
|
|
210
212
|
const { name } = request.params;
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
+
const instance = await getInstance(name);
|
|
214
|
+
|
|
215
|
+
if (!instance) {
|
|
216
|
+
return reply.code(404).send({
|
|
217
|
+
error: 'Instance not found',
|
|
218
|
+
name
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Use botName for PM2 lookup, default to bot-{name}
|
|
223
|
+
const botName = instance.botName || `bot-${name}`;
|
|
224
|
+
const status = await getStatus(botName);
|
|
225
|
+
return { ...status, instanceName: name };
|
|
213
226
|
} catch (error) {
|
|
214
227
|
reply.code(500).send({
|
|
215
228
|
error: 'Failed to get status',
|
|
@@ -238,7 +251,16 @@ export async function registerInstanceRoutes(fastify) {
|
|
|
238
251
|
const { name } = request.params;
|
|
239
252
|
const { lines = 100, logType = 'all' } = request.query;
|
|
240
253
|
|
|
241
|
-
const
|
|
254
|
+
const instance = await getInstance(name);
|
|
255
|
+
if (!instance) {
|
|
256
|
+
return reply.code(404).send({
|
|
257
|
+
error: 'Instance not found',
|
|
258
|
+
name
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const botName = instance.botName || `bot-${name}`;
|
|
263
|
+
const logs = await getLogs(botName, { lines, type: logType });
|
|
242
264
|
return { logs };
|
|
243
265
|
} catch (error) {
|
|
244
266
|
reply.code(500).send({
|
|
@@ -248,5 +270,64 @@ export async function registerInstanceRoutes(fastify) {
|
|
|
248
270
|
}
|
|
249
271
|
});
|
|
250
272
|
|
|
273
|
+
/**
|
|
274
|
+
* GET /api/instances/discover
|
|
275
|
+
* Discover bot instances running in PM2 that are not registered
|
|
276
|
+
*/
|
|
277
|
+
fastify.get('/api/instances/discover', {
|
|
278
|
+
schema: {
|
|
279
|
+
description: 'Discover unregistered bot instances from PM2',
|
|
280
|
+
tags: ['instances']
|
|
281
|
+
}
|
|
282
|
+
}, async (request, reply) => {
|
|
283
|
+
try {
|
|
284
|
+
const discovered = await discoverInstances();
|
|
285
|
+
return { discovered };
|
|
286
|
+
} catch (error) {
|
|
287
|
+
reply.code(500).send({
|
|
288
|
+
error: 'Failed to discover instances',
|
|
289
|
+
message: error.message
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* POST /api/instances/import
|
|
296
|
+
* Import a discovered instance
|
|
297
|
+
*/
|
|
298
|
+
fastify.post('/api/instances/import', {
|
|
299
|
+
schema: {
|
|
300
|
+
description: 'Import a discovered instance',
|
|
301
|
+
body: {
|
|
302
|
+
type: 'object',
|
|
303
|
+
required: ['name'],
|
|
304
|
+
properties: {
|
|
305
|
+
name: { type: 'string' },
|
|
306
|
+
botName: { type: 'string' },
|
|
307
|
+
displayName: { type: 'string' },
|
|
308
|
+
projectPath: { type: 'string' }
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}, async (request, reply) => {
|
|
313
|
+
try {
|
|
314
|
+
const discovered = request.body;
|
|
315
|
+
const result = await importInstance(discovered);
|
|
316
|
+
|
|
317
|
+
if (!result.success) {
|
|
318
|
+
return reply.code(400).send({
|
|
319
|
+
error: result.error
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
reply.code(201).send(result.instance);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
reply.code(500).send({
|
|
326
|
+
error: 'Failed to import instance',
|
|
327
|
+
message: error.message
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
251
332
|
fastify.log.info('Instance routes registered');
|
|
252
333
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
stopProcess,
|
|
13
13
|
restartProcess
|
|
14
14
|
} from '../../core/instance/pm2-bridge.js';
|
|
15
|
+
import { getInstance } from '../../core/instance/manager.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Register operation routes
|
|
@@ -32,7 +33,17 @@ export async function registerOperationRoutes(fastify) {
|
|
|
32
33
|
}, async (request, reply) => {
|
|
33
34
|
try {
|
|
34
35
|
const { name } = request.params;
|
|
35
|
-
const
|
|
36
|
+
const instance = await getInstance(name);
|
|
37
|
+
|
|
38
|
+
if (!instance) {
|
|
39
|
+
return reply.code(404).send({
|
|
40
|
+
error: 'Instance not found',
|
|
41
|
+
name
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const botName = instance.botName || `bot-${name}`;
|
|
46
|
+
const result = await startProcess(botName);
|
|
36
47
|
|
|
37
48
|
if (!result.success) {
|
|
38
49
|
return reply.code(400).send({
|
|
@@ -64,7 +75,17 @@ export async function registerOperationRoutes(fastify) {
|
|
|
64
75
|
}, async (request, reply) => {
|
|
65
76
|
try {
|
|
66
77
|
const { name } = request.params;
|
|
67
|
-
const
|
|
78
|
+
const instance = await getInstance(name);
|
|
79
|
+
|
|
80
|
+
if (!instance) {
|
|
81
|
+
return reply.code(404).send({
|
|
82
|
+
error: 'Instance not found',
|
|
83
|
+
name
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const botName = instance.botName || `bot-${name}`;
|
|
88
|
+
const result = await stopProcess(botName);
|
|
68
89
|
|
|
69
90
|
if (!result.success) {
|
|
70
91
|
return reply.code(400).send({
|
|
@@ -96,7 +117,17 @@ export async function registerOperationRoutes(fastify) {
|
|
|
96
117
|
}, async (request, reply) => {
|
|
97
118
|
try {
|
|
98
119
|
const { name } = request.params;
|
|
99
|
-
const
|
|
120
|
+
const instance = await getInstance(name);
|
|
121
|
+
|
|
122
|
+
if (!instance) {
|
|
123
|
+
return reply.code(404).send({
|
|
124
|
+
error: 'Instance not found',
|
|
125
|
+
name
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const botName = instance.botName || `bot-${name}`;
|
|
130
|
+
const result = await restartProcess(botName);
|
|
100
131
|
|
|
101
132
|
if (!result.success) {
|
|
102
133
|
return reply.code(400).send({
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { spawn } from 'child_process';
|
|
9
9
|
import { isWindows, isWSLAvailable } from '../../core/platform/detector.js';
|
|
10
|
+
import { getInstance } from '../../core/instance/manager.js';
|
|
10
11
|
|
|
11
12
|
// Active log streams by instance name
|
|
12
13
|
const activeStreams = new Map();
|
|
@@ -21,9 +22,13 @@ export async function registerLogStream(fastify) {
|
|
|
21
22
|
* Stream logs for a specific instance
|
|
22
23
|
*/
|
|
23
24
|
fastify.register(async function (fastify) {
|
|
24
|
-
fastify.get('/ws/logs/:name', { websocket: true }, (connection, req) => {
|
|
25
|
+
fastify.get('/ws/logs/:name', { websocket: true }, async (connection, req) => {
|
|
25
26
|
const { name } = req.params;
|
|
26
27
|
|
|
28
|
+
// Get instance to find botName
|
|
29
|
+
const instance = await getInstance(name);
|
|
30
|
+
const botName = instance?.botName || `bot-${name}`;
|
|
31
|
+
|
|
27
32
|
// Close existing stream for this instance if any
|
|
28
33
|
if (activeStreams.has(name)) {
|
|
29
34
|
const existing = activeStreams.get(name);
|
|
@@ -32,7 +37,7 @@ export async function registerLogStream(fastify) {
|
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
connection.socket.on('open', () => {
|
|
35
|
-
fastify.log.info(`Log stream started for: ${name}`);
|
|
40
|
+
fastify.log.info(`Log stream started for: ${name} (${botName})`);
|
|
36
41
|
});
|
|
37
42
|
|
|
38
43
|
// Send initial connection message
|
|
@@ -44,7 +49,7 @@ export async function registerLogStream(fastify) {
|
|
|
44
49
|
|
|
45
50
|
// Start PM2 log stream
|
|
46
51
|
let pm2Cmd = 'pm2';
|
|
47
|
-
let pm2Args = ['logs',
|
|
52
|
+
let pm2Args = ['logs', botName, '--lines', '50', '--raw', '--nostream'];
|
|
48
53
|
|
|
49
54
|
// On Windows, use WSL if available
|
|
50
55
|
if (isWindows()) {
|
|
@@ -10,6 +10,7 @@ import path from 'path';
|
|
|
10
10
|
import { existsSync } from 'fs';
|
|
11
11
|
import { validateInstance } from './validator.js';
|
|
12
12
|
import { paths } from '../platform/index.js';
|
|
13
|
+
import { getProcesses } from './pm2-bridge.js';
|
|
13
14
|
|
|
14
15
|
/** @private */
|
|
15
16
|
const INSTANCES_DIR = paths.getAgentWindowHome();
|
|
@@ -218,3 +219,114 @@ export async function updateInstance(name, updates) {
|
|
|
218
219
|
instance
|
|
219
220
|
};
|
|
220
221
|
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Discover bot-* instances running in PM2 that are not in instances.json
|
|
225
|
+
* @returns {Promise<Array>} List of discovered instances
|
|
226
|
+
*/
|
|
227
|
+
export async function discoverInstances() {
|
|
228
|
+
const data = await readInstances();
|
|
229
|
+
const registeredNames = new Set(data.instances.map(i => i.botName || `bot-${i.name}`));
|
|
230
|
+
const discovered = [];
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const processes = await getProcesses();
|
|
234
|
+
|
|
235
|
+
// Filter for bot-* processes
|
|
236
|
+
const botProcesses = processes.filter(p => p.name && p.name.startsWith('bot-'));
|
|
237
|
+
|
|
238
|
+
for (const proc of botProcesses) {
|
|
239
|
+
// Skip if already registered
|
|
240
|
+
if (registeredNames.has(proc.name)) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Extract instance name from bot-name
|
|
245
|
+
const instanceName = proc.name.replace(/^bot-/, '');
|
|
246
|
+
|
|
247
|
+
// Try to find project path from PM2 process info
|
|
248
|
+
let projectPath = null;
|
|
249
|
+
let pluginPath = null;
|
|
250
|
+
|
|
251
|
+
if (proc.pm2_env?.cwd || proc.cwd) {
|
|
252
|
+
projectPath = proc.pm2_env?.cwd || proc.cwd;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Check if it's a BMAD project
|
|
256
|
+
if (projectPath && existsSync(path.join(projectPath, '_bmad'))) {
|
|
257
|
+
pluginPath = path.join(projectPath, '_agent-bridge', 'src');
|
|
258
|
+
} else if (projectPath && existsSync(path.join(projectPath, 'src', 'bot.js'))) {
|
|
259
|
+
// Simple bot structure
|
|
260
|
+
pluginPath = path.join(projectPath, 'src');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
discovered.push({
|
|
264
|
+
botName: proc.name,
|
|
265
|
+
name: instanceName,
|
|
266
|
+
displayName: instanceName.charAt(0).toUpperCase() + instanceName.slice(1),
|
|
267
|
+
projectPath,
|
|
268
|
+
pluginPath,
|
|
269
|
+
status: proc.status || 'unknown',
|
|
270
|
+
pid: proc.pid,
|
|
271
|
+
memory: proc.memory || 0,
|
|
272
|
+
cpu: proc.cpu || 0,
|
|
273
|
+
uptime: proc.uptime || 0,
|
|
274
|
+
isRunning: proc.status === 'online'
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
// If PM2 is not available, return empty list
|
|
279
|
+
console.error('Failed to discover instances:', error.message);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return discovered;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Import a discovered instance into instances.json
|
|
287
|
+
* @param {Object} discovered - Discovered instance object
|
|
288
|
+
* @returns {Promise<Object>} Result
|
|
289
|
+
*/
|
|
290
|
+
export async function importInstance(discovered) {
|
|
291
|
+
const data = await readInstances();
|
|
292
|
+
|
|
293
|
+
// Check if already exists
|
|
294
|
+
if (data.instances.find(i => i.name === discovered.name)) {
|
|
295
|
+
return {
|
|
296
|
+
success: false,
|
|
297
|
+
error: `实例 "${discovered.name}" 已存在`
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Validate project path if available
|
|
302
|
+
let validatedPath = discovered.projectPath;
|
|
303
|
+
let validatedPluginPath = discovered.pluginPath;
|
|
304
|
+
|
|
305
|
+
if (discovered.projectPath && existsSync(discovered.projectPath)) {
|
|
306
|
+
const validation = await validateInstance(discovered.projectPath);
|
|
307
|
+
if (validation.valid) {
|
|
308
|
+
validatedPath = validation.projectPath;
|
|
309
|
+
validatedPluginPath = validation.pluginPath;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const newInstance = {
|
|
314
|
+
name: discovered.name,
|
|
315
|
+
displayName: discovered.displayName,
|
|
316
|
+
projectPath: validatedPath,
|
|
317
|
+
pluginPath: validatedPluginPath,
|
|
318
|
+
botName: discovered.botName,
|
|
319
|
+
addedAt: new Date().toISOString(),
|
|
320
|
+
tags: ['imported'],
|
|
321
|
+
enabled: true,
|
|
322
|
+
imported: true
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
data.instances.push(newInstance);
|
|
326
|
+
await writeInstances(data);
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
instance: newInstance
|
|
331
|
+
};
|
|
332
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.instance-card[data-v-bbbabd13]{height:100%;transition:all var(--aw-transition-base)}.instance-card[data-v-bbbabd13]:hover{transform:translateY(-2px)}.card-header[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.header-left[data-v-bbbabd13]{display:flex;align-items:center;gap:12px}.header-left .instance-icon[data-v-bbbabd13]{display:flex;align-items:center;justify-content:center;width:40px;height:40px;background:var(--aw-bg-secondary);border-radius:var(--aw-radius-md);color:var(--aw-accent)}.header-left .instance-name[data-v-bbbabd13]{margin:0;font-size:15px;font-weight:600;color:var(--aw-text-primary);letter-spacing:-.01em}.header-left .instance-alias[data-v-bbbabd13]{font-size:12px;color:var(--aw-text-secondary)}.status-indicator[data-v-bbbabd13]{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:12px;font-size:12px;font-weight:500}.status-indicator .status-dot[data-v-bbbabd13]{width:6px;height:6px;border-radius:50%;background:currentColor}.status-indicator.online[data-v-bbbabd13]{background:#34c7591a;color:var(--aw-status-online)}.status-indicator.stopped[data-v-bbbabd13]{background:#8e8e931a;color:var(--aw-status-stopped)}.status-indicator.error[data-v-bbbabd13]{background:#ff3b301a;color:var(--aw-status-error)}.status-indicator.restarting[data-v-bbbabd13]{background:#ff95001a;color:var(--aw-status-restarting)}.card-body[data-v-bbbabd13]{display:flex;flex-direction:column;gap:12px;margin-bottom:16px}.info-row[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center}.info-row .label[data-v-bbbabd13]{font-size:12px;color:var(--aw-text-secondary)}.info-row .value[data-v-bbbabd13]{font-size:12px;font-family:SF Mono,Monaco,Cascadia Code,monospace;color:var(--aw-text-primary)}.stats-row[data-v-bbbabd13]{display:flex;justify-content:space-around;padding:12px 0;border-top:1px solid var(--aw-bg-tertiary);border-bottom:1px solid var(--aw-bg-tertiary)}.stat[data-v-bbbabd13]{display:flex;flex-direction:column;align-items:center;gap:4px}.stat .stat-label[data-v-bbbabd13]{font-size:10px;color:var(--aw-text-secondary);text-transform:uppercase;letter-spacing:.05em}.stat .stat-value[data-v-bbbabd13]{font-size:14px;font-weight:600;color:var(--aw-text-primary)}.tags-row[data-v-bbbabd13]{display:flex;gap:6px;flex-wrap:wrap}.tags-row .tag[data-v-bbbabd13]{padding:3px 8px;font-size:11px;font-weight:500;background:var(--aw-bg-secondary);color:var(--aw-text-secondary);border-radius:6px}.card-actions[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center;padding-top:12px;border-top:1px solid var(--aw-bg-tertiary)}.action-buttons[data-v-bbbabd13]{display:flex;gap:4px}.action-btn[data-v-bbbabd13]{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:transparent;border-radius:var(--aw-radius-sm);color:var(--aw-text-secondary);cursor:pointer;transition:all var(--aw-transition-fast)}.action-btn[data-v-bbbabd13]:hover:not(:disabled){background:var(--aw-bg-secondary);color:var(--aw-text-primary)}.action-btn[data-v-bbbabd13]:disabled{opacity:.4;cursor:not-allowed}.action-btn[data-v-bbbabd13]:active:not(:disabled){transform:scale(.95)}.details-btn[data-v-bbbabd13]{padding:8px 14px;font-size:13px;font-weight:500;color:var(--aw-accent);background:transparent;border:none;border-radius:var(--aw-radius-sm);cursor:pointer;transition:background var(--aw-transition-fast)}.details-btn[data-v-bbbabd13]:hover{background:#0071e31a}.dashboard-view[data-v-
|
|
1
|
+
.instance-card[data-v-bbbabd13]{height:100%;transition:all var(--aw-transition-base)}.instance-card[data-v-bbbabd13]:hover{transform:translateY(-2px)}.card-header[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.header-left[data-v-bbbabd13]{display:flex;align-items:center;gap:12px}.header-left .instance-icon[data-v-bbbabd13]{display:flex;align-items:center;justify-content:center;width:40px;height:40px;background:var(--aw-bg-secondary);border-radius:var(--aw-radius-md);color:var(--aw-accent)}.header-left .instance-name[data-v-bbbabd13]{margin:0;font-size:15px;font-weight:600;color:var(--aw-text-primary);letter-spacing:-.01em}.header-left .instance-alias[data-v-bbbabd13]{font-size:12px;color:var(--aw-text-secondary)}.status-indicator[data-v-bbbabd13]{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:12px;font-size:12px;font-weight:500}.status-indicator .status-dot[data-v-bbbabd13]{width:6px;height:6px;border-radius:50%;background:currentColor}.status-indicator.online[data-v-bbbabd13]{background:#34c7591a;color:var(--aw-status-online)}.status-indicator.stopped[data-v-bbbabd13]{background:#8e8e931a;color:var(--aw-status-stopped)}.status-indicator.error[data-v-bbbabd13]{background:#ff3b301a;color:var(--aw-status-error)}.status-indicator.restarting[data-v-bbbabd13]{background:#ff95001a;color:var(--aw-status-restarting)}.card-body[data-v-bbbabd13]{display:flex;flex-direction:column;gap:12px;margin-bottom:16px}.info-row[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center}.info-row .label[data-v-bbbabd13]{font-size:12px;color:var(--aw-text-secondary)}.info-row .value[data-v-bbbabd13]{font-size:12px;font-family:SF Mono,Monaco,Cascadia Code,monospace;color:var(--aw-text-primary)}.stats-row[data-v-bbbabd13]{display:flex;justify-content:space-around;padding:12px 0;border-top:1px solid var(--aw-bg-tertiary);border-bottom:1px solid var(--aw-bg-tertiary)}.stat[data-v-bbbabd13]{display:flex;flex-direction:column;align-items:center;gap:4px}.stat .stat-label[data-v-bbbabd13]{font-size:10px;color:var(--aw-text-secondary);text-transform:uppercase;letter-spacing:.05em}.stat .stat-value[data-v-bbbabd13]{font-size:14px;font-weight:600;color:var(--aw-text-primary)}.tags-row[data-v-bbbabd13]{display:flex;gap:6px;flex-wrap:wrap}.tags-row .tag[data-v-bbbabd13]{padding:3px 8px;font-size:11px;font-weight:500;background:var(--aw-bg-secondary);color:var(--aw-text-secondary);border-radius:6px}.card-actions[data-v-bbbabd13]{display:flex;justify-content:space-between;align-items:center;padding-top:12px;border-top:1px solid var(--aw-bg-tertiary)}.action-buttons[data-v-bbbabd13]{display:flex;gap:4px}.action-btn[data-v-bbbabd13]{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:transparent;border-radius:var(--aw-radius-sm);color:var(--aw-text-secondary);cursor:pointer;transition:all var(--aw-transition-fast)}.action-btn[data-v-bbbabd13]:hover:not(:disabled){background:var(--aw-bg-secondary);color:var(--aw-text-primary)}.action-btn[data-v-bbbabd13]:disabled{opacity:.4;cursor:not-allowed}.action-btn[data-v-bbbabd13]:active:not(:disabled){transform:scale(.95)}.details-btn[data-v-bbbabd13]{padding:8px 14px;font-size:13px;font-weight:500;color:var(--aw-accent);background:transparent;border:none;border-radius:var(--aw-radius-sm);cursor:pointer;transition:background var(--aw-transition-fast)}.details-btn[data-v-bbbabd13]:hover{background:#0071e31a}.dashboard-view[data-v-af31d52b]{display:flex;flex-direction:column;gap:24px}.dashboard-header[data-v-af31d52b]{display:flex;justify-content:space-between;align-items:flex-start}.dashboard-header .header-actions[data-v-af31d52b]{display:flex;gap:12px}.dashboard-header h1[data-v-af31d52b]{margin:0;font-size:28px;font-weight:600}.dashboard-header .subtitle[data-v-af31d52b]{margin:4px 0 0;color:var(--el-text-color-secondary)}.discover-info[data-v-af31d52b]{padding:0 0 16px;color:var(--el-text-color-secondary);font-size:14px}.empty-discovered[data-v-af31d52b]{padding:40px 0;text-align:center;color:var(--el-text-color-secondary)}.stats-row .stat-card[data-v-af31d52b]{background:linear-gradient(135deg,var(--el-bg-color) 0%,var(--el-bg-color-page) 100%)}.stats-row .stat-card.success[data-v-af31d52b]{border-left:3px solid var(--aw-success)}.stats-row .stat-card.warning[data-v-af31d52b]{border-left:3px solid var(--aw-warning)}.stats-row .stat-card.danger[data-v-af31d52b]{border-left:3px solid var(--aw-danger)}.stats-row .stat-content[data-v-af31d52b]{display:flex;align-items:center;gap:16px}.stats-row .stat-content .stat-icon[data-v-af31d52b]{font-size:32px}.stats-row .stat-content .stat-info[data-v-af31d52b]{display:flex;flex-direction:column}.stats-row .stat-content .stat-info .stat-value[data-v-af31d52b]{font-size:24px;font-weight:600;line-height:1}.stats-row .stat-content .stat-info .stat-label[data-v-af31d52b]{font-size:12px;color:var(--el-text-color-secondary)}.loading-state[data-v-af31d52b]{padding:40px 0}.empty-state[data-v-af31d52b]{display:flex;flex-direction:column;align-items:center;gap:16px;padding:80px 0}.empty-state .empty-icon[data-v-af31d52b]{font-size:64px;opacity:.5}.empty-state h3[data-v-af31d52b]{margin:0;font-size:20px}.empty-state p[data-v-af31d52b]{margin:0;color:var(--el-text-color-secondary)}.instances-grid [class*=el-col][data-v-af31d52b]{margin-bottom:16px}.form-hint[data-v-af31d52b]{font-size:12px;color:var(--el-text-color-secondary);margin-top:4px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{aA as rt,j as Z,ab as m,y as u,z as P,D as a,E as t,R as c,G as dt,B as y,P as q,J as tt,a5 as et,c as k,r as f,Q as _,u as T,C as s,am as ut}from"./vue-vendor-CGSlMM3Y.js";import{d as ct,p as Y,r as pt}from"./element-plus-CSm40ime.js";import{a as I,u as st}from"./main-CMa467nG.js";import{_ as at}from"./_plugin-vue_export-helper-DlAUqK2U.js";const mt={class:"card-header"},vt={class:"header-left"},ft={class:"instance-info"},yt={class:"instance-name"},gt={class:"instance-alias"},ht={class:"status-label"},_t={class:"card-body"},bt={class:"info-row"},wt={class:"value"},kt={key:0,class:"stats-row"},It={class:"stat"},$t={class:"stat-value"},Ct={class:"stat"},xt={class:"stat-value"},Nt={key:0,class:"stat"},Pt={class:"stat-value"},Vt={key:1,class:"tags-row"},jt={class:"card-actions"},Dt={class:"action-buttons"},Mt=["disabled"],Rt=["disabled"],Bt=["disabled"],St={__name:"InstanceCard",props:{instance:{type:Object,required:!0}},setup($,{expose:A}){const p=$,w=rt(),{success:C,error:g}=st(),d=f({status:"unknown",exists:!1,memory:0,cpu:0,uptime:0}),j=k(()=>{const l=d.value.status;return l==="online"?"online":l==="stopped"?"stopped":l==="errored"?"error":l==="restarting"?"restarting":"stopped"}),D=k(()=>{const l=d.value.status;return{online:"Running",stopped:"Stopped",errored:"Error",restarting:"Restarting",unknown:"Unknown"}[l]||"Unknown"}),b=k(()=>{const l=p.instance.projectPath;return l.length>35?"..."+l.slice(-32):l});async function h(){try{const l=await I.getInstanceStatus(p.instance.name);d.value=l}catch{d.value={status:"unknown",exists:!1,memory:0,cpu:0,uptime:0}}}async function M(){try{await I.startInstance(p.instance.name),C("Started",`${p.instance.name} has been started`),await h()}catch(l){g("Failed to start",l.message)}}async function x(){try{await I.stopInstance(p.instance.name),C("Stopped",`${p.instance.name} has been stopped`),await h()}catch(l){g("Failed to stop",l.message)}}async function r(){try{await I.restartInstance(p.instance.name),C("Restarted",`${p.instance.name} has been restarted`),await h()}catch(l){g("Failed to restart",l.message)}}function E(){w.push(`/instances/${p.instance.name}`)}function U(l){const n=l/1024/1024;return n>=1024?(n/1024).toFixed(1)+" GB":Math.round(n)+" MB"}function G(l){if(!l)return"-";const n=Math.floor((Date.now()-l)/1e3);return n<60?`${n}s`:n<3600?`${Math.floor(n/60)}m`:n<86400?`${Math.floor(n/3600)}h`:`${Math.floor(n/86400)}d`}return Z(()=>{h();const l=setInterval(h,1e4);return()=>clearInterval(l)}),A({fetchStatus:h}),(l,n)=>{const K=m("el-card");return u(),P(K,{class:"instance-card"},{default:a(()=>{var N;return[t("div",mt,[t("div",vt,[n[0]||(n[0]=t("div",{class:"instance-icon"},[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"1.5"},[t("rect",{x:"3",y:"3",width:"18",height:"18",rx:"4"}),t("circle",{cx:"12",cy:"12",r:"3"})])],-1)),t("div",ft,[t("h3",yt,c($.instance.displayName||$.instance.name),1),t("span",gt,c($.instance.name),1)])]),t("div",{class:dt(["status-indicator",j.value])},[n[1]||(n[1]=t("span",{class:"status-dot"},null,-1)),t("span",ht,c(D.value),1)],2)]),t("div",_t,[t("div",bt,[n[2]||(n[2]=t("span",{class:"label"},"Path",-1)),t("span",wt,c(b.value),1)]),d.value.exists?(u(),y("div",kt,[t("div",It,[n[3]||(n[3]=t("span",{class:"stat-label"},"Memory",-1)),t("span",$t,c(U(d.value.memory)),1)]),t("div",Ct,[n[4]||(n[4]=t("span",{class:"stat-label"},"CPU",-1)),t("span",xt,c(d.value.cpu)+"%",1)]),d.value.status==="online"?(u(),y("div",Nt,[n[5]||(n[5]=t("span",{class:"stat-label"},"Uptime",-1)),t("span",Pt,c(G(d.value.uptime)),1)])):q("",!0)])):q("",!0),(N=$.instance.tags)!=null&&N.length?(u(),y("div",Vt,[(u(!0),y(tt,null,et($.instance.tags,R=>(u(),y("span",{key:R,class:"tag"},c(R),1))),128))])):q("",!0)]),t("div",jt,[t("div",Dt,[t("button",{class:"action-btn",disabled:d.value.status==="online",title:"Start",onClick:M},[...n[6]||(n[6]=[t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("polygon",{points:"5 3 19 12 5 21 5 3"})],-1)])],8,Mt),t("button",{class:"action-btn",disabled:d.value.status!=="online",title:"Stop",onClick:x},[...n[7]||(n[7]=[t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("rect",{x:"6",y:"4",width:"4",height:"16"}),t("rect",{x:"14",y:"4",width:"4",height:"16"})],-1)])],8,Rt),t("button",{class:"action-btn",disabled:d.value.status==="unknown",title:"Restart",onClick:r},[...n[8]||(n[8]=[t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[t("polyline",{points:"23 4 23 10 17 10"}),t("polyline",{points:"1 20 1 14 7 14"}),t("path",{d:"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"})],-1)])],8,Bt)]),t("button",{class:"details-btn",onClick:E}," Details ")])]}),_:1})}}},At=at(St,[["__scopeId","data-v-bbbabd13"]]),Ut={class:"dashboard-view"},Ft={class:"dashboard-header"},zt={class:"header-actions"},Tt={class:"stat-content"},qt={class:"stat-info"},Et={class:"stat-value"},Gt={class:"stat-content"},Kt={class:"stat-info"},Lt={class:"stat-value"},Ot={class:"stat-content"},Wt={class:"stat-info"},Jt={class:"stat-value"},Qt={class:"stat-content"},Ht={class:"stat-info"},Xt={class:"stat-value"},Yt={key:0,class:"loading-state"},Zt={key:1,class:"empty-state"},te={key:0,class:"loading-state"},ee={key:1,class:"empty-discovered"},se={__name:"Dashboard",setup($){const{success:A,error:p}=st(),w=f([]),C=f(!0),g=f(!1),d=f(!1),j=f(!1),D=f(null),b=f([]),h=f(!1),M=f(null),x=f([]),r=f({name:"",displayName:"",projectPath:"",tagsInput:""}),E={name:[{required:!0,message:"Name is required"},{pattern:/^[a-z0-9-]+$/,message:"Only lowercase letters, numbers, and hyphens"}],projectPath:[{required:!0,message:"Project path is required"}]},U=k(()=>w.value.filter(i=>i.enabled).length),G=k(()=>w.value.length-U.value),l=k(()=>0),n=k(()=>b.value.length>0),K=k(()=>b.value.length);async function N(){C.value=!0;try{w.value=await I.getInstances(),await R()}catch(i){p("Failed to load",i.message)}finally{C.value=!1}}async function R(){try{const i=await I.discoverInstances();b.value=i.discovered||[]}catch{b.value=[]}}async function nt(){h.value=!0;try{await R()}catch(i){p("Discovery failed",i.message)}finally{h.value=!1}}async function lt(i){M.value=i.name;try{await I.importInstance({name:i.name,botName:i.botName,displayName:i.displayName,projectPath:i.projectPath}),x.value.push(i.name),A("Imported",`Instance "${i.displayName}" has been imported`),await N(),x.value.length>=b.value.length&&(d.value=!1,x.value=[])}catch(e){p("Import failed",e.message)}finally{M.value=null}}async function L(){var e;if(await((e=D.value)==null?void 0:e.validate().catch(()=>!1))){j.value=!0;try{const v=r.value.tagsInput?r.value.tagsInput.split(",").map(V=>V.trim()).filter(Boolean):[];await I.addInstance({name:r.value.name,displayName:r.value.displayName||r.value.name,projectPath:r.value.projectPath,tags:v}),A("Added",`Instance "${r.value.name}" has been added`),g.value=!1,W(),await N()}catch(v){p("Failed to add",v.message)}finally{j.value=!1}}}function O(){g.value=!1,W()}function W(){var i;r.value={name:"",displayName:"",projectPath:"",tagsInput:""},(i=D.value)==null||i.clearValidation()}return Z(()=>{N();const i=setInterval(N,3e4);return()=>clearInterval(i)}),(i,e)=>{const v=m("el-button"),V=m("el-card"),B=m("el-col"),J=m("el-row"),Q=m("el-skeleton"),S=m("el-table-column"),H=m("el-tag"),ot=m("el-table"),X=m("el-dialog"),F=m("el-input"),z=m("el-form-item"),it=m("el-form");return u(),y("div",Ut,[t("div",Ft,[e[11]||(e[11]=t("div",null,[t("h1",null,"Dashboard"),t("p",{class:"subtitle"},"Manage your AgentWindow bot instances")],-1)),t("div",zt,[n.value?(u(),P(v,{key:0,type:"info",icon:T(ct),onClick:e[0]||(e[0]=o=>d.value=!0)},{default:a(()=>[_(" Import "+c(K.value)+" Running ",1)]),_:1},8,["icon"])):q("",!0),s(v,{type:"primary",icon:T(Y),onClick:e[1]||(e[1]=o=>g.value=!0)},{default:a(()=>[...e[10]||(e[10]=[_(" Add Instance ",-1)])]),_:1},8,["icon"])])]),s(J,{gutter:16,class:"stats-row"},{default:a(()=>[s(B,{xs:12,sm:6},{default:a(()=>[s(V,{class:"stat-card"},{default:a(()=>[t("div",Tt,[e[13]||(e[13]=t("span",{class:"stat-icon"},"📦",-1)),t("div",qt,[t("span",Et,c(w.value.length),1),e[12]||(e[12]=t("span",{class:"stat-label"},"Total",-1))])])]),_:1})]),_:1}),s(B,{xs:12,sm:6},{default:a(()=>[s(V,{class:"stat-card success"},{default:a(()=>[t("div",Gt,[e[15]||(e[15]=t("span",{class:"stat-icon"},"🟢",-1)),t("div",Kt,[t("span",Lt,c(U.value),1),e[14]||(e[14]=t("span",{class:"stat-label"},"Running",-1))])])]),_:1})]),_:1}),s(B,{xs:12,sm:6},{default:a(()=>[s(V,{class:"stat-card warning"},{default:a(()=>[t("div",Ot,[e[17]||(e[17]=t("span",{class:"stat-icon"},"⏸️",-1)),t("div",Wt,[t("span",Jt,c(G.value),1),e[16]||(e[16]=t("span",{class:"stat-label"},"Stopped",-1))])])]),_:1})]),_:1}),s(B,{xs:12,sm:6},{default:a(()=>[s(V,{class:"stat-card danger"},{default:a(()=>[t("div",Qt,[e[19]||(e[19]=t("span",{class:"stat-icon"},"⚠️",-1)),t("div",Ht,[t("span",Xt,c(l.value),1),e[18]||(e[18]=t("span",{class:"stat-label"},"Errors",-1))])])]),_:1})]),_:1})]),_:1}),C.value?(u(),y("div",Yt,[s(Q,{rows:3,animated:""})])):w.value.length===0?(u(),y("div",Zt,[e[21]||(e[21]=t("div",{class:"empty-icon"},"🪟",-1)),e[22]||(e[22]=t("h3",null,"No instances yet",-1)),e[23]||(e[23]=t("p",null,"Add your first AgentWindow bot instance to get started",-1)),s(v,{type:"primary",icon:T(Y),onClick:e[2]||(e[2]=o=>g.value=!0)},{default:a(()=>[...e[20]||(e[20]=[_(" Add Instance ",-1)])]),_:1},8,["icon"])])):(u(),P(J,{key:2,gutter:16,class:"instances-grid"},{default:a(()=>[(u(!0),y(tt,null,et(w.value,o=>(u(),P(B,{key:o.name,xs:24,sm:12,lg:8},{default:a(()=>[s(At,{instance:o},null,8,["instance"])]),_:2},1024))),128))]),_:1})),s(X,{modelValue:d.value,"onUpdate:modelValue":e[4]||(e[4]=o=>d.value=o),title:"Import Running Instances",width:"600px"},{footer:a(()=>[s(v,{onClick:e[3]||(e[3]=o=>d.value=!1)},{default:a(()=>[...e[26]||(e[26]=[_("Close",-1)])]),_:1}),s(v,{type:"primary",icon:T(pt),onClick:nt},{default:a(()=>[...e[27]||(e[27]=[_("Refresh",-1)])]),_:1},8,["icon"])]),default:a(()=>[e[28]||(e[28]=t("div",{class:"discover-info"},[t("p",null,"The following bot instances are running in PM2 but not yet registered:")],-1)),h.value?(u(),y("div",te,[s(Q,{rows:2,animated:""})])):b.value.length===0?(u(),y("div",ee,[...e[24]||(e[24]=[t("p",null,"No unregistered instances found.",-1)])])):(u(),P(ot,{key:2,data:b.value,stripe:"",style:{width:"100%"}},{default:a(()=>[s(S,{prop:"displayName",label:"Name",width:"140"}),s(S,{prop:"botName",label:"PM2 Name",width:"130"}),s(S,{label:"Status",width:"90"},{default:a(({row:o})=>[o.isRunning?(u(),P(H,{key:0,type:"success",size:"small"},{default:a(()=>[...e[25]||(e[25]=[_("Running",-1)])]),_:1})):(u(),P(H,{key:1,type:"info",size:"small"},{default:a(()=>[_(c(o.status),1)]),_:2},1024))]),_:1}),s(S,{prop:"projectPath",label:"Path","show-overflow-tooltip":""}),s(S,{label:"Action",width:"80",align:"center"},{default:a(({row:o})=>[s(v,{type:"primary",size:"small",loading:M.value===o.name,disabled:x.value.includes(o.name),onClick:ae=>lt(o)},{default:a(()=>[_(c(x.value.includes(o.name)?"Done":"Import"),1)]),_:2},1032,["loading","disabled","onClick"])]),_:1})]),_:1},8,["data"]))]),_:1},8,["modelValue"]),s(X,{modelValue:g.value,"onUpdate:modelValue":e[9]||(e[9]=o=>g.value=o),title:"Add Instance",width:"500px","before-close":O},{footer:a(()=>[s(v,{onClick:O},{default:a(()=>[...e[30]||(e[30]=[_("Cancel",-1)])]),_:1}),s(v,{type:"primary",loading:j.value,onClick:L},{default:a(()=>[...e[31]||(e[31]=[_(" Add Instance ",-1)])]),_:1},8,["loading"])]),default:a(()=>[s(it,{ref_key:"formRef",ref:D,model:r.value,rules:E,"label-width":"100px"},{default:a(()=>[s(z,{label:"Name",prop:"name"},{default:a(()=>[s(F,{modelValue:r.value.name,"onUpdate:modelValue":e[5]||(e[5]=o=>r.value.name=o),placeholder:"my-bot",onKeyup:ut(L,["enter"])},null,8,["modelValue"])]),_:1}),s(z,{label:"Display Name",prop:"displayName"},{default:a(()=>[s(F,{modelValue:r.value.displayName,"onUpdate:modelValue":e[6]||(e[6]=o=>r.value.displayName=o),placeholder:"My Bot"},null,8,["modelValue"])]),_:1}),s(z,{label:"Project Path",prop:"projectPath"},{default:a(()=>[s(F,{modelValue:r.value.projectPath,"onUpdate:modelValue":e[7]||(e[7]=o=>r.value.projectPath=o),placeholder:"/path/to/project"},null,8,["modelValue"]),e[29]||(e[29]=t("div",{class:"form-hint"},"Path to the bot project directory",-1))]),_:1}),s(z,{label:"Tags",prop:"tags"},{default:a(()=>[s(F,{modelValue:r.value.tagsInput,"onUpdate:modelValue":e[8]||(e[8]=o=>r.value.tagsInput=o),placeholder:"prod, staging (comma separated)"},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])])}}},re=at(se,[["__scopeId","data-v-af31d52b"]]);export{re as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{r as b,j as Y,W as se,f as le,ab as u,y as p,B as w,E as a,C as t,D as s,Q as v,u as k,z as H,P as z,J as M,a5 as Z,G as K,R as r,c as E,n as oe,aB as ie,aA as ue}from"./vue-vendor-CGSlMM3Y.js";import{d as re,b as de,f as ce,c as pe,l as me,v as _e,e as fe,
|
|
1
|
+
import{r as b,j as Y,W as se,f as le,ab as u,y as p,B as w,E as a,C as t,D as s,Q as v,u as k,z as H,P as z,J as M,a5 as Z,G as K,R as r,c as E,n as oe,aB as ie,aA as ue}from"./vue-vendor-CGSlMM3Y.js";import{d as re,b as de,f as ce,c as pe,l as me,v as _e,e as fe,g as ve,m as ge,a as we}from"./element-plus-CSm40ime.js";import{a as V,u as ye}from"./main-CMa467nG.js";import{_ as ee}from"./_plugin-vue_export-helper-DlAUqK2U.js";const he={class:"log-toolbar"},be={class:"toolbar-left"},ke={class:"toolbar-right"},xe={key:0,class:"empty-logs"},Ce={class:"log-timestamp"},Se={key:0,class:"log-type"},$e={class:"log-message"},Le={key:1,class:"loading-logs"},De={__name:"LogViewer",props:{instanceName:{type:String,required:!0},expanded:{type:Boolean,default:!1}},emits:["expand","collapse"],setup(j,{emit:F}){const C=j,S=F,_=b([]),l=b(!1),m=b(!1),x=b(C.expanded),f=b("all"),L=b(""),D=b(null);let y=null;const N=E(()=>{let i=_.value;if(f.value!=="all"&&(i=i.filter(n=>String(n.data||n).toLowerCase().includes(f.value==="out"?"stdout":"stderr"))),L.value){const n=L.value.toLowerCase();i=i.filter(d=>String(d.data||d).toLowerCase().includes(n))}return i});function I(i){const n=String(i.data||i).toLowerCase();return n.includes("error")||n.includes("err")||i.type==="error"?"log-error":n.includes("warn")||i.type==="warning"?"log-warn":n.includes("info")?"log-info":""}function A(i){return i?new Date(i).toLocaleTimeString("en-US",{hour12:!1}):""}function W(i){i?B():U()}function B(){if(y)return;const i=window.location.protocol==="https:"?"wss:":"ws:",n=window.location.host,d=`${i}//${n}/ws/logs/${C.instanceName}`;y=new WebSocket(d),y.onopen=()=>{l.value=!1},y.onmessage=g=>{try{const h=JSON.parse(g.data);h.type==="log"&&(_.value.push(h),_.value.length>1e3&&(_.value=_.value.slice(-1e3)),oe(()=>{D.value&&(D.value.scrollTop=D.value.scrollHeight)}))}catch{_.value.push({data:g.data,timestamp:Date.now()})}},y.onerror=()=>{l.value=!1},y.onclose=()=>{y=null,m.value&&setTimeout(B,3e3)}}function U(){y&&(y.close(),y=null)}async function q(){l.value=!0;try{const n=await(await fetch(`/api/instances/${C.instanceName}/logs?lines=100`)).json();n.logs&&(_.value=n.logs.split(`
|
|
2
2
|
`).filter(d=>d.trim()).map(d=>({data:d,timestamp:Date.now()})))}catch{}finally{l.value=!1}}function O(){_.value=[]}function o(){const i=_.value.map(h=>h.data||h).join(`
|
|
3
3
|
`),n=new Blob([i],{type:"text/plain"}),d=URL.createObjectURL(n),g=document.createElement("a");g.href=d,g.download=`${C.instanceName}-logs-${Date.now()}.txt`,g.click(),URL.revokeObjectURL(d)}function e(){x.value=!0,S("expand")}function G(){x.value=!1,S("collapse")}return Y(()=>{q()}),se(()=>{U()}),le(()=>C.expanded,i=>{x.value=i}),(i,n)=>{const d=u("el-checkbox"),g=u("el-option"),h=u("el-select"),J=u("el-input"),R=u("el-button"),Q=u("el-icon");return p(),w("div",{class:K(["log-viewer",{expanded:x.value}])},[a("div",he,[a("div",be,[t(d,{modelValue:m.value,"onUpdate:modelValue":n[0]||(n[0]=c=>m.value=c),onChange:W},{default:s(()=>[...n[3]||(n[3]=[a("span",null,"Live",-1)])]),_:1},8,["modelValue"]),t(h,{modelValue:f.value,"onUpdate:modelValue":n[1]||(n[1]=c=>f.value=c),size:"small",style:{width:"100px"}},{default:s(()=>[t(g,{label:"All",value:"all"}),t(g,{label:"Stdout",value:"out"}),t(g,{label:"Stderr",value:"err"})]),_:1},8,["modelValue"]),t(J,{modelValue:L.value,"onUpdate:modelValue":n[2]||(n[2]=c=>L.value=c),size:"small",placeholder:"Search logs...","prefix-icon":"Search",style:{width:"200px"},clearable:""},null,8,["modelValue"])]),a("div",ke,[t(R,{size:"small",icon:k(re),onClick:o},{default:s(()=>[...n[4]||(n[4]=[v(" Export ",-1)])]),_:1},8,["icon"]),t(R,{size:"small",icon:k(de),onClick:O},{default:s(()=>[...n[5]||(n[5]=[v(" Clear ",-1)])]),_:1},8,["icon"]),j.expanded?(p(),H(R,{key:1,size:"small",icon:k(pe),onClick:G},null,8,["icon"])):(p(),H(R,{key:0,size:"small",icon:k(ce),onClick:e},null,8,["icon"]))])]),a("div",{class:"log-content",ref_key:"logContentRef",ref:D},[N.value.length===0?(p(),w("div",xe,[...n[6]||(n[6]=[a("span",null,"No logs to display",-1)])])):z("",!0),(p(!0),w(M,null,Z(N.value,(c,P)=>(p(),w("div",{key:P,class:K(["log-line",I(c)])},[a("span",Ce,r(A(c.timestamp)),1),c.type!=="log"?(p(),w("span",Se,r(c.type),1)):z("",!0),a("span",$e,r(c.data||c),1)],2))),128)),l.value?(p(),w("div",Le,[t(Q,{class:"is-loading"},{default:s(()=>[t(k(me))]),_:1})])):z("",!0)],512)],2)}}},Ie=ee(De,[["__scopeId","data-v-d564c329"]]),Re={class:"instance-detail-view"},Ve={key:0,class:"loading-state"},Ne={key:1,class:"error-state"},Be={class:"detail-header"},Ue={class:"header-content"},Pe={class:"instance-icon"},Te={class:"instance-name"},ze={class:"header-actions"},Me={class:"status-panel"},Ee={class:"status-indicator"},je={class:"status-text"},Fe={class:"status-stats"},Ae={class:"stat-item"},We={class:"stat-value"},qe={class:"stat-item"},Oe={class:"stat-value"},Ge={class:"stat-item"},Je={class:"stat-value"},Qe={class:"stat-item"},He={class:"stat-value"},Ke={key:1},Xe={__name:"InstanceDetail",setup(j){const F=ie(),C=ue(),{success:S,error:_}=ye(),l=b(null),m=b({status:"unknown",exists:!1}),x=b(!0),f=b(null),L=E(()=>{var o,e;return(e=(o=l.value)==null?void 0:o.tags)!=null&&e.includes("prod")?"🏢":"🤖"}),D=E(()=>{const o=m.value.status;return o==="online"?"online":o==="stopped"?"stopped":o==="errored"?"error":""}),y=E(()=>{const o=m.value.status;return{online:"Running",stopped:"Stopped",errored:"Error",restarting:"Restarting"}[o]||"Unknown"});async function N(){x.value=!0;try{const o=F.params.name;l.value=await V.getInstance(o),await I()}catch{l.value=null}finally{x.value=!1}}async function I(){try{m.value=await V.getInstanceStatus(l.value.name)}catch{m.value={status:"unknown",exists:!1}}}async function A(){f.value="start";try{await V.startInstance(l.value.name),S("Started",`${l.value.name} has been started`),await I()}catch(o){_("Failed to start",o.message)}finally{f.value=null}}async function W(){f.value="stop";try{await V.stopInstance(l.value.name),S("Stopped",`${l.value.name} has been stopped`),await I()}catch(o){_("Failed to stop",o.message)}finally{f.value=null}}async function B(){f.value="restart";try{await V.restartInstance(l.value.name),S("Restarted",`${l.value.name} has been restarted`),await I()}catch(o){_("Failed to restart",o.message)}finally{f.value=null}}async function U(o){switch(o){case"delete":try{await we.confirm(`Are you sure you want to delete "${l.value.name}"?`,"Confirm Delete",{type:"warning"}),await V.removeInstance(l.value.name),S("Deleted","Instance has been removed"),C.push("/")}catch(e){err!=="cancel"&&_("Failed",e.message)}break}}function q(o){if(!o)return"-";const e=o/1024/1024;return e>=1024?(e/1024).toFixed(1)+" GB":Math.round(e)+" MB"}function O(o){return o?new Date(o).toLocaleString():"-"}return Y(N),(o,e)=>{const G=u("el-skeleton"),i=u("el-button"),n=u("el-result"),d=u("el-page-header"),g=u("el-button-group"),h=u("el-dropdown-item"),J=u("el-dropdown-menu"),R=u("el-dropdown"),Q=u("el-divider"),c=u("el-card"),P=u("el-col"),$=u("el-descriptions-item"),te=u("el-tag"),ae=u("el-descriptions"),ne=u("el-row");return p(),w("div",Re,[x.value?(p(),w("div",Ve,[t(G,{rows:5,animated:""})])):l.value?(p(),w(M,{key:2},[a("div",Be,[t(d,{onBack:e[1]||(e[1]=T=>o.$router.push("/"))},{content:s(()=>[a("div",Ue,[a("span",Pe,r(L.value),1),a("div",null,[a("h2",null,r(l.value.displayName||l.value.name),1),a("span",Te,r(l.value.name),1)])])]),_:1}),a("div",ze,[t(g,null,{default:s(()=>[t(i,{icon:k(_e),disabled:m.value.status==="online",loading:f.value==="start",onClick:A},{default:s(()=>[...e[3]||(e[3]=[v(" Start ",-1)])]),_:1},8,["icon","disabled","loading"]),t(i,{icon:k(fe),disabled:m.value.status!=="online",loading:f.value==="stop",onClick:W},{default:s(()=>[...e[4]||(e[4]=[v(" Stop ",-1)])]),_:1},8,["icon","disabled","loading"]),t(i,{icon:k(ve),loading:f.value==="restart",onClick:B},{default:s(()=>[...e[5]||(e[5]=[v(" Restart ",-1)])]),_:1},8,["icon","loading"])]),_:1}),t(R,{onCommand:U},{dropdown:s(()=>[t(J,null,{default:s(()=>[t(h,{command:"logs"},{default:s(()=>[...e[7]||(e[7]=[v("View Logs",-1)])]),_:1}),t(h,{command:"config"},{default:s(()=>[...e[8]||(e[8]=[v("Edit Config",-1)])]),_:1}),t(h,{command:"delete",divided:""},{default:s(()=>[...e[9]||(e[9]=[v("Delete Instance",-1)])]),_:1})]),_:1})]),default:s(()=>[t(i,{icon:k(ge)},{default:s(()=>[...e[6]||(e[6]=[v(" More ",-1)])]),_:1},8,["icon"])]),_:1})])]),t(ne,{gutter:20,class:"detail-content"},{default:s(()=>[t(P,{xs:24,lg:8},{default:s(()=>[t(c,{header:"Status"},{default:s(()=>[a("div",Me,[a("div",Ee,[a("span",{class:K(["status-dot",D.value])},null,2),a("span",je,r(y.value),1)]),m.value.exists?(p(),w(M,{key:0},[t(Q),a("div",Fe,[a("div",Ae,[e[10]||(e[10]=a("span",{class:"stat-label"},"PID",-1)),a("span",We,r(m.value.pid||"-"),1)]),a("div",qe,[e[11]||(e[11]=a("span",{class:"stat-label"},"Memory",-1)),a("span",Oe,r(q(m.value.memory)),1)]),a("div",Ge,[e[12]||(e[12]=a("span",{class:"stat-label"},"CPU",-1)),a("span",Je,r(m.value.cpu)+"%",1)]),a("div",Qe,[e[13]||(e[13]=a("span",{class:"stat-label"},"Restarts",-1)),a("span",He,r(m.value.restarts),1)])])],64)):z("",!0)])]),_:1})]),_:1}),t(P,{xs:24,lg:16},{default:s(()=>[t(c,{header:"Information"},{default:s(()=>[t(ae,{column:1,border:""},{default:s(()=>[t($,{label:"Name"},{default:s(()=>[v(r(l.value.name),1)]),_:1}),t($,{label:"Display Name"},{default:s(()=>[v(r(l.value.displayName||"-"),1)]),_:1}),t($,{label:"Project Path"},{default:s(()=>[a("code",null,r(l.value.projectPath),1)]),_:1}),t($,{label:"Plugin Path"},{default:s(()=>[a("code",null,r(l.value.pluginPath||"-"),1)]),_:1}),t($,{label:"Config Path"},{default:s(()=>[a("code",null,r(l.value.configPath||"Default"),1)]),_:1}),t($,{label:"Added"},{default:s(()=>[v(r(O(l.value.addedAt)),1)]),_:1}),t($,{label:"Tags"},{default:s(()=>{var T;return[(T=l.value.tags)!=null&&T.length?(p(!0),w(M,{key:0},Z(l.value.tags,X=>(p(),H(te,{key:X,size:"small",style:{"margin-right":"4px"}},{default:s(()=>[v(r(X),1)]),_:2},1024))),128)):(p(),w("span",Ke,"-"))]}),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),t(c,{header:"Recent Logs",class:"logs-card"},{default:s(()=>[t(Ie,{"instance-name":l.value.name,expanded:!1},null,8,["instance-name"])]),_:1})],64)):(p(),w("div",Ne,[t(n,{icon:"error",title:"Instance not found","sub-title":"The requested instance does not exist"},{extra:s(()=>[t(i,{type:"primary",onClick:e[0]||(e[0]=T=>o.$router.push("/"))},{default:s(()=>[...e[2]||(e[2]=[v("Back to Dashboard",-1)])]),_:1})]),_:1})]))])}}},at=ee(Xe,[["__scopeId","data-v-f1b6dde0"]]);export{at as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as p,u as B}from"./main-
|
|
1
|
+
import{a as p,u as B}from"./main-CMa467nG.js";import{_ as I}from"./_plugin-vue_export-helper-DlAUqK2U.js";import{a as k}from"./element-plus-CSm40ime.js";import{j as x,y as _,B as N,E as f,C as a,D as n,M as $,z,Q as i,R as E,ac as T,r as b,ab as o}from"./vue-vendor-CGSlMM3Y.js";const V={class:"instances-view"},j={__name:"Instances",setup(M){const{success:v,error:r}=B(),d=b([]),c=b(!0);async function u(){c.value=!0;try{d.value=await p.getInstances()}catch(t){r("Failed to load",t.message)}finally{c.value=!1}}async function y(t){try{await k.confirm(`Are you sure you want to delete instance "${t.name}"?`,"Confirm Delete",{type:"warning",confirmButtonText:"Delete",cancelButtonText:"Cancel"}),await p.removeInstance(t.name),v("Deleted",`Instance "${t.name}" has been removed`),await u()}catch(e){e!=="cancel"&&r("Failed to delete",e.message)}}return x(u),(t,e)=>{const s=o("el-table-column"),g=o("el-tag"),m=o("el-button"),h=o("el-table"),w=o("el-card"),D=T("loading");return _(),N("div",V,[e[2]||(e[2]=f("div",{class:"view-header"},[f("h1",null,"Instances")],-1)),a(w,null,{default:n(()=>[$((_(),z(h,{data:d.value,stripe:""},{default:n(()=>[a(s,{prop:"name",label:"Name",width:"180"}),a(s,{prop:"displayName",label:"Display Name"}),a(s,{prop:"projectPath",label:"Project Path"}),a(s,{prop:"enabled",label:"Status",width:"100"},{default:n(({row:l})=>[a(g,{type:l.enabled?"success":"info",size:"small"},{default:n(()=>[i(E(l.enabled?"Enabled":"Disabled"),1)]),_:2},1032,["type"])]),_:1}),a(s,{label:"Actions",width:"200",align:"right"},{default:n(({row:l})=>[a(m,{size:"small",onClick:C=>t.$router.push(`/instances/${l.name}`)},{default:n(()=>[...e[0]||(e[0]=[i(" View ",-1)])]),_:1},8,["onClick"]),a(m,{size:"small",type:"danger",plain:"",onClick:C=>y(l)},{default:n(()=>[...e[1]||(e[1]=[i(" Delete ",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[D,c.value]])]),_:1})])}}},Q=I(j,[["__scopeId","data-v-b1513f53"]]);export{Q as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as M}from"./main-
|
|
1
|
+
import{b as M}from"./main-CMa467nG.js";import{_ as I}from"./_plugin-vue_export-helper-DlAUqK2U.js";import{r as B,j as W,y as g,B as $,E as r,C as t,D as o,u,z as v,Q as i,R as c,ab as s,c as D}from"./vue-vendor-CGSlMM3Y.js";import"./element-plus-CSm40ime.js";const N={class:"settings-view"},A={class:"setting-item"},C={__name:"Settings",setup(E){const{systemInfo:d,fetchSystemInfo:w}=M(),_=B(localStorage.getItem("darkMode")==="true"),b=D(()=>{var n;const a=(n=d.value)==null?void 0:n.platform;return{darwin:"macOS",linux:"Linux",win32:"Windows"}[a]||a});function k(){localStorage.setItem("darkMode",_.value),document.documentElement.classList.toggle("dark",_.value)}function h(a){if(!a)return"-";const e=Math.floor(a/86400),n=Math.floor(a%86400/3600),m=Math.floor(a%3600/60);return e>0?`${e}d ${n}h ${m}m`:n>0?`${n}h ${m}m`:`${m}m`}return W(()=>{w()}),(a,e)=>{const n=s("el-descriptions-item"),m=s("el-descriptions"),y=s("el-skeleton"),p=s("el-card"),f=s("el-col"),V=s("el-switch"),x=s("el-divider"),S=s("el-row");return g(),$("div",N,[e[4]||(e[4]=r("div",{class:"view-header"},[r("h1",null,"Settings")],-1)),t(S,{gutter:20},{default:o(()=>[t(f,{span:24},{default:o(()=>[t(p,{header:"System Information"},{default:o(()=>[u(d)?(g(),v(m,{key:0,column:2,border:""},{default:o(()=>[t(n,{label:"Platform"},{default:o(()=>[i(c(b.value),1)]),_:1}),t(n,{label:"Node Version"},{default:o(()=>[i(c(u(d).nodeVersion),1)]),_:1}),t(n,{label:"AgentWindow Version"},{default:o(()=>{var l;return[i(c((l=u(d).agentWindow)==null?void 0:l.version),1)]}),_:1}),t(n,{label:"Home Directory"},{default:o(()=>{var l;return[i(c((l=u(d).agentWindow)==null?void 0:l.home),1)]}),_:1}),t(n,{label:"Uptime",span:2},{default:o(()=>[i(c(h(u(d).uptime)),1)]),_:1})]),_:1})):(g(),v(y,{key:1,rows:4,animated:""}))]),_:1})]),_:1}),t(f,{xs:24,md:12},{default:o(()=>[t(p,{header:"Appearance"},{default:o(()=>[r("div",A,[e[1]||(e[1]=r("span",null,"Dark Mode",-1)),t(V,{modelValue:_.value,"onUpdate:modelValue":e[0]||(e[0]=l=>_.value=l),onChange:k},null,8,["modelValue"])])]),_:1})]),_:1}),t(f,{xs:24,md:12},{default:o(()=>[t(p,{header:"About"},{default:o(()=>[e[2]||(e[2]=r("p",null,"AgentWindow Web UI provides a browser-based interface for managing your bot instances.",-1)),t(x),e[3]||(e[3]=r("p",{class:"about-text"},[i(" Version 1.0.0"),r("br"),i(" Built with Vue 3 + Element Plus ")],-1))]),_:1})]),_:1})]),_:1})])}}},z=I(C,[["__scopeId","data-v-a16409cb"]]);export{z as default};
|