agent-dag 1.30.0 → 1.30.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.
@@ -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-CgugXiGZ.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DtE3W-dV.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-BLOOP_Fy.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.30.0",
3
+ "version": "1.30.2",
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": {
@@ -62,12 +62,38 @@ let _lastNudge = 0;
62
62
  * Fire-and-forget. The result lands in the store for the next poll to pick up;
63
63
  * making the caller wait would just delay the numbers it already has.
64
64
  */
65
- function nudgeCollector(rows, now) {
65
+ /**
66
+ * Whether anything is waiting to be collected.
67
+ *
68
+ * Judged per account that actually exists, and an account counts as waiting in
69
+ * three cases:
70
+ *
71
+ * - it has no usage row at all;
72
+ * - it has a row whose fetchedAt is not a number. claude-swap writes a row
73
+ * when an account is added and fills in the numbers when it first polls,
74
+ * so "row exists" is not the same as "has been fetched" — and that is the
75
+ * state a freshly added account sits in. Treating the row's existence as
76
+ * proof of a fetch left a new account reading "never fetched" forever;
77
+ * - its own schedule says the next poll is due.
78
+ *
79
+ * Rows are consulted only for accounts in the store. A removed account leaves
80
+ * its row behind, permanently overdue and impossible to collect because the
81
+ * account is gone — counting those meant something was always due and the
82
+ * collector was asked every minute for the rest of the session.
83
+ */
84
+ export function collectionDue(rows, slots, now) {
85
+ for (const slot of slots) {
86
+ const r = rows[slot];
87
+ if (!r) return true; // never seen
88
+ if (typeof r.fetchedAt !== "number") return true; // seen, never fetched
89
+ if (typeof r.nextPollAt === "number" && r.nextPollAt * 1000 <= now) return true;
90
+ }
91
+ return false;
92
+ }
93
+
94
+ function nudgeCollector(rows, slots, now) {
66
95
  if (now - _lastNudge < NUDGE_EVERY_MS) return;
67
- const due = Object.values(rows).some(r =>
68
- typeof r?.nextPollAt === "number" && r.nextPollAt * 1000 <= now
69
- );
70
- if (!due) return;
96
+ if (!collectionDue(rows, slots, now)) return;
71
97
 
72
98
  _lastNudge = now;
73
99
  // Fire-and-forget: this function is deliberately synchronous so callers never
@@ -132,8 +158,10 @@ export async function fetchClaudeAccounts({ force = false } = {}) {
132
158
  // A schema bump means the rows may not mean what this code thinks they do.
133
159
  const rows = usage?.schemaVersion === 2 ? (usage.accounts ?? {}) : {};
134
160
 
135
- // Kick a collection for the NEXT poll if claude-swap says an account is due.
136
- nudgeCollector(rows, now);
161
+ // Kick a collection for the NEXT poll if anything is due either because
162
+ // claude-swap's schedule says so, or because an account has never been
163
+ // fetched at all.
164
+ nudgeCollector(rows, Object.keys(seq.accounts), now);
137
165
 
138
166
  const order = Array.isArray(seq.sequence) && seq.sequence.length
139
167
  ? seq.sequence.map(String)
@@ -295,5 +323,11 @@ export async function seedFirstAccount() {
295
323
 
296
324
  invalidateClaudeAccountsCache();
297
325
  const count = existsSync(seqPath) ? accountCount(await readJson(seqPath)) : 0;
326
+ if (count > 0) {
327
+ // Collect straight away. Otherwise the first thing the user sees is their
328
+ // account listed with "never fetched" beside it, waiting on a poll cycle
329
+ // for numbers that are the reason the panel exists.
330
+ runDetached(await cswapBin(), ["list"]);
331
+ }
298
332
  return count > 0 ? { state: "added", count } : { state: "nothing-to-add" };
299
333
  }