agent-dag 1.33.11 → 1.33.13
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-Cif0aUlE.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.13",
|
|
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/exec.mjs
CHANGED
|
@@ -199,24 +199,39 @@ export function runInteractive(cmd, args, { timeout = 300_000, maxOutput = 256 <
|
|
|
199
199
|
if (i >= tries.length) return finish(-1, { code: "ENOENT" });
|
|
200
200
|
const raw = tries[i];
|
|
201
201
|
const { file, args: argv, opts } = isBatch(raw) ? viaCmd(raw, args) : { file: raw, args, opts: {} };
|
|
202
|
+
let proc;
|
|
202
203
|
try {
|
|
203
|
-
|
|
204
|
+
proc = spawn(file, argv, { stdio: ["pipe", "pipe", "pipe"], shell: false, windowsHide: true, ...opts });
|
|
204
205
|
} catch (err) {
|
|
205
206
|
return tryNext(err) ? attempt(i + 1) : finish(-1, err);
|
|
206
207
|
}
|
|
207
|
-
child
|
|
208
|
+
child = proc;
|
|
209
|
+
// A spelling that fails to spawn emits 'error' AND THEN 'close' — with code
|
|
210
|
+
// -2 after an ENOENT. Once the error handler has moved on to the next
|
|
211
|
+
// candidate, that trailing 'close' is news about a child nobody is waiting
|
|
212
|
+
// for any more, and answering it settled `done` with ok:false while the
|
|
213
|
+
// real child was still running. On Windows that is the normal path, not a
|
|
214
|
+
// corner case: `claude.exe` does not exist, `claude.cmd` does, so the very
|
|
215
|
+
// first login reported "the code was not accepted" while the child it had
|
|
216
|
+
// abandoned went on to complete the OAuth and switch the live account.
|
|
217
|
+
// Every listener below therefore speaks only while its own child is the
|
|
218
|
+
// current one.
|
|
219
|
+
const stale = () => proc !== child;
|
|
220
|
+
proc.on("error", (err) => {
|
|
221
|
+
if (stale()) return;
|
|
208
222
|
// Only retry another spelling while nothing has run yet; a mid-run error
|
|
209
223
|
// is this child's failure, not evidence the name was wrong.
|
|
210
224
|
if (tryNext(err) && !stdout && !stderr) { child = null; return attempt(i + 1); }
|
|
211
225
|
finish(-1, err);
|
|
212
226
|
});
|
|
213
|
-
|
|
227
|
+
proc.on("spawn", () => resolved.set(cmd, raw));
|
|
214
228
|
// Capped so a runaway child cannot grow the heap without bound; the tail is
|
|
215
229
|
// what carries the error, so the head is what gets dropped.
|
|
216
230
|
const keep = (buf, text) => (buf + text).slice(-maxOutput);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
231
|
+
proc.stdout?.on("data", (d) => { if (stale()) return; const t = String(d); stdout = keep(stdout, t); emitLines(t); });
|
|
232
|
+
proc.stderr?.on("data", (d) => { if (stale()) return; const t = String(d); stderr = keep(stderr, t); emitLines(t); });
|
|
233
|
+
proc.on("close", (code) => {
|
|
234
|
+
if (stale()) return;
|
|
220
235
|
// Same cmd.exe case as in `run`: exit 1 with "is not recognized" means
|
|
221
236
|
// this spelling does not exist, not that the tool failed.
|
|
222
237
|
if (code !== 0 && looksMissing(`${stderr}\n${stdout}`)) {
|
package/src/server/index.mjs
CHANGED
|
@@ -1288,6 +1288,22 @@ function randomPort(min, max) {
|
|
|
1288
1288
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
1289
1289
|
}
|
|
1290
1290
|
|
|
1291
|
+
// Parse a request target into a URL, or null when it cannot be parsed.
|
|
1292
|
+
//
|
|
1293
|
+
// The base is the constant "http://localhost", never the Host header. Node's
|
|
1294
|
+
// HTTP parser hands the header through verbatim, so a client sending
|
|
1295
|
+
// `Host: bad host` used to produce `new URL("/", "http://bad host")`, which
|
|
1296
|
+
// throws ERR_INVALID_URL synchronously inside the request listener. Nothing
|
|
1297
|
+
// catches that — it becomes an uncaughtException, the worker exits 1 and the
|
|
1298
|
+
// supervisor tears the whole deck down for a single malformed request. Only
|
|
1299
|
+
// the path and the query are ever read from this URL, so the authority half
|
|
1300
|
+
// is free to be a constant — which is what every other new URL call site in
|
|
1301
|
+
// this file already does. Anything else unparseable answers 400 instead.
|
|
1302
|
+
export function requestUrl(rawUrl) {
|
|
1303
|
+
try { return new URL(rawUrl ?? "/", "http://localhost"); }
|
|
1304
|
+
catch { return null; }
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1291
1307
|
async function tryListen(server, port, host) {
|
|
1292
1308
|
return new Promise((res, rej) => {
|
|
1293
1309
|
server.once("error", rej);
|
|
@@ -1340,7 +1356,10 @@ export async function startServer({ port = 4317, host = "127.0.0.1", persist = n
|
|
|
1340
1356
|
});
|
|
1341
1357
|
|
|
1342
1358
|
const server = createServer((req, res) => {
|
|
1343
|
-
const url =
|
|
1359
|
+
const url = requestUrl(req.url);
|
|
1360
|
+
// Unparseable request target. Nothing below can route it, and throwing here
|
|
1361
|
+
// would be an uncaughtException inside the listener — i.e. the whole deck.
|
|
1362
|
+
if (!url) return send(res, 400, { error: "bad request target" });
|
|
1344
1363
|
|
|
1345
1364
|
if (req.method === "POST" && url.pathname === "/api/event") return guard(handleEventIngest(req, res), res);
|
|
1346
1365
|
if (req.method === "GET" && url.pathname === "/api/health") return handleHealth(req, res);
|