agent-dag 1.33.76 → 1.33.78
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/deck.js
CHANGED
|
@@ -77,7 +77,7 @@ const persist = flags.noPersist
|
|
|
77
77
|
? null
|
|
78
78
|
: (flags.history ?? join(claudeConfigDir(), "agent-dag", "events.jsonl"));
|
|
79
79
|
|
|
80
|
-
const { installHooks,
|
|
80
|
+
const { installHooks, keepDiscovery, removeDiscovery, hasCodexInstalled } =
|
|
81
81
|
await import(pathToFileURL(join(PKG_ROOT, "src/server/installer.mjs")).href);
|
|
82
82
|
const { startServer, hookToken } =
|
|
83
83
|
await import(pathToFileURL(join(PKG_ROOT, "src/server/index.mjs")).href);
|
|
@@ -328,9 +328,31 @@ if (RESPAWN) {
|
|
|
328
328
|
else process.stdout.write("\n");
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
// The discovery file is the whole of how a hook finds this deck: hook.js
|
|
332
|
+
// enumerates that directory and nothing else. Writing it once at boot meant
|
|
333
|
+
// anything that later took it away left a deck that listened, served, and
|
|
334
|
+
// received not one event — with nothing on screen to say so. So it is checked
|
|
335
|
+
// on a timer, put back when it goes missing, and its absence is stated out loud
|
|
336
|
+
// rather than left to look like an idle afternoon.
|
|
337
|
+
//
|
|
331
338
|
// The token goes in with the port: it is what lets a hook tell this deck from
|
|
332
339
|
// whatever else may later be listening on the same number. See hookToken().
|
|
333
|
-
|
|
340
|
+
let registered = null;
|
|
341
|
+
const discovery = keepDiscovery({
|
|
342
|
+
port: realPort,
|
|
343
|
+
workspace,
|
|
344
|
+
token: hookToken(),
|
|
345
|
+
onState: (state) => {
|
|
346
|
+
const first = registered === null;
|
|
347
|
+
registered = state.ok;
|
|
348
|
+
if (!state.ok) reportUnregistered(state);
|
|
349
|
+
else if (!first) reportReregistered(state);
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
const discoveryFile = discovery.file;
|
|
353
|
+
// Now, not in five seconds: nothing should reach the pulse line below without
|
|
354
|
+
// the deck knowing whether the hooks can see it.
|
|
355
|
+
await discovery.check();
|
|
334
356
|
|
|
335
357
|
// Never on a respawn: the tab that asked for the restart is still open and
|
|
336
358
|
// reconnecting on its own. A second one would be the deck talking over itself.
|
|
@@ -344,9 +366,19 @@ if (openBrowser && !RESPAWN) {
|
|
|
344
366
|
// ── Pulse indicator ───────────────────────────────────────────────────────────
|
|
345
367
|
if (tty) {
|
|
346
368
|
const pulseFrames = [`${C.green}●${C.reset}`, `${C.dim}●${C.reset}`];
|
|
369
|
+
const LISTENING = "listening — Ctrl+C to stop";
|
|
370
|
+
// A deck no hook can find is not listening in any sense the user cares
|
|
371
|
+
// about, and the pulse is the one line that stays on screen for hours — so
|
|
372
|
+
// it is where this has to be said.
|
|
373
|
+
const UNREGISTERED = "listening, but not registered — hooks cannot find this deck";
|
|
374
|
+
// Padded on the plain text, before any colour: the line is redrawn over
|
|
375
|
+
// itself with \r, so the shorter message has to cover the longer one.
|
|
376
|
+
const width = UNREGISTERED.length + 3;
|
|
347
377
|
let pi = 0;
|
|
348
378
|
setInterval(() => {
|
|
349
|
-
|
|
379
|
+
const text = (registered ? LISTENING : UNREGISTERED).padEnd(width);
|
|
380
|
+
const colour = registered ? C.dim : C.yellow;
|
|
381
|
+
process.stdout.write(`\r ${pulseFrames[pi++ % 2]} ${colour}${text}${C.reset}`);
|
|
350
382
|
}, 800).unref();
|
|
351
383
|
}
|
|
352
384
|
|
|
@@ -358,6 +390,10 @@ const shutdown = async (code = 0) => {
|
|
|
358
390
|
if (tty && code !== RESTART_CODE && code !== UPGRADE_CODE) {
|
|
359
391
|
process.stdout.write(`\n\n ${C.yellow}◉ shutting down…${C.reset}\n`);
|
|
360
392
|
}
|
|
393
|
+
// Stopped first, always: a tick landing after the unlink would re-register a
|
|
394
|
+
// deck that is on its way out, and leave the file behind for the hooks to
|
|
395
|
+
// find once nothing is listening.
|
|
396
|
+
discovery.stop();
|
|
361
397
|
await removeDiscovery(discoveryFile);
|
|
362
398
|
server.close(() => process.exit(code));
|
|
363
399
|
// SSE connections never end by themselves, so close() alone would sit out the
|
|
@@ -369,10 +405,25 @@ const shutdown = async (code = 0) => {
|
|
|
369
405
|
};
|
|
370
406
|
process.on("SIGINT", () => shutdown(0));
|
|
371
407
|
process.on("SIGTERM", () => shutdown(0));
|
|
372
|
-
process.on("beforeExit", () => removeDiscovery(discoveryFile));
|
|
408
|
+
process.on("beforeExit", () => { discovery.stop(); removeDiscovery(discoveryFile); });
|
|
373
409
|
|
|
374
410
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
375
411
|
|
|
412
|
+
// The deck is up and the hooks cannot see it. Said in full — the path, the
|
|
413
|
+
// reason — because the alternative is what this replaced: an ordinary-looking
|
|
414
|
+
// deck that simply never shows a session.
|
|
415
|
+
function reportUnregistered({ file, error }) {
|
|
416
|
+
const why = error?.message ? ` — ${error.message}` : "";
|
|
417
|
+
process.stdout.write(
|
|
418
|
+
`\n ${C.yellow}⚠${C.reset} ${C.bold}not registered${C.reset}${C.dim}${why}${C.reset}\n` +
|
|
419
|
+
` ${C.dim}hooks find this deck through ${file}, so until that file exists no events arrive.${C.reset}\n`,
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function reportReregistered({ file }) {
|
|
424
|
+
process.stdout.write(`\n ${C.green}✓${C.reset} ${C.dim}registered again → ${file}${C.reset}\n`);
|
|
425
|
+
}
|
|
426
|
+
|
|
376
427
|
function parseArgs(args) {
|
|
377
428
|
const out = {};
|
|
378
429
|
for (let i = 0; i < args.length; i++) {
|