agent-dag 1.33.28 → 1.33.30
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
|
@@ -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-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DmDKN8d2.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-Cpi89XJ8.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.
|
|
3
|
+
"version": "1.33.30",
|
|
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": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// concurrent adds pick the same number and the second write silently drops the
|
|
17
17
|
// first account's record. Nothing upstream prevents it, so every mutation here
|
|
18
18
|
// goes through one mutex.
|
|
19
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
19
20
|
import { readFile } from "node:fs/promises";
|
|
20
21
|
import { homedir } from "node:os";
|
|
21
22
|
import { join } from "node:path";
|
|
@@ -49,15 +50,28 @@ function backupRoot() {
|
|
|
49
50
|
|
|
50
51
|
let _chain = Promise.resolve();
|
|
51
52
|
|
|
53
|
+
// Whether the code running right now is itself the mutation holding the lock.
|
|
54
|
+
// Async context rather than a plain boolean, which could not tell that apart
|
|
55
|
+
// from another request that merely arrived while the lock was held — and would
|
|
56
|
+
// wave that one through, which is the opposite of a mutex.
|
|
57
|
+
const _holder = new AsyncLocalStorage();
|
|
58
|
+
|
|
52
59
|
/**
|
|
53
60
|
* One store mutation at a time.
|
|
54
61
|
*
|
|
55
62
|
* Not defence against another process — that would need claude-swap's own file
|
|
56
63
|
* lock, which `add` does not take either. This is defence against ourselves:
|
|
57
64
|
* two browser tabs, or a double-click, are enough to race a slot assignment.
|
|
65
|
+
*
|
|
66
|
+
* Re-entrant, because a mutation that reaches for the lock from inside one
|
|
67
|
+
* would otherwise wait for itself forever: the chain cannot advance past the
|
|
68
|
+
* outer link until it settles, and the outer link is blocked on this call. It
|
|
69
|
+
* already has exclusive access, so it simply runs.
|
|
58
70
|
*/
|
|
59
71
|
export function withStoreLock(fn) {
|
|
60
|
-
|
|
72
|
+
if (_holder.getStore()) return Promise.resolve().then(fn);
|
|
73
|
+
const held = () => _holder.run(true, fn);
|
|
74
|
+
const next = _chain.then(held, held);
|
|
61
75
|
// Keep the chain alive even when a link rejects, or every later mutation
|
|
62
76
|
// inherits the failure.
|
|
63
77
|
_chain = next.then(() => {}, () => {});
|
|
@@ -329,13 +343,26 @@ export async function submitLoginCode(code) {
|
|
|
329
343
|
export async function cancelLogin() {
|
|
330
344
|
const flow = _login;
|
|
331
345
|
if (!flow) return { ok: true, ...loginState() };
|
|
346
|
+
// Stopping the child touches no file, so it happens straight away: a cancel
|
|
347
|
+
// that waited its turn first would leave `claude auth login` sitting on the
|
|
348
|
+
// user's next attempt for the rest of its five minutes.
|
|
332
349
|
try { flow.child?.kill(); } catch { /* already gone */ }
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
350
|
+
// Switching back does touch the store, so it is queued like every other
|
|
351
|
+
// mutation. Cancel is reachable while submitLoginCode holds the lock — the
|
|
352
|
+
// dialog fires it on Escape, mid-registration — and running `cswap switch`
|
|
353
|
+
// beside an in-flight `cswap add` is precisely the unlocked read-modify-write
|
|
354
|
+
// of sequence.json the mutex exists to prevent: claude-swap takes no file lock
|
|
355
|
+
// around `add`, so whichever write lands second drops the other's record.
|
|
356
|
+
return withStoreLock(async () => {
|
|
357
|
+
// The login may have completed before the cancel arrived, in which case the
|
|
358
|
+
// live credentials already moved and putting them back is the point.
|
|
359
|
+
await restoreActive(flow.previousActive);
|
|
360
|
+
invalidateClaudeAccountsCache();
|
|
361
|
+
// A newer sign-in can have started while this waited its turn; clearing the
|
|
362
|
+
// slot then would drop a live flow's handle instead of this dead one's.
|
|
363
|
+
if (flow === _login) _login = null;
|
|
364
|
+
return { ok: true, ...loginState() };
|
|
365
|
+
});
|
|
339
366
|
}
|
|
340
367
|
|
|
341
368
|
/** Put the account that was active before the login back in front. */
|
package/src/server/quota.mjs
CHANGED
|
@@ -238,13 +238,15 @@ function stripAnsi(s) {
|
|
|
238
238
|
*/
|
|
239
239
|
// Parse "Jun 18, 4:09pm" (local time, no tz) into unix seconds.
|
|
240
240
|
// Claude shows times in the user's local timezone, so parsing as local is correct.
|
|
241
|
-
function parseResetToSec(resetStr) {
|
|
241
|
+
export function parseResetToSec(resetStr) {
|
|
242
242
|
if (!resetStr) return null;
|
|
243
243
|
try {
|
|
244
244
|
const year = new Date().getFullYear();
|
|
245
|
-
// "4:09pm" → "4:09 PM" so Date.parse handles it
|
|
245
|
+
// "4:09pm" → "4:09 PM" so Date.parse handles it. Minutes are optional in
|
|
246
|
+
// the CLI's output ("9am"); Date.parse rejects "9 AM", so supply ":00".
|
|
246
247
|
const norm = resetStr
|
|
247
|
-
.replace(/(\d{1,2}
|
|
248
|
+
.replace(/(\d{1,2})(?::(\d{2}))?\s*(am|pm)/i,
|
|
249
|
+
(_all, h, mm, ampm) => `${h}:${mm ?? "00"} ${ampm}`)
|
|
248
250
|
.trim();
|
|
249
251
|
const d = new Date(`${norm} ${year}`);
|
|
250
252
|
return isNaN(d.getTime()) ? null : Math.floor(d.getTime() / 1000);
|