agent-dag 3.8.8 → 3.8.9
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/bin/agent-dag.js +2 -2
- package/bin/deck.js +13 -4
- package/dist/web/assets/{index-DLRqo4Ty.js → index-Dq0gpZ5v.js} +2 -2
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/server/browser-presence.mjs +9 -0
- package/src/server/browser-react.mjs +8 -2
- package/src/server/claude-accounts.mjs +17 -1
- package/src/server/self-update.mjs +36 -2
- package/src/server/supervisor.mjs +3 -3
- package/src/server/term.mjs +9 -2
package/dist/web/index.html
CHANGED
|
@@ -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-
|
|
43
|
+
<script type="module" crossorigin src="/assets/index-Dq0gpZ5v.js"></script>
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/index-ByAgTqB8.css">
|
|
45
45
|
</head>
|
|
46
46
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.9",
|
|
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. Run it with npx ccdeck.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/release-notes.json
CHANGED
|
@@ -31,6 +31,12 @@
|
|
|
31
31
|
"about a defect in the type, and the suite refuses both it and no space at",
|
|
32
32
|
"all."
|
|
33
33
|
],
|
|
34
|
+
"3.8.9": [
|
|
35
|
+
{
|
|
36
|
+
"title": "\ud83d\udda5\ufe0f Four things that only went wrong on somebody else's operating system",
|
|
37
|
+
"body": "**Ubuntu:** the deck knew where Chromium and Brave keep their profiles when installed as a snap or a flatpak \u2014 which on a default Ubuntu is the only place Chromium is \u2014 but not what those programs are called. So it reported them as not running while they were, and refused to quit them. Both now work.\n\n**Windows:** the deck asked the system whether it could write to the folder an update installs into, and Windows always answers yes for a folder whatever the permissions say. It offered you an update that then died inside npm with a permission error. It now finds out by trying, and declines up front with the command to run yourself \u2014 which is what every other platform already got.\n\n**Linux:** if `XDG_DATA_HOME` was set to something starting with `~`, as it is from a systemd unit or a Dockerfile, the deck and claude-swap looked in two different places for your accounts. The panel said you had none while `cswap list` showed them all.\n\n**Plain terminals:** six messages used a typographic dash the old Windows console and the Linux text console cannot draw, so a box appeared mid-sentence \u2014 including in the line that explains why no events are arriving. They use the plain form on those terminals now, like everything else already did."
|
|
38
|
+
}
|
|
39
|
+
],
|
|
34
40
|
"3.8.8": [
|
|
35
41
|
{
|
|
36
42
|
"title": "\ud83d\udcc9 A false 99% on the memory chart, and three other quiet failures",
|
|
@@ -76,6 +76,15 @@ const APP_NAME = {
|
|
|
76
76
|
"chrome-beta": "chrome",
|
|
77
77
|
"chrome-canary": "chrome",
|
|
78
78
|
chromium: "chromium",
|
|
79
|
+
// The two roots `browserRoots` emits and this table used to miss (#794).
|
|
80
|
+
// The snap path's own comment there says it "is the only Chromium root a
|
|
81
|
+
// default Ubuntu install has" — so on stock Ubuntu the panel reported
|
|
82
|
+
// Chromium as not running while it was running, and the quit reaction,
|
|
83
|
+
// which `available("linux")` does offer, answered `unknown_browser` on
|
|
84
|
+
// every finding from either of them. darwin covers all 8 of its roots and
|
|
85
|
+
// win32 all 7 of its own; only this table was short.
|
|
86
|
+
"chromium-snap": "chromium",
|
|
87
|
+
"brave-flatpak": "brave",
|
|
79
88
|
brave: "brave",
|
|
80
89
|
edge: "msedge",
|
|
81
90
|
vivaldi: "vivaldi-bin",
|
|
@@ -206,10 +206,16 @@ export async function closeTab(browserKey, url, platform = process.platform, dep
|
|
|
206
206
|
|
|
207
207
|
/** Quit a browser. The only reaction that takes the session back. */
|
|
208
208
|
export async function quitBrowser(browserKey, platform = process.platform, deps = {}) {
|
|
209
|
-
const app = appName(browserKey);
|
|
210
|
-
if (!app) return { ok: false, reason: "unknown_browser" };
|
|
211
209
|
const exec = deps.run ?? run;
|
|
212
210
|
if (platform === "darwin") {
|
|
211
|
+
// The darwin display-name table is consulted HERE rather than at the top of
|
|
212
|
+
// the function (#794). It used to gate every platform, so a browser missing
|
|
213
|
+
// from a macOS-only table — `chromium-snap` and `brave-flatpak`, the two
|
|
214
|
+
// roots a default Ubuntu install actually has — answered `unknown_browser`
|
|
215
|
+
// on Linux before the branch that would have known what to do with it was
|
|
216
|
+
// ever reached.
|
|
217
|
+
const app = appName(browserKey);
|
|
218
|
+
if (!app) return { ok: false, reason: "unknown_browser" };
|
|
213
219
|
const r = await exec("osascript", [
|
|
214
220
|
// `--`, as everywhere else that hands osascript an operand. `app` comes
|
|
215
221
|
// from a fixed table so it is safe by construction; the separator costs
|
|
@@ -39,7 +39,23 @@ import { homedir, platform } from "node:os";
|
|
|
39
39
|
export function backupRoot() {
|
|
40
40
|
if (process.env.CLAUDE_SWAP_BACKUP) return process.env.CLAUDE_SWAP_BACKUP;
|
|
41
41
|
if (platform() === "linux") {
|
|
42
|
-
|
|
42
|
+
// `~` IS EXPANDED BEFORE THE ABSOLUTENESS TEST (#796), which is what
|
|
43
|
+
// claude-swap's own paths.py does: `Path(os.path.expanduser(xdg))` and then
|
|
44
|
+
// `is_absolute()`, under a docstring saying it exists so that "values like
|
|
45
|
+
// `~/data` set via systemd unit files or Dockerfiles (which don't get shell
|
|
46
|
+
// expansion) still work". This function claims to mirror that and did not.
|
|
47
|
+
//
|
|
48
|
+
// Unexpanded, `XDG_DATA_HOME=~/data` failed `startsWith("/")` and the deck
|
|
49
|
+
// read ~/.local/share/claude-swap while cswap read and wrote
|
|
50
|
+
// ~/data/claude-swap. The Accounts panel then reported `no_accounts` while
|
|
51
|
+
// `cswap list` showed the roster — and the damaging part is
|
|
52
|
+
// `seedFirstAccount`, which reads a missing sequence file as zero accounts,
|
|
53
|
+
// passes its `before > 0` guard, and runs `cswap add` against a populated
|
|
54
|
+
// store, re-pointing activeAccountNumber with nothing here to restore it.
|
|
55
|
+
const raw = process.env.XDG_DATA_HOME;
|
|
56
|
+
const xdg = raw === "~" ? homedir()
|
|
57
|
+
: raw?.startsWith("~/") ? join(homedir(), raw.slice(2))
|
|
58
|
+
: raw;
|
|
43
59
|
if (xdg && xdg.startsWith("/")) return join(xdg, "claude-swap");
|
|
44
60
|
return join(homedir(), ".local/share/claude-swap");
|
|
45
61
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// it by name and only where it can actually work: a global install, on a
|
|
23
23
|
// directory we can write, outside a git checkout and outside an npx cache.
|
|
24
24
|
// Everywhere else this stays what it has always been — a printed command.
|
|
25
|
-
import { accessSync, constants as FS, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { accessSync, constants as FS, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
26
26
|
import { spawn } from "node:child_process";
|
|
27
27
|
import { homedir } from "node:os";
|
|
28
28
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -894,8 +894,42 @@ export function upgradeMode(blockedReason) {
|
|
|
894
894
|
return blockedReason === "npx" ? "npx" : null;
|
|
895
895
|
}
|
|
896
896
|
|
|
897
|
+
/**
|
|
898
|
+
* Can this user write into `p`?
|
|
899
|
+
*
|
|
900
|
+
* ON WINDOWS THE QUESTION HAS TO BE ASKED BY WRITING (#795). libuv's
|
|
901
|
+
* `fs__access` short-circuits to success for anything carrying
|
|
902
|
+
* FILE_ATTRIBUTE_DIRECTORY — "Directories cannot be read-only on Windows" — and
|
|
903
|
+
* never consults the ACL; Node documents this. Both arguments this is called
|
|
904
|
+
* with are always directories, so `writable` was unconditionally true there,
|
|
905
|
+
* `upgradeBlockedReason` could never answer `not_writable`, and the banner
|
|
906
|
+
* offered "Update & restart" on the common nvm-windows layout where the global
|
|
907
|
+
* prefix is C:\Program Files\nodejs and a non-elevated shell cannot write it.
|
|
908
|
+
* npm then died with EPERM and the user got a truncated npm log tail in a
|
|
909
|
+
* 46-character box — where a POSIX user in the same position gets "the install
|
|
910
|
+
* directory is not writable by this user" and the command to paste. The comment
|
|
911
|
+
* on upgradeBlockedReason states the intent the platform defeated: "Failing
|
|
912
|
+
* inside npm with EACCES tells the user less than declining up front does."
|
|
913
|
+
*
|
|
914
|
+
* The probe is `createTemp`'s "wx" pattern, synchronously: a name nothing else
|
|
915
|
+
* can be using, created exclusively and removed at once. POSIX keeps
|
|
916
|
+
* `accessSync`, where it is correct and cheaper.
|
|
917
|
+
*/
|
|
897
918
|
function dirWritable(p) {
|
|
898
|
-
|
|
919
|
+
if (process.platform !== "win32") {
|
|
920
|
+
try { accessSync(p, FS.W_OK); return true; } catch { return false; }
|
|
921
|
+
}
|
|
922
|
+
// `wx` fails if the name exists, so a collision reads as "not writable"
|
|
923
|
+
// rather than clobbering somebody's file — hence pid and a random suffix.
|
|
924
|
+
const probe = join(p, `.ccdeck-w-${process.pid}-${Math.random().toString(36).slice(2, 8)}`);
|
|
925
|
+
try {
|
|
926
|
+
writeFileSync(probe, "", { flag: "wx" });
|
|
927
|
+
return true;
|
|
928
|
+
} catch {
|
|
929
|
+
return false;
|
|
930
|
+
} finally {
|
|
931
|
+
try { unlinkSync(probe); } catch { /* never created, or already gone */ }
|
|
932
|
+
}
|
|
899
933
|
}
|
|
900
934
|
|
|
901
935
|
/** The same question, answered against the real filesystem and environment. */
|
|
@@ -225,13 +225,13 @@ export function upgradeAttempt({
|
|
|
225
225
|
* banner and the terminal say, so it has to name the version, say what already
|
|
226
226
|
* happened to it, and leave the user somewhere to go. The copyable command is
|
|
227
227
|
* already on screen next to it. */
|
|
228
|
-
export function upgradeRefusalText({ reason, waitMs = 0, attempt = 0 } = {}, target = null) {
|
|
228
|
+
export function upgradeRefusalText({ reason, waitMs = 0, attempt = 0, dash = "—" } = {}, target = null) {
|
|
229
229
|
const what = target ? `v${target}` : "this update";
|
|
230
230
|
if (reason === "exhausted") {
|
|
231
|
-
return `${what} failed to fetch ${attempt} times
|
|
231
|
+
return `${what} failed to fetch ${attempt} times ${dash} not trying again from here; run the command yourself`;
|
|
232
232
|
}
|
|
233
233
|
const left = waitMs >= 60_000 ? `${Math.ceil(waitMs / 60_000)}m` : `${Math.max(1, Math.ceil(waitMs / 1000))}s`;
|
|
234
|
-
return `${what} failed to fetch a moment ago
|
|
234
|
+
return `${what} failed to fetch a moment ago ${dash} waiting ${left} before trying again`;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/**
|
package/src/server/term.mjs
CHANGED
|
@@ -628,12 +628,19 @@ export function pulseDot(beat, { registered = true, claude = true, busy = null }
|
|
|
628
628
|
*
|
|
629
629
|
* @param file the discovery file that could not be written.
|
|
630
630
|
* @param claude whether this deck is watching Claude Code at all.
|
|
631
|
+
* @param dash the em dash, or the ASCII stand-in on a console that cannot draw
|
|
632
|
+
* one (#797). A parameter for the same reason `renameNotice` takes one: this
|
|
633
|
+
* module's own header says "every glyph the deck prints — punctuation
|
|
634
|
+
* included, since an em dash is as absent from CP437 as a check mark — comes
|
|
635
|
+
* from one of them", and this sentence had it hardcoded. On a legacy cmd.exe
|
|
636
|
+
* or the Linux virtual console the reader got a box in the middle of the one
|
|
637
|
+
* line explaining why no events are arriving.
|
|
631
638
|
*/
|
|
632
|
-
export function unregisteredDetail({ file, claude = true }) {
|
|
639
|
+
export function unregisteredDetail({ file, claude = true, dash = "—" }) {
|
|
633
640
|
if (claude) {
|
|
634
641
|
return `Claude Code hooks find this deck through ${file}, so until that file exists no Claude Code events arrive.`;
|
|
635
642
|
}
|
|
636
|
-
return `Codex capture does not use ${file}
|
|
643
|
+
return `Codex capture does not use ${file} ${dash} the deck tails the rollout files itself ${dash} so events still arrive. Only decks sharing one events log need it, to agree on which of them records.`;
|
|
637
644
|
}
|
|
638
645
|
|
|
639
646
|
// ── cursor ───────────────────────────────────────────────────────────────────
|