agent-window 1.0.2 → 1.0.4

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.2",
3
+ "version": "1.0.4",
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,
@@ -248,5 +250,64 @@ export async function registerInstanceRoutes(fastify) {
248
250
  }
249
251
  });
250
252
 
253
+ /**
254
+ * GET /api/instances/discover
255
+ * Discover bot instances running in PM2 that are not registered
256
+ */
257
+ fastify.get('/api/instances/discover', {
258
+ schema: {
259
+ description: 'Discover unregistered bot instances from PM2',
260
+ tags: ['instances']
261
+ }
262
+ }, async (request, reply) => {
263
+ try {
264
+ const discovered = await discoverInstances();
265
+ return { discovered };
266
+ } catch (error) {
267
+ reply.code(500).send({
268
+ error: 'Failed to discover instances',
269
+ message: error.message
270
+ });
271
+ }
272
+ });
273
+
274
+ /**
275
+ * POST /api/instances/import
276
+ * Import a discovered instance
277
+ */
278
+ fastify.post('/api/instances/import', {
279
+ schema: {
280
+ description: 'Import a discovered instance',
281
+ body: {
282
+ type: 'object',
283
+ required: ['name'],
284
+ properties: {
285
+ name: { type: 'string' },
286
+ botName: { type: 'string' },
287
+ displayName: { type: 'string' },
288
+ projectPath: { type: 'string' }
289
+ }
290
+ }
291
+ }
292
+ }, async (request, reply) => {
293
+ try {
294
+ const discovered = request.body;
295
+ const result = await importInstance(discovered);
296
+
297
+ if (!result.success) {
298
+ return reply.code(400).send({
299
+ error: result.error
300
+ });
301
+ }
302
+
303
+ reply.code(201).send(result.instance);
304
+ } catch (error) {
305
+ reply.code(500).send({
306
+ error: 'Failed to import instance',
307
+ message: error.message
308
+ });
309
+ }
310
+ });
311
+
251
312
  fastify.log.info('Instance routes registered');
252
313
  }
package/src/api/server.js CHANGED
@@ -75,23 +75,32 @@ export function createServer(options = {}) {
75
75
  registerWebSocket(fastify);
76
76
 
77
77
  // Serve static files (frontend build)
78
- const distPath = join(process.cwd(), 'web', 'dist');
79
- if (existsSync(distPath)) {
78
+ // __dirname is src/api/, so we go up two levels to package root, then into web/dist
79
+ const distPath = join(__dirname, '..', '..', 'web', 'dist');
80
+ const hasDist = existsSync(distPath);
81
+
82
+ if (hasDist) {
80
83
  fastify.register(fastifyStatic, {
81
84
  root: distPath,
82
- prefix: '/'
83
- });
84
-
85
- // SPA fallback - serve index.html for non-API routes
86
- fastify.setNotFoundHandler(async (request, reply) => {
87
- if (request.url.startsWith('/api/') || request.url.startsWith('/ws/')) {
88
- reply.code(404).send({ error: 'Not found' });
89
- } else {
90
- reply.sendFile('index.html');
91
- }
85
+ prefix: '/',
86
+ decorateReply: false
92
87
  });
93
88
  }
94
89
 
90
+ // SPA fallback - serve index.html for non-API routes (if dist exists)
91
+ fastify.setNotFoundHandler(async (request, reply) => {
92
+ if (request.url.startsWith('/api/') || request.url.startsWith('/ws/')) {
93
+ reply.code(404).send({ error: 'Not found' });
94
+ } else if (hasDist) {
95
+ reply.sendFile('index.html');
96
+ } else {
97
+ reply.code(500).send({
98
+ error: 'Frontend not built',
99
+ message: 'The web UI assets are not available. Please report this issue.'
100
+ });
101
+ }
102
+ });
103
+
95
104
  // Graceful shutdown
96
105
  const gracefulShutdown = async (signal) => {
97
106
  fastify.log.info(`Received ${signal}, shutting down gracefully...`);
@@ -110,7 +119,7 @@ export function createServer(options = {}) {
110
119
  */
111
120
  export function getPackageVersion() {
112
121
  try {
113
- const pkgPath = join(process.cwd(), 'package.json');
122
+ const pkgPath = join(__dirname, '..', '..', 'package.json');
114
123
  const pkg = require(pkgPath);
115
124
  return pkg.version || 'unknown';
116
125
  } catch {
@@ -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};