@songsid/agend 2.3.3-beta.8 → 2.3.3
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/claude-code.js +17 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +15 -0
- package/dist/backend/codex.js +67 -18
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +60 -17
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/daemon.d.ts +17 -0
- package/dist/daemon.js +85 -9
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +31 -0
- package/dist/fleet-manager.js +106 -12
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +13 -0
- package/dist/instance-lifecycle.js +30 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +10 -2
- package/dist/locale.js.map +1 -1
- package/dist/parked-notices.d.ts +87 -0
- package/dist/parked-notices.js +194 -0
- package/dist/parked-notices.js.map +1 -0
- package/dist/public-link-progress.d.ts +5 -2
- package/dist/public-link-progress.js +4 -3
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-web-link.d.ts +10 -0
- package/dist/public-web-link.js +24 -5
- package/dist/public-web-link.js.map +1 -1
- package/dist/settings-api.d.ts +10 -0
- package/dist/settings-api.js +41 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +5 -0
- package/dist/tunnel/cloudflared.js +32 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +2 -1
- package/dist/tunnel/named-diagnostics.js +4 -1
- package/dist/tunnel/named-diagnostics.js.map +1 -1
- package/dist/tunnel/named-link-test.d.ts +90 -0
- package/dist/tunnel/named-link-test.js +270 -0
- package/dist/tunnel/named-link-test.js.map +1 -0
- package/dist/tunnel/purpose-lane.d.ts +3 -1
- package/dist/tunnel/purpose-lane.js +2 -0
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/ui/panel-settings.js +5 -3
- package/dist/ui/settings-named-test.js +144 -0
- package/dist/ui/settings-strings.js +6 -6
- package/dist/ui/shared/app.css +7 -0
- package/dist/ui/shared/web-authorize.js +2 -2
- package/package.json +1 -1
package/dist/daemon.js
CHANGED
|
@@ -1264,8 +1264,19 @@ export class Daemon extends EventEmitter {
|
|
|
1264
1264
|
dialogParkedSince = 0;
|
|
1265
1265
|
/** Identity of that dialog: its pattern, not its description (two tables may describe one screen differently). */
|
|
1266
1266
|
dialogParkedKey = null;
|
|
1267
|
+
/**
|
|
1268
|
+
* #2893: the held dialog whose heldReason was last logged. Its own state, not the parked clock's: the delivery probe
|
|
1269
|
+
* starts that clock too, and must not use up the one log line. Cleared with the hold, so a later hold logs again.
|
|
1270
|
+
*/
|
|
1271
|
+
heldReasonLoggedKey = null;
|
|
1267
1272
|
dialogParkedInteractionEpisode = null;
|
|
1268
1273
|
dialogParkedReported = false;
|
|
1274
|
+
/**
|
|
1275
|
+
* #2897: a "needs a human" notice is out for a dialog, and what it lives with: "parked" — the parked clock (retired when
|
|
1276
|
+
* that dialog leaves the pane or another replaces it); "answer" — an answer episode of a dialog the parked clock does
|
|
1277
|
+
* not track (a non-blocking one, whose scans pass no blocking dialog): retired when that episode ends.
|
|
1278
|
+
*/
|
|
1279
|
+
parkedNoticeOut = null;
|
|
1269
1280
|
/** #2675: the card on screen that a person can answer from the chat — what it asks, since when, and whether it was posted. */
|
|
1270
1281
|
remoteCardShown = null;
|
|
1271
1282
|
/** #2675: when (performance.now, taken before its capture) the newest read the card tracker used was started. */
|
|
@@ -3724,8 +3735,18 @@ export class Daemon extends EventEmitter {
|
|
|
3724
3735
|
this.noteLiveIncidentDialog(dialog, pane);
|
|
3725
3736
|
if (dialog.blocksDelivery || dialog.holdOnly)
|
|
3726
3737
|
blockingSeen = dialog;
|
|
3727
|
-
if (dialog.holdOnly)
|
|
3728
|
-
|
|
3738
|
+
if (dialog.holdOnly) {
|
|
3739
|
+
// Recognised, deliberately not answered; trackDialogParked reports it. Why an automatic answer passed it by
|
|
3740
|
+
// is logged once, when this hold begins (#2893).
|
|
3741
|
+
if (this.heldReasonLoggedKey !== Daemon.dialogKey(dialog)) {
|
|
3742
|
+
const reason = Daemon.heldReasonOf(dialog, pane);
|
|
3743
|
+
if (Object.keys(reason).length) {
|
|
3744
|
+
this.heldReasonLoggedKey = Daemon.dialogKey(dialog);
|
|
3745
|
+
this.logger.warn({ description: dialog.description, ...reason }, "Runtime dialog held — not auto-answering");
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
break;
|
|
3749
|
+
}
|
|
3729
3750
|
// Reported as ignoring the daemon: the SAME request (the identity the count was made on — verbatim, the
|
|
3730
3751
|
// backend's own when it names one) is answered only once per DIALOG_ANSWER_BACKOFF_MS. Anything else — another
|
|
3731
3752
|
// request, an unexplained difference, the dialog gone — is not held back here; the answer path below ends or
|
|
@@ -3788,7 +3809,7 @@ export class Daemon extends EventEmitter {
|
|
|
3788
3809
|
return;
|
|
3789
3810
|
if (dialog.verifyAfterKeys && autoKey)
|
|
3790
3811
|
this.claimAutoDialog(dialog);
|
|
3791
|
-
this.logger.info(`Auto-dismissing runtime dialog: ${dialog.description}`);
|
|
3812
|
+
this.logger.info(Daemon.answerDetailOf(dialog, currentPane), `Auto-dismissing runtime dialog: ${dialog.description}`);
|
|
3792
3813
|
const SPECIAL_KEYS = new Set(["Up", "Down", "Enter", "Escape", "Right", "Left"]);
|
|
3793
3814
|
for (const key of dialog.keys) {
|
|
3794
3815
|
if (stale())
|
|
@@ -3879,8 +3900,10 @@ export class Daemon extends EventEmitter {
|
|
|
3879
3900
|
// Reached only when no dialog was answered this poll (none on screen, a fenced one, or one waiting out its
|
|
3880
3901
|
// backoff): unless it is the one backing off, the screen that was being answered is gone, and the next dialog is
|
|
3881
3902
|
// a new one.
|
|
3882
|
-
if (!answersBackedOff)
|
|
3903
|
+
if (!answersBackedOff && this.dialogAnswers) {
|
|
3883
3904
|
this.dialogAnswers = null;
|
|
3905
|
+
this.retireParkedNotice("answer");
|
|
3906
|
+
}
|
|
3884
3907
|
this.trackDialogParked(blockingSeen);
|
|
3885
3908
|
this.trackRemoteCard(blockingSeen, pane, captureMono);
|
|
3886
3909
|
if (blockingSeen)
|
|
@@ -8435,6 +8458,7 @@ export class Daemon extends EventEmitter {
|
|
|
8435
8458
|
*/
|
|
8436
8459
|
endDialogEpisode(clearParked = true) {
|
|
8437
8460
|
this.dialogAnswers = null;
|
|
8461
|
+
this.retireParkedNotice("answer");
|
|
8438
8462
|
if (clearParked)
|
|
8439
8463
|
this.trackDialogParked(null);
|
|
8440
8464
|
}
|
|
@@ -8461,8 +8485,11 @@ export class Daemon extends EventEmitter {
|
|
|
8461
8485
|
*/
|
|
8462
8486
|
noteDialogAnswer(dialog, outcome, screen) {
|
|
8463
8487
|
const key = Daemon.answerKey(dialog);
|
|
8464
|
-
if (!this.dialogAnswers || this.dialogAnswers.key !== key)
|
|
8465
|
-
this.dialogAnswers
|
|
8488
|
+
if (!this.dialogAnswers || this.dialogAnswers.key !== key) {
|
|
8489
|
+
if (this.dialogAnswers)
|
|
8490
|
+
this.retireParkedNotice("answer"); // #2897: a different screen: the reported one is over
|
|
8491
|
+
this.dialogAnswers = { key, ignored: 0, reported: false, screen, lastAnswerAt: 0 };
|
|
8492
|
+
} // the exact screen being counted: every answer in the episode saw this same one
|
|
8466
8493
|
const episode = this.dialogAnswers;
|
|
8467
8494
|
if (outcome !== "ignored") {
|
|
8468
8495
|
this.endDialogEpisode(outcome === "took");
|
|
@@ -8478,6 +8505,8 @@ export class Daemon extends EventEmitter {
|
|
|
8478
8505
|
this.dialogParkedReported = true;
|
|
8479
8506
|
const holdsDeliveries = dialog.blocksDelivery === true || dialog.holdOnly === true;
|
|
8480
8507
|
this.logger.warn({ dialog: dialog.description, attempts: episode.ignored, holdsDeliveries }, "Runtime dialog is ignoring AgEnD's answer — reporting for a human");
|
|
8508
|
+
// #2897: a dialog the parked clock tracks keeps its notice until it leaves the pane; any other, until this episode ends.
|
|
8509
|
+
this.parkedNoticeOut = this.dialogParkedSince !== 0 && this.dialogParkedKey === Daemon.dialogKey(dialog) ? "parked" : "answer";
|
|
8481
8510
|
this.emit("dialog_answer_ignored", { name: this.name, description: dialog.description, attempts: episode.ignored, holdsDeliveries });
|
|
8482
8511
|
}
|
|
8483
8512
|
/**
|
|
@@ -8551,6 +8580,24 @@ export class Daemon extends EventEmitter {
|
|
|
8551
8580
|
this.remoteCardAnswering = false;
|
|
8552
8581
|
}
|
|
8553
8582
|
}
|
|
8583
|
+
/** #2893: a held dialog's own account of why no automatic answer took it (RuntimeDialog.heldReason); {} when none. */
|
|
8584
|
+
static heldReasonOf(dialog, pane) {
|
|
8585
|
+
try {
|
|
8586
|
+
return dialog.heldReason?.(pane) ?? {};
|
|
8587
|
+
}
|
|
8588
|
+
catch {
|
|
8589
|
+
return {};
|
|
8590
|
+
}
|
|
8591
|
+
}
|
|
8592
|
+
/** What an answered dialog says about the answer (RuntimeDialog.answerDetail); {} when it gives none. */
|
|
8593
|
+
static answerDetailOf(dialog, pane) {
|
|
8594
|
+
try {
|
|
8595
|
+
return dialog.answerDetail?.(pane) ?? {};
|
|
8596
|
+
}
|
|
8597
|
+
catch {
|
|
8598
|
+
return {};
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8554
8601
|
/**
|
|
8555
8602
|
* Remember how long a blocking dialog has been on screen. Once it has
|
|
8556
8603
|
* outlived DIALOG_PARKED_NOTIFY_MS — the auto-dismiss did not take, or the
|
|
@@ -8559,14 +8606,24 @@ export class Daemon extends EventEmitter {
|
|
|
8559
8606
|
* is safe. Identity is the pattern, so the delivery gate and the runtime
|
|
8560
8607
|
* scanner (same canonical list) never reset each other's clock.
|
|
8561
8608
|
*/
|
|
8609
|
+
/** #2897: the notice out for a dialog is out of date (its `owner` ended): the fleet takes it back. */
|
|
8610
|
+
retireParkedNotice(owner) {
|
|
8611
|
+
if (this.parkedNoticeOut !== owner)
|
|
8612
|
+
return;
|
|
8613
|
+
this.parkedNoticeOut = null;
|
|
8614
|
+
this.emit("dialog_unparked", { name: this.name });
|
|
8615
|
+
}
|
|
8562
8616
|
trackDialogParked(dialog) {
|
|
8563
8617
|
if (!dialog) {
|
|
8564
8618
|
if (this.dialogParkedSince !== 0)
|
|
8565
8619
|
this.logger.info({ dialog: this.dialogParkedKey }, "Blocking dialog is gone from the pane");
|
|
8566
8620
|
this.dialogParkedSince = 0;
|
|
8567
8621
|
this.dialogParkedKey = null;
|
|
8622
|
+
this.heldReasonLoggedKey = null;
|
|
8568
8623
|
this.dialogParkedInteractionEpisode = null;
|
|
8569
8624
|
this.dialogParkedReported = false;
|
|
8625
|
+
// #2897: whatever it posted is out of date — the fleet takes its notices back.
|
|
8626
|
+
this.retireParkedNotice("parked");
|
|
8570
8627
|
return;
|
|
8571
8628
|
}
|
|
8572
8629
|
const key = Daemon.dialogKey(dialog);
|
|
@@ -8578,6 +8635,9 @@ export class Daemon extends EventEmitter {
|
|
|
8578
8635
|
if (episode !== null)
|
|
8579
8636
|
this.dialogParkedInteractionEpisode = episode;
|
|
8580
8637
|
if (this.dialogParkedSince === 0 || this.dialogParkedKey !== key) {
|
|
8638
|
+
// #2897: a different dialog replaced the one being tracked — that one's notices are out of date.
|
|
8639
|
+
if (this.dialogParkedSince !== 0)
|
|
8640
|
+
this.retireParkedNotice("parked");
|
|
8581
8641
|
this.dialogParkedSince = Date.now();
|
|
8582
8642
|
this.dialogParkedKey = key;
|
|
8583
8643
|
this.dialogParkedReported = false;
|
|
@@ -8589,6 +8649,7 @@ export class Daemon extends EventEmitter {
|
|
|
8589
8649
|
this.dialogParkedReported = true;
|
|
8590
8650
|
if (!this.dialogParkedReported && Date.now() - this.dialogParkedSince >= (unrecognised ? 0 : DIALOG_PARKED_NOTIFY_MS)) {
|
|
8591
8651
|
this.dialogParkedReported = true;
|
|
8652
|
+
this.parkedNoticeOut = "parked";
|
|
8592
8653
|
this.logger.warn({ dialog: dialog.description, parkedForMs: Date.now() - this.dialogParkedSince }, "CLI dialog is still on screen — not auto-answering, reporting for a human");
|
|
8593
8654
|
this.emit("dialog_parked", { name: this.name, description: dialog.description, holdOnly: dialog.holdOnly === true,
|
|
8594
8655
|
...(dialog.parkedAdvice ? { advice: dialog.parkedAdvice } : {}),
|
|
@@ -11427,6 +11488,13 @@ export class Daemon extends EventEmitter {
|
|
|
11427
11488
|
this.recoveryNativeWork = false;
|
|
11428
11489
|
this.recoveryCancelled = false;
|
|
11429
11490
|
this.dialogAnswers = null;
|
|
11491
|
+
// #2897: a relaunched CLI shows none of the old dialogs — whatever notice was out for one is out of date.
|
|
11492
|
+
// A dialog still tracked when the new CLI shows it again is reported afresh (its old notice is gone).
|
|
11493
|
+
if (this.parkedNoticeOut) {
|
|
11494
|
+
this.parkedNoticeOut = null;
|
|
11495
|
+
this.dialogParkedReported = false;
|
|
11496
|
+
this.emit("dialog_unparked", { name: this.name });
|
|
11497
|
+
}
|
|
11430
11498
|
this.cancelCapacityNudge("the instance was stopped, paused or respawned");
|
|
11431
11499
|
this.lastErrorEpisode = null;
|
|
11432
11500
|
this.nudgeBaselines = null;
|
|
@@ -12809,6 +12877,8 @@ export class Daemon extends EventEmitter {
|
|
|
12809
12877
|
this.noteCodexReserveDialog(dialog, pane);
|
|
12810
12878
|
this.noteLiveIncidentDialog(dialog, pane);
|
|
12811
12879
|
cleanReadyPolls = 0;
|
|
12880
|
+
// Before the parked clock below claims it: a hold seen for the first time is said once, with its reason (#2893).
|
|
12881
|
+
const firstSight = this.dialogParkedKey !== Daemon.dialogKey(dialog);
|
|
12812
12882
|
// Start the parked clock for every delivery-blocking dialog, exact
|
|
12813
12883
|
// ones included: if the auto-dismiss keeps failing here, the human
|
|
12814
12884
|
// report should count from first sight, not from the runtime scan.
|
|
@@ -12837,14 +12907,16 @@ export class Daemon extends EventEmitter {
|
|
|
12837
12907
|
}
|
|
12838
12908
|
if (dialog.holdOnly) {
|
|
12839
12909
|
// Recognised but deliberately not answered (see RuntimeDialog.holdOnly).
|
|
12840
|
-
if (
|
|
12841
|
-
this.
|
|
12910
|
+
if (firstSight) {
|
|
12911
|
+
const reason = this.heldReasonLoggedKey !== Daemon.dialogKey(dialog) ? Daemon.heldReasonOf(dialog, pane) : {};
|
|
12912
|
+
if (Object.keys(reason).length)
|
|
12913
|
+
this.heldReasonLoggedKey = Daemon.dialogKey(dialog);
|
|
12914
|
+
this.logger.warn({ description: dialog.description, ...reason }, "Startup dialog held — not auto-answering, deliveries stay blocked");
|
|
12842
12915
|
}
|
|
12843
12916
|
this.trackDialogParked(dialog);
|
|
12844
12917
|
matched = true;
|
|
12845
12918
|
break;
|
|
12846
12919
|
}
|
|
12847
|
-
this.logger.info(`Dismissing startup dialog: ${dialog.description}`);
|
|
12848
12920
|
// Restart is exactly when inbound messages pile up, and nothing gates
|
|
12849
12921
|
// delivery on `spawning`. Take the pane lock for the key sequence so a
|
|
12850
12922
|
// queued message cannot be pasted into a half-dismissed trust dialog.
|
|
@@ -12857,6 +12929,7 @@ export class Daemon extends EventEmitter {
|
|
|
12857
12929
|
// a pane that is no longer this launch's is not read or keyed.
|
|
12858
12930
|
if (!owned())
|
|
12859
12931
|
return false;
|
|
12932
|
+
let answeredPane = pane;
|
|
12860
12933
|
if (dialog.inputBlocked) {
|
|
12861
12934
|
const currentPane = await this.tmux.capturePane();
|
|
12862
12935
|
this.startupAdmission?.();
|
|
@@ -12865,7 +12938,10 @@ export class Daemon extends EventEmitter {
|
|
|
12865
12938
|
return false;
|
|
12866
12939
|
if (!Daemon.dialogMatches(dialog, currentPane))
|
|
12867
12940
|
return false;
|
|
12941
|
+
answeredPane = currentPane;
|
|
12868
12942
|
}
|
|
12943
|
+
// Said of the screen actually answered — the one re-read under the lock (#2896 review).
|
|
12944
|
+
this.logger.info(Daemon.answerDetailOf(dialog, answeredPane), `Dismissing startup dialog: ${dialog.description}`);
|
|
12869
12945
|
if (dialog.autoResolutionKey) {
|
|
12870
12946
|
attemptedSafetyChoices.add(dialog.autoResolutionKey);
|
|
12871
12947
|
this.claimAutoDialog(dialog);
|