@songsid/agend 2.1.7 → 2.1.8-beta.1
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/codex.d.ts +4 -0
- package/dist/backend/codex.js +76 -24
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +8 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/daemon.d.ts +21 -0
- package/dist/daemon.js +64 -3
- package/dist/daemon.js.map +1 -1
- package/dist/ui/settings.html +120 -38
- package/package.json +1 -1
package/dist/daemon.js
CHANGED
|
@@ -979,6 +979,25 @@ export class Daemon extends EventEmitter {
|
|
|
979
979
|
* after the startup scan can still swallow that message's Enter.
|
|
980
980
|
*/
|
|
981
981
|
inputTransientGuardGeneration = null;
|
|
982
|
+
/**
|
|
983
|
+
* The spawn whose passive transients are over, independently of the
|
|
984
|
+
* startup-proof tail above. A transient screen can be quoted verbatim by the
|
|
985
|
+
* transcript (a cropped quote of the resume screen is byte-identical to the
|
|
986
|
+
* real one), so the pane alone must not be able to hold input. AgEnD's own
|
|
987
|
+
* launch state retires the check, per launch attempt: a launch that cannot show one, the real
|
|
988
|
+
* transient seen and then gone, or a "transient" that never changed for
|
|
989
|
+
* INPUT_TRANSIENT_STALL_MS. (The first submitted message retires the whole
|
|
990
|
+
* guard, as before.)
|
|
991
|
+
*/
|
|
992
|
+
inputTransientRetiredAttempt = null;
|
|
993
|
+
/** The launch attempt in which a passive transient was actually observed on screen. */
|
|
994
|
+
inputTransientSeenAttempt = null;
|
|
995
|
+
/**
|
|
996
|
+
* One per command actually launched. A spawn can launch more than once
|
|
997
|
+
* (spawnClaudeWindow retries a failed resume without a new beginSpawn), and
|
|
998
|
+
* each launch paints its own transient, so retirement is per attempt.
|
|
999
|
+
*/
|
|
1000
|
+
launchAttempt = 0;
|
|
982
1001
|
skipResume = false;
|
|
983
1002
|
startupAborted = false;
|
|
984
1003
|
/** First time the current on-screen blocking dialog was seen (0 = none); drives the parked report. */
|
|
@@ -4945,19 +4964,39 @@ export class Daemon extends EventEmitter {
|
|
|
4945
4964
|
if (this.inputTransientGuardGeneration === null
|
|
4946
4965
|
|| this.inputTransientGuardGeneration !== this.spawnGeneration)
|
|
4947
4966
|
return [];
|
|
4967
|
+
if (this.inputTransientRetiredAttempt === this.launchAttempt)
|
|
4968
|
+
return [];
|
|
4948
4969
|
return this.backend?.getInputUnavailableTransients?.() ?? [];
|
|
4949
4970
|
}
|
|
4971
|
+
/** Stop honouring passive transients for the current spawn. */
|
|
4972
|
+
retireInputTransients(reason) {
|
|
4973
|
+
if (this.inputTransientRetiredAttempt === this.launchAttempt)
|
|
4974
|
+
return;
|
|
4975
|
+
this.inputTransientRetiredAttempt = this.launchAttempt;
|
|
4976
|
+
this.logger.debug({ reason, generation: this.spawnGeneration, attempt: this.launchAttempt }, "Startup input transient retired for this launch");
|
|
4977
|
+
}
|
|
4950
4978
|
/** Match a passive transient against the current interactive screen. */
|
|
4951
4979
|
inputTransientInPane(pane) {
|
|
4952
|
-
|
|
4980
|
+
const transients = this.guardedInputTransients();
|
|
4981
|
+
if (transients.length === 0)
|
|
4982
|
+
return null;
|
|
4983
|
+
for (const transient of transients) {
|
|
4953
4984
|
// `pattern` is only a cheap pre-filter. `isActive` is deliberately the
|
|
4954
4985
|
// authority because users and agents routinely quote diagnostic text.
|
|
4955
4986
|
transient.pattern.lastIndex = 0;
|
|
4956
4987
|
if (!transient.pattern.test(pane))
|
|
4957
4988
|
continue;
|
|
4958
|
-
if (transient.isActive(pane))
|
|
4989
|
+
if (transient.isActive(pane)) {
|
|
4990
|
+
this.inputTransientSeenAttempt = this.launchAttempt;
|
|
4959
4991
|
return transient;
|
|
4992
|
+
}
|
|
4960
4993
|
}
|
|
4994
|
+
// The phase is over once it has been seen to end; from then on the same
|
|
4995
|
+
// screen is a quote. A settled-looking pane before that proves nothing:
|
|
4996
|
+
// codex 0.154 painted the prompt and footer first and "Resuming session…"
|
|
4997
|
+
// a moment later — the reason this guard outlives the startup scan.
|
|
4998
|
+
if (this.inputTransientSeenAttempt === this.launchAttempt)
|
|
4999
|
+
this.retireInputTransients("transient ended");
|
|
4961
5000
|
return null;
|
|
4962
5001
|
}
|
|
4963
5002
|
/** Capture failure is unknown, never evidence that input is available. */
|
|
@@ -4993,7 +5032,12 @@ export class Daemon extends EventEmitter {
|
|
|
4993
5032
|
return budget;
|
|
4994
5033
|
}
|
|
4995
5034
|
async probeInputTransient() {
|
|
4996
|
-
|
|
5035
|
+
// A retired transient still leaves the startup guard armed: an unreadable
|
|
5036
|
+
// pane keeps answering "unknown", so it stalls out on the same budget
|
|
5037
|
+
// instead of letting a delivery poll a dark pane for ever.
|
|
5038
|
+
const armed = this.inputTransientGuardGeneration !== null && this.inputTransientGuardGeneration === this.spawnGeneration
|
|
5039
|
+
&& (this.backend?.getInputUnavailableTransients?.().length ?? 0) > 0;
|
|
5040
|
+
if (!armed || !this.tmux)
|
|
4997
5041
|
return { state: "clear" };
|
|
4998
5042
|
try {
|
|
4999
5043
|
const pane = await this.tmux.capturePane();
|
|
@@ -5059,6 +5103,11 @@ export class Daemon extends EventEmitter {
|
|
|
5059
5103
|
stalledForMs: budget.stalled ? INPUT_TRANSIENT_STALL_MS : undefined,
|
|
5060
5104
|
ceilingMs: timeoutMs,
|
|
5061
5105
|
}, "CLI input stayed unavailable — refusing to send Enter");
|
|
5106
|
+
// A screen that did not change for the whole stall window is not a
|
|
5107
|
+
// load in progress. This delivery still fails, but the same screen
|
|
5108
|
+
// (possibly a quote) must not fail every later one too.
|
|
5109
|
+
if (budget.stalled && observedDescription !== null)
|
|
5110
|
+
this.retireInputTransients("transient stalled");
|
|
5062
5111
|
return false;
|
|
5063
5112
|
}
|
|
5064
5113
|
await new Promise(r => setTimeout(r, INPUT_TRANSIENT_POLL_MS));
|
|
@@ -5306,6 +5355,11 @@ export class Daemon extends EventEmitter {
|
|
|
5306
5355
|
stalledForMs: transientBudget.stalled ? INPUT_TRANSIENT_STALL_MS : undefined,
|
|
5307
5356
|
ceilingMs: INPUT_TRANSIENT_WAIT_MS,
|
|
5308
5357
|
}, "CLI input stayed unavailable during the delivery-readiness wait");
|
|
5358
|
+
// Same rule as the pre-Enter wait: a screen frozen for the whole
|
|
5359
|
+
// stall window is not a load in progress, so it holds this delivery
|
|
5360
|
+
// only.
|
|
5361
|
+
if (transientBudget.stalled)
|
|
5362
|
+
this.retireInputTransients("transient stalled");
|
|
5309
5363
|
return false;
|
|
5310
5364
|
}
|
|
5311
5365
|
await new Promise(r => setTimeout(r, BOTTOM_READY_POLL_MS));
|
|
@@ -7570,6 +7624,13 @@ export class Daemon extends EventEmitter {
|
|
|
7570
7624
|
}
|
|
7571
7625
|
}
|
|
7572
7626
|
const cmd = `${envPrefix} ` + this.backend.buildCommand(launchConfig);
|
|
7627
|
+
// Every launched command re-arms the passive-transient check, including a
|
|
7628
|
+
// retry inside the same spawn: its load is a new one.
|
|
7629
|
+
this.launchAttempt++;
|
|
7630
|
+
// A launch that cannot paint a passive transient (Codex: a fresh start
|
|
7631
|
+
// never shows "Resuming session…") must not honour one quoted on screen.
|
|
7632
|
+
if (this.backend.launchMayShowInputTransient?.() === false)
|
|
7633
|
+
this.retireInputTransients("launch shows none");
|
|
7573
7634
|
// e.g. Codex could not read its session DB and chose a fallback (#984):
|
|
7574
7635
|
// the operator should know which conversation this launch continues.
|
|
7575
7636
|
const launchWarning = this.backend.consumeLaunchWarning?.() ?? null;
|