@songsid/agend 2.1.4-beta.14 → 2.1.4-beta.15
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/kiro.js +7 -5
- package/dist/backend/kiro.js.map +1 -1
- package/dist/daemon.d.ts +8 -0
- package/dist/daemon.js +28 -10
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +13 -2
- package/dist/fleet-manager.js +65 -6
- package/dist/fleet-manager.js.map +1 -1
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -289,6 +289,13 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
289
289
|
*/
|
|
290
290
|
private enforceWarmCap;
|
|
291
291
|
private waitForInstanceIdle;
|
|
292
|
+
/**
|
|
293
|
+
* Ask the daemon to capture the pane before answering, then wait for any state
|
|
294
|
+
* report produced after this request. The ordinary query is intentionally
|
|
295
|
+
* cache-only (idle gates call it frequently); this opt-in refresh is reserved
|
|
296
|
+
* for lifecycle decisions where a stale state would strand UI.
|
|
297
|
+
*/
|
|
298
|
+
private refreshInstanceExecutionState;
|
|
292
299
|
private deliverWithIdleGate;
|
|
293
300
|
/**
|
|
294
301
|
* Hand a payload to an instance's IPC, waiting out a *transient* disconnect.
|
|
@@ -712,10 +719,14 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
712
719
|
private startProgressTicker;
|
|
713
720
|
/**
|
|
714
721
|
* After a reply: give the instance REPLY_RETIRE_GRACE_MS to resume working; if
|
|
715
|
-
* it has not, retire its button.
|
|
716
|
-
*
|
|
722
|
+
* it has not, retire its button. The daemon is asked for a fresh pane capture
|
|
723
|
+
* before deciding. Reading only the transition cache stranded the first
|
|
724
|
+
* post-restart bubble when its startup "working" report never got a matching
|
|
725
|
+
* idle edge. Re-arming replaces the previous timer, so a burst of replies ends
|
|
726
|
+
* with exactly one pending check.
|
|
717
727
|
*/
|
|
718
728
|
private armReplyGrace;
|
|
729
|
+
private finishReplyGrace;
|
|
719
730
|
/** Retire (delete) every cancel button belonging to an instance. */
|
|
720
731
|
private retireInstanceButtons;
|
|
721
732
|
/** Begin retiring one button (delete + bounded retry on failure). Idempotent:
|
package/dist/fleet-manager.js
CHANGED
|
@@ -107,6 +107,8 @@ const CANCEL_BTN_IDLE_RETIRE_GRACE_MS = 2_000;
|
|
|
107
107
|
* button alone (the idle edge retires it when the run really ends).
|
|
108
108
|
*/
|
|
109
109
|
const REPLY_RETIRE_GRACE_MS = 2 * 60_000;
|
|
110
|
+
/** Bound for the daemon to capture the pane and answer a post-reply state query. */
|
|
111
|
+
const REPLY_STATE_REFRESH_TIMEOUT_MS = 2_000;
|
|
110
112
|
/**
|
|
111
113
|
* The daemon only broadcasts execution state on TRANSITIONS, so a long
|
|
112
114
|
* single-state run sends nothing for hours. The idle backstop therefore pokes a
|
|
@@ -899,6 +901,48 @@ export class FleetManager {
|
|
|
899
901
|
query();
|
|
900
902
|
});
|
|
901
903
|
}
|
|
904
|
+
/**
|
|
905
|
+
* Ask the daemon to capture the pane before answering, then wait for any state
|
|
906
|
+
* report produced after this request. The ordinary query is intentionally
|
|
907
|
+
* cache-only (idle gates call it frequently); this opt-in refresh is reserved
|
|
908
|
+
* for lifecycle decisions where a stale state would strand UI.
|
|
909
|
+
*/
|
|
910
|
+
refreshInstanceExecutionState(instanceName, timeoutMs) {
|
|
911
|
+
const ipc = this.instanceIpcClients.get(instanceName);
|
|
912
|
+
if (!ipc?.connected)
|
|
913
|
+
return Promise.resolve(false);
|
|
914
|
+
const previous = this.instanceStateCache.get(instanceName);
|
|
915
|
+
return new Promise(resolve => {
|
|
916
|
+
let settled = false;
|
|
917
|
+
const finish = (refreshed) => {
|
|
918
|
+
if (settled)
|
|
919
|
+
return;
|
|
920
|
+
settled = true;
|
|
921
|
+
clearTimeout(timeout);
|
|
922
|
+
const waiters = this.instanceIdleWaiters.get(instanceName);
|
|
923
|
+
waiters?.delete(check);
|
|
924
|
+
if (waiters?.size === 0)
|
|
925
|
+
this.instanceIdleWaiters.delete(instanceName);
|
|
926
|
+
resolve(refreshed);
|
|
927
|
+
};
|
|
928
|
+
const check = () => {
|
|
929
|
+
if (this.instanceStateCache.get(instanceName) !== previous)
|
|
930
|
+
finish(true);
|
|
931
|
+
};
|
|
932
|
+
const waiters = this.instanceIdleWaiters.get(instanceName) ?? new Set();
|
|
933
|
+
waiters.add(check);
|
|
934
|
+
this.instanceIdleWaiters.set(instanceName, waiters);
|
|
935
|
+
const timeout = setTimeout(() => finish(false), timeoutMs);
|
|
936
|
+
timeout.unref?.();
|
|
937
|
+
const sent = ipc.send({
|
|
938
|
+
type: "query_instance_state",
|
|
939
|
+
requestId: `reply-grace-${Date.now()}`,
|
|
940
|
+
refresh: true,
|
|
941
|
+
});
|
|
942
|
+
if (!sent)
|
|
943
|
+
finish(false);
|
|
944
|
+
});
|
|
945
|
+
}
|
|
902
946
|
async deliverWithIdleGate(instanceName, payload, timeoutMs) {
|
|
903
947
|
let idleObservedAfter = this.lastDeliveryAt.get(instanceName) ?? 0;
|
|
904
948
|
if (this.lifecycle.isPaused(instanceName)) {
|
|
@@ -5424,8 +5468,11 @@ export class FleetManager {
|
|
|
5424
5468
|
}
|
|
5425
5469
|
/**
|
|
5426
5470
|
* After a reply: give the instance REPLY_RETIRE_GRACE_MS to resume working; if
|
|
5427
|
-
* it has not, retire its button.
|
|
5428
|
-
*
|
|
5471
|
+
* it has not, retire its button. The daemon is asked for a fresh pane capture
|
|
5472
|
+
* before deciding. Reading only the transition cache stranded the first
|
|
5473
|
+
* post-restart bubble when its startup "working" report never got a matching
|
|
5474
|
+
* idle edge. Re-arming replaces the previous timer, so a burst of replies ends
|
|
5475
|
+
* with exactly one pending check.
|
|
5429
5476
|
*/
|
|
5430
5477
|
armReplyGrace(instanceName) {
|
|
5431
5478
|
for (const entry of this.cancelButtons.values()) {
|
|
@@ -5437,14 +5484,26 @@ export class FleetManager {
|
|
|
5437
5484
|
entry.replyGraceTimer = undefined;
|
|
5438
5485
|
if (!this.cancelButtons.has(entry.messageId))
|
|
5439
5486
|
return;
|
|
5440
|
-
|
|
5441
|
-
return; // resumed — a long run keeps its button
|
|
5442
|
-
this.logger.info({ instanceName, messageId: entry.messageId }, "Cancel button retired — no work resumed after reply");
|
|
5443
|
-
this.retireButton(entry);
|
|
5487
|
+
void this.finishReplyGrace(instanceName, entry);
|
|
5444
5488
|
}, REPLY_RETIRE_GRACE_MS);
|
|
5445
5489
|
entry.replyGraceTimer.unref?.();
|
|
5446
5490
|
}
|
|
5447
5491
|
}
|
|
5492
|
+
async finishReplyGrace(instanceName, entry) {
|
|
5493
|
+
const refreshed = await this.refreshInstanceExecutionState(instanceName, REPLY_STATE_REFRESH_TIMEOUT_MS);
|
|
5494
|
+
if (!this.cancelButtons.has(entry.messageId) || entry.retiring)
|
|
5495
|
+
return;
|
|
5496
|
+
if (!refreshed) {
|
|
5497
|
+
// Fail safe: without an authoritative answer, retain a potentially live
|
|
5498
|
+
// Cancel button. The 5-minute/30-minute/24-hour safety nets still apply.
|
|
5499
|
+
this.logger.debug({ instanceName, messageId: entry.messageId }, "Cancel reply-grace state refresh timed out");
|
|
5500
|
+
return;
|
|
5501
|
+
}
|
|
5502
|
+
if (!this.getInstanceIdle(instanceName))
|
|
5503
|
+
return; // genuine long run keeps its button
|
|
5504
|
+
this.logger.info({ instanceName, messageId: entry.messageId }, "Cancel button retired — no work resumed after reply");
|
|
5505
|
+
this.retireButton(entry);
|
|
5506
|
+
}
|
|
5448
5507
|
/** Retire (delete) every cancel button belonging to an instance. */
|
|
5449
5508
|
retireInstanceButtons(instanceName) {
|
|
5450
5509
|
// Snapshot first — retireButton may delete entries from the map on success.
|