@agentdeck/bridge 1.0.8 → 1.0.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/dist/ask-gate.d.ts +113 -0
- package/dist/ask-gate.d.ts.map +1 -0
- package/dist/ask-gate.js +110 -0
- package/dist/ask-gate.js.map +1 -0
- package/dist/auth.d.ts +8 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -0
- package/dist/auth.js.map +1 -1
- package/dist/awaiting-overlay.d.ts +54 -6
- package/dist/awaiting-overlay.d.ts.map +1 -1
- package/dist/awaiting-overlay.js +109 -26
- package/dist/awaiting-overlay.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +74 -4
- package/dist/cli.js.map +1 -1
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +238 -19
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/http-auth-gate.d.ts +40 -0
- package/dist/http-auth-gate.d.ts.map +1 -0
- package/dist/http-auth-gate.js +46 -0
- package/dist/http-auth-gate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/mdns.d.ts +7 -1
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +7 -3
- package/dist/mdns.js.map +1 -1
- package/dist/modules/mdns-module.d.ts.map +1 -1
- package/dist/modules/mdns-module.js +3 -1
- package/dist/modules/mdns-module.js.map +1 -1
- package/dist/observed-inject.d.ts +21 -5
- package/dist/observed-inject.d.ts.map +1 -1
- package/dist/observed-inject.js +85 -22
- package/dist/observed-inject.js.map +1 -1
- package/dist/observed-steering.d.ts +38 -0
- package/dist/observed-steering.d.ts.map +1 -1
- package/dist/observed-steering.js +53 -0
- package/dist/observed-steering.js.map +1 -1
- package/dist/passive-observer.d.ts +9 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +90 -5
- package/dist/passive-observer.js.map +1 -1
- package/dist/permission-resolver.d.ts +11 -0
- package/dist/permission-resolver.d.ts.map +1 -1
- package/dist/permission-resolver.js +23 -3
- package/dist/permission-resolver.js.map +1 -1
- package/dist/session-registry.d.ts +23 -2
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +56 -5
- package/dist/session-registry.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -365,6 +365,7 @@ program
|
|
|
365
365
|
.option('--wake-word', 'Enable wake word voice assistant ("오픈클로")')
|
|
366
366
|
.option('--remote-daemon', 'Opt in to attaching this session to a daemon on another machine (gates --daemon-host and mDNS discovery)')
|
|
367
367
|
.option('--daemon-host <host>', 'Explicit remote daemon endpoint (host or host:port); requires --remote-daemon')
|
|
368
|
+
.option('--daemon-token <token>', 'Pairing token of the remote hub (~/.agentdeck/auth-token there); or set AGENTDECK_DAEMON_TOKEN')
|
|
368
369
|
.option('--no-env-args', 'Ignore AGENTDECK_COMMANDER_ARGS and AGENTDECK_<AGENT>_ARGS for this invocation')
|
|
369
370
|
.option('--weight <n>', 'Deck/tab sort order override (integer, lower first; default 0)', parseWeight)
|
|
370
371
|
.action(async (opts) => {
|
|
@@ -380,6 +381,7 @@ program
|
|
|
380
381
|
wakeWord: !!opts.wakeWord,
|
|
381
382
|
remoteDaemon: !!opts.remoteDaemon,
|
|
382
383
|
daemonHost: opts.daemonHost,
|
|
384
|
+
daemonToken: opts.daemonToken,
|
|
383
385
|
weight: opts.weight,
|
|
384
386
|
modules: opts.local ? { mdns: false, adb: false, serial: false, pixoo: false, timebox: false } : {
|
|
385
387
|
mdns: false, // daemon-only — session bridges never advertise mDNS
|
|
@@ -402,6 +404,7 @@ program
|
|
|
402
404
|
.option('--no-codex-hooks', 'Skip ~/.codex/config.toml hook install')
|
|
403
405
|
.option('--remote-daemon', 'Opt in to attaching this session to a daemon on another machine (gates --daemon-host and mDNS discovery)')
|
|
404
406
|
.option('--daemon-host <host>', 'Explicit remote daemon endpoint (host or host:port); requires --remote-daemon')
|
|
407
|
+
.option('--daemon-token <token>', 'Pairing token of the remote hub (~/.agentdeck/auth-token there); or set AGENTDECK_DAEMON_TOKEN')
|
|
405
408
|
.option('--no-env-args', 'Ignore AGENTDECK_COMMANDER_ARGS and AGENTDECK_<AGENT>_ARGS for this invocation')
|
|
406
409
|
.option('--weight <n>', 'Deck/tab sort order override (integer, lower first; default 0)', parseWeight)
|
|
407
410
|
.action(async (opts) => {
|
|
@@ -439,6 +442,7 @@ program
|
|
|
439
442
|
postit: opts.postit !== false,
|
|
440
443
|
remoteDaemon: !!opts.remoteDaemon,
|
|
441
444
|
daemonHost: opts.daemonHost,
|
|
445
|
+
daemonToken: opts.daemonToken,
|
|
442
446
|
weight: opts.weight,
|
|
443
447
|
modules: opts.local ? { mdns: false, adb: false, serial: false, pixoo: false, timebox: false } : {
|
|
444
448
|
mdns: false, // daemon-only
|
|
@@ -461,6 +465,7 @@ program
|
|
|
461
465
|
.option('--no-opencode-hooks', 'Skip OpenCode observer plugin install')
|
|
462
466
|
.option('--remote-daemon', 'Opt in to attaching this session to a daemon on another machine (gates --daemon-host and mDNS discovery)')
|
|
463
467
|
.option('--daemon-host <host>', 'Explicit remote daemon endpoint (host or host:port); requires --remote-daemon')
|
|
468
|
+
.option('--daemon-token <token>', 'Pairing token of the remote hub (~/.agentdeck/auth-token there); or set AGENTDECK_DAEMON_TOKEN')
|
|
464
469
|
.option('--no-env-args', 'Ignore AGENTDECK_COMMANDER_ARGS and AGENTDECK_<AGENT>_ARGS for this invocation')
|
|
465
470
|
.option('--weight <n>', 'Deck/tab sort order override (integer, lower first; default 0)', parseWeight)
|
|
466
471
|
.action(async (opts) => {
|
|
@@ -497,6 +502,7 @@ program
|
|
|
497
502
|
postit: opts.postit !== false,
|
|
498
503
|
remoteDaemon: !!opts.remoteDaemon,
|
|
499
504
|
daemonHost: opts.daemonHost,
|
|
505
|
+
daemonToken: opts.daemonToken,
|
|
500
506
|
weight: opts.weight,
|
|
501
507
|
modules: opts.local ? { mdns: false, adb: false, serial: false, pixoo: false, timebox: false } : {
|
|
502
508
|
mdns: false,
|
|
@@ -515,6 +521,7 @@ program
|
|
|
515
521
|
.option('--local', 'Disable all device modules')
|
|
516
522
|
.option('--remote-daemon', 'Opt in to attaching this session to a daemon on another machine (gates --daemon-host and mDNS discovery)')
|
|
517
523
|
.option('--daemon-host <host>', 'Explicit remote daemon endpoint (host or host:port); requires --remote-daemon')
|
|
524
|
+
.option('--daemon-token <token>', 'Pairing token of the remote hub (~/.agentdeck/auth-token there); or set AGENTDECK_DAEMON_TOKEN')
|
|
518
525
|
// Commander-layer half only: monitor spawns no agent command to weave into.
|
|
519
526
|
.option('--no-env-args', 'Ignore AGENTDECK_COMMANDER_ARGS for this invocation')
|
|
520
527
|
.option('--weight <n>', 'Deck/tab sort order override (integer, lower first; default 0)', parseWeight)
|
|
@@ -530,6 +537,7 @@ program
|
|
|
530
537
|
debug: opts.debug,
|
|
531
538
|
remoteDaemon: !!opts.remoteDaemon,
|
|
532
539
|
daemonHost: opts.daemonHost,
|
|
540
|
+
daemonToken: opts.daemonToken,
|
|
533
541
|
weight: opts.weight,
|
|
534
542
|
modules: opts.local ? { mdns: false, adb: false, serial: false, pixoo: false, timebox: false } : undefined,
|
|
535
543
|
});
|
|
@@ -550,7 +558,7 @@ daemon
|
|
|
550
558
|
.option('-f, --foreground', 'Run in foreground (default: background fork)')
|
|
551
559
|
.option('--wake-word', 'Enable wake word voice assistant ("오픈클로")')
|
|
552
560
|
.action(async (opts) => {
|
|
553
|
-
const { findExistingDaemon, probeDaemonHealth, readDaemonInfo, removeDaemonInfo, removeDaemonSession, requestDaemonStandDown, requestDaemonShutdown, waitForDaemonExit } = await import('./session-registry.js');
|
|
561
|
+
const { findExistingDaemon, probeDaemonHealth, readDaemonInfo, removeDaemonInfo, removeDaemonSession, requestDaemonStandDown, requestDaemonShutdown, waitForDaemonExit, waitForPortBindable } = await import('./session-registry.js');
|
|
554
562
|
// Reverse two-tier upgrade path: the macOS app may already own the canonical
|
|
555
563
|
// port with its in-process Swift daemon (Tier 1 — limited: no ADB devices,
|
|
556
564
|
// no subscription usage, …). A plain "already running → exit" would strand
|
|
@@ -571,13 +579,52 @@ daemon
|
|
|
571
579
|
await requestDaemonShutdown(targetPort);
|
|
572
580
|
acked = true; // shutdown is best-effort (no ack body); rely on the exit wait
|
|
573
581
|
}
|
|
574
|
-
|
|
582
|
+
// Two conditions, not one. `waitForDaemonExit` proves the app stopped
|
|
583
|
+
// answering; `waitForPortBindable` proves the socket is actually gone.
|
|
584
|
+
// The app releases the port with NWListener.cancel(), which returns
|
|
585
|
+
// before the teardown completes — binding on the first signal alone is
|
|
586
|
+
// what silently demoted this daemon to the 9121 fallback and left the
|
|
587
|
+
// canonical port ownerless.
|
|
588
|
+
if (acked
|
|
589
|
+
&& await waitForDaemonExit(targetPort, 12000)
|
|
590
|
+
// 30s, and that is not padding. Cancelling the app's NWListener does
|
|
591
|
+
// not free the port: macOS keeps a NECP reservation on it for ~14s
|
|
592
|
+
// afterwards, during which `lsof` shows no sockets at all and bind()
|
|
593
|
+
// still returns EADDRINUSE (measured 2026-08-06 — bindable at ~17s).
|
|
594
|
+
// Anything shorter gives up while the kernel, not the app, is holding
|
|
595
|
+
// the port. The app's takeover-yield window is longer still (45s), so
|
|
596
|
+
// it stays off the port until well after this wait has claimed it.
|
|
597
|
+
&& await waitForPortBindable(targetPort, 30000)) {
|
|
575
598
|
log(`App daemon yielded port ${targetPort}. Starting CLI daemon…`);
|
|
576
599
|
// fall through — port is clear, proceed to bind below
|
|
577
600
|
}
|
|
578
601
|
else {
|
|
579
|
-
|
|
580
|
-
|
|
602
|
+
// The app yielded but the PORT did not come back, and that is often
|
|
603
|
+
// not the app's doing: a WiFi device that has gone to sleep with bytes
|
|
604
|
+
// still queued to it leaves its socket in LAST_ACK on this port, and
|
|
605
|
+
// TCP holds that until it exhausts retransmits — minutes, sometimes.
|
|
606
|
+
// Network.framework exposes no SO_LINGER, so the app cannot RST out of
|
|
607
|
+
// it (measured 2026-08-06: two sleeping ESP32 boards, 11901 and 4
|
|
608
|
+
// bytes queued, were the only things left on 9120).
|
|
609
|
+
//
|
|
610
|
+
// Carry on rather than exiting. The daemon binds a fallback port and
|
|
611
|
+
// writes it to daemon.json, which is what every client resolves
|
|
612
|
+
// through and what the app itself re-reads when its yield window ends
|
|
613
|
+
// — so the deck keeps working. What must NOT happen is this being
|
|
614
|
+
// silent, which is how the canonical port ended up owned by nobody
|
|
615
|
+
// with the CLI reporting success.
|
|
616
|
+
log(`The AgentDeck app yielded port ${targetPort} but the port has not been released `
|
|
617
|
+
+ `(usually a sleeping WiFi device holding a half-closed socket on it).`);
|
|
618
|
+
if (opts.port) {
|
|
619
|
+
// The port was ASKED for, not defaulted to. Quietly binding a
|
|
620
|
+
// different one would answer a question the user did not ask;
|
|
621
|
+
// an explicit choice fails loudly instead.
|
|
622
|
+
log(`Quit the AgentDeck app and retry, or choose another port.`);
|
|
623
|
+
process.exit(1);
|
|
624
|
+
}
|
|
625
|
+
log(`Starting on a fallback port instead — clients resolve it from daemon.json. `
|
|
626
|
+
+ `For the canonical port, quit the AgentDeck app and retry, or pass -p.`);
|
|
627
|
+
// fall through to normal port selection
|
|
581
628
|
}
|
|
582
629
|
}
|
|
583
630
|
else {
|
|
@@ -1287,6 +1334,29 @@ program
|
|
|
1287
1334
|
// qrcode not available
|
|
1288
1335
|
}
|
|
1289
1336
|
});
|
|
1337
|
+
program
|
|
1338
|
+
.command('token')
|
|
1339
|
+
.description('Show or rotate the pairing token (~/.agentdeck/auth-token)')
|
|
1340
|
+
.argument('[action]', "'show' (default) prints the token; 'rotate' replaces it", 'show')
|
|
1341
|
+
.action(async (action) => {
|
|
1342
|
+
const { getOrCreateToken, rotateToken } = await import('./auth.js');
|
|
1343
|
+
if (action === 'rotate') {
|
|
1344
|
+
const token = rotateToken();
|
|
1345
|
+
log(`New pairing token: ${token}`);
|
|
1346
|
+
log('All paired clients must re-pair: rescan the QR on companion apps (agentdeck qr),');
|
|
1347
|
+
log('re-provision WiFi ESP32 boards (they re-provision automatically over USB serial),');
|
|
1348
|
+
log('and update AGENTDECK_DAEMON_TOKEN on any remote workers.');
|
|
1349
|
+
log('Restart the daemon (agentdeck daemon restart) so it picks up the new token.');
|
|
1350
|
+
}
|
|
1351
|
+
else if (action === 'show') {
|
|
1352
|
+
log(getOrCreateToken());
|
|
1353
|
+
log('(Anyone with this token can control your sessions over the LAN — treat it like a password.)');
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
console.error(`Unknown action '${action}' — use 'show' or 'rotate'.`);
|
|
1357
|
+
process.exitCode = 1;
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1290
1360
|
program
|
|
1291
1361
|
.command('inject-test')
|
|
1292
1362
|
.description('Test observed-answer injection into a terminal or app (tuning aid)')
|