agent-dag 1.36.1 → 1.36.3

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.
@@ -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-DWHO_6dI.js"></script>
43
+ <script type="module" crossorigin src="/assets/index-BuvNYv3F.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.1",
3
+ "version": "1.36.3",
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": {
@@ -268,11 +268,53 @@ async function readSwap(platform = process.platform) {
268
268
  const TOP_N = 8;
269
269
 
270
270
  /**
271
- * Rows out of `ps -Aceo pid,pcpu,pmem,comm -r`.
271
+ * The `ps` argument list, which is not the same list on both Unixes.
272
272
  *
273
- * `-c` gives the executable name without its full path and without the argv
274
- * that would leak a prompt or a token into the UI; `-r` sorts by current CPU,
275
- * which is the ordering that answers "what is eating this machine right now".
273
+ * `-r` was shipped for both and means two different things. On BSD it sorts the
274
+ * output by current CPU, which is the ordering the panel is built around. On
275
+ * Linux procps it is *"restrict the selection to only running processes"* a
276
+ * filter on state `R`, applied in PID order. A Linux deck therefore listed
277
+ * whatever happened to be on a CPU at the instant of the sample: usually one or
278
+ * two rows on an idle machine, and never the busiest ones, since a process
279
+ * pinning a core while blocked on I/O sits in `D` and one merely burning CPU
280
+ * over time is normally caught in `S`. Nothing errored and nothing was empty,
281
+ * which is why it survived two releases (#492).
282
+ *
283
+ * `--sort=-pcpu` is procps' own way to say what `-r` says on BSD. The column
284
+ * order is deliberately identical on both so one parser reads both, and `comm`
285
+ * stays last so a name containing a space survives intact.
286
+ *
287
+ * Keyed on linux rather than on darwin, because linux is the platform that is
288
+ * wrong: `-r` sorts on every BSD, while `--sort` is a procps long option that
289
+ * would make FreeBSD and OpenBSD exit non-zero. This way the only branch that
290
+ * changes is the one that was broken.
291
+ *
292
+ * Pure and exported for the same reason the parsers are: the command
293
+ * construction is the part that differs per platform, and a fixture cannot
294
+ * prove which flags were passed to produce it.
295
+ */
296
+ export function psArgs(platform = process.platform) {
297
+ // procps: an explicit CPU sort, and `comm` in `-o` is what keeps argv — and
298
+ // any prompt or token on it — out of the panel. Linux `comm` comes from
299
+ // /proc/<pid>/comm and is capped at 15 characters.
300
+ if (platform === "linux") return ["-eo", "pid,pcpu,pmem,comm", "--sort=-pcpu"];
301
+ // BSD/macOS: `-c` prints the accounting name rather than the argument vector,
302
+ // and `-r` sorts by current CPU.
303
+ return ["-Aceo", "pid,pcpu,pmem,comm", "-r"];
304
+ }
305
+
306
+ /**
307
+ * Rows out of `ps -o pid,pcpu,pmem,comm`, in that column order on both Unixes —
308
+ * see psArgs for how each platform is asked for it.
309
+ *
310
+ * `pcpu` is a percentage of ONE core on both, so a multi-threaded process runs
311
+ * past 100 and that is information rather than an error: 157 is one and a half
312
+ * cores. cpuFromDeltas puts the Windows column on this same scale.
313
+ *
314
+ * There is no row limit in the query because neither `ps` has one and `run`
315
+ * deliberately never inherits a shell, so there is no `| head` to pipe into.
316
+ * The loop below stops at `limit` instead, which costs one parse of a string
317
+ * we have already paid to read.
276
318
  */
277
319
  export function parsePsProcesses(text, limit = TOP_N) {
278
320
  const lines = String(text ?? "").trim().split("\n");
@@ -333,10 +375,21 @@ export function parseGetProcessJson(json, totalMem) {
333
375
  * number invented from its whole lifetime, which would rank a freshly spawned
334
376
  * compiler as though it had been burning a core since boot.
335
377
  *
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.
378
+ * Per core, NOT per machine, because that is what the column beside it means:
379
+ * `ps -o pcpu` is a percentage of one core on both Unixes and is reported
380
+ * unmodified, so a row reading 157 there is a process using one and a half
381
+ * cores. This used to divide by the core count and clamp to 100 on the reasoning
382
+ * that Unix reported 0-100 — it does not, and never did, so the normalisation
383
+ * corrected a scale that already matched and introduced the mismatch it was
384
+ * written to prevent: on a 12-core machine six busy cores read 600 on macOS and
385
+ * 50 on Windows (#493). One CPU-second burned per wall-second is 100 here, on
386
+ * every platform.
387
+ *
388
+ * Core count is deliberately not a parameter any more. The aggregate meter's
389
+ * 0-100 convention (see cpuPercent) is a different question with a different
390
+ * answer, and the only way this drifts back is if a core count is in reach.
338
391
  */
339
- export function cpuFromDeltas(rows, prev, elapsedMs, cores, limit = TOP_N) {
392
+ export function cpuFromDeltas(rows, prev, elapsedMs, limit = TOP_N) {
340
393
  const secs = elapsedMs / 1000;
341
394
  const out = rows.map(r => {
342
395
  const before = prev instanceof Map ? prev.get(r.pid) : undefined;
@@ -345,7 +398,7 @@ export function cpuFromDeltas(rows, prev, elapsedMs, cores, limit = TOP_N) {
345
398
  const d = r.cpuSec - before;
346
399
  // A counter that went backwards means the pid was reused by a different
347
400
  // 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));
401
+ if (d >= 0) cpu = Math.round((d / secs) * 1000) / 10;
349
402
  }
350
403
  return { pid: r.pid, cpu, mem: r.mem, name: r.name };
351
404
  });
@@ -374,12 +427,12 @@ export async function readProcesses(platform = process.platform) {
374
427
  if (!out) return [];
375
428
  const rows = parseGetProcessJson(out.trim(), os.totalmem());
376
429
  const now = Date.now();
377
- const result = cpuFromDeltas(rows, prevProcCpu, now - prevProcAt, os.cpus().length);
430
+ const result = cpuFromDeltas(rows, prevProcCpu, now - prevProcAt);
378
431
  prevProcCpu = new Map(rows.filter(r => r.cpuSec != null).map(r => [r.pid, r.cpuSec]));
379
432
  prevProcAt = now;
380
433
  return result;
381
434
  }
382
- const out = await run("ps", ["-Aceo", "pid,pcpu,pmem,comm", "-r"], 4_000);
435
+ const out = await run("ps", psArgs(platform), 4_000);
383
436
  return out ? parsePsProcesses(out) : [];
384
437
  }
385
438