agentgui 1.0.236 → 1.0.237
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/bin/gmgui.cjs +15 -5
- package/lib/claude-runner.js +17 -5
- package/package.json +1 -1
- package/server.js +15 -7
- package/static/js/conversations.js +25 -10
- package/static/js/streaming-renderer.js +33 -18
- package/telemetry-id +1 -0
package/bin/gmgui.cjs
CHANGED
|
@@ -16,19 +16,29 @@ async function gmgui(args = []) {
|
|
|
16
16
|
const installer = 'npm';
|
|
17
17
|
|
|
18
18
|
// Ensure dependencies are installed only if node_modules is missing
|
|
19
|
-
// Skip this for bunx which
|
|
19
|
+
// Skip this for bunx/npx which manage dependencies independently
|
|
20
20
|
const nodeModulesPath = path.join(projectRoot, 'node_modules');
|
|
21
|
-
const
|
|
21
|
+
const execPath = process.env.npm_execpath || '';
|
|
22
|
+
const isBunx = execPath.includes('bun') || process.env.BUN_INSTALL;
|
|
23
|
+
const isNpx = execPath.includes('npx') || process.env._.includes('npx');
|
|
24
|
+
|
|
25
|
+
// Also skip if running from temp/cache directory (bunx/npm cache)
|
|
26
|
+
const isFromCache = projectRoot.includes('node_modules') &&
|
|
27
|
+
(projectRoot.includes('.bun') || projectRoot.includes('_npx') || projectRoot.includes('npm-cache'));
|
|
22
28
|
|
|
23
|
-
if (!isBunx && !fs.existsSync(nodeModulesPath)) {
|
|
29
|
+
if (!isBunx && !isNpx && !isFromCache && !fs.existsSync(nodeModulesPath)) {
|
|
24
30
|
console.log(`Installing dependencies with ${installer}...`);
|
|
25
31
|
const installResult = spawnSync(installer, ['install'], {
|
|
26
32
|
cwd: projectRoot,
|
|
27
|
-
stdio: 'inherit'
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
shell: true
|
|
28
35
|
});
|
|
29
|
-
if (installResult.status !== 0) {
|
|
36
|
+
if (installResult.status !== 0 && installResult.status !== null) {
|
|
30
37
|
throw new Error(`${installer} install failed with code ${installResult.status}`);
|
|
31
38
|
}
|
|
39
|
+
if (installResult.error) {
|
|
40
|
+
throw new Error(`${installer} install failed: ${installResult.error.message}`);
|
|
41
|
+
}
|
|
32
42
|
}
|
|
33
43
|
|
|
34
44
|
const port = process.env.PORT || 3000;
|
package/lib/claude-runner.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
|
|
3
|
+
const isWindows = process.platform === 'win32';
|
|
4
|
+
|
|
5
|
+
function getSpawnOptions(cwd, additionalOptions = {}) {
|
|
6
|
+
const options = { cwd, ...additionalOptions };
|
|
7
|
+
if (isWindows) {
|
|
8
|
+
options.shell = true;
|
|
9
|
+
}
|
|
10
|
+
return options;
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
/**
|
|
4
14
|
* Agent Framework
|
|
5
15
|
* Extensible registry for AI agent CLI integrations
|
|
@@ -51,7 +61,7 @@ class AgentRunner {
|
|
|
51
61
|
} = config;
|
|
52
62
|
|
|
53
63
|
const args = this.buildArgs(prompt, config);
|
|
54
|
-
const proc = spawn(this.command, args,
|
|
64
|
+
const proc = spawn(this.command, args, getSpawnOptions(cwd));
|
|
55
65
|
|
|
56
66
|
if (config.onPid) {
|
|
57
67
|
try { config.onPid(proc.pid); } catch (e) {}
|
|
@@ -211,7 +221,7 @@ class AgentRunner {
|
|
|
211
221
|
const baseArgs = this.requiresAdapter && this.adapterCommand ? this.adapterArgs : this.buildArgs(prompt, config);
|
|
212
222
|
const args = [...baseArgs];
|
|
213
223
|
|
|
214
|
-
const proc = spawn(cmd, args,
|
|
224
|
+
const proc = spawn(cmd, args, getSpawnOptions(cwd));
|
|
215
225
|
|
|
216
226
|
if (config.onPid) {
|
|
217
227
|
try { config.onPid(proc.pid); } catch (e) {}
|
|
@@ -474,13 +484,15 @@ class AgentRegistry {
|
|
|
474
484
|
|
|
475
485
|
listACPAvailable() {
|
|
476
486
|
const { spawnSync } = require('child_process');
|
|
487
|
+
const isWindows = process.platform === 'win32';
|
|
477
488
|
return this.list().filter(agent => {
|
|
478
489
|
try {
|
|
479
|
-
const
|
|
490
|
+
const whichCmd = isWindows ? 'where' : 'which';
|
|
491
|
+
const which = spawnSync(whichCmd, [agent.command], { encoding: 'utf-8', timeout: 3000 });
|
|
480
492
|
if (which.status !== 0) return false;
|
|
481
|
-
const binPath = (which.stdout || '').trim();
|
|
493
|
+
const binPath = (which.stdout || '').trim().split('\n')[0].trim();
|
|
482
494
|
if (!binPath) return false;
|
|
483
|
-
const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000 });
|
|
495
|
+
const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000, shell: isWindows });
|
|
484
496
|
return check.status === 0 && (check.stdout || '').trim().length > 0;
|
|
485
497
|
} catch {
|
|
486
498
|
return false;
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1260,7 +1260,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1260
1260
|
delete childEnv.PORT;
|
|
1261
1261
|
delete childEnv.BASE_URL;
|
|
1262
1262
|
delete childEnv.HOT_RELOAD;
|
|
1263
|
-
const
|
|
1263
|
+
const isWindows = os.platform() === 'win32';
|
|
1264
|
+
const child = spawn('npm', ['run', script], { cwd: wd, stdio: ['ignore', 'pipe', 'pipe'], detached: true, env: childEnv, shell: isWindows });
|
|
1264
1265
|
activeScripts.set(conversationId, { process: child, script, startTime: Date.now() });
|
|
1265
1266
|
broadcastSync({ type: 'script_started', conversationId, script, timestamp: Date.now() });
|
|
1266
1267
|
|
|
@@ -1508,7 +1509,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1508
1509
|
|
|
1509
1510
|
const child = spawn(authCmd.cmd, authCmd.args, {
|
|
1510
1511
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1511
|
-
env: { ...process.env, FORCE_COLOR: '1' }
|
|
1512
|
+
env: { ...process.env, FORCE_COLOR: '1' },
|
|
1513
|
+
shell: os.platform() === 'win32'
|
|
1512
1514
|
});
|
|
1513
1515
|
activeScripts.set(conversationId, { process: child, script: 'auth-' + agentId, startTime: Date.now() });
|
|
1514
1516
|
broadcastSync({ type: 'script_started', conversationId, script: 'auth-' + agentId, agentId, timestamp: Date.now() });
|
|
@@ -1721,12 +1723,14 @@ const server = http.createServer(async (req, res) => {
|
|
|
1721
1723
|
return;
|
|
1722
1724
|
}
|
|
1723
1725
|
try {
|
|
1724
|
-
|
|
1726
|
+
const isWindows = os.platform() === 'win32';
|
|
1727
|
+
execSync('git clone https://github.com/' + repo + '.git', {
|
|
1725
1728
|
cwd: cloneDir,
|
|
1726
1729
|
encoding: 'utf-8',
|
|
1727
1730
|
timeout: 120000,
|
|
1728
1731
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1729
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }
|
|
1732
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
|
|
1733
|
+
shell: isWindows
|
|
1730
1734
|
});
|
|
1731
1735
|
sendJSON(req, res, 200, { ok: true, repo, path: targetPath, name: repoName });
|
|
1732
1736
|
} catch (err) {
|
|
@@ -1756,7 +1760,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1756
1760
|
|
|
1757
1761
|
if (pathOnly === '/api/git/check-remote-ownership' && req.method === 'GET') {
|
|
1758
1762
|
try {
|
|
1759
|
-
const
|
|
1763
|
+
const isWindows = os.platform() === 'win32';
|
|
1764
|
+
const result = execSync('git remote get-url origin' + (isWindows ? '' : ' 2>/dev/null'), { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
|
|
1760
1765
|
const remoteUrl = result.trim();
|
|
1761
1766
|
const statusResult = execSync('git status --porcelain', { encoding: 'utf-8', cwd: STARTUP_CWD });
|
|
1762
1767
|
const hasChanges = statusResult.trim().length > 0;
|
|
@@ -1770,7 +1775,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1770
1775
|
|
|
1771
1776
|
if (pathOnly === '/api/git/push' && req.method === 'POST') {
|
|
1772
1777
|
try {
|
|
1773
|
-
|
|
1778
|
+
const isWindows = os.platform() === 'win32';
|
|
1779
|
+
execSync('git add -A && git commit -m "Auto-commit" && git push', { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
|
|
1774
1780
|
sendJSON(req, res, 200, { success: true });
|
|
1775
1781
|
} catch (err) {
|
|
1776
1782
|
sendJSON(req, res, 500, { error: err.message });
|
|
@@ -1784,7 +1790,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
1784
1790
|
const expandedPath = decodedPath.startsWith('~') ?
|
|
1785
1791
|
decodedPath.replace('~', os.homedir()) : decodedPath;
|
|
1786
1792
|
const normalizedPath = path.normalize(expandedPath);
|
|
1787
|
-
|
|
1793
|
+
const isWindows = os.platform() === 'win32';
|
|
1794
|
+
const isAbsolute = isWindows ? /^[A-Za-z]:[\\\/]/.test(normalizedPath) : normalizedPath.startsWith('/');
|
|
1795
|
+
if (!isAbsolute || normalizedPath.includes('..')) {
|
|
1788
1796
|
res.writeHead(403); res.end('Forbidden'); return;
|
|
1789
1797
|
}
|
|
1790
1798
|
try {
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
* Includes folder browser for selecting working directory on new conversation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
function pathSplit(p) {
|
|
8
|
+
return p.split(/[\/\\]/).filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function pathBasename(p) {
|
|
12
|
+
const parts = pathSplit(p);
|
|
13
|
+
return parts.length ? parts.pop() : '';
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
class ConversationManager {
|
|
8
17
|
constructor() {
|
|
9
18
|
this.conversations = [];
|
|
@@ -176,7 +185,8 @@ class ConversationManager {
|
|
|
176
185
|
li.innerHTML = `<span class="folder-list-item-icon">📁</span><span class="folder-list-item-name">${this.escapeHtml(folder.name)}</span>`;
|
|
177
186
|
li.addEventListener('click', () => {
|
|
178
187
|
const expandedBase = dirPath === '~' ? this.folderBrowser.homePath : dirPath;
|
|
179
|
-
const
|
|
188
|
+
const separator = expandedBase.includes('\\') ? '\\' : '/';
|
|
189
|
+
const newPath = expandedBase + separator + folder.name;
|
|
180
190
|
this.loadFolders(newPath);
|
|
181
191
|
});
|
|
182
192
|
this.folderBrowser.listEl.appendChild(li);
|
|
@@ -189,26 +199,31 @@ class ConversationManager {
|
|
|
189
199
|
|
|
190
200
|
getParentPath(dirPath) {
|
|
191
201
|
const expanded = dirPath === '~' ? this.folderBrowser.homePath : dirPath;
|
|
192
|
-
const parts = expanded
|
|
193
|
-
if (parts.length <= 1)
|
|
202
|
+
const parts = pathSplit(expanded);
|
|
203
|
+
if (parts.length <= 1) {
|
|
204
|
+
const separator = expanded.includes('\\') ? '\\' : '/';
|
|
205
|
+
return separator;
|
|
206
|
+
}
|
|
194
207
|
parts.pop();
|
|
195
|
-
|
|
208
|
+
const separator = expanded.includes('\\') ? '\\' : '/';
|
|
209
|
+
return separator + parts.join(separator);
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
renderBreadcrumb(dirPath) {
|
|
199
213
|
if (!this.folderBrowser.breadcrumbEl) return;
|
|
200
214
|
|
|
201
215
|
const expanded = dirPath === '~' ? this.folderBrowser.homePath : dirPath;
|
|
202
|
-
const parts = expanded
|
|
216
|
+
const parts = pathSplit(expanded);
|
|
217
|
+
const separator = expanded.includes('\\') ? '\\' : '/';
|
|
203
218
|
|
|
204
219
|
let html = '';
|
|
205
|
-
html +=
|
|
220
|
+
html += `<span class="folder-breadcrumb-segment" data-path="${separator}">${separator} </span>`;
|
|
206
221
|
|
|
207
222
|
let accumulated = '';
|
|
208
223
|
for (let i = 0; i < parts.length; i++) {
|
|
209
|
-
accumulated +=
|
|
224
|
+
accumulated += separator + parts[i];
|
|
210
225
|
const isLast = i === parts.length - 1;
|
|
211
|
-
html +=
|
|
226
|
+
html += `<span class="folder-breadcrumb-separator">${separator}</span>`;
|
|
212
227
|
html += `<span class="folder-breadcrumb-segment${isLast ? '' : ''}" data-path="${this.escapeHtml(accumulated)}">${this.escapeHtml(parts[i])}</span>`;
|
|
213
228
|
}
|
|
214
229
|
|
|
@@ -227,7 +242,7 @@ class ConversationManager {
|
|
|
227
242
|
const expanded = currentPath === '~' ? this.folderBrowser.homePath : currentPath;
|
|
228
243
|
this.closeFolderBrowser();
|
|
229
244
|
|
|
230
|
-
const dirName = expanded
|
|
245
|
+
const dirName = pathBasename(expanded) || 'root';
|
|
231
246
|
window.dispatchEvent(new CustomEvent('create-new-conversation', {
|
|
232
247
|
detail: { workingDirectory: expanded, title: dirName }
|
|
233
248
|
}));
|
|
@@ -398,7 +413,7 @@ class ConversationManager {
|
|
|
398
413
|
const timestamp = conv.created_at ? new Date(conv.created_at).toLocaleDateString() : 'Unknown';
|
|
399
414
|
const agent = this.getAgentDisplayName(conv.agentType);
|
|
400
415
|
const modelLabel = conv.model ? ` (${conv.model})` : '';
|
|
401
|
-
const wd = conv.workingDirectory ? conv.workingDirectory
|
|
416
|
+
const wd = conv.workingDirectory ? pathBasename(conv.workingDirectory) : '';
|
|
402
417
|
const metaParts = [agent + modelLabel, timestamp];
|
|
403
418
|
if (wd) metaParts.push(wd);
|
|
404
419
|
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
* for Claude Code streaming execution display
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
function pathSplit(p) {
|
|
8
|
+
return p.split(/[\/\\]/).filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function pathBasename(p) {
|
|
12
|
+
const parts = pathSplit(p);
|
|
13
|
+
return parts.length ? parts.pop() : '';
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
class StreamingRenderer {
|
|
8
17
|
constructor(config = {}) {
|
|
9
18
|
// Configuration
|
|
@@ -523,7 +532,7 @@ class StreamingRenderer {
|
|
|
523
532
|
*/
|
|
524
533
|
renderFilePath(filePath) {
|
|
525
534
|
if (!filePath) return '';
|
|
526
|
-
const parts = filePath
|
|
535
|
+
const parts = pathSplit(filePath);
|
|
527
536
|
const fileName = parts.pop();
|
|
528
537
|
const dir = parts.join('/');
|
|
529
538
|
return `<div class="tool-param-file"><span class="file-icon">📄</span>${dir ? `<span class="file-dir">${this.escapeHtml(dir)}/</span>` : ''}<span class="file-name">${this.escapeHtml(fileName)}</span></div>`;
|
|
@@ -660,18 +669,16 @@ class StreamingRenderer {
|
|
|
660
669
|
getToolUseTitle(toolName, input) {
|
|
661
670
|
const normalizedName = toolName.replace(/^mcp__[^_]+__/, '');
|
|
662
671
|
if (normalizedName === 'Edit' && input.file_path) {
|
|
663
|
-
const parts = input.file_path
|
|
672
|
+
const parts = pathSplit(input.file_path);
|
|
664
673
|
const fileName = parts.pop();
|
|
665
674
|
const dir = parts.slice(-2).join('/');
|
|
666
675
|
return dir ? `${dir}/${fileName}` : fileName;
|
|
667
676
|
}
|
|
668
677
|
if (normalizedName === 'Read' && input.file_path) {
|
|
669
|
-
|
|
670
|
-
return parts.pop();
|
|
678
|
+
return pathBasename(input.file_path);
|
|
671
679
|
}
|
|
672
680
|
if (normalizedName === 'Write' && input.file_path) {
|
|
673
|
-
|
|
674
|
-
return parts.pop();
|
|
681
|
+
return pathBasename(input.file_path);
|
|
675
682
|
}
|
|
676
683
|
if (normalizedName === 'Bash' || normalizedName === 'bash') {
|
|
677
684
|
const cmd = input.command || input.commands || '';
|
|
@@ -684,7 +691,7 @@ class StreamingRenderer {
|
|
|
684
691
|
try { return new URL(input.url).hostname; } catch (e) { return input.url.substring(0, 40); }
|
|
685
692
|
}
|
|
686
693
|
if (normalizedName === 'WebSearch' && input.query) return input.query.substring(0, 50);
|
|
687
|
-
if (input.file_path) return input.file_path
|
|
694
|
+
if (input.file_path) return pathBasename(input.file_path);
|
|
688
695
|
if (input.command) {
|
|
689
696
|
const c = typeof input.command === 'string' ? input.command : JSON.stringify(input.command);
|
|
690
697
|
return c.length > 50 ? c.substring(0, 47) + '...' : c;
|
|
@@ -748,11 +755,14 @@ class StreamingRenderer {
|
|
|
748
755
|
}
|
|
749
756
|
|
|
750
757
|
const lines = trimmed.split('\n');
|
|
751
|
-
const allFilePaths = lines.length > 1 && lines.every(l =>
|
|
758
|
+
const allFilePaths = lines.length > 1 && lines.every(l => {
|
|
759
|
+
const t = l.trim();
|
|
760
|
+
return t === '' || t.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(t);
|
|
761
|
+
});
|
|
752
762
|
if (allFilePaths && lines.filter(l => l.trim()).length > 0) {
|
|
753
763
|
const fileHtml = lines.filter(l => l.trim()).map(l => {
|
|
754
764
|
const p = l.trim();
|
|
755
|
-
const parts = p
|
|
765
|
+
const parts = pathSplit(p);
|
|
756
766
|
const name = parts.pop();
|
|
757
767
|
const dir = parts.join('/');
|
|
758
768
|
return `<div style="display:flex;align-items:center;gap:0.375rem;padding:0.1875rem 0;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem"><span style="opacity:0.5">📄</span><span style="color:var(--color-text-secondary)">${this.escapeHtml(dir)}/</span><span style="font-weight:600">${this.escapeHtml(name)}</span></div>`;
|
|
@@ -785,7 +795,8 @@ class StreamingRenderer {
|
|
|
785
795
|
const lines = data.split('\n').length;
|
|
786
796
|
return `<div style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;background:var(--color-bg-code);color:#d1d5db;padding:0.5rem;border-radius:0.375rem;line-height:1.5">${this.escapeHtml(data.substring(0, 1000))}${data.length > 1000 ? '\n... (' + (data.length - 1000) + ' more chars, ' + lines + ' lines)' : ''}</div>`;
|
|
787
797
|
}
|
|
788
|
-
|
|
798
|
+
const looksLikePath = data.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(data);
|
|
799
|
+
if (looksLikePath && !data.includes(' ') && data.includes('.')) return this.renderFilePath(data);
|
|
789
800
|
return `<span style="color:var(--color-text-primary)">${this.escapeHtml(data)}</span>`;
|
|
790
801
|
}
|
|
791
802
|
|
|
@@ -986,11 +997,14 @@ class StreamingRenderer {
|
|
|
986
997
|
return html;
|
|
987
998
|
}
|
|
988
999
|
|
|
989
|
-
const allFilePaths = lines.length > 1 && lines.every(l =>
|
|
1000
|
+
const allFilePaths = lines.length > 1 && lines.every(l => {
|
|
1001
|
+
const t = l.trim();
|
|
1002
|
+
return t === '' || t.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(t);
|
|
1003
|
+
});
|
|
990
1004
|
if (allFilePaths && lines.filter(l => l.trim()).length > 0) {
|
|
991
1005
|
const fileHtml = lines.filter(l => l.trim()).map(l => {
|
|
992
1006
|
const p = l.trim();
|
|
993
|
-
const parts = p
|
|
1007
|
+
const parts = pathSplit(p);
|
|
994
1008
|
const name = parts.pop();
|
|
995
1009
|
const dir = parts.join('/');
|
|
996
1010
|
return `<div style="display:flex;align-items:center;gap:0.375rem;padding:0.1875rem 0;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem"><span style="opacity:0.5">📄</span><span style="color:var(--color-text-secondary)">${esc(dir)}/</span><span style="font-weight:600">${esc(name)}</span></div>`;
|
|
@@ -1103,15 +1117,15 @@ class StreamingRenderer {
|
|
|
1103
1117
|
|
|
1104
1118
|
static getToolTitle(toolName, input) {
|
|
1105
1119
|
const n = toolName.replace(/^mcp__[^_]+__/, '');
|
|
1106
|
-
if (n === 'Edit' && input.file_path) { const p = input.file_path
|
|
1107
|
-
if (n === 'Read' && input.file_path) return input.file_path
|
|
1108
|
-
if (n === 'Write' && input.file_path) return input.file_path
|
|
1120
|
+
if (n === 'Edit' && input.file_path) { const p = pathSplit(input.file_path); const f = p.pop(); const d = p.slice(-2).join('/'); return d ? d+'/'+f : f; }
|
|
1121
|
+
if (n === 'Read' && input.file_path) return pathBasename(input.file_path);
|
|
1122
|
+
if (n === 'Write' && input.file_path) return pathBasename(input.file_path);
|
|
1109
1123
|
if ((n === 'Bash' || n === 'bash') && (input.command || input.commands)) { const c = typeof (input.command||input.commands) === 'string' ? (input.command||input.commands) : JSON.stringify(input.command||input.commands); return c.length > 60 ? c.substring(0,57)+'...' : c; }
|
|
1110
1124
|
if (n === 'Glob' && input.pattern) return input.pattern;
|
|
1111
1125
|
if (n === 'Grep' && input.pattern) return input.pattern;
|
|
1112
1126
|
if (n === 'WebFetch' && input.url) { try { return new URL(input.url).hostname; } catch(e) { return input.url.substring(0,40); } }
|
|
1113
1127
|
if (n === 'WebSearch' && input.query) return input.query.substring(0,50);
|
|
1114
|
-
if (input.file_path) return input.file_path
|
|
1128
|
+
if (input.file_path) return pathBasename(input.file_path);
|
|
1115
1129
|
if (input.command) { const c = typeof input.command === 'string' ? input.command : JSON.stringify(input.command); return c.length > 50 ? c.substring(0,47)+'...' : c; }
|
|
1116
1130
|
if (input.query) return input.query.substring(0,50);
|
|
1117
1131
|
return '';
|
|
@@ -1134,8 +1148,9 @@ class StreamingRenderer {
|
|
|
1134
1148
|
if (data.length > 500) {
|
|
1135
1149
|
return `<div style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;background:var(--color-bg-code);color:#d1d5db;padding:0.5rem;border-radius:0.375rem;line-height:1.5">${esc(data.substring(0, 1000))}${data.length > 1000 ? '\n... (' + (data.length - 1000) + ' more chars)' : ''}</div>`;
|
|
1136
1150
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1151
|
+
const looksLikePath = /^[A-Za-z]:[\\\/]/.test(data) || data.startsWith('/');
|
|
1152
|
+
if (looksLikePath && !data.includes(' ') && data.includes('.')) {
|
|
1153
|
+
const parts = pathSplit(data);
|
|
1139
1154
|
const name = parts.pop();
|
|
1140
1155
|
const dir = parts.join('/');
|
|
1141
1156
|
return `<div style="display:flex;align-items:center;gap:0.375rem;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.8rem"><span style="opacity:0.5">📄</span><span style="color:var(--color-text-secondary)">${esc(dir)}/</span><span style="font-weight:600">${esc(name)}</span></div>`;
|
package/telemetry-id
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
814cd4b3-ffd4-44c7-abbd-b2d9e757f0fc
|