@songsid/agend 2.1.4-beta.18 → 2.1.4-beta.19
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/backend/antigravity.d.ts +1 -0
- package/dist/backend/antigravity.js +4 -0
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/codex.d.ts +17 -0
- package/dist/backend/codex.js +51 -0
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +10 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +48 -21
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +5 -3
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +1 -1
- package/dist/cli.js +31 -21
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +3 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +33 -0
- package/dist/daemon.js +134 -6
- package/dist/daemon.js.map +1 -1
- package/dist/doctor.js +34 -27
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -0
- package/dist/fleet-manager.d.ts +14 -0
- package/dist/fleet-manager.js +305 -75
- package/dist/fleet-manager.js.map +1 -1
- package/dist/locale.js +656 -330
- package/dist/locale.js.map +1 -1
- package/dist/outbound-handlers.js +5 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/restart-progress.d.ts +2 -0
- package/dist/restart-progress.js +3 -0
- package/dist/restart-progress.js.map +1 -1
- package/dist/scheduler/db.d.ts +5 -0
- package/dist/scheduler/db.js +35 -0
- package/dist/scheduler/db.js.map +1 -1
- package/dist/tips.d.ts +34 -0
- package/dist/tips.js +554 -0
- package/dist/tips.js.map +1 -0
- package/dist/topic-commands.d.ts +5 -2
- package/dist/topic-commands.js +101 -61
- package/dist/topic-commands.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/ui/dashboard.html +55 -32
- package/dist/ui/settings.html +46 -37
- package/dist/ui/view.html +23 -15
- package/package.json +1 -1
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGlF,SAAS,gBAAgB,CAAmB,MAAS,EAAE,MAAkB;IACvE,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAA6B,CAAC;IACxD,MAAM,YAAY,GAAG,MAAiC,CAAC;IAEvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,IACE,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACzB,OAAO,SAAS,KAAK,QAAQ;YAC7B,SAAS,KAAK,IAAI;YAClB,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EACzB,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAC5B,SAAmB,EACnB,SAA4B,CAC7B,CAAC;QACJ,CAAC;aAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,MAAsB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,kBAAkB,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAoB;IACjD,eAAe,EAAE,CAAC,EAAE,eAAe;IACnC,kBAAkB,EAAE,EAAE;IACtB,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ;CAC3D,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAuB;IACvD,OAAO,EAAE,IAAI;IACb,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAuB;IACvD,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAA8C;IAChF,gBAAgB,EAAE,CAAC,EAAE,iCAAiC;IACtD,gBAAgB,EAAE,IAAI,EAAE,gDAAgD;IACxE,eAAe,EAAE,KAAK,EAAE,4EAA4E;IACpG,aAAa,EAAE,KAAK,EAAE,oEAAoE;IAE1F,OAAO,EAAE,QAAQ;IACjB,QAAQ,EAAE;QACR,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,EAAE;KACT;IACD,cAAc,EAAE;QACd,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,GAAG;KACjB;IACD,gBAAgB,EAAE;QAChB,eAAe,EAAE,OAAO;QACxB,aAAa,EAAE,CAAC,EAAE,gEAAgE;KACnF;IACD,SAAS,EAAE,MAAM;CAClB,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,4BAA4B,CAC1C,gBAAyC,EAAE;IAE3C,OAAO,gBAAgB,CACrB,uBAAkD,EAClD,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare function buildInstructionReloadNotice(binaryName: string, instanc
|
|
|
11
11
|
export declare const DEFAULT_STUCK_TIMEOUT_MS: number;
|
|
12
12
|
export declare const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2000;
|
|
13
13
|
export declare const DEFAULT_STATE_SAFETY_SWEEP_MS = 60000;
|
|
14
|
+
/** Coalesce one cosmetic-redraw burst before comparing the visible pane. */
|
|
15
|
+
export declare const PERIODIC_REDRAW_PROBE_MS = 25;
|
|
14
16
|
/** A foreground server/port-forward should hand control back or be acknowledged. */
|
|
15
17
|
export declare const DEFAULT_BLOCKING_PROCESS_GRACE_MS: number;
|
|
16
18
|
/**
|
|
@@ -348,6 +350,7 @@ export declare class Daemon extends EventEmitter {
|
|
|
348
350
|
/** Fallback safety sweep used only when no shared tmux control client exists. */
|
|
349
351
|
private instanceStateMonitorTimer;
|
|
350
352
|
private instanceStateIdleTimer;
|
|
353
|
+
private instanceStateOutputProbeTimer;
|
|
351
354
|
private instanceStateStuckTimer;
|
|
352
355
|
private instanceStateOutputListener;
|
|
353
356
|
private instanceStateOutputEventName;
|
|
@@ -374,6 +377,20 @@ export declare class Daemon extends EventEmitter {
|
|
|
374
377
|
* would silently no-op exactly when we most need to stop feeding the CLI.
|
|
375
378
|
*/
|
|
376
379
|
private pausePending;
|
|
380
|
+
/**
|
|
381
|
+
* An auth failure was detected and nothing has resolved it yet.
|
|
382
|
+
*
|
|
383
|
+
* Separate from `pausePending` because it must outlive it: the deferred pause
|
|
384
|
+
* clears `pausePending` as soon as it fires, but if that pause is refused the
|
|
385
|
+
* instance is still auth-broken and must not resume raising alarms.
|
|
386
|
+
*/
|
|
387
|
+
private authFailureUnresolved;
|
|
388
|
+
/**
|
|
389
|
+
* Let the next pause() proceed from a stuck pane. Set only for the auth-deferred
|
|
390
|
+
* pause — see the pausePending consumption site for why waiting for idle there
|
|
391
|
+
* is waiting forever.
|
|
392
|
+
*/
|
|
393
|
+
private pauseAllowStuck;
|
|
377
394
|
private pauseWakeState;
|
|
378
395
|
private pauseWakeTransition;
|
|
379
396
|
private modelOverride;
|
|
@@ -592,6 +609,13 @@ export declare class Daemon extends EventEmitter {
|
|
|
592
609
|
/** Relay the pane's final text to the channel, marked as a daemon proxy reply. */
|
|
593
610
|
private sendProxyReply;
|
|
594
611
|
private clearInstanceStateIdleTimer;
|
|
612
|
+
private clearInstanceStateOutputProbeTimer;
|
|
613
|
+
/**
|
|
614
|
+
* Periodic status-line hooks can generate `%output` without changing a single
|
|
615
|
+
* visible cell. Probe the pane once per burst: a changed capture is real work;
|
|
616
|
+
* an identical ready capture remains idle and emits no state edge.
|
|
617
|
+
*/
|
|
618
|
+
private scheduleInstanceStateOutputProbe;
|
|
595
619
|
private clearInstanceStateStuckTimer;
|
|
596
620
|
private scheduleInstanceStateStuckDeadline;
|
|
597
621
|
private scheduleInstanceStateIdleCapture;
|
|
@@ -717,6 +741,15 @@ export declare class Daemon extends EventEmitter {
|
|
|
717
741
|
* serial in both cases so separate PTY writes can never overlap.
|
|
718
742
|
*/
|
|
719
743
|
private deliverMessage;
|
|
744
|
+
/**
|
|
745
|
+
* A raw `%output` silence check is authoritative for ordinary TUIs. It is not
|
|
746
|
+
* for a backend such as agy whose status-line hook periodically redraws an
|
|
747
|
+
* identical screen. In that case trust an idle pane-state snapshot only when
|
|
748
|
+
* it was captured after both the latest output and the latest control-client
|
|
749
|
+
* observation reset.
|
|
750
|
+
*/
|
|
751
|
+
private isPaneIdleForDelivery;
|
|
752
|
+
private waitForPaneIdleForDelivery;
|
|
720
753
|
/**
|
|
721
754
|
* The write half of a delivery: paste → Enter → confirm, with retries.
|
|
722
755
|
*
|
package/dist/daemon.js
CHANGED
|
@@ -47,6 +47,8 @@ export function buildInstructionReloadNotice(binaryName, instanceName, instanceD
|
|
|
47
47
|
export const DEFAULT_STUCK_TIMEOUT_MS = 10 * 60_000;
|
|
48
48
|
export const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2_000;
|
|
49
49
|
export const DEFAULT_STATE_SAFETY_SWEEP_MS = 60_000;
|
|
50
|
+
/** Coalesce one cosmetic-redraw burst before comparing the visible pane. */
|
|
51
|
+
export const PERIODIC_REDRAW_PROBE_MS = 25;
|
|
50
52
|
/** A foreground server/port-forward should hand control back or be acknowledged. */
|
|
51
53
|
export const DEFAULT_BLOCKING_PROCESS_GRACE_MS = 2 * 60_000;
|
|
52
54
|
const LAST_INBOUND_FILE = "last-inbound-at";
|
|
@@ -732,6 +734,7 @@ export class Daemon extends EventEmitter {
|
|
|
732
734
|
/** Fallback safety sweep used only when no shared tmux control client exists. */
|
|
733
735
|
instanceStateMonitorTimer = null;
|
|
734
736
|
instanceStateIdleTimer = null;
|
|
737
|
+
instanceStateOutputProbeTimer = null;
|
|
735
738
|
instanceStateStuckTimer = null;
|
|
736
739
|
instanceStateOutputListener = null;
|
|
737
740
|
instanceStateOutputEventName = null;
|
|
@@ -762,6 +765,20 @@ export class Daemon extends EventEmitter {
|
|
|
762
765
|
* would silently no-op exactly when we most need to stop feeding the CLI.
|
|
763
766
|
*/
|
|
764
767
|
pausePending = false;
|
|
768
|
+
/**
|
|
769
|
+
* An auth failure was detected and nothing has resolved it yet.
|
|
770
|
+
*
|
|
771
|
+
* Separate from `pausePending` because it must outlive it: the deferred pause
|
|
772
|
+
* clears `pausePending` as soon as it fires, but if that pause is refused the
|
|
773
|
+
* instance is still auth-broken and must not resume raising alarms.
|
|
774
|
+
*/
|
|
775
|
+
authFailureUnresolved = false;
|
|
776
|
+
/**
|
|
777
|
+
* Let the next pause() proceed from a stuck pane. Set only for the auth-deferred
|
|
778
|
+
* pause — see the pausePending consumption site for why waiting for idle there
|
|
779
|
+
* is waiting forever.
|
|
780
|
+
*/
|
|
781
|
+
pauseAllowStuck = false;
|
|
765
782
|
pauseWakeState = "active";
|
|
766
783
|
pauseWakeTransition = null;
|
|
767
784
|
// Model failover: override model on next spawn when rate-limited
|
|
@@ -1770,6 +1787,7 @@ export class Daemon extends EventEmitter {
|
|
|
1770
1787
|
if (seen > 0)
|
|
1771
1788
|
this.lastErrorCount.set(Daemon.errorPatternKey(ep), seen);
|
|
1772
1789
|
}
|
|
1790
|
+
this.authFailureUnresolved = false;
|
|
1773
1791
|
this.clearErrorRecoveryGate();
|
|
1774
1792
|
this.logger.info({ downtime_s: downtime }, "PTY error recovered — agent is ready again");
|
|
1775
1793
|
this.emit("pty_recovered", { name: this.name, downtime_s: downtime });
|
|
@@ -1831,6 +1849,11 @@ export class Daemon extends EventEmitter {
|
|
|
1831
1849
|
if (ep.action === "failover")
|
|
1832
1850
|
this.lastFailoverAt = now;
|
|
1833
1851
|
const message = this.resolveErrorMessage(pane, ep);
|
|
1852
|
+
// Remember an auth failure for as long as it is unresolved. An auth-broken
|
|
1853
|
+
// CLI cannot finish the turn it is holding, so every other detector in this
|
|
1854
|
+
// scan would otherwise keep reporting the same dead instance forever.
|
|
1855
|
+
if (ep.type === "auth_error")
|
|
1856
|
+
this.authFailureUnresolved = true;
|
|
1834
1857
|
this.logger.warn({ errorType: ep.type, action: ep.action }, `PTY error detected: ${message}`);
|
|
1835
1858
|
this.emit("pty_error", { name: this.name, ...ep, message });
|
|
1836
1859
|
break; // Only handle first unsuppressed new error per scan
|
|
@@ -2061,7 +2084,14 @@ export class Daemon extends EventEmitter {
|
|
|
2061
2084
|
if (this.getPauseWakeState() !== "active")
|
|
2062
2085
|
return;
|
|
2063
2086
|
}
|
|
2064
|
-
|
|
2087
|
+
// `pauseAllowStuck` is consumed here, not merely read: it authorises exactly
|
|
2088
|
+
// one pause from a stuck pane (the auth-deferred one) and must never leak
|
|
2089
|
+
// into an ordinary idle-timeout pause of a busy instance.
|
|
2090
|
+
const allowStuck = this.pauseAllowStuck;
|
|
2091
|
+
this.pauseAllowStuck = false;
|
|
2092
|
+
const pausableState = this.instanceState === "idle"
|
|
2093
|
+
|| (allowStuck && this.instanceState === "stuck");
|
|
2094
|
+
if (!pausableState || this.pasteQueueDepth > 0) {
|
|
2065
2095
|
this.pauseRequested = false;
|
|
2066
2096
|
return;
|
|
2067
2097
|
}
|
|
@@ -2125,6 +2155,7 @@ export class Daemon extends EventEmitter {
|
|
|
2125
2155
|
// An explicit wake (e.g. after the user re-logs in) cancels a deferred
|
|
2126
2156
|
// auth pause — otherwise the instance would pause again the moment it idles.
|
|
2127
2157
|
this.pausePending = false;
|
|
2158
|
+
this.authFailureUnresolved = false;
|
|
2128
2159
|
if (this.pauseWakeState === "active")
|
|
2129
2160
|
return;
|
|
2130
2161
|
if (this.pauseWakeState === "pausing")
|
|
@@ -2221,8 +2252,13 @@ export class Daemon extends EventEmitter {
|
|
|
2221
2252
|
if (snapshot.state !== "idle")
|
|
2222
2253
|
this.pauseRequested = false;
|
|
2223
2254
|
// A pause deferred by an auth failure: retry the moment the pane settles.
|
|
2224
|
-
|
|
2255
|
+
// "stuck" counts as settled here, and that is the whole point — an expired
|
|
2256
|
+
// session cannot complete the turn it is holding, so the pane never returns
|
|
2257
|
+
// to idle and waiting for idle meant waiting forever. The instance stayed
|
|
2258
|
+
// live, kept its warm slot, and re-raised a hang alert on every scan.
|
|
2259
|
+
if (this.pausePending && (snapshot.state === "idle" || snapshot.state === "stuck") && this.pasteQueueDepth === 0) {
|
|
2225
2260
|
this.pausePending = false;
|
|
2261
|
+
this.pauseAllowStuck = snapshot.state === "stuck";
|
|
2226
2262
|
this.emit("auto_pause_requested", { name: this.name, idleSince: snapshot.stateChangedAt });
|
|
2227
2263
|
return;
|
|
2228
2264
|
}
|
|
@@ -2349,6 +2385,25 @@ export class Daemon extends EventEmitter {
|
|
|
2349
2385
|
clearTimeout(this.instanceStateIdleTimer);
|
|
2350
2386
|
this.instanceStateIdleTimer = null;
|
|
2351
2387
|
}
|
|
2388
|
+
clearInstanceStateOutputProbeTimer() {
|
|
2389
|
+
if (this.instanceStateOutputProbeTimer)
|
|
2390
|
+
clearTimeout(this.instanceStateOutputProbeTimer);
|
|
2391
|
+
this.instanceStateOutputProbeTimer = null;
|
|
2392
|
+
}
|
|
2393
|
+
/**
|
|
2394
|
+
* Periodic status-line hooks can generate `%output` without changing a single
|
|
2395
|
+
* visible cell. Probe the pane once per burst: a changed capture is real work;
|
|
2396
|
+
* an identical ready capture remains idle and emits no state edge.
|
|
2397
|
+
*/
|
|
2398
|
+
scheduleInstanceStateOutputProbe() {
|
|
2399
|
+
if (this.instanceStateOutputProbeTimer)
|
|
2400
|
+
return;
|
|
2401
|
+
this.instanceStateOutputProbeTimer = setTimeout(() => {
|
|
2402
|
+
this.instanceStateOutputProbeTimer = null;
|
|
2403
|
+
void this.captureAndEvaluateInstanceState("output_probe", this.instanceStateLastOutputAt);
|
|
2404
|
+
}, PERIODIC_REDRAW_PROBE_MS);
|
|
2405
|
+
this.instanceStateOutputProbeTimer.unref?.();
|
|
2406
|
+
}
|
|
2352
2407
|
clearInstanceStateStuckTimer() {
|
|
2353
2408
|
if (this.instanceStateStuckTimer)
|
|
2354
2409
|
clearTimeout(this.instanceStateStuckTimer);
|
|
@@ -2393,6 +2448,8 @@ export class Daemon extends EventEmitter {
|
|
|
2393
2448
|
if (this.statePollInFlight) {
|
|
2394
2449
|
if (reason === "idle_debounce")
|
|
2395
2450
|
this.scheduleInstanceStateIdleCapture();
|
|
2451
|
+
if (reason === "output_probe")
|
|
2452
|
+
this.scheduleInstanceStateOutputProbe();
|
|
2396
2453
|
return;
|
|
2397
2454
|
}
|
|
2398
2455
|
this.statePollInFlight = true;
|
|
@@ -2401,9 +2458,19 @@ export class Daemon extends EventEmitter {
|
|
|
2401
2458
|
const pane = await this.tmux.capturePane();
|
|
2402
2459
|
// Output received while capture-pane was in flight makes this snapshot
|
|
2403
2460
|
// stale. Its output handler has already armed a new debounce.
|
|
2404
|
-
|
|
2405
|
-
|| (this.instanceStateLastOutputAt > 0 && this.instanceStateLastOutputAt >= captureStartedAt)
|
|
2461
|
+
const outputMovedDuringCapture = (expectedOutputAt > 0 && this.instanceStateLastOutputAt > expectedOutputAt)
|
|
2462
|
+
|| (this.instanceStateLastOutputAt > 0 && this.instanceStateLastOutputAt >= captureStartedAt);
|
|
2463
|
+
if (outputMovedDuringCapture) {
|
|
2464
|
+
if (reason === "output_probe") {
|
|
2465
|
+
// A second burst overtook the probe. Do not bless its stale capture as
|
|
2466
|
+
// idle: continuous output is the safer working signal, while the next
|
|
2467
|
+
// quiet probe/debounce can still prove that it was only repainting.
|
|
2468
|
+
this.applyInstanceStateSnapshot(this.instanceStateMachine.recordOutput(this.instanceStateLastOutputAt));
|
|
2469
|
+
this.scheduleInstanceStateIdleCapture();
|
|
2470
|
+
this.scheduleInstanceStateStuckDeadline(this.instanceStateLastOutputAt);
|
|
2471
|
+
}
|
|
2406
2472
|
return;
|
|
2473
|
+
}
|
|
2407
2474
|
const observedChangeAt = expectedOutputAt || captureStartedAt;
|
|
2408
2475
|
// One observation per capture. This used to call observe() twice with the
|
|
2409
2476
|
// same pane: the second call always saw an unchanged pane, so the
|
|
@@ -2455,6 +2522,14 @@ export class Daemon extends EventEmitter {
|
|
|
2455
2522
|
if (!windowId || event.windowId !== windowId || !this.instanceStateMachine)
|
|
2456
2523
|
return;
|
|
2457
2524
|
this.instanceStateLastOutputAt = event.at;
|
|
2525
|
+
if (this.backend?.hasPeriodicPaneRedraw?.() === true && this.instanceState === "idle") {
|
|
2526
|
+
// Do not emit idle→working solely because agy repainted an identical
|
|
2527
|
+
// footer. The short capture probe below still observes genuine pane
|
|
2528
|
+
// changes promptly and moves the state to working.
|
|
2529
|
+
this.scheduleInstanceStateOutputProbe();
|
|
2530
|
+
this.scheduleInstanceStateIdleCapture();
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2458
2533
|
const snapshot = this.instanceStateMachine.recordOutput(event.at);
|
|
2459
2534
|
this.applyInstanceStateSnapshot(snapshot);
|
|
2460
2535
|
this.scheduleInstanceStateIdleCapture();
|
|
@@ -2505,6 +2580,7 @@ export class Daemon extends EventEmitter {
|
|
|
2505
2580
|
stopInstanceStateMonitor() {
|
|
2506
2581
|
this.instanceStateMonitorActive = false;
|
|
2507
2582
|
this.clearInstanceStateIdleTimer();
|
|
2583
|
+
this.clearInstanceStateOutputProbeTimer();
|
|
2508
2584
|
this.clearInstanceStateStuckTimer();
|
|
2509
2585
|
if (this.instanceStateMonitorTimer)
|
|
2510
2586
|
clearInterval(this.instanceStateMonitorTimer);
|
|
@@ -2539,6 +2615,15 @@ export class Daemon extends EventEmitter {
|
|
|
2539
2615
|
this.logger.debug(diagnostic, "Suppressing stuck notification without pending work");
|
|
2540
2616
|
return;
|
|
2541
2617
|
}
|
|
2618
|
+
// An auth-broken instance IS stuck, and stays stuck: it cannot finish the
|
|
2619
|
+
// turn it is holding, so pendingWork never clears and this fired on every
|
|
2620
|
+
// scan forever. The notification is also useless — it offers Restart/Wait
|
|
2621
|
+
// and asks General for help, but only the user re-logging in fixes this, and
|
|
2622
|
+
// they have already been told exactly that by the auth alert.
|
|
2623
|
+
if (this.authFailureUnresolved) {
|
|
2624
|
+
this.logger.debug(diagnostic, "Suppressing stuck notification — unresolved auth failure (re-login required)");
|
|
2625
|
+
return;
|
|
2626
|
+
}
|
|
2542
2627
|
this.logger.warn(diagnostic, "Instance pane stuck with pending work");
|
|
2543
2628
|
this.hangDetector?.emit("hang", { unchangedForMs: snapshot.unchangedForMs });
|
|
2544
2629
|
}
|
|
@@ -3023,7 +3108,7 @@ export class Daemon extends EventEmitter {
|
|
|
3023
3108
|
// If the CLI is busy, either hand the complete submission to its native input
|
|
3024
3109
|
// queue or wait for idle. Native queue support is an explicit backend capability:
|
|
3025
3110
|
// normal Enter input has steering/interrupt semantics in several other CLIs.
|
|
3026
|
-
if (windowId && this.controlClient && !this.
|
|
3111
|
+
if (windowId && this.controlClient && !this.isPaneIdleForDelivery(windowId)) {
|
|
3027
3112
|
if (status)
|
|
3028
3113
|
this.emit("message_queued", status);
|
|
3029
3114
|
if (supportsQueuedInput || opts?.steer) {
|
|
@@ -3037,7 +3122,7 @@ export class Daemon extends EventEmitter {
|
|
|
3037
3122
|
}
|
|
3038
3123
|
else {
|
|
3039
3124
|
this.logger.debug("CLI busy — queuing message until idle");
|
|
3040
|
-
const becameIdle = await this.
|
|
3125
|
+
const becameIdle = await this.waitForPaneIdleForDelivery(windowId);
|
|
3041
3126
|
if (cancelled())
|
|
3042
3127
|
return false;
|
|
3043
3128
|
if (!becameIdle) {
|
|
@@ -3061,6 +3146,49 @@ export class Daemon extends EventEmitter {
|
|
|
3061
3146
|
return this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status);
|
|
3062
3147
|
});
|
|
3063
3148
|
}
|
|
3149
|
+
/**
|
|
3150
|
+
* A raw `%output` silence check is authoritative for ordinary TUIs. It is not
|
|
3151
|
+
* for a backend such as agy whose status-line hook periodically redraws an
|
|
3152
|
+
* identical screen. In that case trust an idle pane-state snapshot only when
|
|
3153
|
+
* it was captured after both the latest output and the latest control-client
|
|
3154
|
+
* observation reset.
|
|
3155
|
+
*/
|
|
3156
|
+
isPaneIdleForDelivery(windowId) {
|
|
3157
|
+
if (!this.controlClient)
|
|
3158
|
+
return true;
|
|
3159
|
+
if (this.controlClient.isIdle(windowId))
|
|
3160
|
+
return true;
|
|
3161
|
+
if (this.backend?.hasPeriodicPaneRedraw?.() !== true || this.instanceState !== "idle")
|
|
3162
|
+
return false;
|
|
3163
|
+
const lastOutputAt = this.controlClient.getLastOutputAt(windowId);
|
|
3164
|
+
if (lastOutputAt === undefined || !this.instanceStateMachine)
|
|
3165
|
+
return false;
|
|
3166
|
+
const observedAt = this.instanceStateMachine.snapshot().observedAt;
|
|
3167
|
+
return observedAt >= lastOutputAt
|
|
3168
|
+
&& observedAt >= this.controlClient.getObservationResetAt();
|
|
3169
|
+
}
|
|
3170
|
+
waitForPaneIdleForDelivery(windowId, timeoutMs = 30 * 60_000) {
|
|
3171
|
+
if (!this.controlClient)
|
|
3172
|
+
return Promise.resolve(true);
|
|
3173
|
+
if (this.backend?.hasPeriodicPaneRedraw?.() !== true) {
|
|
3174
|
+
return this.controlClient.waitUntilIdle(windowId, timeoutMs);
|
|
3175
|
+
}
|
|
3176
|
+
if (this.isPaneIdleForDelivery(windowId))
|
|
3177
|
+
return Promise.resolve(true);
|
|
3178
|
+
return new Promise(resolve => {
|
|
3179
|
+
const check = setInterval(() => {
|
|
3180
|
+
if (!this.isPaneIdleForDelivery(windowId))
|
|
3181
|
+
return;
|
|
3182
|
+
clearInterval(check);
|
|
3183
|
+
clearTimeout(timer);
|
|
3184
|
+
resolve(true);
|
|
3185
|
+
}, 50);
|
|
3186
|
+
const timer = setTimeout(() => {
|
|
3187
|
+
clearInterval(check);
|
|
3188
|
+
resolve(false);
|
|
3189
|
+
}, timeoutMs);
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3064
3192
|
/**
|
|
3065
3193
|
* The write half of a delivery: paste → Enter → confirm, with retries.
|
|
3066
3194
|
*
|