swarmpath-claudecode-bridge 1.2.0 → 1.2.1
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/index.mjs +16 -2
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -151,6 +151,7 @@ const cfg = loadConfig();
|
|
|
151
151
|
const SERVER = getArg('server') || cfg.server || process.env.SWARMPATH_SERVER;
|
|
152
152
|
let TOKEN = getArg('token') || process.env.SWARMPATH_TOKEN;
|
|
153
153
|
let CWD = getArg('cwd') || process.cwd();
|
|
154
|
+
const ROOT_CWD = resolve(CWD); // Sandbox root — cd cannot escape this directory
|
|
154
155
|
|
|
155
156
|
if (!SERVER) {
|
|
156
157
|
console.error('❌ 未配置服务器。请先运行: npx swarmpath-claudecode-bridge --setup');
|
|
@@ -186,8 +187,10 @@ const terminalSessions = new Map();
|
|
|
186
187
|
const HEARTBEAT_MS = 30_000;
|
|
187
188
|
const RECONNECT_MS = 5_000;
|
|
188
189
|
const MAX_RECONNECT_MS = 60_000;
|
|
190
|
+
const MAX_RECONNECT_ATTEMPTS = 5; // Exit after 5 failed reconnects
|
|
189
191
|
const TOKEN_REFRESH_MS = 12 * 60 * 1000; // Refresh token every 12 min (before 15-min expiry)
|
|
190
192
|
let reconnectDelay = RECONNECT_MS;
|
|
193
|
+
let reconnectAttempts = 0;
|
|
191
194
|
|
|
192
195
|
// ---------------------------------------------------------------------------
|
|
193
196
|
// Token auto-refresh
|
|
@@ -217,6 +220,7 @@ function connect() {
|
|
|
217
220
|
ws.on('open', () => {
|
|
218
221
|
console.log('✅ Connected to SwarmPath server');
|
|
219
222
|
reconnectDelay = RECONNECT_MS;
|
|
223
|
+
reconnectAttempts = 0;
|
|
220
224
|
|
|
221
225
|
clearInterval(heartbeatTimer);
|
|
222
226
|
heartbeatTimer = setInterval(() => {
|
|
@@ -267,7 +271,12 @@ function connect() {
|
|
|
267
271
|
|
|
268
272
|
function scheduleReconnect() {
|
|
269
273
|
if (reconnectTimer) return;
|
|
270
|
-
|
|
274
|
+
reconnectAttempts++;
|
|
275
|
+
if (reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
|
|
276
|
+
console.log(`\n❌ 连续 ${MAX_RECONNECT_ATTEMPTS} 次重连失败,自动退出。`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
console.log(`⏳ Reconnecting in ${reconnectDelay / 1000}s ... (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
|
|
271
280
|
reconnectTimer = setTimeout(() => {
|
|
272
281
|
reconnectTimer = null;
|
|
273
282
|
reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_MS);
|
|
@@ -533,6 +542,10 @@ function handleFileRequest(msg) {
|
|
|
533
542
|
if (action === 'cd') {
|
|
534
543
|
const target = msg.path || '..';
|
|
535
544
|
const newCwd = resolve(CWD, target);
|
|
545
|
+
// Security: only allow navigating into subdirectories of ROOT_CWD
|
|
546
|
+
if (!newCwd.startsWith(ROOT_CWD + '/') && newCwd !== ROOT_CWD) {
|
|
547
|
+
throw new Error(`Access denied: cannot navigate above root directory (${ROOT_CWD})`);
|
|
548
|
+
}
|
|
536
549
|
const st = statSync(newCwd);
|
|
537
550
|
if (!st.isDirectory()) throw new Error('Not a directory');
|
|
538
551
|
CWD = newCwd;
|
|
@@ -547,7 +560,7 @@ function handleFileRequest(msg) {
|
|
|
547
560
|
const relPath = msg.path;
|
|
548
561
|
if (!relPath) throw new Error('path required');
|
|
549
562
|
const fullPath = resolve(CWD, relPath);
|
|
550
|
-
if (!fullPath.startsWith(
|
|
563
|
+
if (!fullPath.startsWith(ROOT_CWD + '/') && fullPath !== ROOT_CWD) throw new Error('Access denied: outside sandbox root');
|
|
551
564
|
const ext = extname(fullPath).toLowerCase();
|
|
552
565
|
const mime = MIME_MAP[ext] || 'application/octet-stream';
|
|
553
566
|
const isText = mime.startsWith('text/') || mime === 'application/json' || mime === 'text/markdown';
|
|
@@ -623,5 +636,6 @@ process.on('SIGTERM', shutdown);
|
|
|
623
636
|
// ---------------------------------------------------------------------------
|
|
624
637
|
console.log('🌐 SwarmPath Claude Code Bridge');
|
|
625
638
|
console.log(`📁 Working directory: ${CWD}`);
|
|
639
|
+
console.log(`🔒 Sandbox root: ${ROOT_CWD} (cd cannot escape)`);
|
|
626
640
|
startTokenRefresh();
|
|
627
641
|
connect();
|