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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-window",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A window to interact with AI agents through chat interfaces. Simplified interaction, powerful backend capabilities.",
5
5
  "type": "module",
6
6
  "main": "src/bot.js",
@@ -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 status = await getStatus(name);
212
- return status;
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 logs = await getLogs(name, { lines, type: logType });
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 result = await startProcess(name);
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 result = await stopProcess(name);
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 result = await restartProcess(name);
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', name, '--lines', '50', '--raw', '--nostream'];
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-8cc433c7]{display:flex;flex-direction:column;gap:24px}.dashboard-header[data-v-8cc433c7]{display:flex;justify-content:space-between;align-items:flex-start}.dashboard-header h1[data-v-8cc433c7]{margin:0;font-size:28px;font-weight:600}.dashboard-header .subtitle[data-v-8cc433c7]{margin:4px 0 0;color:var(--el-text-color-secondary)}.stats-row .stat-card[data-v-8cc433c7]{background:linear-gradient(135deg,var(--el-bg-color) 0%,var(--el-bg-color-page) 100%)}.stats-row .stat-card.success[data-v-8cc433c7]{border-left:3px solid var(--aw-success)}.stats-row .stat-card.warning[data-v-8cc433c7]{border-left:3px solid var(--aw-warning)}.stats-row .stat-card.danger[data-v-8cc433c7]{border-left:3px solid var(--aw-danger)}.stats-row .stat-content[data-v-8cc433c7]{display:flex;align-items:center;gap:16px}.stats-row .stat-content .stat-icon[data-v-8cc433c7]{font-size:32px}.stats-row .stat-content .stat-info[data-v-8cc433c7]{display:flex;flex-direction:column}.stats-row .stat-content .stat-info .stat-value[data-v-8cc433c7]{font-size:24px;font-weight:600;line-height:1}.stats-row .stat-content .stat-info .stat-label[data-v-8cc433c7]{font-size:12px;color:var(--el-text-color-secondary)}.loading-state[data-v-8cc433c7]{padding:40px 0}.empty-state[data-v-8cc433c7]{display:flex;flex-direction:column;align-items:center;gap:16px;padding:80px 0}.empty-state .empty-icon[data-v-8cc433c7]{font-size:64px;opacity:.5}.empty-state h3[data-v-8cc433c7]{margin:0;font-size:20px}.empty-state p[data-v-8cc433c7]{margin:0;color:var(--el-text-color-secondary)}.instances-grid [class*=el-col][data-v-8cc433c7]{margin-bottom:16px}.form-hint[data-v-8cc433c7]{font-size:12px;color:var(--el-text-color-secondary);margin-top:4px}
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,r as ve,m as ge,a as we}from"./element-plus-Jr6qTeY5.js";import{a as V,u as ye}from"./main-D3cdXAiV.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(`
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-D3cdXAiV.js";import{_ as I}from"./_plugin-vue_export-helper-DlAUqK2U.js";import{a as k}from"./element-plus-Jr6qTeY5.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
+ 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-D3cdXAiV.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-Jr6qTeY5.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};
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};