agent-dag 1.36.0 → 1.36.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/dist/web/index.html
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
document.documentElement.setAttribute("data-theme", stored === "light" ? "light" : "dark");
|
|
41
41
|
})();
|
|
42
42
|
</script>
|
|
43
|
-
<script type="module" crossorigin src="/assets/index-
|
|
43
|
+
<script type="module" crossorigin src="/assets/index-DWHO_6dI.js"></script>
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/index-CaAP5Ufx.css">
|
|
45
45
|
</head>
|
|
46
46
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.1",
|
|
4
4
|
"description": "Live deck of Claude Code and Codex agents — watch tool calls, token spend and every Claude Code subagent on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -287,48 +287,97 @@ export function parsePsProcesses(text, limit = TOP_N) {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/**
|
|
290
|
-
* Rows out of
|
|
290
|
+
* Rows out of `Get-Process`.
|
|
291
291
|
*
|
|
292
|
-
* `
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
292
|
+
* NOT `Win32_PerfFormattedData_PerfProc_Process`, which is what this used and
|
|
293
|
+
* which is not a class you may assume exists. It is published by perflib, and
|
|
294
|
+
* perflib is deregistered often enough to matter — a corporate image, a bad
|
|
295
|
+
* in-place upgrade, a half-run `lodctr`. On a machine reported from the field
|
|
296
|
+
* the class was simply absent (`Get-CimInstance: Invalid class`), and `typeperf`
|
|
297
|
+
* failed identically, which places the fault below WMI rather than in it. WMI
|
|
298
|
+
* was only mirroring what perflib had stopped publishing.
|
|
298
299
|
*
|
|
299
|
-
* `
|
|
300
|
+
* `Get-Process` reads through NtQuerySystemInformation instead, so it depends on
|
|
301
|
+
* nothing that can be unregistered. The cost is that its `CPU` is total
|
|
302
|
+
* processor SECONDS since the process started, not a rate — so a percentage has
|
|
303
|
+
* to be derived from two readings, exactly the way the machine-wide figure is
|
|
304
|
+
* already derived from two tick samples. Reliability is worth one extra poll:
|
|
305
|
+
* an instant number from a class that may not exist is worth nothing at all.
|
|
300
306
|
*/
|
|
301
|
-
export function
|
|
307
|
+
export function parseGetProcessJson(json, totalMem) {
|
|
302
308
|
let rows;
|
|
303
309
|
try { rows = typeof json === "string" ? JSON.parse(json) : json; }
|
|
304
310
|
catch { return []; }
|
|
305
311
|
if (!rows) return [];
|
|
306
312
|
if (!Array.isArray(rows)) rows = [rows];
|
|
307
|
-
const cores = os.cpus().length || 1;
|
|
308
313
|
return rows
|
|
309
|
-
.filter(r => r && r.
|
|
314
|
+
.filter(r => r && r.ProcessName)
|
|
310
315
|
.map(r => ({
|
|
311
|
-
pid: Number(r.
|
|
312
|
-
|
|
313
|
-
//
|
|
314
|
-
|
|
316
|
+
pid: Number(r.Id) || 0,
|
|
317
|
+
name: String(r.ProcessName),
|
|
318
|
+
// Null rather than 0 when the process denies the read: a system process
|
|
319
|
+
// we cannot query has an unknown CPU time, and calling that zero would
|
|
320
|
+
// rank it as idle.
|
|
321
|
+
cpuSec: typeof r.CPU === "number" ? r.CPU : null,
|
|
315
322
|
mem: totalMem > 0
|
|
316
323
|
? Math.round((Number(r.WorkingSetPrivate) || 0) / totalMem * 1000) / 10
|
|
317
324
|
: 0,
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Turn two `Get-Process` readings into a percentage per process.
|
|
330
|
+
*
|
|
331
|
+
* `prev` maps pid to the cpuSec of the previous reading. A pid absent from it —
|
|
332
|
+
* a process that started since — has no delta and reports null rather than a
|
|
333
|
+
* number invented from its whole lifetime, which would rank a freshly spawned
|
|
334
|
+
* compiler as though it had been burning a core since boot.
|
|
335
|
+
*
|
|
336
|
+
* Normalised by core count so a Windows row means the same thing as the Unix
|
|
337
|
+
* one: 100 is one machine, not one core.
|
|
338
|
+
*/
|
|
339
|
+
export function cpuFromDeltas(rows, prev, elapsedMs, cores, limit = TOP_N) {
|
|
340
|
+
const secs = elapsedMs / 1000;
|
|
341
|
+
const out = rows.map(r => {
|
|
342
|
+
const before = prev instanceof Map ? prev.get(r.pid) : undefined;
|
|
343
|
+
let cpu = null;
|
|
344
|
+
if (r.cpuSec != null && before != null && secs > 0) {
|
|
345
|
+
const d = r.cpuSec - before;
|
|
346
|
+
// A counter that went backwards means the pid was reused by a different
|
|
347
|
+
// process; report nothing rather than a negative or a wild number.
|
|
348
|
+
if (d >= 0) cpu = Math.max(0, Math.min(100, Math.round((d / secs / Math.max(1, cores)) * 1000) / 10));
|
|
349
|
+
}
|
|
350
|
+
return { pid: r.pid, cpu, mem: r.mem, name: r.name };
|
|
351
|
+
});
|
|
352
|
+
// Until the second reading lands there is no CPU to sort on, so the list is
|
|
353
|
+
// ordered by memory — which is a real answer to "what is this machine doing",
|
|
354
|
+
// not a placeholder.
|
|
355
|
+
const haveCpu = out.some(r => r.cpu != null);
|
|
356
|
+
out.sort(haveCpu
|
|
357
|
+
? (a, b) => (b.cpu ?? -1) - (a.cpu ?? -1)
|
|
358
|
+
: (a, b) => b.mem - a.mem);
|
|
359
|
+
return out.slice(0, limit);
|
|
322
360
|
}
|
|
323
361
|
|
|
324
362
|
/** The process list, on demand only — never on the ambient timer. */
|
|
363
|
+
/** Previous Windows reading, so the next one can be a rate. Cleared with the
|
|
364
|
+
* rest of the sampler state. */
|
|
365
|
+
let prevProcCpu = null;
|
|
366
|
+
let prevProcAt = 0;
|
|
367
|
+
|
|
325
368
|
export async function readProcesses(platform = process.platform) {
|
|
326
369
|
if (platform === "win32") {
|
|
327
370
|
const out = await run("powershell.exe", [
|
|
328
371
|
"-NoProfile", "-NonInteractive", "-Command",
|
|
329
|
-
"Get-
|
|
372
|
+
"Get-Process | Select-Object Id,ProcessName,CPU,@{n='WorkingSetPrivate';e={$_.PrivateMemorySize64}} | ConvertTo-Json -Compress",
|
|
330
373
|
], 6_000);
|
|
331
|
-
|
|
374
|
+
if (!out) return [];
|
|
375
|
+
const rows = parseGetProcessJson(out.trim(), os.totalmem());
|
|
376
|
+
const now = Date.now();
|
|
377
|
+
const result = cpuFromDeltas(rows, prevProcCpu, now - prevProcAt, os.cpus().length);
|
|
378
|
+
prevProcCpu = new Map(rows.filter(r => r.cpuSec != null).map(r => [r.pid, r.cpuSec]));
|
|
379
|
+
prevProcAt = now;
|
|
380
|
+
return result;
|
|
332
381
|
}
|
|
333
382
|
const out = await run("ps", ["-Aceo", "pid,pcpu,pmem,comm", "-r"], 4_000);
|
|
334
383
|
return out ? parsePsProcesses(out) : [];
|
|
@@ -386,6 +435,8 @@ export function stopSystemMetrics() {
|
|
|
386
435
|
memory = null;
|
|
387
436
|
cores = null;
|
|
388
437
|
swap = null;
|
|
438
|
+
prevProcCpu = null;
|
|
439
|
+
prevProcAt = 0;
|
|
389
440
|
}
|
|
390
441
|
|
|
391
442
|
/**
|