agentgui 1.0.397 → 1.0.398
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 +3 -2
- package/scripts/patch-fsbrowse.js +88 -0
- package/server.js +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentgui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.398",
|
|
4
4
|
"description": "Multi-agent ACP client with real-time communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"homepage": "https://github.com/AnEntrypoint/agentgui#readme",
|
|
18
18
|
"scripts": {
|
|
19
19
|
"start": "node server.js",
|
|
20
|
-
"dev": "node server.js --watch"
|
|
20
|
+
"dev": "node server.js --watch",
|
|
21
|
+
"postinstall": "node scripts/patch-fsbrowse.js"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@anthropic-ai/claude-code": "^2.1.37",
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Patch script to fix Windows path duplication issue in fsbrowse
|
|
4
|
+
* Fixes: Error ENOENT: no such file or directory, scandir 'C:\C:\dev'
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
const fsbrowsePath = path.join(__dirname, '..', 'node_modules', 'fsbrowse', 'index.js');
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(fsbrowsePath)) {
|
|
16
|
+
console.warn('[PATCH] fsbrowse not found, skipping patch');
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
let content = fs.readFileSync(fsbrowsePath, 'utf8');
|
|
22
|
+
|
|
23
|
+
// Check if patch is already applied
|
|
24
|
+
if (content.includes('sanitizedIsAbsoluteOnDrive')) {
|
|
25
|
+
console.log('[PATCH] fsbrowse Windows path fix already applied');
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Replace the makeResolver function with the fixed version
|
|
30
|
+
const oldMakeResolver = `function makeResolver(baseDir) {
|
|
31
|
+
return function resolveWithBaseDir(relPath) {
|
|
32
|
+
const sanitized = sanitizePath(relPath);
|
|
33
|
+
const fullPath = path.resolve(baseDir, sanitized);
|
|
34
|
+
if (!fullPath.startsWith(baseDir)) {
|
|
35
|
+
return { ok: false, error: 'EPATHINJECTION' };
|
|
36
|
+
}
|
|
37
|
+
return { ok: true, path: fullPath };
|
|
38
|
+
};
|
|
39
|
+
}`;
|
|
40
|
+
|
|
41
|
+
const newMakeResolver = `function makeResolver(baseDir) {
|
|
42
|
+
const normalizedBase = path.normalize(baseDir);
|
|
43
|
+
const baseDriveLetter = normalizedBase.match(/^[A-Z]:/i)?.[0];
|
|
44
|
+
|
|
45
|
+
return function resolveWithBaseDir(relPath) {
|
|
46
|
+
const sanitized = sanitizePath(relPath);
|
|
47
|
+
let fullPath;
|
|
48
|
+
|
|
49
|
+
// Extract drive letter from both paths to check for same-drive duplication on Windows
|
|
50
|
+
const sanitizedDriveLetter = sanitized.match(/^[A-Z]:/i)?.[0];
|
|
51
|
+
const sanitizedIsAbsoluteOnDrive = /^[A-Z]:/i.test(sanitized);
|
|
52
|
+
|
|
53
|
+
// If both paths are on the same Windows drive, strip the drive letter from relPath
|
|
54
|
+
// to avoid duplication like C:\\C:\\dev
|
|
55
|
+
if (baseDriveLetter && sanitizedIsAbsoluteOnDrive && sanitizedDriveLetter === baseDriveLetter) {
|
|
56
|
+
// Remove drive letter and leading slashes to make it relative
|
|
57
|
+
const relativePath = sanitized.replace(/^[A-Z]:[\/\\]?/i, '');
|
|
58
|
+
fullPath = path.resolve(normalizedBase, relativePath);
|
|
59
|
+
} else {
|
|
60
|
+
fullPath = path.resolve(normalizedBase, sanitized);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Normalize for consistent comparison
|
|
64
|
+
const normalizedFullPath = path.normalize(fullPath);
|
|
65
|
+
const normalizedComparisonBase = path.normalize(normalizedBase);
|
|
66
|
+
|
|
67
|
+
// Check path injection - convert backslashes to forward slashes for comparison
|
|
68
|
+
const normalizedCheck = normalizedFullPath.replace(/\\\\/g, '/');
|
|
69
|
+
const normalizedBaseCheck = normalizedComparisonBase.replace(/\\\\/g, '/');
|
|
70
|
+
|
|
71
|
+
if (!normalizedCheck.startsWith(normalizedBaseCheck)) {
|
|
72
|
+
return { ok: false, error: 'EPATHINJECTION' };
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, path: normalizedFullPath };
|
|
75
|
+
};
|
|
76
|
+
}`;
|
|
77
|
+
|
|
78
|
+
if (content.includes(oldMakeResolver)) {
|
|
79
|
+
content = content.replace(oldMakeResolver, newMakeResolver);
|
|
80
|
+
fs.writeFileSync(fsbrowsePath, content, 'utf8');
|
|
81
|
+
console.log('[PATCH] fsbrowse Windows path fix applied successfully');
|
|
82
|
+
} else {
|
|
83
|
+
console.warn('[PATCH] Could not find makeResolver function to patch');
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error('[PATCH] Error applying fsbrowse patch:', err.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
package/server.js
CHANGED
|
@@ -295,8 +295,10 @@ expressApp.use(BASE_URL + '/files/:conversationId', (req, res, next) => {
|
|
|
295
295
|
if (!conv || !conv.workingDirectory) {
|
|
296
296
|
return res.status(404).json({ error: 'Conversation not found or no working directory' });
|
|
297
297
|
}
|
|
298
|
+
// Normalize the working directory path to avoid Windows path duplication issues
|
|
299
|
+
const normalizedWorkingDir = path.resolve(conv.workingDirectory);
|
|
298
300
|
// Create a fresh fsbrowse router for this conversation's directory
|
|
299
|
-
const router = fsbrowse({ baseDir:
|
|
301
|
+
const router = fsbrowse({ baseDir: normalizedWorkingDir, name: 'Files' });
|
|
300
302
|
// Strip the conversationId param from the path before passing to fsbrowse
|
|
301
303
|
req.baseUrl = BASE_URL + '/files/' + req.params.conversationId;
|
|
302
304
|
router(req, res, next);
|
|
@@ -1073,7 +1075,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
1073
1075
|
|
|
1074
1076
|
if (pathOnly === '/api/conversations' && req.method === 'POST') {
|
|
1075
1077
|
const body = await parseBody(req);
|
|
1076
|
-
|
|
1078
|
+
// Normalize working directory to avoid Windows path issues
|
|
1079
|
+
const normalizedWorkingDir = body.workingDirectory ? path.resolve(body.workingDirectory) : null;
|
|
1080
|
+
const conversation = queries.createConversation(body.agentId, body.title, normalizedWorkingDir, body.model || null);
|
|
1077
1081
|
queries.createEvent('conversation.created', { agentId: body.agentId, workingDirectory: conversation.workingDirectory, model: conversation.model }, conversation.id);
|
|
1078
1082
|
broadcastSync({ type: 'conversation_created', conversation });
|
|
1079
1083
|
sendJSON(req, res, 201, { conversation });
|
|
@@ -1099,6 +1103,10 @@ const server = http.createServer(async (req, res) => {
|
|
|
1099
1103
|
|
|
1100
1104
|
if (req.method === 'POST' || req.method === 'PUT') {
|
|
1101
1105
|
const body = await parseBody(req);
|
|
1106
|
+
// Normalize working directory if present to avoid Windows path issues
|
|
1107
|
+
if (body.workingDirectory) {
|
|
1108
|
+
body.workingDirectory = path.resolve(body.workingDirectory);
|
|
1109
|
+
}
|
|
1102
1110
|
const conv = queries.updateConversation(convMatch[1], body);
|
|
1103
1111
|
if (!conv) { sendJSON(req, res, 404, { error: 'Conversation not found' }); return; }
|
|
1104
1112
|
queries.createEvent('conversation.updated', body, convMatch[1]);
|