indieclaw-agent 1.1.0 → 1.1.2
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.js +131 -38
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -210,6 +210,7 @@ function handleFsDelete(ws, { id, path: filePath }) {
|
|
|
210
210
|
// --- System Stats ---
|
|
211
211
|
function handleSystemStats(ws, { id }) {
|
|
212
212
|
const platform = os.platform();
|
|
213
|
+
const mem = platform === 'darwin' ? getDarwinMemory() : getLinuxMemory();
|
|
213
214
|
const stats = {
|
|
214
215
|
hostname: os.hostname(),
|
|
215
216
|
platform,
|
|
@@ -220,17 +221,61 @@ function handleSystemStats(ws, { id }) {
|
|
|
220
221
|
cores: os.cpus().length,
|
|
221
222
|
usage: getCpuUsage(platform),
|
|
222
223
|
},
|
|
223
|
-
memory:
|
|
224
|
-
total: os.totalmem(),
|
|
225
|
-
free: os.freemem(),
|
|
226
|
-
used: os.totalmem() - os.freemem(),
|
|
227
|
-
usagePercent: Math.round(((os.totalmem() - os.freemem()) / os.totalmem()) * 100),
|
|
228
|
-
},
|
|
224
|
+
memory: mem,
|
|
229
225
|
disk: getDiskUsage(platform),
|
|
230
226
|
};
|
|
231
227
|
reply(ws, id, stats);
|
|
232
228
|
}
|
|
233
229
|
|
|
230
|
+
function getDarwinMemory() {
|
|
231
|
+
const total = os.totalmem();
|
|
232
|
+
try {
|
|
233
|
+
const out = execSync('vm_stat', { timeout: 3000 }).toString();
|
|
234
|
+
const pageMatch = out.match(/page size of (\d+) bytes/);
|
|
235
|
+
const pageSize = pageMatch ? parseInt(pageMatch[1], 10) : 16384;
|
|
236
|
+
|
|
237
|
+
const val = (key) => {
|
|
238
|
+
const m = out.match(new RegExp(key + ':\\s+(\\d+)'));
|
|
239
|
+
return m ? parseInt(m[1], 10) : 0;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const wired = val('Pages wired down');
|
|
243
|
+
const active = val('Pages active');
|
|
244
|
+
const compressed = val('Pages occupied by compressor');
|
|
245
|
+
const purgeable = val('Pages purgeable');
|
|
246
|
+
|
|
247
|
+
// Used = wired + active (minus purgeable) + compressed — matches Activity Monitor
|
|
248
|
+
const used = (wired + active - purgeable + compressed) * pageSize;
|
|
249
|
+
const free = total - used;
|
|
250
|
+
return {
|
|
251
|
+
total,
|
|
252
|
+
free: Math.max(free, 0),
|
|
253
|
+
used: Math.min(used, total),
|
|
254
|
+
usagePercent: Math.round((Math.min(used, total) / total) * 100),
|
|
255
|
+
};
|
|
256
|
+
} catch {
|
|
257
|
+
// Fallback to Node.js (inaccurate on macOS but better than nothing)
|
|
258
|
+
const free = os.freemem();
|
|
259
|
+
return {
|
|
260
|
+
total,
|
|
261
|
+
free,
|
|
262
|
+
used: total - free,
|
|
263
|
+
usagePercent: Math.round(((total - free) / total) * 100),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function getLinuxMemory() {
|
|
269
|
+
const total = os.totalmem();
|
|
270
|
+
const free = os.freemem();
|
|
271
|
+
return {
|
|
272
|
+
total,
|
|
273
|
+
free,
|
|
274
|
+
used: total - free,
|
|
275
|
+
usagePercent: Math.round(((total - free) / total) * 100),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
234
279
|
function getCpuUsage(platform) {
|
|
235
280
|
try {
|
|
236
281
|
if (platform === 'linux') {
|
|
@@ -251,23 +296,32 @@ function getCpuUsage(platform) {
|
|
|
251
296
|
|
|
252
297
|
function getDiskUsage(platform) {
|
|
253
298
|
try {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
//
|
|
299
|
+
if (platform === 'darwin') {
|
|
300
|
+
// macOS APFS: "Used" column only shows one volume's data
|
|
301
|
+
// Calculate used = total - available for accurate results
|
|
302
|
+
const out = execSync('df -k /', { timeout: 5000 }).toString();
|
|
303
|
+
const lines = out.trim().split('\n').slice(1);
|
|
304
|
+
return lines.map((line) => {
|
|
305
|
+
const parts = line.trim().split(/\s+/);
|
|
306
|
+
// Columns: Filesystem 1K-blocks Used Available Capacity iused ifree %iused Mounted
|
|
307
|
+
const total = parseInt(parts[1], 10) * 1024;
|
|
308
|
+
const available = parseInt(parts[3], 10) * 1024;
|
|
309
|
+
const used = total - available;
|
|
262
310
|
return {
|
|
263
311
|
filesystem: parts[0],
|
|
264
|
-
mount: parts[8] ||
|
|
265
|
-
total
|
|
266
|
-
used
|
|
267
|
-
available
|
|
268
|
-
usagePercent:
|
|
312
|
+
mount: parts[8] || '/',
|
|
313
|
+
total,
|
|
314
|
+
used,
|
|
315
|
+
available,
|
|
316
|
+
usagePercent: Math.round((used / total) * 100),
|
|
269
317
|
};
|
|
270
|
-
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
// Linux
|
|
321
|
+
const out = execSync('df -k / --output=source,size,used,avail,pcent,target', { timeout: 5000 }).toString();
|
|
322
|
+
const lines = out.trim().split('\n').slice(1);
|
|
323
|
+
return lines.map((line) => {
|
|
324
|
+
const parts = line.trim().split(/\s+/);
|
|
271
325
|
return {
|
|
272
326
|
filesystem: parts[0],
|
|
273
327
|
total: parseInt(parts[1], 10) * 1024,
|
|
@@ -455,46 +509,85 @@ function handleCronList(ws, { id }) {
|
|
|
455
509
|
});
|
|
456
510
|
}
|
|
457
511
|
|
|
458
|
-
// --- Terminal (PTY) ---
|
|
512
|
+
// --- Terminal (PTY with child_process fallback) ---
|
|
459
513
|
function handleTerminalStart(ws, { id }) {
|
|
460
|
-
|
|
461
|
-
|
|
514
|
+
const shell = process.env.SHELL || '/bin/bash';
|
|
515
|
+
|
|
516
|
+
// Try node-pty first
|
|
517
|
+
if (pty) {
|
|
518
|
+
try {
|
|
519
|
+
const term = pty.spawn(shell, [], {
|
|
520
|
+
name: 'xterm-256color',
|
|
521
|
+
cols: 80,
|
|
522
|
+
rows: 24,
|
|
523
|
+
cwd: os.homedir(),
|
|
524
|
+
env: { ...process.env, TERM: 'xterm-256color' },
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
term._ws = ws;
|
|
528
|
+
term._isPty = true;
|
|
529
|
+
terminals.set(id, term);
|
|
530
|
+
|
|
531
|
+
term.onData((data) => {
|
|
532
|
+
send(ws, { type: 'terminal.output', id, data });
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
term.onExit(({ exitCode }) => {
|
|
536
|
+
send(ws, { type: 'terminal.exit', id, exitCode });
|
|
537
|
+
terminals.delete(id);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
return reply(ws, id, { pid: term.pid });
|
|
541
|
+
} catch (err) {
|
|
542
|
+
console.log(`[agent] node-pty spawn failed (${err.message}), using fallback`);
|
|
543
|
+
}
|
|
462
544
|
}
|
|
463
545
|
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
cols: 80,
|
|
468
|
-
rows: 24,
|
|
546
|
+
// Fallback: child_process.spawn
|
|
547
|
+
const { spawn } = require('child_process');
|
|
548
|
+
const proc = spawn(shell, ['-i'], {
|
|
469
549
|
cwd: os.homedir(),
|
|
470
|
-
env: { ...process.env, TERM: '
|
|
550
|
+
env: { ...process.env, TERM: 'dumb' },
|
|
551
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
471
552
|
});
|
|
472
553
|
|
|
473
|
-
|
|
474
|
-
|
|
554
|
+
proc._ws = ws;
|
|
555
|
+
proc._isPty = false;
|
|
475
556
|
|
|
476
|
-
|
|
477
|
-
send(ws, { type: 'terminal.output', id, data });
|
|
557
|
+
proc.stdout.on('data', (data) => {
|
|
558
|
+
send(ws, { type: 'terminal.output', id, data: data.toString() });
|
|
478
559
|
});
|
|
479
560
|
|
|
480
|
-
|
|
481
|
-
send(ws, { type: 'terminal.
|
|
561
|
+
proc.stderr.on('data', (data) => {
|
|
562
|
+
send(ws, { type: 'terminal.output', id, data: data.toString() });
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
proc.on('exit', (exitCode) => {
|
|
566
|
+
send(ws, { type: 'terminal.exit', id, exitCode: exitCode ?? 0 });
|
|
482
567
|
terminals.delete(id);
|
|
483
568
|
});
|
|
484
569
|
|
|
485
|
-
|
|
570
|
+
terminals.set(id, proc);
|
|
571
|
+
reply(ws, id, { pid: proc.pid });
|
|
486
572
|
}
|
|
487
573
|
|
|
488
574
|
function handleTerminalInput(ws, { id, data }) {
|
|
489
575
|
const term = terminals.get(id);
|
|
490
576
|
if (!term) return replyError(ws, id, 'Terminal not found');
|
|
491
|
-
term.
|
|
577
|
+
if (term._isPty) {
|
|
578
|
+
term.write(data);
|
|
579
|
+
} else {
|
|
580
|
+
term.stdin.write(data);
|
|
581
|
+
}
|
|
492
582
|
}
|
|
493
583
|
|
|
494
584
|
function handleTerminalResize(ws, { id, cols, rows }) {
|
|
495
585
|
const term = terminals.get(id);
|
|
496
586
|
if (!term) return replyError(ws, id, 'Terminal not found');
|
|
497
|
-
term.resize
|
|
587
|
+
if (term._isPty && term.resize) {
|
|
588
|
+
term.resize(cols, rows);
|
|
589
|
+
}
|
|
590
|
+
// fallback processes don't support resize
|
|
498
591
|
}
|
|
499
592
|
|
|
500
593
|
function handleTerminalStop(ws, { id }) {
|