agentgui 1.0.474 → 1.0.480

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.
@@ -14,14 +14,72 @@ const TOOLS = [
14
14
 
15
15
  const statusCache = new Map();
16
16
  const installLocks = new Map();
17
+ const versionCache = new Map();
17
18
 
18
19
  const getTool = (id) => TOOLS.find(t => t.id === id);
19
20
 
21
+ const getNodeModulesPath = () => {
22
+ const __dirname = path.dirname(new URL(import.meta.url).pathname);
23
+ return path.join(__dirname, '..', 'node_modules');
24
+ };
25
+
26
+ const getInstalledVersion = (pkg) => {
27
+ try {
28
+ const nodeModulesPath = getNodeModulesPath();
29
+ const pkgJsonPath = path.join(nodeModulesPath, pkg, 'package.json');
30
+ if (fs.existsSync(pkgJsonPath)) {
31
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
32
+ return pkgJson.version;
33
+ }
34
+ } catch (_) {}
35
+ return null;
36
+ };
37
+
38
+ const getPublishedVersion = async (pkg) => {
39
+ try {
40
+ const cacheKey = `published-${pkg}`;
41
+ const cached = versionCache.get(cacheKey);
42
+ if (cached && Date.now() - cached.timestamp < 3600000) {
43
+ return cached.version;
44
+ }
45
+
46
+ const cmd = isWindows ? 'npm.cmd' : 'npm';
47
+ const result = await new Promise((resolve) => {
48
+ const proc = spawn(cmd, ['view', pkg, 'version'], {
49
+ stdio: ['pipe', 'pipe', 'pipe'],
50
+ timeout: 5000,
51
+ shell: isWindows
52
+ });
53
+ let stdout = '';
54
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
55
+ const timer = setTimeout(() => {
56
+ try { proc.kill('SIGKILL'); } catch (_) {}
57
+ resolve(null);
58
+ }, 5000);
59
+ proc.on('close', (code) => {
60
+ clearTimeout(timer);
61
+ resolve(code === 0 ? stdout.trim() : null);
62
+ });
63
+ proc.on('error', () => {
64
+ clearTimeout(timer);
65
+ resolve(null);
66
+ });
67
+ });
68
+
69
+ if (result) {
70
+ versionCache.set(cacheKey, { version: result, timestamp: Date.now() });
71
+ }
72
+ return result;
73
+ } catch (_) {
74
+ return null;
75
+ }
76
+ };
77
+
20
78
  const checkToolInstalled = (pkg) => {
21
79
  try {
22
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
23
- const nodeModulesPath = path.join(__dirname, '..', 'node_modules', pkg);
24
- return fs.existsSync(nodeModulesPath);
80
+ const nodeModulesPath = getNodeModulesPath();
81
+ const nodeModulesPackagePath = path.join(nodeModulesPath, pkg);
82
+ return fs.existsSync(nodeModulesPackagePath);
25
83
  } catch (_) {
26
84
  return false;
27
85
  }
@@ -30,7 +88,7 @@ const checkToolInstalled = (pkg) => {
30
88
  const checkToolViaBunx = async (pkg) => {
31
89
  try {
32
90
  const cmd = isWindows ? 'bunx.cmd' : 'bunx';
33
- return new Promise((resolve) => {
91
+ const checkResult = await new Promise((resolve) => {
34
92
  const proc = spawn(cmd, [pkg, '--version'], {
35
93
  stdio: ['pipe', 'pipe', 'pipe'],
36
94
  timeout: 10000,
@@ -42,7 +100,8 @@ const checkToolViaBunx = async (pkg) => {
42
100
  const timer = setTimeout(() => {
43
101
  try { proc.kill('SIGKILL'); } catch (_) {}
44
102
  const installed = checkToolInstalled(pkg);
45
- resolve({ installed, isUpToDate: installed, upgradeNeeded: false, output: 'timeout' });
103
+ const installedVersion = getInstalledVersion(pkg);
104
+ resolve({ installed, isUpToDate: installed, upgradeNeeded: false, output: 'timeout', installedVersion });
46
105
  }, 10000);
47
106
  proc.on('close', (code) => {
48
107
  clearTimeout(timer);
@@ -50,16 +109,36 @@ const checkToolViaBunx = async (pkg) => {
50
109
  const installed = code === 0 || checkToolInstalled(pkg);
51
110
  const upgradeNeeded = output.includes('Upgrading') || output.includes('upgrade');
52
111
  const isUpToDate = installed && !upgradeNeeded;
53
- resolve({ installed, isUpToDate, upgradeNeeded, output });
112
+ const installedVersion = getInstalledVersion(pkg);
113
+ resolve({ installed, isUpToDate, upgradeNeeded, output, installedVersion });
54
114
  });
55
115
  proc.on('error', () => {
56
116
  clearTimeout(timer);
57
117
  const installed = checkToolInstalled(pkg);
58
- resolve({ installed, isUpToDate: false, upgradeNeeded: false, output: '' });
118
+ const installedVersion = getInstalledVersion(pkg);
119
+ resolve({ installed, isUpToDate: false, upgradeNeeded: false, output: '', installedVersion });
59
120
  });
60
121
  });
122
+
123
+ const publishedVersion = await getPublishedVersion(pkg);
124
+ const compareVersions = (v1, v2) => {
125
+ if (!v1 || !v2) return false;
126
+ const parts1 = v1.split('.').map(Number);
127
+ const parts2 = v2.split('.').map(Number);
128
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
129
+ const p1 = parts1[i] || 0;
130
+ const p2 = parts2[i] || 0;
131
+ if (p1 < p2) return true;
132
+ if (p1 > p2) return false;
133
+ }
134
+ return false;
135
+ };
136
+
137
+ const needsUpdate = checkResult.installed && publishedVersion && compareVersions(checkResult.installedVersion, publishedVersion);
138
+ return { ...checkResult, publishedVersion, upgradeNeeded: needsUpdate };
61
139
  } catch (_) {
62
- return { installed: checkToolInstalled(pkg), isUpToDate: false, upgradeNeeded: false, output: '' };
140
+ const installedVersion = getInstalledVersion(pkg);
141
+ return { installed: checkToolInstalled(pkg), isUpToDate: false, upgradeNeeded: false, output: '', installedVersion, publishedVersion: null };
63
142
  }
64
143
  };
65
144
 
@@ -92,6 +171,8 @@ export async function checkToolStatusAsync(toolId) {
92
171
  installed: cached.installed,
93
172
  isUpToDate: cached.isUpToDate,
94
173
  upgradeNeeded: cached.upgradeNeeded,
174
+ installedVersion: cached.installedVersion,
175
+ publishedVersion: cached.publishedVersion,
95
176
  timestamp: cached.timestamp
96
177
  };
97
178
  }
@@ -102,6 +183,8 @@ export async function checkToolStatusAsync(toolId) {
102
183
  installed: result.installed,
103
184
  isUpToDate: result.isUpToDate,
104
185
  upgradeNeeded: result.upgradeNeeded,
186
+ installedVersion: result.installedVersion,
187
+ publishedVersion: result.publishedVersion,
105
188
  timestamp: Date.now()
106
189
  };
107
190
 
@@ -178,6 +261,8 @@ export function getAllTools() {
178
261
  installed: cached?.installed ?? false,
179
262
  isUpToDate: cached?.isUpToDate ?? false,
180
263
  upgradeNeeded: cached?.upgradeNeeded ?? false,
264
+ installedVersion: cached?.installedVersion ?? null,
265
+ publishedVersion: cached?.publishedVersion ?? null,
181
266
  timestamp: cached?.timestamp ?? 0
182
267
  };
183
268
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.474",
3
+ "version": "1.0.480",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -1792,7 +1792,9 @@ const server = http.createServer(async (req, res) => {
1792
1792
  status: t.installed ? (t.isUpToDate ? 'installed' : 'needs_update') : 'not_installed',
1793
1793
  isUpToDate: t.isUpToDate,
1794
1794
  upgradeNeeded: t.upgradeNeeded,
1795
- hasUpdate: t.upgradeNeeded && t.installed
1795
+ hasUpdate: t.upgradeNeeded && t.installed,
1796
+ installedVersion: t.installedVersion,
1797
+ publishedVersion: t.publishedVersion
1796
1798
  }));
1797
1799
  sendJSON(req, res, 200, { tools: result });
1798
1800
  return;
@@ -314,3 +314,25 @@
314
314
  font-size: 0.875rem;
315
315
  margin-bottom: 0.5rem;
316
316
  }
317
+
318
+ .tool-versions {
319
+ display: flex;
320
+ flex-direction: column;
321
+ gap: 0.25rem;
322
+ font-size: 0.75rem;
323
+ color: var(--color-text-secondary);
324
+ background: var(--color-bg-secondary);
325
+ padding: 0.5rem;
326
+ border-radius: 0.25rem;
327
+ }
328
+
329
+ .tool-version-item {
330
+ display: flex;
331
+ align-items: center;
332
+ gap: 0.375rem;
333
+ }
334
+
335
+ .tool-version-item strong {
336
+ color: var(--color-text-primary);
337
+ font-weight: 600;
338
+ }
@@ -162,6 +162,17 @@
162
162
  var statusClass = getStatusClass(tool);
163
163
  var isInstalling = tool.status === 'installing' || tool.status === 'updating';
164
164
  var hasAction = !tool.installed || tool.hasUpdate || tool.status === 'failed';
165
+ var versionInfo = '';
166
+ if (tool.installedVersion || tool.publishedVersion) {
167
+ versionInfo = '<div class="tool-versions">';
168
+ if (tool.installedVersion) {
169
+ versionInfo += '<span class="tool-version-item">Installed: <strong>' + esc(tool.installedVersion) + '</strong></span>';
170
+ }
171
+ if (tool.publishedVersion) {
172
+ versionInfo += '<span class="tool-version-item">Published: <strong>' + esc(tool.publishedVersion) + '</strong></span>';
173
+ }
174
+ versionInfo += '</div>';
175
+ }
165
176
 
166
177
  return '<div class="tool-item">' +
167
178
  '<div class="tool-header">' +
@@ -171,6 +182,7 @@
171
182
  '<span>' + getStatusText(tool) + '</span>' +
172
183
  '</span>' +
173
184
  '</div>' +
185
+ versionInfo +
174
186
  (tool.description ? '<div class="tool-details">' + esc(tool.description) + '</div>' : '') +
175
187
  (isInstalling && tool.progress !== undefined ?
176
188
  '<div class="tool-progress-container">' +