@papercraneai/sandbox-agent 0.1.6 → 0.1.8
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/dist/index.js +35 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createServer } from "http";
|
|
|
4
4
|
import { WebSocketServer, WebSocket } from "ws";
|
|
5
5
|
import { Tail } from "tail";
|
|
6
6
|
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
7
|
-
import { readdir, stat, mkdir, readFile, writeFile, access, unlink } from "fs/promises";
|
|
7
|
+
import { readdir, stat, mkdir, readFile, writeFile, access, unlink, rm } from "fs/promises";
|
|
8
8
|
import { join, dirname, resolve } from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
10
|
import { spawn, execSync } from "child_process";
|
|
@@ -383,11 +383,14 @@ const showPreviewTool = tool("ShowPreview", "Shows the preview iframe for a spec
|
|
|
383
383
|
}]
|
|
384
384
|
};
|
|
385
385
|
});
|
|
386
|
-
//
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
386
|
+
// Factory to create a fresh MCP server per chat session
|
|
387
|
+
// (each Protocol instance can only be connected to one transport at a time)
|
|
388
|
+
function createClientToolsServer() {
|
|
389
|
+
return createSdkMcpServer({
|
|
390
|
+
name: "client-tools",
|
|
391
|
+
tools: [showPreviewTool]
|
|
392
|
+
});
|
|
393
|
+
}
|
|
391
394
|
// Recursively build file tree
|
|
392
395
|
async function buildFileTree(dirPath) {
|
|
393
396
|
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
@@ -837,13 +840,17 @@ app.delete("/files/delete", async (req, res) => {
|
|
|
837
840
|
res.status(403).json({ error: "Access denied: path outside project directory" });
|
|
838
841
|
return;
|
|
839
842
|
}
|
|
840
|
-
//
|
|
843
|
+
// Prevent deleting the project root itself
|
|
844
|
+
if (resolvedPath === resolvedProject) {
|
|
845
|
+
res.status(400).json({ error: "Cannot delete the project root directory" });
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const recursive = req.query.recursive === "true" || req.body?.recursive === true;
|
|
849
|
+
// Check if path exists
|
|
850
|
+
let isDirectory = false;
|
|
841
851
|
try {
|
|
842
852
|
const stats = await stat(fullPath);
|
|
843
|
-
|
|
844
|
-
res.status(400).json({ error: "Cannot delete a directory, only files", path: sanitizedPath });
|
|
845
|
-
return;
|
|
846
|
-
}
|
|
853
|
+
isDirectory = stats.isDirectory();
|
|
847
854
|
}
|
|
848
855
|
catch (error) {
|
|
849
856
|
if (error.code === "ENOENT") {
|
|
@@ -852,8 +859,17 @@ app.delete("/files/delete", async (req, res) => {
|
|
|
852
859
|
}
|
|
853
860
|
throw error;
|
|
854
861
|
}
|
|
855
|
-
|
|
856
|
-
|
|
862
|
+
if (isDirectory && !recursive) {
|
|
863
|
+
res.status(400).json({ error: "Cannot delete a directory without recursive flag", path: sanitizedPath });
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
// Delete file or directory
|
|
867
|
+
if (isDirectory) {
|
|
868
|
+
await rm(fullPath, { recursive: true });
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
await unlink(fullPath);
|
|
872
|
+
}
|
|
857
873
|
log.info({ path: sanitizedPath }, "File deleted");
|
|
858
874
|
res.json({
|
|
859
875
|
success: true,
|
|
@@ -1167,13 +1183,14 @@ app.post("/chat", async (req, res) => {
|
|
|
1167
1183
|
"KillShell",
|
|
1168
1184
|
"mcp__client-tools__ShowPreview"
|
|
1169
1185
|
];
|
|
1186
|
+
const clientTools = createClientToolsServer();
|
|
1170
1187
|
const options = {
|
|
1171
1188
|
maxTurns,
|
|
1172
1189
|
cwd,
|
|
1173
1190
|
permissionMode: "bypassPermissions",
|
|
1174
1191
|
allowDangerouslySkipPermissions: true,
|
|
1175
1192
|
mcpServers: {
|
|
1176
|
-
"client-tools":
|
|
1193
|
+
"client-tools": clientTools
|
|
1177
1194
|
},
|
|
1178
1195
|
allowedTools: allowedTools || defaultTools,
|
|
1179
1196
|
settingSources: ["project"],
|
|
@@ -1254,6 +1271,10 @@ app.post("/chat", async (req, res) => {
|
|
|
1254
1271
|
res.end();
|
|
1255
1272
|
}
|
|
1256
1273
|
}
|
|
1274
|
+
finally {
|
|
1275
|
+
// Close the per-session MCP server to free resources
|
|
1276
|
+
await clientTools.instance?.close().catch(() => { });
|
|
1277
|
+
}
|
|
1257
1278
|
});
|
|
1258
1279
|
// =============================================================================
|
|
1259
1280
|
// Registration & Heartbeat
|