agent-dag 1.33.147 → 1.33.148
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
|
@@ -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-BJ7WjcQT.js"></script>
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/index-DhGa0tR_.css">
|
|
45
45
|
</head>
|
|
46
46
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.148",
|
|
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": {
|
package/src/server/index.mjs
CHANGED
|
@@ -1375,14 +1375,18 @@ async function handleVersion(req, res) {
|
|
|
1375
1375
|
//
|
|
1376
1376
|
// It is deliberately not folded into `name`, which is documented as the
|
|
1377
1377
|
// package an upgrade would install and is load-bearing for the update flow.
|
|
1378
|
-
// The two answer different questions and
|
|
1379
|
-
//
|
|
1378
|
+
// The two answer different questions and give different answers: `name` is
|
|
1379
|
+
// read off the install on disk and is always known, while this one is the
|
|
1380
|
+
// command that was typed and is silent wherever it cannot be proven — every
|
|
1381
|
+
// Windows global install, and every `npm i -g ccdeck`, whose stub spawns the
|
|
1382
|
+
// deck by absolute path and leaves nothing in argv to read.
|
|
1380
1383
|
send(res, 200, { ...report, canRestart: _canRestart, invokedAs: invokedName({ pkgRoot: PKG_ROOT }) });
|
|
1381
1384
|
}
|
|
1382
1385
|
|
|
1383
|
-
// Runs `npm i -g
|
|
1384
|
-
// fixed inside self-update.mjs
|
|
1385
|
-
//
|
|
1386
|
+
// Runs `npm i -g <this deck>@latest`, and only that: the argument vector is
|
|
1387
|
+
// fixed inside self-update.mjs — including which of the three published names
|
|
1388
|
+
// it installs, which comes from the layout npm built rather than from the
|
|
1389
|
+
// request. Answers immediately — progress is read back from /api/version.
|
|
1386
1390
|
async function handleUpgrade(_req, res) {
|
|
1387
1391
|
const { startUpgrade } = await import(
|
|
1388
1392
|
pathToFileURL(join(PKG_ROOT, "src/server/self-update.mjs")).href
|
|
@@ -176,6 +176,89 @@ export function npxRestartSpec(pkgRoot, name = "agents-deck") {
|
|
|
176
176
|
return npxSpecFromMeta(meta, name);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// ── the package that installed us ────────────────────────────────────────────
|
|
180
|
+
//
|
|
181
|
+
// Two of the three names on npm are this tarball republished; the third is not
|
|
182
|
+
// this tarball at all. `ccdeck` is a stub that ships nothing but bin/ and
|
|
183
|
+
// depends on `agents-deck`, so `npm i -g ccdeck` produces a layout no other
|
|
184
|
+
// install does: npm stopped hoisting a global package's dependencies in v7, so
|
|
185
|
+
// the deck lands at `<prefix>/lib/node_modules/ccdeck/node_modules/agents-deck`
|
|
186
|
+
// and the process runs out of a directory owned by a package it is not named
|
|
187
|
+
// after.
|
|
188
|
+
//
|
|
189
|
+
// #351 taught the stub to FIND the deck there. Nothing downstream learned about
|
|
190
|
+
// it, so every self-update surface went on naming `agents-deck` — which in that
|
|
191
|
+
// layout resolves to `<prefix>/lib/node_modules/agents-deck`, a directory this
|
|
192
|
+
// process never reads and a `npm i -g ccdeck` user usually does not have at
|
|
193
|
+
// all. "Update now" therefore installed a second, unrelated tree: the running
|
|
194
|
+
// install never moved, so installedVersion stayed put, the restart notice never
|
|
195
|
+
// came, and the banner offered the identical update forever while the upgrade
|
|
196
|
+
// reported "done".
|
|
197
|
+
//
|
|
198
|
+
// So the name to install is not the name this build was PUBLISHED under, it is
|
|
199
|
+
// the name the install was REACHED under — and under the stub layout that is
|
|
200
|
+
// written on disk one directory up. Read from there rather than from argv[1]
|
|
201
|
+
// (invoked-as.mjs answers the neighbouring question of which command the user
|
|
202
|
+
// TYPED, and cannot answer this one): the stub spawns the deck by absolute
|
|
203
|
+
// path, so argv[1] reads `agent-dag.js` under all three names, and on Windows
|
|
204
|
+
// npm's .cmd/.ps1 shims never pass the typed name on at all. The directory npm
|
|
205
|
+
// built is the one carrier that survives every platform.
|
|
206
|
+
|
|
207
|
+
/** Every name this deck is published under.
|
|
208
|
+
*
|
|
209
|
+
* `agents-deck` and `agent-dag` are one tarball published twice — see
|
|
210
|
+
* .github/workflows/publish.yml, which renames it between the two — and
|
|
211
|
+
* `ccdeck` is the stub that depends on it. The same three strings as
|
|
212
|
+
* invoked-as.mjs's COMMANDS, and deliberately not that list: this is the set
|
|
213
|
+
* of npm PACKAGES a `npm i -g` may name, that is the set of bin commands a
|
|
214
|
+
* user may type. They are equal only because the rename made them so, and a
|
|
215
|
+
* test pins them against each other rather than either side assuming it. */
|
|
216
|
+
export const ALIAS_PACKAGES = ["agents-deck", "agent-dag", "ccdeck"];
|
|
217
|
+
|
|
218
|
+
/** The directory of the package this one is installed INSIDE, or null when it
|
|
219
|
+
* is not inside one. Pure — path arithmetic only, so a Windows layout can be
|
|
220
|
+
* tested on a POSIX box and both separators are split on, exactly as npxRoot
|
|
221
|
+
* does it and for the same reason. */
|
|
222
|
+
export function hostRoot(pkgRoot) {
|
|
223
|
+
if (typeof pkgRoot !== "string") return null;
|
|
224
|
+
const parts = pkgRoot.split(/[\\/]/);
|
|
225
|
+
// `<host>/node_modules/<us>` and nothing else: the segment directly above us
|
|
226
|
+
// has to be the node_modules npm nested us into, and the one above that is
|
|
227
|
+
// the host. A scoped package would sit one level deeper, under `@scope`, and
|
|
228
|
+
// is refused here rather than guessed at — none of the three names is scoped.
|
|
229
|
+
if (parts.length < 3 || parts[parts.length - 2] !== "node_modules") return null;
|
|
230
|
+
// Keep the separator the input used: a Windows path must come back as one.
|
|
231
|
+
const sep = pkgRoot.includes("\\") && !pkgRoot.includes("/") ? "\\" : "/";
|
|
232
|
+
return parts.slice(0, -2).join(sep) || null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** The host package's name, out of its own manifest — but only when it is one
|
|
236
|
+
* of this deck's aliases AND it declares a dependency on us.
|
|
237
|
+
*
|
|
238
|
+
* The alias half is the load-bearing one. Any project that lists `agents-deck`
|
|
239
|
+
* in its dependencies and runs it out of its own node_modules — a workspace, a
|
|
240
|
+
* CI job, a tool that embeds the deck — is in exactly the same shape on disk
|
|
241
|
+
* as the stub, and answering with THAT name would have the deck offering to
|
|
242
|
+
* `npm i -g their-app@latest`: a package it has no business installing, and on
|
|
243
|
+
* a private name one that does not exist. Confining the answer to the three
|
|
244
|
+
* published names leaves every such install with the fallback it has today. */
|
|
245
|
+
export function hostNameFromMeta(meta, name = "agents-deck") {
|
|
246
|
+
const host = typeof meta?.name === "string" ? meta.name : null;
|
|
247
|
+
if (!host || !ALIAS_PACKAGES.includes(host)) return null;
|
|
248
|
+
return typeof meta?.dependencies?.[name] === "string" ? host : null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** The same, answered against the filesystem: `{ root, name }` for the alias
|
|
252
|
+
* package this copy was installed as a dependency of, or null. */
|
|
253
|
+
export function hostPackage(pkgRoot, name = "agents-deck") {
|
|
254
|
+
const root = hostRoot(pkgRoot);
|
|
255
|
+
if (!root) return null;
|
|
256
|
+
let meta = null;
|
|
257
|
+
try { meta = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); } catch { return null; }
|
|
258
|
+
const host = hostNameFromMeta(meta, name);
|
|
259
|
+
return host ? { root, name: host } : null;
|
|
260
|
+
}
|
|
261
|
+
|
|
179
262
|
/** The package an upgrade would actually install here — the only package worth
|
|
180
263
|
* asking npm about.
|
|
181
264
|
*
|
|
@@ -188,14 +271,24 @@ export function npxRestartSpec(pkgRoot, name = "agents-deck") {
|
|
|
188
271
|
* install — the ETARGET below, with a window measured in publishes rather than
|
|
189
272
|
* in seconds of propagation.
|
|
190
273
|
*
|
|
191
|
-
* Deriving the name from
|
|
274
|
+
* Deriving the name from what would actually be installed keeps the two halves
|
|
192
275
|
* consistent by construction: whatever the command will install is what gets
|
|
193
|
-
* asked about, and the per-name marker follows the same name.
|
|
194
|
-
*
|
|
195
|
-
* the
|
|
276
|
+
* asked about, and the per-name marker follows the same name. Each install
|
|
277
|
+
* shape carries that answer somewhere different — npx in the spec it recorded,
|
|
278
|
+
* a stub install in the layout npm built, a plain global install nowhere,
|
|
279
|
+
* because there the published name is already the right one. */
|
|
196
280
|
export function upgradeName(pkgRoot, name = "agents-deck") {
|
|
197
|
-
|
|
198
|
-
|
|
281
|
+
// A checkout installs nothing at all, so the published name is the only
|
|
282
|
+
// sensible subject for the version question — and the only one whose
|
|
283
|
+
// dist-tag says anything about the branch the maintainer is sitting on.
|
|
284
|
+
if (isGitCheckout(pkgRoot)) return name;
|
|
285
|
+
if (isNpxInstall(pkgRoot)) return bareSpecName(npxRestartSpec(pkgRoot, name)) ?? name;
|
|
286
|
+
// Left: a global install, where the answer is whichever package owns the
|
|
287
|
+
// directory npm would rewrite. That is `name` for `npm i -g agents-deck` and
|
|
288
|
+
// for `npm i -g agent-dag`, and the stub for `npm i -g ccdeck` — the one
|
|
289
|
+
// shape where the two differ, and the one where naming `name` installed a
|
|
290
|
+
// tree this process could not see.
|
|
291
|
+
return hostPackage(pkgRoot, name)?.name ?? name;
|
|
199
292
|
}
|
|
200
293
|
|
|
201
294
|
/** The exact line the user can paste, for the way THIS copy was installed. */
|
|
@@ -204,7 +297,11 @@ export function upgradeCommand(pkgRoot, name = "agents-deck") {
|
|
|
204
297
|
// so `npm run build` is part of the answer rather than an afterthought.
|
|
205
298
|
if (isGitCheckout(pkgRoot)) return "git pull && npm run build";
|
|
206
299
|
if (isNpxInstall(pkgRoot)) return `npx -y ${upgradeName(pkgRoot, name)}@latest`;
|
|
207
|
-
|
|
300
|
+
// Through upgradeName for the same reason the npx line above it is: the
|
|
301
|
+
// printed command is the user's escape hatch when the button fails or is not
|
|
302
|
+
// offered, and one that names a package this install cannot be replaced by is
|
|
303
|
+
// worse than none — it looks like it worked.
|
|
304
|
+
return `npm i -g ${upgradeName(pkgRoot, name)}@latest`;
|
|
208
305
|
}
|
|
209
306
|
|
|
210
307
|
// ── what npm has ─────────────────────────────────────────────────────────────
|
|
@@ -533,12 +630,19 @@ function dirWritable(p) {
|
|
|
533
630
|
|
|
534
631
|
/** The same question, answered against the real filesystem and environment. */
|
|
535
632
|
export function upgradeBlock(pkgRoot) {
|
|
633
|
+
// Whatever `npm i -g` would rewrite is what has to be writable, and under the
|
|
634
|
+
// stub layout that is not this directory: `npm i -g ccdeck` replaces
|
|
635
|
+
// <prefix>/lib/node_modules/ccdeck, and the copy running out of its nested
|
|
636
|
+
// node_modules goes with it. In practice both pairs answer the same, since
|
|
637
|
+
// one npm install created them with one owner — but the question is about the
|
|
638
|
+
// tree the command touches, and that tree is the host's.
|
|
639
|
+
const target = hostPackage(pkgRoot)?.root ?? pkgRoot;
|
|
536
640
|
return upgradeBlockedReason({
|
|
537
641
|
git: isGitCheckout(pkgRoot),
|
|
538
642
|
npx: isNpxInstall(pkgRoot),
|
|
539
643
|
// npm -g rewrites the package directory and its parent (the global
|
|
540
644
|
// node_modules), so both have to be ours to write.
|
|
541
|
-
writable: dirWritable(
|
|
645
|
+
writable: dirWritable(target) && dirWritable(resolve(target, "..")),
|
|
542
646
|
optedOut: process.env.AGENTS_DECK_NO_INSTALL === "1",
|
|
543
647
|
});
|
|
544
648
|
}
|
|
@@ -726,15 +830,22 @@ export function upgradeStatus() {
|
|
|
726
830
|
* Start `npm i -g <name>@latest` in the background.
|
|
727
831
|
*
|
|
728
832
|
* Returns immediately with the accepted command, or a refusal. Never installs
|
|
729
|
-
* anything except this
|
|
730
|
-
* argument vector is fixed here, not
|
|
833
|
+
* anything except this deck — under one of its own three published names, and
|
|
834
|
+
* never at a version the caller chose. The argument vector is fixed here, not
|
|
835
|
+
* assembled from request input: the only thing that varies is which alias, and
|
|
836
|
+
* that is read off the install on disk and confined to ALIAS_PACKAGES.
|
|
731
837
|
*/
|
|
732
838
|
export function startUpgrade({ pkgRoot, name = "agents-deck" }) {
|
|
733
839
|
if (_upgrade.state === "running") return { ok: true, already: true, command: _upgrade.command };
|
|
734
840
|
const blocked = upgradeBlock(pkgRoot);
|
|
735
841
|
if (blocked) return { ok: false, reason: blocked, command: upgradeCommand(pkgRoot, name) };
|
|
736
842
|
|
|
737
|
-
|
|
843
|
+
// The package this install can actually be replaced by — the stub for a
|
|
844
|
+
// `npm i -g ccdeck`, the published name everywhere else. Installing `name`
|
|
845
|
+
// there wrote a tree this process never reads, so the version on disk never
|
|
846
|
+
// moved and the same update was offered forever.
|
|
847
|
+
const target = upgradeName(pkgRoot, name);
|
|
848
|
+
const args = ["install", "-g", `${target}@latest`, "--no-audit", "--no-fund", "--loglevel", "error"];
|
|
738
849
|
const command = `npm ${args.join(" ")}`;
|
|
739
850
|
_upgrade = { state: "running", command, error: null, at: Date.now() };
|
|
740
851
|
|