@rynx-ai/runtime 0.1.11-beta.30 → 0.1.11-beta.31
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/codex-app-server/forwarder.js +7 -7
- package/dist/host.js +30 -54
- package/dist/runner/child.d.ts +1 -0
- package/dist/runner/child.js +88 -9
- package/package.json +2 -2
|
@@ -52,13 +52,13 @@ function isTurnScopedMethod(method) {
|
|
|
52
52
|
function canRecoverMissedTurnFrom(method) {
|
|
53
53
|
return method === "item/agentMessage/delta" || method === "item/plan/delta";
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
55
|
+
/** Live deltas require the bridge's exact active Codex turn. Assistant/plan
|
|
56
|
+
* deltas may recover a missed `turn/started` when
|
|
57
57
|
* fully scoped; command output never opens or recovers a Turn. */
|
|
58
58
|
function requiresMatchingActiveTurn(method) {
|
|
59
59
|
return canRecoverMissedTurnFrom(method) || method === "item/commandExecution/outputDelta";
|
|
60
60
|
}
|
|
61
|
-
/**
|
|
61
|
+
/** Turn content that remains valid independently of lifecycle status. */
|
|
62
62
|
function isIndependentTurnContent(method) {
|
|
63
63
|
return method === "item/started" ||
|
|
64
64
|
method === "item/reasoning/textDelta" ||
|
|
@@ -412,8 +412,8 @@ export class CodexSessionForwarder {
|
|
|
412
412
|
}
|
|
413
413
|
if (requiresMatchingActiveTurn(method)) {
|
|
414
414
|
if (this.currentTurnIdValue !== null) {
|
|
415
|
-
// An id-less delta is not attributable to the active Turn.
|
|
416
|
-
//
|
|
415
|
+
// An id-less delta is not attributable to the active Turn. Require
|
|
416
|
+
// the exact active Turn id before forwarding it.
|
|
417
417
|
if (carriedTurnId !== this.currentTurnIdValue)
|
|
418
418
|
return;
|
|
419
419
|
}
|
|
@@ -465,8 +465,8 @@ export class CodexSessionForwarder {
|
|
|
465
465
|
if (canonicalEvents.some((event) => event.type !== "reasoning_delta" && event.type !== "reasoning_completed")) {
|
|
466
466
|
this.flushDeferredAssistantMessage();
|
|
467
467
|
}
|
|
468
|
-
//
|
|
469
|
-
//
|
|
468
|
+
// Item/content delivery is independent from turn lifecycle status. A
|
|
469
|
+
// scoped item or reasoning delta that arrives after the terminal
|
|
470
470
|
// edge remains visible, but must not synthesize another running response.
|
|
471
471
|
if (!this.turnOpen &&
|
|
472
472
|
this.currentTurnIdValue === null &&
|
package/dist/host.js
CHANGED
|
@@ -21,7 +21,7 @@ import { buildCodexRemoteArgs } from "./terminal/codex-tui.js";
|
|
|
21
21
|
import { buildClaudeTuiArgs } from "./terminal/claude-tui.js";
|
|
22
22
|
import { providerAdditionalDirs, threadWorkspaceParams, turnWorkspaceParams, } from "./provider-workspace.js";
|
|
23
23
|
import { ensureProjectTrusted } from "./claude/trust.js";
|
|
24
|
-
import { claudeAttachmentToken, claudeInputText,
|
|
24
|
+
import { claudeAttachmentToken, claudeInputText, runtimeUserContent, } from "./input-resources.js";
|
|
25
25
|
import { claudeBridgeDir, prepareClaudeBridgeDir, removeManagedClaudeSettings, writeManagedClaudeSettings, } from "./claude/native-bridge.js";
|
|
26
26
|
import { ClaudeLiveSession, injectViaTerminal, } from "./claude/native-integration.js";
|
|
27
27
|
import { buildClaudeHookSettings } from "./claude/native-hooks.js";
|
|
@@ -873,7 +873,6 @@ export class LocalAgentHost {
|
|
|
873
873
|
markTerminalReady,
|
|
874
874
|
injectLock: Promise.resolve(),
|
|
875
875
|
pendingInjectedInputs: [],
|
|
876
|
-
publishInjectedInput: () => undefined,
|
|
877
876
|
publishTurnAdmission: () => undefined,
|
|
878
877
|
publishTurnAdmissionFailure: () => undefined,
|
|
879
878
|
publishInterrupted: () => undefined,
|
|
@@ -930,14 +929,6 @@ export class LocalAgentHost {
|
|
|
930
929
|
});
|
|
931
930
|
return normalizer;
|
|
932
931
|
};
|
|
933
|
-
live.publishInjectedInput = (turnId, content) => {
|
|
934
|
-
const n = startNormalizer(turnId);
|
|
935
|
-
const pending = live.pendingInjectedInputs.find((entry) => entry.signature === JSON.stringify(content) && entry.responseId === undefined);
|
|
936
|
-
if (pending && currentResponseId)
|
|
937
|
-
pending.responseId = currentResponseId;
|
|
938
|
-
for (const se of n.userInput(content))
|
|
939
|
-
emitCurrent(se);
|
|
940
|
-
};
|
|
941
932
|
live.publishTurnAdmission = () => {
|
|
942
933
|
emitCurrent({
|
|
943
934
|
type: "session.status",
|
|
@@ -970,7 +961,7 @@ export class LocalAgentHost {
|
|
|
970
961
|
contentNormalizers.set(responseId, contentNormalizer);
|
|
971
962
|
}
|
|
972
963
|
for (const event of produce(contentNormalizer)) {
|
|
973
|
-
//
|
|
964
|
+
// Item/transient content is attached to the Turn's response id
|
|
974
965
|
// independently of lifecycle status. Reuse Rynx's canonical item
|
|
975
966
|
// normalization but suppress its synthetic lifecycle edges.
|
|
976
967
|
if (event.type !== "response.created" && event.type !== "session.status") {
|
|
@@ -982,14 +973,16 @@ export class LocalAgentHost {
|
|
|
982
973
|
const normalizedContent = typeof content === "string"
|
|
983
974
|
? [{ type: "input_text", text: content }]
|
|
984
975
|
: content;
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}
|
|
991
|
-
if (pending)
|
|
976
|
+
// The Provider does not echo a caller id and may reformat the text, so the
|
|
977
|
+
// first native user record drains the oldest injected input instead of
|
|
978
|
+
// comparing message text.
|
|
979
|
+
const pending = live.pendingInjectedInputs[0];
|
|
980
|
+
if (pending) {
|
|
992
981
|
pending.observed = true;
|
|
982
|
+
if (pending.state === "accepted") {
|
|
983
|
+
live.pendingInjectedInputs.shift();
|
|
984
|
+
}
|
|
985
|
+
}
|
|
993
986
|
return normalizedContent;
|
|
994
987
|
};
|
|
995
988
|
const rememberSettledInteraction = (interactionId) => {
|
|
@@ -1293,16 +1286,12 @@ export class LocalAgentHost {
|
|
|
1293
1286
|
},
|
|
1294
1287
|
onUserMessage: (content) => {
|
|
1295
1288
|
const normalizedContent = observedUserContent(content);
|
|
1296
|
-
if (!normalizedContent)
|
|
1297
|
-
return;
|
|
1298
1289
|
const n = normalizer ?? startNormalizer();
|
|
1299
1290
|
for (const se of n.userInput(normalizedContent))
|
|
1300
1291
|
emitCurrent(se);
|
|
1301
1292
|
},
|
|
1302
1293
|
onTurnContentUserMessage: (turnId, content) => {
|
|
1303
1294
|
const normalizedContent = observedUserContent(content);
|
|
1304
|
-
if (!normalizedContent)
|
|
1305
|
-
return;
|
|
1306
1295
|
turnContentEvents(turnId, (n) => n.userInput(normalizedContent));
|
|
1307
1296
|
},
|
|
1308
1297
|
onEvent: (event) => {
|
|
@@ -1823,8 +1812,6 @@ export class LocalAgentHost {
|
|
|
1823
1812
|
const text = claudeInputText(runtimeInput);
|
|
1824
1813
|
const content = runtimeUserContent(runtimeInput);
|
|
1825
1814
|
const pendingInput = {
|
|
1826
|
-
content,
|
|
1827
|
-
signature: JSON.stringify(content),
|
|
1828
1815
|
state: "awaiting",
|
|
1829
1816
|
observed: false,
|
|
1830
1817
|
};
|
|
@@ -1855,8 +1842,12 @@ export class LocalAgentHost {
|
|
|
1855
1842
|
if (token)
|
|
1856
1843
|
claude.pendingImageInputs.delete(token);
|
|
1857
1844
|
}
|
|
1858
|
-
else
|
|
1859
|
-
|
|
1845
|
+
else {
|
|
1846
|
+
pendingInput.responseId = result.responseId;
|
|
1847
|
+
if (pendingInput.observed)
|
|
1848
|
+
forgetPendingInput();
|
|
1849
|
+
else
|
|
1850
|
+
pendingInput.state = "accepted";
|
|
1860
1851
|
}
|
|
1861
1852
|
return result;
|
|
1862
1853
|
}
|
|
@@ -1873,17 +1864,7 @@ export class LocalAgentHost {
|
|
|
1873
1864
|
if (!bound || !threadId)
|
|
1874
1865
|
return { outcome: "notReady" };
|
|
1875
1866
|
const nativeInput = buildRuntimeUserInput(runtimeInput);
|
|
1876
|
-
const content = runtimeUserContent(runtimeInput);
|
|
1877
|
-
const providerEcho = codexUserEchoContent(nativeInput);
|
|
1878
|
-
const providerEchoContent = typeof providerEcho === "string"
|
|
1879
|
-
? [{ type: "input_text", text: providerEcho }]
|
|
1880
|
-
: providerEcho;
|
|
1881
1867
|
const pendingInput = {
|
|
1882
|
-
content,
|
|
1883
|
-
signature: JSON.stringify(content),
|
|
1884
|
-
...(providerEchoContent
|
|
1885
|
-
? { providerEchoSignature: JSON.stringify(providerEchoContent) }
|
|
1886
|
-
: {}),
|
|
1887
1868
|
state: "awaiting",
|
|
1888
1869
|
observed: false,
|
|
1889
1870
|
};
|
|
@@ -1921,13 +1902,11 @@ export class LocalAgentHost {
|
|
|
1921
1902
|
expectedTurnId: turnId,
|
|
1922
1903
|
input: nativeInput,
|
|
1923
1904
|
});
|
|
1924
|
-
|
|
1905
|
+
pendingInput.responseId = `resp_codex_${steered.turnId}`;
|
|
1906
|
+
if (pendingInput.observed)
|
|
1925
1907
|
forgetPendingInput();
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
live.publishInjectedInput(steered.turnId, pendingInput.content);
|
|
1929
|
-
pendingInput.state = "optimistic";
|
|
1930
|
-
}
|
|
1908
|
+
else
|
|
1909
|
+
pendingInput.state = "accepted";
|
|
1931
1910
|
live.forwarder.noteTurnAccepted(steered.turnId);
|
|
1932
1911
|
return { outcome: "steered", responseId: `resp_codex_${steered.turnId}` };
|
|
1933
1912
|
}
|
|
@@ -1985,13 +1964,11 @@ export class LocalAgentHost {
|
|
|
1985
1964
|
...turnWorkspaceParams(live.runtime, live.workspace, live.sandbox),
|
|
1986
1965
|
approvalPolicy: live.approvalPolicy,
|
|
1987
1966
|
});
|
|
1988
|
-
|
|
1967
|
+
pendingInput.responseId = `resp_codex_${started.turnId}`;
|
|
1968
|
+
if (pendingInput.observed)
|
|
1989
1969
|
forgetPendingInput();
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
live.publishInjectedInput(started.turnId, pendingInput.content);
|
|
1993
|
-
pendingInput.state = "optimistic";
|
|
1994
|
-
}
|
|
1970
|
+
else
|
|
1971
|
+
pendingInput.state = "accepted";
|
|
1995
1972
|
// The injection RPC and active-turn write are one serialized operation.
|
|
1996
1973
|
// Do not wait for the independent observer connection's `turn/started`:
|
|
1997
1974
|
// a second message accepted in that window must steer, not double-start.
|
|
@@ -2515,14 +2492,13 @@ export class LocalAgentHost {
|
|
|
2515
2492
|
if (token && content)
|
|
2516
2493
|
live.pendingImageInputs.delete(token);
|
|
2517
2494
|
const normalizedContent = content ?? [{ type: "input_text", text }];
|
|
2518
|
-
const
|
|
2519
|
-
const pending = live.pendingInjectedInputs.find((entry) => entry.signature === signature);
|
|
2495
|
+
const pending = live.pendingInjectedInputs[0];
|
|
2520
2496
|
if (pending) {
|
|
2521
2497
|
pending.responseId = currentResponseId;
|
|
2522
|
-
live.pendingInjectedInputs.splice(live.pendingInjectedInputs.indexOf(pending), 1);
|
|
2523
|
-
if (pending.state === "optimistic")
|
|
2524
|
-
return;
|
|
2525
2498
|
pending.observed = true;
|
|
2499
|
+
if (pending.state === "accepted") {
|
|
2500
|
+
live.pendingInjectedInputs.shift();
|
|
2501
|
+
}
|
|
2526
2502
|
}
|
|
2527
2503
|
for (const se of n.userInput(normalizedContent))
|
|
2528
2504
|
emitCurrent(se);
|
|
@@ -2574,7 +2550,7 @@ export class LocalAgentHost {
|
|
|
2574
2550
|
const message = error.message || "Agent turn failed";
|
|
2575
2551
|
if (!normalizer) {
|
|
2576
2552
|
// Native pane/forwarder death is Session-level even when Claude is
|
|
2577
|
-
// between Turns.
|
|
2553
|
+
// between Turns. Emit a bare failed edge; the
|
|
2578
2554
|
// explicit zero also retires any sticky background-shell tally.
|
|
2579
2555
|
emitCurrent({
|
|
2580
2556
|
type: "session.status",
|
package/dist/runner/child.d.ts
CHANGED
|
@@ -80,6 +80,7 @@ export declare class RunnerSession {
|
|
|
80
80
|
private readonly attachments;
|
|
81
81
|
private readonly attachmentThreadIds;
|
|
82
82
|
private readonly traexStartupWatchers;
|
|
83
|
+
private readonly traexStartupGates;
|
|
83
84
|
private readonly terminalWatchers;
|
|
84
85
|
/** Opens are async; a close received before attach resolves tombstones the id. */
|
|
85
86
|
private readonly pendingTerminalOpens;
|
package/dist/runner/child.js
CHANGED
|
@@ -45,10 +45,13 @@ function terminalFailureDetail(pane) {
|
|
|
45
45
|
.slice(-1_000);
|
|
46
46
|
}
|
|
47
47
|
const TRAEX_STARTUP_WATCH_MS = 20_000;
|
|
48
|
+
const TRAEX_STARTUP_DISCOVERY_MS = 5_000;
|
|
48
49
|
const TRAEX_STARTUP_POLL_MS = 100;
|
|
49
50
|
const TRAEX_AUTHORIZATION_POLL_MS = 500;
|
|
50
51
|
const TRAEX_AUTHORIZATION_WAIT_MS = 15 * 60_000;
|
|
51
|
-
const
|
|
52
|
+
const TRAEX_ESCAPE_CONFIRM_MS = 1_000;
|
|
53
|
+
const TRAEX_ESCAPE_COOLDOWN_MS = 1_000;
|
|
54
|
+
const TRAEX_REPEAT_PROMPT_CONFIRM_MS = 5_000;
|
|
52
55
|
const MIRROR_IMAGE_ACK_TIMEOUT_MS = 30_000;
|
|
53
56
|
function normalizeTraexPane(pane) {
|
|
54
57
|
return pane.toLowerCase().replace(/\s+/g, " ").trim();
|
|
@@ -58,6 +61,9 @@ function isTraexAuthorizationPending(pane) {
|
|
|
58
61
|
pane.includes("open this link in your browser") &&
|
|
59
62
|
pane.includes("press esc to cancel");
|
|
60
63
|
}
|
|
64
|
+
function isTraexStartupActivity(pane) {
|
|
65
|
+
return pane.includes("updating traecode cli") || pane.includes("updating trae cli");
|
|
66
|
+
}
|
|
61
67
|
function isTerminalProtocolResponse(input) {
|
|
62
68
|
// xterm answers terminal queries through the same onData channel as real
|
|
63
69
|
// keystrokes. CSI carries device/focus/position reports; OSC carries color
|
|
@@ -116,6 +122,7 @@ export class RunnerSession {
|
|
|
116
122
|
attachments = new Map();
|
|
117
123
|
attachmentThreadIds = new Map();
|
|
118
124
|
traexStartupWatchers = new Map();
|
|
125
|
+
traexStartupGates = new Map();
|
|
119
126
|
terminalWatchers = new Map();
|
|
120
127
|
/** Opens are async; a close received before attach resolves tombstones the id. */
|
|
121
128
|
pendingTerminalOpens = new Set();
|
|
@@ -437,6 +444,13 @@ export class RunnerSession {
|
|
|
437
444
|
else if (msg.waitForReady !== false && provider.waitLiveReady) {
|
|
438
445
|
ready = await provider.waitLiveReady(msg.localThreadId);
|
|
439
446
|
}
|
|
447
|
+
// Message delivery is serialized behind Traex's startup modal handling.
|
|
448
|
+
// Otherwise app-server can accept a Turn while the TUI watcher is still
|
|
449
|
+
// sending Escape, and the same key becomes `turn/interrupt` as soon as
|
|
450
|
+
// the modal disappears. Setup-terminal opens remain non-blocking.
|
|
451
|
+
if (runtime === "traex" && msg.waitForReady !== false) {
|
|
452
|
+
await this.traexStartupGates.get(msg.localThreadId);
|
|
453
|
+
}
|
|
440
454
|
const readinessError = ready
|
|
441
455
|
? undefined
|
|
442
456
|
: providerFailure(provider, msg.localThreadId, {
|
|
@@ -619,7 +633,13 @@ export class RunnerSession {
|
|
|
619
633
|
if (spec.skipTraexStartupPrompts) {
|
|
620
634
|
const watcher = Symbol(localThreadId);
|
|
621
635
|
this.traexStartupWatchers.set(localThreadId, watcher);
|
|
622
|
-
|
|
636
|
+
const gate = this.skipTraexStartupPrompts(localThreadId, term, watcher);
|
|
637
|
+
this.traexStartupGates.set(localThreadId, gate);
|
|
638
|
+
void gate.finally(() => {
|
|
639
|
+
if (this.traexStartupGates.get(localThreadId) === gate) {
|
|
640
|
+
this.traexStartupGates.delete(localThreadId);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
623
643
|
}
|
|
624
644
|
this.liveProvider.attachTerminalInjector?.(localThreadId, term);
|
|
625
645
|
this.watchNativeTerminal(localThreadId, terminalId, term);
|
|
@@ -694,6 +714,7 @@ export class RunnerSession {
|
|
|
694
714
|
id: "welcome",
|
|
695
715
|
matches: (pane) => pane.includes("welcome to trae cli") && pane.includes("press enter to continue"),
|
|
696
716
|
dismiss: () => terminal.sendEnter(),
|
|
717
|
+
requiresEscapeConfirmation: false,
|
|
697
718
|
},
|
|
698
719
|
{
|
|
699
720
|
id: "migration",
|
|
@@ -702,6 +723,7 @@ export class RunnerSession {
|
|
|
702
723
|
pane.includes("select what to import") &&
|
|
703
724
|
(pane.includes("skip for now") || pane.includes("don't ask again")),
|
|
704
725
|
dismiss: () => terminal.interrupt(),
|
|
726
|
+
requiresEscapeConfirmation: true,
|
|
705
727
|
},
|
|
706
728
|
{
|
|
707
729
|
id: "hooks",
|
|
@@ -709,12 +731,16 @@ export class RunnerSession {
|
|
|
709
731
|
pane.includes("trust all and continue") &&
|
|
710
732
|
pane.includes("continue without trusting"),
|
|
711
733
|
dismiss: () => terminal.interrupt(),
|
|
734
|
+
requiresEscapeConfirmation: true,
|
|
712
735
|
},
|
|
713
736
|
];
|
|
714
|
-
let
|
|
715
|
-
let
|
|
737
|
+
let activeWelcome = false;
|
|
738
|
+
let pendingEscapePromptId;
|
|
739
|
+
const dismissedPromptIds = new Set();
|
|
740
|
+
let dismissedAnyPrompt = false;
|
|
716
741
|
const startedAt = Date.now();
|
|
717
742
|
let deadline = startedAt + TRAEX_STARTUP_WATCH_MS;
|
|
743
|
+
let discoveryDeadline = startedAt + TRAEX_STARTUP_DISCOVERY_MS;
|
|
718
744
|
const authorizationDeadline = startedAt + TRAEX_AUTHORIZATION_WAIT_MS;
|
|
719
745
|
const terminalId = `${localThreadId}-main`;
|
|
720
746
|
while (!this.shuttingDown &&
|
|
@@ -727,6 +753,9 @@ export class RunnerSession {
|
|
|
727
753
|
const prompt = prompts.find((candidate) => candidate.matches(pane));
|
|
728
754
|
const now = Date.now();
|
|
729
755
|
const authorizationPending = isTraexAuthorizationPending(pane);
|
|
756
|
+
if (isTraexStartupActivity(pane)) {
|
|
757
|
+
discoveryDeadline = now + TRAEX_STARTUP_DISCOVERY_MS;
|
|
758
|
+
}
|
|
730
759
|
// Human device authorization routinely takes longer than the normal
|
|
731
760
|
// startup-modal window. Keep watching while that known screen remains,
|
|
732
761
|
// then preserve a full window for welcome/migration/hooks after sign-in.
|
|
@@ -735,13 +764,63 @@ export class RunnerSession {
|
|
|
735
764
|
deadline = now + TRAEX_STARTUP_WATCH_MS;
|
|
736
765
|
}
|
|
737
766
|
if (!prompt) {
|
|
738
|
-
|
|
767
|
+
activeWelcome = false;
|
|
768
|
+
pendingEscapePromptId = undefined;
|
|
769
|
+
// Every dismissal is followed by a one-second cooldown before the next
|
|
770
|
+
// capture. If no known modal remains then, startup prompt handling is
|
|
771
|
+
// complete and message injection may safely begin.
|
|
772
|
+
if (dismissedAnyPrompt)
|
|
773
|
+
break;
|
|
774
|
+
// A clean Traex home may have no startup modal at all. Preserve a
|
|
775
|
+
// five-second discovery window for late modals, but do not impose the
|
|
776
|
+
// old full 20-second watcher lifetime on every cold message. A visible
|
|
777
|
+
// updater keeps the full startup window because prompts may follow it.
|
|
778
|
+
if (now >= discoveryDeadline &&
|
|
779
|
+
!authorizationPending &&
|
|
780
|
+
!isTraexStartupActivity(pane))
|
|
781
|
+
break;
|
|
739
782
|
}
|
|
740
|
-
else if (prompt.
|
|
741
|
-
|
|
783
|
+
else if (!prompt.requiresEscapeConfirmation) {
|
|
784
|
+
pendingEscapePromptId = undefined;
|
|
785
|
+
if (!activeWelcome && !dismissedPromptIds.has(prompt.id)) {
|
|
786
|
+
prompt.dismiss();
|
|
787
|
+
dismissedPromptIds.add(prompt.id);
|
|
788
|
+
dismissedAnyPrompt = true;
|
|
789
|
+
await new Promise((resolve) => {
|
|
790
|
+
const timer = setTimeout(resolve, TRAEX_ESCAPE_COOLDOWN_MS);
|
|
791
|
+
timer.unref();
|
|
792
|
+
});
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
activeWelcome = true;
|
|
796
|
+
}
|
|
797
|
+
else if (prompt.id !== pendingEscapePromptId) {
|
|
798
|
+
activeWelcome = false;
|
|
799
|
+
pendingEscapePromptId = prompt.id;
|
|
800
|
+
await new Promise((resolve) => {
|
|
801
|
+
// Traex can show hooks -> migration -> hooks during one startup. The
|
|
802
|
+
// trailing hooks screen normally disappears on its own, so observe a
|
|
803
|
+
// previously handled prompt type for five seconds before acting.
|
|
804
|
+
const timer = setTimeout(resolve, dismissedPromptIds.has(prompt.id)
|
|
805
|
+
? TRAEX_REPEAT_PROMPT_CONFIRM_MS
|
|
806
|
+
: TRAEX_ESCAPE_CONFIRM_MS);
|
|
807
|
+
timer.unref();
|
|
808
|
+
});
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
742
812
|
prompt.dismiss();
|
|
743
|
-
|
|
744
|
-
|
|
813
|
+
dismissedPromptIds.add(prompt.id);
|
|
814
|
+
dismissedAnyPrompt = true;
|
|
815
|
+
// Keep the id through the cooldown. If the same prompt is genuinely
|
|
816
|
+
// still active after a sent key, the next check retries it; a prompt
|
|
817
|
+
// that disappeared during the cooldown never receives another key.
|
|
818
|
+
pendingEscapePromptId = prompt.id;
|
|
819
|
+
await new Promise((resolve) => {
|
|
820
|
+
const timer = setTimeout(resolve, TRAEX_ESCAPE_COOLDOWN_MS);
|
|
821
|
+
timer.unref();
|
|
822
|
+
});
|
|
823
|
+
continue;
|
|
745
824
|
}
|
|
746
825
|
await new Promise((resolve) => {
|
|
747
826
|
const timer = setTimeout(resolve, authorizationPending ? TRAEX_AUTHORIZATION_POLL_MS : TRAEX_STARTUP_POLL_MS);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/runtime",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.31",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"node-pty": "1.2.0-beta.15",
|
|
28
28
|
"smol-toml": "1.7.1",
|
|
29
29
|
"ws": "^8.21.0",
|
|
30
|
-
"@rynx-ai/core": "0.1.11-beta.
|
|
30
|
+
"@rynx-ai/core": "0.1.11-beta.31"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/ws": "^8.18.1"
|