agent-dag 1.33.44 → 1.33.45

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>agents-deck</title>
7
7
  <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='84' font-size='84'%3E%E2%97%89%3C/text%3E%3C/svg%3E" />
8
- <script type="module" crossorigin src="/assets/index-B5ak55yo.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BnOcuI0t.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-CF2yG9oG.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-dag",
3
- "version": "1.33.44",
3
+ "version": "1.33.45",
4
4
  "description": "Live deck of Claude Code and Codex agents — watch parallel subagents fork, call tools, and return on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,8 @@
19
19
  // notably on macOS, where Claude Code keeps credentials in the Keychain
20
20
  // and that file does not exist, so this is the ONLY self-service path
21
21
  // there. It is also the most expensive: a whole Claude Code process per
22
- // poll. On Windows the binary is a .cmd wrapper, so exec() (shell-based)
23
- // is used for correct quoting + stdin.
22
+ // poll. On Windows the binary may be a .cmd wrapper, so exec()
23
+ // (shell-based) is used for correct quoting + stdin.
24
24
  //
25
25
  // 2 and 3 are rate-floored (SELF_POLL_MS) and gated behind the same 429
26
26
  // cooldown; 1 is not, because it is a local file read.
@@ -29,11 +29,10 @@ import { exec } from "node:child_process";
29
29
  import { promisify } from "node:util";
30
30
  import { existsSync } from "node:fs";
31
31
  import { readFile } from "node:fs/promises";
32
- import { join } from "node:path";
33
- import { homedir, platform } from "node:os";
32
+ import { join, posix as posixPath, win32 as winPath } from "node:path";
33
+ import { homedir } from "node:os";
34
34
 
35
35
  const execAsync = promisify(exec);
36
- const IS_WIN = platform() === "win32";
37
36
 
38
37
  const CREDS_PATH = join(homedir(), ".claude", ".credentials.json");
39
38
  const USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
@@ -298,31 +297,65 @@ function parseUsageText(raw) {
298
297
  return Object.keys(result).length > 0 ? result : null;
299
298
  }
300
299
 
300
+ /**
301
+ * Every place the `claude` CLI is known to live, in the order to try them.
302
+ *
303
+ * Pure, and the platform, environment and home directory are parameters, so the
304
+ * Windows list can be checked from a Mac — which is the only way this list stays
305
+ * right, since it exists entirely for machines the author is not sitting at.
306
+ */
307
+ export function quotaClaudeCandidates(platform = process.platform, env = process.env, home = homedir()) {
308
+ // The path flavour follows the PLATFORM ARGUMENT, not the host: node's `join`
309
+ // would emit forward slashes when the Windows list is built on a Mac.
310
+ const { join } = platform === "win32" ? winPath : posixPath;
311
+ if (platform !== "win32") {
312
+ return [
313
+ "claude",
314
+ join(home, ".local", "bin", "claude"),
315
+ "/usr/local/bin/claude",
316
+ "/opt/homebrew/bin/claude",
317
+ ];
318
+ }
319
+ return [
320
+ // The native installer, which ships a bare claude.exe and NO .cmd shim. It
321
+ // was the one install this branch could not reach: the npm path below does
322
+ // not exist on such a machine, and the bare-name fallback used to be spelled
323
+ // `claude.cmd`, which cmd.exe cannot resolve to an .exe — PATHEXT supplies a
324
+ // missing extension, it never substitutes one that is already there.
325
+ join(home, ".local", "bin", "claude.exe"),
326
+ // `npm i -g @anthropic-ai/claude-code`. npm's global prefix is %APPDATA%\npm
327
+ // — Roaming rather than Local, deliberately, since it follows the user
328
+ // between machines — and APPDATA is read from the environment because a
329
+ // roaming profile puts it on a network share, not under the home directory.
330
+ join(env.APPDATA || join(home, "AppData", "Roaming"), "npm", "claude.cmd"),
331
+ // Last resort: the bare name, which cmd.exe resolves through PATH + PATHEXT
332
+ // and so finds claude.exe and claude.cmd alike.
333
+ "claude",
334
+ ];
335
+ }
336
+
301
337
  /** Build the shell command string for `claude --print /usage`.
302
338
  *
303
339
  * We use exec() (shell-based) so cmd.exe / sh processes redirects.
304
340
  * On Windows: `< nul` closes stdin immediately, preventing the 3-second
305
341
  * "no stdin data" wait the claude CLI does when it detects a pipe.
306
342
  * On Unix: `< /dev/null` has the same effect.
343
+ *
344
+ * Exported, with everything it touches injectable, so the Windows branch is
345
+ * testable from the platforms this repo is actually developed on.
307
346
  */
308
- function buildQuotaShellCmd() {
309
- if (IS_WIN) {
310
- const npmBin = join(homedir(), "AppData", "Roaming", "npm", "claude.cmd");
311
- const bin = existsSync(npmBin) ? npmBin : "claude.cmd";
312
- // exec() on Windows uses cmd /c, so < nul redirect works fine.
313
- // Wrap path in quotes in case of spaces in username.
314
- return `"${bin}" --print /usage < nul`;
315
- }
316
- const candidates = [
317
- "claude",
318
- join(homedir(), ".local", "bin", "claude"),
319
- "/usr/local/bin/claude",
320
- "/opt/homebrew/bin/claude",
321
- ];
322
- for (const c of candidates) {
323
- if (!c.includes("/") || existsSync(c)) return `${c} --print /usage < /dev/null`;
324
- }
325
- return "claude --print /usage < /dev/null";
347
+ export function buildQuotaShellCmd(platform = process.platform, env = process.env,
348
+ home = homedir(), exists = existsSync) {
349
+ const win = platform === "win32";
350
+ const sep = win ? "\\" : "/";
351
+ // A bare name is left to the shell's own lookup; a full path is only worth
352
+ // naming when it is actually there.
353
+ const bin = quotaClaudeCandidates(platform, env, home)
354
+ .find(c => !c.includes(sep) || exists(c)) ?? "claude";
355
+ // Quote a path — a username can contain a space — but not a bare name, which
356
+ // cmd.exe resolves more predictably unquoted.
357
+ const quoted = bin.includes(sep) ? `"${bin}"` : bin;
358
+ return `${quoted} --print /usage < ${win ? "nul" : "/dev/null"}`;
326
359
  }
327
360
 
328
361
  export async function fetchClaudeQuota({ force = false } = {}) {