agent-dag 1.33.4 → 1.33.6
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/assets/index-Cezbph7B.css +1 -0
- package/dist/web/assets/index-z0Jp5RyB.js +66 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/server/cswap-admin.mjs +3 -1
- package/src/server/index.mjs +6 -2
- package/src/server/self-update.mjs +42 -6
- package/dist/web/assets/index-CUIo58CG.js +0 -66
- package/dist/web/assets/index-hRjhJVfb.css +0 -1
package/dist/web/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
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-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-z0Jp5RyB.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Cezbph7B.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.6",
|
|
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": {
|
|
@@ -407,10 +407,12 @@ export async function importAccount(blob) {
|
|
|
407
407
|
const slot = newSlot(before, after);
|
|
408
408
|
invalidateClaudeAccountsCache();
|
|
409
409
|
if (slot != null) runDetached(await cswapBin(), ["list"]);
|
|
410
|
+
// Who arrived, so the dialog can name them instead of saying "an account".
|
|
411
|
+
const email = slot != null ? (after.emails[slot] || null) : null;
|
|
410
412
|
// No new slot is not an error: without --force, cswap skips an account it
|
|
411
413
|
// already holds. Saying which happened is the difference between "it
|
|
412
414
|
// worked" and "why is nothing different".
|
|
413
|
-
return { ok: true, added: slot != null, num: slot, output: firstUseful(r.stdout) };
|
|
415
|
+
return { ok: true, added: slot != null, num: slot, email, output: firstUseful(r.stdout) };
|
|
414
416
|
});
|
|
415
417
|
}
|
|
416
418
|
|
package/src/server/index.mjs
CHANGED
|
@@ -1024,11 +1024,15 @@ function handleSse(req, res) {
|
|
|
1024
1024
|
// no file to read — so the deck must not offer to do it.
|
|
1025
1025
|
let _canRestart = false;
|
|
1026
1026
|
|
|
1027
|
-
async function handleVersion(
|
|
1027
|
+
async function handleVersion(req, res) {
|
|
1028
1028
|
const { versionReport } = await import(
|
|
1029
1029
|
pathToFileURL(join(PKG_ROOT, "src/server/self-update.mjs")).href
|
|
1030
1030
|
);
|
|
1031
|
-
|
|
1031
|
+
// ?refresh=1 asks npm now rather than reusing the cached answer — what the
|
|
1032
|
+
// version chip does when clicked, for the user who has just published or is
|
|
1033
|
+
// wondering whether the check is working at all.
|
|
1034
|
+
const force = new URL(req.url, "http://localhost").searchParams.get("refresh") === "1";
|
|
1035
|
+
const report = await versionReport({ running: RUNNING_VERSION, pkgRoot: PKG_ROOT, force });
|
|
1032
1036
|
send(res, 200, { ...report, canRestart: _canRestart });
|
|
1033
1037
|
}
|
|
1034
1038
|
|
|
@@ -26,7 +26,16 @@ import { spawn } from "node:child_process";
|
|
|
26
26
|
import { homedir } from "node:os";
|
|
27
27
|
import { dirname, join, resolve } from "node:path";
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// Once an hour, not once a day.
|
|
30
|
+
//
|
|
31
|
+
// The daily cadence was copied from the ccusage and cswap checks, where it is
|
|
32
|
+
// right: those answer "is a different tool out of date", and nobody is waiting
|
|
33
|
+
// on it. This one answers "is the thing you are looking at out of date", and a
|
|
34
|
+
// day is long enough that a deck started shortly before a release shows nothing
|
|
35
|
+
// at all until tomorrow — reported from a machine running `npx ccdeck`, which
|
|
36
|
+
// is the case where it bites hardest, since npx runs are short-lived and each
|
|
37
|
+
// one inherits the same stale marker. The request is ~20 bytes.
|
|
38
|
+
const CHECK_MS = 3600_000;
|
|
30
39
|
const FETCH_TIMEOUT_MS = 6_000;
|
|
31
40
|
// A third marker path: ccusage owns ~/.agents-deck/ccusage/.last-update-check
|
|
32
41
|
// and cswap owns ~/.agents-deck/.cswap-update-check. Sharing one would make the
|
|
@@ -181,11 +190,34 @@ function writeMarker(at, version) {
|
|
|
181
190
|
} catch { /* a read-only home must not break the deck */ }
|
|
182
191
|
}
|
|
183
192
|
|
|
193
|
+
// The marker is shared by every deck on the machine, so one deck's check
|
|
194
|
+
// silences the others for the rest of the window. Asking once per PROCESS fixes
|
|
195
|
+
// that, and it lands the check exactly where the user expects the truth: a
|
|
196
|
+
// freshly started deck — which for `npx ccdeck` is every single run.
|
|
197
|
+
let _askedThisProcess = false;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Whether to ask npm, or reuse the answer on disk. Pure, because "why did no
|
|
201
|
+
* banner appear" is the question this feature gets asked, and the rule behind
|
|
202
|
+
* it should be readable in one place.
|
|
203
|
+
*/
|
|
204
|
+
export function checkDue({ at, now, first = false, force = false, ttlMs = CHECK_MS }) {
|
|
205
|
+
if (force || first) return true; // explicit ask, or this process's first
|
|
206
|
+
if (typeof at !== "number") return true; // never checked
|
|
207
|
+
if (at > now) return true; // marker from the future: a moved clock
|
|
208
|
+
return now - at >= ttlMs;
|
|
209
|
+
}
|
|
210
|
+
|
|
184
211
|
/** Last known npm `latest`, refreshed at most once per CHECK_MS. Returns the
|
|
185
|
-
* cached answer immediately when the window has not elapsed.
|
|
186
|
-
|
|
212
|
+
* cached answer immediately when the window has not elapsed.
|
|
213
|
+
*
|
|
214
|
+
* `force` skips the window: the first call in this process, and an explicit
|
|
215
|
+
* "check now" from the UI. */
|
|
216
|
+
async function latestOnNpm(name, now, force = false) {
|
|
187
217
|
const m = readMarker();
|
|
188
|
-
|
|
218
|
+
const first = !_askedThisProcess;
|
|
219
|
+
_askedThisProcess = true;
|
|
220
|
+
if (!checkDue({ at: m?.at, now, first, force })) return m?.version ?? null;
|
|
189
221
|
if (_inflight) return _inflight;
|
|
190
222
|
_inflight = fetchLatest(name)
|
|
191
223
|
// Stamp before deciding what to keep: a failed lookup must burn the day's
|
|
@@ -350,7 +382,7 @@ export function lastMeaningfulLine(text) {
|
|
|
350
382
|
/** Full answer for GET /api/version. Never throws, never blocks on the network
|
|
351
383
|
* for longer than FETCH_TIMEOUT_MS, and answers the local half even when the
|
|
352
384
|
* registry is unreachable. */
|
|
353
|
-
export async function versionReport({ running, pkgRoot, name = "agents-deck", now = Date.now() }) {
|
|
385
|
+
export async function versionReport({ running, pkgRoot, name = "agents-deck", now = Date.now(), force = false }) {
|
|
354
386
|
const installed = installedVersion(pkgRoot);
|
|
355
387
|
// Only an explicit opt-out silences the registry.
|
|
356
388
|
//
|
|
@@ -365,13 +397,17 @@ export async function versionReport({ running, pkgRoot, name = "agents-deck", no
|
|
|
365
397
|
const skipRegistry =
|
|
366
398
|
process.env.AGENTS_DECK_NO_UPDATE_CHECK === "1" ||
|
|
367
399
|
process.env.AGENTS_DECK_NO_INSTALL === "1";
|
|
368
|
-
const latest = skipRegistry ? null : await latestOnNpm(name, now);
|
|
400
|
+
const latest = skipRegistry ? null : await latestOnNpm(name, now, force);
|
|
369
401
|
const blocked = upgradeBlock(pkgRoot);
|
|
370
402
|
return {
|
|
371
403
|
name,
|
|
372
404
|
running: running ?? null,
|
|
373
405
|
installed,
|
|
374
406
|
latest,
|
|
407
|
+
// When npm was last asked, so the UI can say it rather than leaving the
|
|
408
|
+
// user to wonder whether the check runs at all.
|
|
409
|
+
checkedAt: skipRegistry ? null : (readMarker()?.at ?? null),
|
|
410
|
+
checkDisabled: skipRegistry,
|
|
375
411
|
notice: pickNotice({ running, installed, latest }),
|
|
376
412
|
command: upgradeCommand(pkgRoot, name),
|
|
377
413
|
// Why an in-app `npm i -g` is refused, when it is — so the UI can say so
|