@scotthuang/agent-knock-knock 0.13.3 → 0.13.4
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/CHANGELOG.md +14 -0
- package/README.md +13 -5
- package/dist/src/callback-outbox-policy.js +27 -6
- package/dist/src/callback-outbox-policy.js.map +1 -1
- package/dist/src/callback-outbox-service.d.ts +4 -30
- package/dist/src/callback-outbox-service.js +21 -154
- package/dist/src/callback-outbox-service.js.map +1 -1
- package/dist/src/callback-outbox-settlement.js +13 -8
- package/dist/src/callback-outbox-settlement.js.map +1 -1
- package/dist/src/callback-route-service.d.ts +46 -0
- package/dist/src/callback-route-service.js +155 -0
- package/dist/src/callback-route-service.js.map +1 -0
- package/dist/src/codex-process-incarnation.d.ts +8 -0
- package/dist/src/codex-process-incarnation.js +36 -0
- package/dist/src/codex-process-incarnation.js.map +1 -0
- package/dist/src/deferred-foreground-conflict-policy.d.ts +22 -0
- package/dist/src/deferred-foreground-conflict-policy.js +52 -0
- package/dist/src/deferred-foreground-conflict-policy.js.map +1 -0
- package/dist/src/durable-notification-kernel.d.ts +94 -0
- package/dist/src/durable-notification-kernel.js +68 -0
- package/dist/src/durable-notification-kernel.js.map +1 -0
- package/dist/src/herdr-socket-transport.d.ts +43 -0
- package/dist/src/herdr-socket-transport.js +170 -0
- package/dist/src/herdr-socket-transport.js.map +1 -0
- package/dist/src/herdr-terminal-control-provider.d.ts +2 -45
- package/dist/src/herdr-terminal-control-provider.js +2 -172
- package/dist/src/herdr-terminal-control-provider.js.map +1 -1
- package/dist/src/host-adapter-capabilities.d.ts +35 -0
- package/dist/src/host-adapter-capabilities.js +146 -0
- package/dist/src/host-adapter-capabilities.js.map +1 -0
- package/dist/src/host-adapter.d.ts +9 -3
- package/dist/src/host-adapter.js +33 -9
- package/dist/src/host-adapter.js.map +1 -1
- package/dist/src/host-bridge-tools.d.ts +3 -4
- package/dist/src/host-bridge-tools.js +49 -92
- package/dist/src/host-bridge-tools.js.map +1 -1
- package/dist/src/host-bridge.js +5 -5
- package/dist/src/host-bridge.js.map +1 -1
- package/dist/src/host-monitor-reconciliation.d.ts +6 -0
- package/dist/src/host-monitor-reconciliation.js +96 -0
- package/dist/src/host-monitor-reconciliation.js.map +1 -0
- package/dist/src/native-thread-lifecycle-cli-adapter.js +116 -60
- package/dist/src/native-thread-lifecycle-cli-adapter.js.map +1 -1
- package/dist/src/openclaw-list-projection.d.ts +2 -0
- package/dist/src/openclaw-list-projection.js +3 -0
- package/dist/src/openclaw-list-projection.js.map +1 -0
- package/dist/src/openclaw-model-facing-field-policy.d.ts +2 -0
- package/dist/src/openclaw-model-facing-field-policy.js +3 -0
- package/dist/src/openclaw-model-facing-field-policy.js.map +1 -0
- package/dist/src/openclaw-plugin-command-adapter.d.ts +6 -29
- package/dist/src/openclaw-plugin-command-adapter.js +7 -2660
- package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
- package/dist/src/openclaw-plugin-helpers.d.ts +2 -148
- package/dist/src/openclaw-plugin-helpers.js +2 -1844
- package/dist/src/openclaw-plugin-helpers.js.map +1 -1
- package/dist/src/openclaw-plugin-schemas.d.ts +2 -563
- package/dist/src/openclaw-plugin-schemas.js +2 -572
- package/dist/src/openclaw-plugin-schemas.js.map +1 -1
- package/dist/src/openclaw-plugin-supervisor.d.ts +4 -5
- package/dist/src/openclaw-plugin-supervisor.js +5 -94
- package/dist/src/openclaw-plugin-supervisor.js.map +1 -1
- package/dist/src/openclaw-plugin-value-helpers.d.ts +2 -0
- package/dist/src/openclaw-plugin-value-helpers.js +3 -0
- package/dist/src/openclaw-plugin-value-helpers.js.map +1 -0
- package/dist/src/openclaw-private-authority-offers.d.ts +4 -39
- package/dist/src/openclaw-private-authority-offers.js +3 -258
- package/dist/src/openclaw-private-authority-offers.js.map +1 -1
- package/dist/src/semantic-private-authority-offers.d.ts +41 -0
- package/dist/src/semantic-private-authority-offers.js +261 -0
- package/dist/src/semantic-private-authority-offers.js.map +1 -0
- package/dist/src/semantic-tool-arguments.d.ts +9 -0
- package/dist/src/semantic-tool-arguments.js +64 -0
- package/dist/src/semantic-tool-arguments.js.map +1 -0
- package/dist/src/semantic-tool-catalog.d.ts +48 -0
- package/dist/src/semantic-tool-catalog.js +105 -0
- package/dist/src/semantic-tool-catalog.js.map +1 -0
- package/dist/src/semantic-tool-command-helpers.d.ts +145 -0
- package/dist/src/semantic-tool-command-helpers.js +1272 -0
- package/dist/src/semantic-tool-command-helpers.js.map +1 -0
- package/dist/src/semantic-tool-list-projection.d.ts +10 -0
- package/dist/src/semantic-tool-list-projection.js +497 -0
- package/dist/src/semantic-tool-list-projection.js.map +1 -0
- package/dist/src/semantic-tool-model-facing-field-policy.d.ts +3 -0
- package/dist/src/semantic-tool-model-facing-field-policy.js +66 -0
- package/dist/src/semantic-tool-model-facing-field-policy.js.map +1 -0
- package/dist/src/semantic-tool-presentation.d.ts +37 -0
- package/dist/src/semantic-tool-presentation.js +680 -0
- package/dist/src/semantic-tool-presentation.js.map +1 -0
- package/dist/src/semantic-tool-private-authority.d.ts +39 -0
- package/dist/src/semantic-tool-private-authority.js +602 -0
- package/dist/src/semantic-tool-private-authority.js.map +1 -0
- package/dist/src/semantic-tool-relay.d.ts +16 -0
- package/dist/src/semantic-tool-relay.js +175 -0
- package/dist/src/semantic-tool-relay.js.map +1 -0
- package/dist/src/semantic-tool-runtime.d.ts +10 -0
- package/dist/src/semantic-tool-runtime.js +1157 -0
- package/dist/src/semantic-tool-runtime.js.map +1 -0
- package/dist/src/semantic-tool-schemas.d.ts +563 -0
- package/dist/src/semantic-tool-schemas.js +573 -0
- package/dist/src/semantic-tool-schemas.js.map +1 -0
- package/dist/src/semantic-tool-value-helpers.d.ts +5 -0
- package/dist/src/semantic-tool-value-helpers.js +27 -0
- package/dist/src/semantic-tool-value-helpers.js.map +1 -0
- package/dist/src/store-event-presentation.d.ts +17 -0
- package/dist/src/store-event-presentation.js +33 -0
- package/dist/src/store-event-presentation.js.map +1 -0
- package/dist/src/store.d.ts +3 -16
- package/dist/src/store.js +2 -30
- package/dist/src/store.js.map +1 -1
- package/dist/src/terminal-action-projection.d.ts +2 -98
- package/dist/src/terminal-action-projection.js +13 -215
- package/dist/src/terminal-action-projection.js.map +1 -1
- package/dist/src/terminal-agent-bridge.d.ts +14 -340
- package/dist/src/terminal-agent-bridge.js +155 -3226
- package/dist/src/terminal-agent-bridge.js.map +1 -1
- package/dist/src/terminal-approval-cli-adapter.d.ts +17 -0
- package/dist/src/terminal-approval-cli-adapter.js +921 -0
- package/dist/src/terminal-approval-cli-adapter.js.map +1 -0
- package/dist/src/terminal-command-cli-adapter.d.ts +2 -429
- package/dist/src/terminal-command-cli-adapter.js +344 -6061
- package/dist/src/terminal-command-cli-adapter.js.map +1 -1
- package/dist/src/terminal-command-cli-ports.d.ts +443 -0
- package/dist/src/terminal-command-cli-ports.js +2 -0
- package/dist/src/terminal-command-cli-ports.js.map +1 -0
- package/dist/src/terminal-command-dispatch-preparation.d.ts +81 -0
- package/dist/src/terminal-command-dispatch-preparation.js +209 -0
- package/dist/src/terminal-command-dispatch-preparation.js.map +1 -0
- package/dist/src/terminal-command-dispatch-transport.d.ts +35 -0
- package/dist/src/terminal-command-dispatch-transport.js +859 -0
- package/dist/src/terminal-command-dispatch-transport.js.map +1 -0
- package/dist/src/terminal-command-foreground-proof.d.ts +32 -0
- package/dist/src/terminal-command-foreground-proof.js +72 -0
- package/dist/src/terminal-command-foreground-proof.js.map +1 -0
- package/dist/src/terminal-command-send-preflight.d.ts +41 -0
- package/dist/src/terminal-command-send-preflight.js +86 -0
- package/dist/src/terminal-command-send-preflight.js.map +1 -0
- package/dist/src/terminal-composer-classifier.d.ts +55 -0
- package/dist/src/terminal-composer-classifier.js +638 -0
- package/dist/src/terminal-composer-classifier.js.map +1 -0
- package/dist/src/terminal-dispatch-recovery-authority.d.ts +56 -0
- package/dist/src/terminal-dispatch-recovery-authority.js +251 -0
- package/dist/src/terminal-dispatch-recovery-authority.js.map +1 -0
- package/dist/src/terminal-dispatch-recovery-cli-adapter.d.ts +1 -9
- package/dist/src/terminal-dispatch-recovery-cli-adapter.js +5 -240
- package/dist/src/terminal-dispatch-recovery-cli-adapter.js.map +1 -1
- package/dist/src/terminal-handoff-cli-adapter.d.ts +1 -11
- package/dist/src/terminal-handoff-cli-adapter.js +2 -39
- package/dist/src/terminal-handoff-cli-adapter.js.map +1 -1
- package/dist/src/terminal-human-explicit-send-cli-adapter.d.ts +25 -0
- package/dist/src/terminal-human-explicit-send-cli-adapter.js +903 -0
- package/dist/src/terminal-human-explicit-send-cli-adapter.js.map +1 -0
- package/dist/src/terminal-identity-authority-cli-adapter.d.ts +1 -6
- package/dist/src/terminal-identity-authority-cli-adapter.js +3 -33
- package/dist/src/terminal-identity-authority-cli-adapter.js.map +1 -1
- package/dist/src/terminal-interaction-cli-adapter.js +209 -210
- package/dist/src/terminal-interaction-cli-adapter.js.map +1 -1
- package/dist/src/terminal-interaction-core.d.ts +0 -2
- package/dist/src/terminal-interaction-core.js +4 -3
- package/dist/src/terminal-interaction-core.js.map +1 -1
- package/dist/src/terminal-interaction-protocol.d.ts +21 -0
- package/dist/src/terminal-interaction-protocol.js +74 -0
- package/dist/src/terminal-interaction-protocol.js.map +1 -1
- package/dist/src/terminal-interaction-response-bridge.d.ts +126 -0
- package/dist/src/terminal-interaction-response-bridge.js +579 -0
- package/dist/src/terminal-interaction-response-bridge.js.map +1 -0
- package/dist/src/terminal-interaction-response-transaction.d.ts +44 -0
- package/dist/src/terminal-interaction-response-transaction.js +56 -0
- package/dist/src/terminal-interaction-response-transaction.js.map +1 -0
- package/dist/src/terminal-list-action-policy.d.ts +43 -0
- package/dist/src/terminal-list-action-policy.js +164 -0
- package/dist/src/terminal-list-action-policy.js.map +1 -0
- package/dist/src/terminal-list-cli-adapter.d.ts +6 -36
- package/dist/src/terminal-list-cli-adapter.js +241 -1946
- package/dist/src/terminal-list-cli-adapter.js.map +1 -1
- package/dist/src/terminal-list-facts.d.ts +129 -0
- package/dist/src/terminal-list-facts.js +179 -0
- package/dist/src/terminal-list-facts.js.map +1 -0
- package/dist/src/terminal-list-inventory.d.ts +59 -0
- package/dist/src/terminal-list-inventory.js +194 -0
- package/dist/src/terminal-list-inventory.js.map +1 -0
- package/dist/src/terminal-list-ownership-service.d.ts +118 -0
- package/dist/src/terminal-list-ownership-service.js +1003 -0
- package/dist/src/terminal-list-ownership-service.js.map +1 -0
- package/dist/src/terminal-list-projection-service.d.ts +49 -0
- package/dist/src/terminal-list-projection-service.js +407 -0
- package/dist/src/terminal-list-projection-service.js.map +1 -0
- package/dist/src/terminal-list-renderer.d.ts +11 -11
- package/dist/src/terminal-list-renderer.js +168 -119
- package/dist/src/terminal-list-renderer.js.map +1 -1
- package/dist/src/terminal-managed-send-cli-adapter.d.ts +33 -0
- package/dist/src/terminal-managed-send-cli-adapter.js +994 -0
- package/dist/src/terminal-managed-send-cli-adapter.js.map +1 -0
- package/dist/src/terminal-managed-turn-list-action-policy.d.ts +47 -0
- package/dist/src/terminal-managed-turn-list-action-policy.js +64 -0
- package/dist/src/terminal-managed-turn-list-action-policy.js.map +1 -0
- package/dist/src/terminal-model-control-action-policy.d.ts +60 -0
- package/dist/src/terminal-model-control-action-policy.js +96 -0
- package/dist/src/terminal-model-control-action-policy.js.map +1 -0
- package/dist/src/terminal-model-control-availability.d.ts +68 -0
- package/dist/src/terminal-model-control-availability.js +157 -0
- package/dist/src/terminal-model-control-availability.js.map +1 -0
- package/dist/src/terminal-model-control-bridge.d.ts +48 -0
- package/dist/src/terminal-model-control-bridge.js +259 -0
- package/dist/src/terminal-model-control-bridge.js.map +1 -0
- package/dist/src/terminal-model-control-profile.d.ts +55 -0
- package/dist/src/terminal-model-control-profile.js +137 -0
- package/dist/src/terminal-model-control-profile.js.map +1 -0
- package/dist/src/terminal-model-control-subject.d.ts +34 -0
- package/dist/src/terminal-model-control-subject.js +58 -0
- package/dist/src/terminal-model-control-subject.js.map +1 -0
- package/dist/src/terminal-model-control-transaction.d.ts +19 -0
- package/dist/src/terminal-model-control-transaction.js +39 -0
- package/dist/src/terminal-model-control-transaction.js.map +1 -0
- package/dist/src/terminal-model-control.d.ts +37 -18
- package/dist/src/terminal-model-control.js +285 -194
- package/dist/src/terminal-model-control.js.map +1 -1
- package/dist/src/terminal-monitor-application-service.js +50 -17
- package/dist/src/terminal-monitor-application-service.js.map +1 -1
- package/dist/src/terminal-native-inspection-bridge.d.ts +211 -0
- package/dist/src/terminal-native-inspection-bridge.js +1127 -0
- package/dist/src/terminal-native-inspection-bridge.js.map +1 -0
- package/dist/src/terminal-runtime-cli-adapter.d.ts +2 -2
- package/dist/src/terminal-runtime-cli-adapter.js.map +1 -1
- package/dist/src/terminal-submission-retry-application.d.ts +24 -0
- package/dist/src/terminal-submission-retry-application.js +402 -0
- package/dist/src/terminal-submission-retry-application.js.map +1 -0
- package/dist/src/terminal-submission-retry-ports.d.ts +30 -0
- package/dist/src/terminal-submission-retry-ports.js +2 -0
- package/dist/src/terminal-submission-retry-ports.js.map +1 -0
- package/dist/src/terminal-submission-retry-reconciliation.d.ts +236 -0
- package/dist/src/terminal-submission-retry-reconciliation.js +1130 -0
- package/dist/src/terminal-submission-retry-reconciliation.js.map +1 -0
- package/dist/src/terminal-submission-retry-transport.d.ts +58 -0
- package/dist/src/terminal-submission-retry-transport.js +675 -0
- package/dist/src/terminal-submission-retry-transport.js.map +1 -0
- package/dist/src/terminal-text-submission-bridge.d.ts +200 -0
- package/dist/src/terminal-text-submission-bridge.js +632 -0
- package/dist/src/terminal-text-submission-bridge.js.map +1 -0
- package/dist/src/terminal-user-explicit-send-policy.d.ts +29 -0
- package/dist/src/terminal-user-explicit-send-policy.js +46 -0
- package/dist/src/terminal-user-explicit-send-policy.js.map +1 -0
- package/dist/src/terminal-watch-cli-adapter.js +91 -143
- package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
- package/dist/src/terminal-watch-codec.d.ts +9 -0
- package/dist/src/terminal-watch-codec.js +1051 -0
- package/dist/src/terminal-watch-codec.js.map +1 -0
- package/dist/src/terminal-watch-interaction-response-store.d.ts +19 -0
- package/dist/src/terminal-watch-interaction-response-store.js +87 -0
- package/dist/src/terminal-watch-interaction-response-store.js.map +1 -0
- package/dist/src/terminal-watch-record.d.ts +319 -0
- package/dist/src/terminal-watch-record.js +742 -0
- package/dist/src/terminal-watch-record.js.map +1 -0
- package/dist/src/terminal-watch-service.js +48 -27
- package/dist/src/terminal-watch-service.js.map +1 -1
- package/dist/src/terminal-watch-store.d.ts +3 -279
- package/dist/src/terminal-watch-store.js +5 -1779
- package/dist/src/terminal-watch-store.js.map +1 -1
- package/package.json +7 -2
- package/templates/openclaw-skills/agent-knock-knock/SKILL.md +1 -1
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { claudeInjectedPasteProofEligible, revalidateClaudeComposerProof, settleClaudeInjectedPasteComposer } from "./claude-injected-paste-proof.js";
|
|
3
|
+
import { TerminalControlInputNotSentError } from "./terminal-control-provider.js";
|
|
4
|
+
// Verified Codex profiles through 0.154.0 keep Enter in paste/newline mode for
|
|
5
|
+
// 120ms after burst input. Cross that boundary rather than landing on it, and
|
|
6
|
+
// also require observable composer stability instead of treating this delay
|
|
7
|
+
// alone as acceptance.
|
|
8
|
+
export const CODEX_PASTE_ENTER_SETTLE_MS = 121;
|
|
9
|
+
export const CODEX_MULTILINE_SETTLE_POLL_MS = 30;
|
|
10
|
+
// A capture can itself take longer than the old two-second deadline on a busy
|
|
11
|
+
// tmux server. Give repaint discovery a bounded five-second window and, once
|
|
12
|
+
// an exact frame has been observed, always allow the required stable/final
|
|
13
|
+
// captures to complete instead of letting the first I/O consume their budget.
|
|
14
|
+
const CODEX_MULTILINE_SETTLE_TIMEOUT_MS = 5_000;
|
|
15
|
+
export const CODEX_MULTILINE_STABLE_CAPTURES = 2;
|
|
16
|
+
export const CODEX_EXACT_CANDIDATE_GRACE_CAPTURES = 8;
|
|
17
|
+
export const CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES = 240;
|
|
18
|
+
/** A terminal send failed at a boundary that proves input never started. */
|
|
19
|
+
export class TerminalInputNotStartedError extends Error {
|
|
20
|
+
code = "AKK_TERMINAL_INPUT_NOT_STARTED";
|
|
21
|
+
constructor(message, options = {}) {
|
|
22
|
+
super(message, options);
|
|
23
|
+
this.name = "TerminalInputNotStartedError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Text is already in the terminal composer, but this bridge invocation proved
|
|
28
|
+
* that it never called the Enter transport boundary.
|
|
29
|
+
*
|
|
30
|
+
* Callers may persist this as narrow recovery evidence. It says nothing about
|
|
31
|
+
* whether the draft remains exact or whether a later human action submitted
|
|
32
|
+
* it; those facts must be re-observed under the terminal lock.
|
|
33
|
+
*/
|
|
34
|
+
export class TerminalEnterDispatchNotAttemptedError extends Error {
|
|
35
|
+
code = "AKK_TERMINAL_ENTER_DISPATCH_NOT_ATTEMPTED";
|
|
36
|
+
stage = "enter_not_attempted";
|
|
37
|
+
constructor(message, options = {}) {
|
|
38
|
+
super(message, options);
|
|
39
|
+
this.name = "TerminalEnterDispatchNotAttemptedError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The caller's one-shot Enter reservation was invoked, so this recovery
|
|
44
|
+
* attempt is permanently consumed even though C-m was not proven dispatched.
|
|
45
|
+
*/
|
|
46
|
+
export class TerminalEnterDispatchReservedError extends Error {
|
|
47
|
+
code = "AKK_TERMINAL_ENTER_DISPATCH_RESERVED";
|
|
48
|
+
stage = "enter_reserved";
|
|
49
|
+
doNotRetry = true;
|
|
50
|
+
constructor(message, options = {}) {
|
|
51
|
+
super(message, options);
|
|
52
|
+
this.name = "TerminalEnterDispatchReservedError";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function terminalSendComposerRequirements(agent, multiline, options) {
|
|
56
|
+
const exactEmptyRetryAuthority = options.requireExactEmptyComposerAfterBeforeText;
|
|
57
|
+
const requireExactEmptyComposerBeforeText = options.requireExactEmptyComposerBeforeText === true;
|
|
58
|
+
const userExplicitEnterAfterTextWithoutComposerVeto = options.userExplicitEnterAfterTextWithoutComposerVeto === true;
|
|
59
|
+
if (userExplicitEnterAfterTextWithoutComposerVeto &&
|
|
60
|
+
(agent !== "codex" || !requireExactEmptyComposerBeforeText)) {
|
|
61
|
+
throw new TerminalInputNotStartedError("composer-veto-free Enter requires Codex and an exact-empty pre-text user-explicit boundary");
|
|
62
|
+
}
|
|
63
|
+
const requireExactComposer = !userExplicitEnterAfterTextWithoutComposerVeto &&
|
|
64
|
+
((agent === "codex" && multiline) ||
|
|
65
|
+
options.requireExactComposerBeforeEnter === true ||
|
|
66
|
+
requireExactEmptyComposerBeforeText ||
|
|
67
|
+
exactEmptyRetryAuthority !== undefined);
|
|
68
|
+
if (exactEmptyRetryAuthority !== undefined &&
|
|
69
|
+
(agent !== "codex" ||
|
|
70
|
+
options.beforeText === undefined ||
|
|
71
|
+
!/^[0-9a-f]{64}$/u.test(exactEmptyRetryAuthority.preliminaryComposerDigest))) {
|
|
72
|
+
throw new TerminalInputNotStartedError("exact-empty replacement requires Codex, a reservation hook, and a preliminary composer digest");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
exactEmptyRetryAuthority,
|
|
76
|
+
requireExactEmptyComposerBeforeText,
|
|
77
|
+
requireExactComposer
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function recordTerminalSendStage(options, event, preserveUserInput, previousError) {
|
|
81
|
+
try {
|
|
82
|
+
await options.onTransportStage?.(event);
|
|
83
|
+
return previousError;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (!preserveUserInput)
|
|
87
|
+
throw error;
|
|
88
|
+
return previousError ?? error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function runTerminalSendBeforeEnter(options, context, preserveUserInput, previousError) {
|
|
92
|
+
try {
|
|
93
|
+
await options.beforeEnter?.(context);
|
|
94
|
+
return previousError;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (!preserveUserInput)
|
|
98
|
+
throw error;
|
|
99
|
+
return previousError ?? error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function waitForUserExplicitCodexEnter(input) {
|
|
103
|
+
if (!input.enabled)
|
|
104
|
+
return;
|
|
105
|
+
await input.sleep(Math.max(0, CODEX_PASTE_ENTER_SETTLE_MS -
|
|
106
|
+
(input.nowMs() - input.textInjectedAt)));
|
|
107
|
+
}
|
|
108
|
+
function throwPostTextHookFailureAfterUserEnter(enabled, error) {
|
|
109
|
+
if (!enabled || error === undefined)
|
|
110
|
+
return;
|
|
111
|
+
throw new TerminalEnterDispatchReservedError("user-explicit Codex Enter was dispatched but post-text bookkeeping failed; do not retry", { cause: error });
|
|
112
|
+
}
|
|
113
|
+
export class TerminalTextSubmissionBridge {
|
|
114
|
+
runtime;
|
|
115
|
+
classifiers;
|
|
116
|
+
constructor(input) {
|
|
117
|
+
this.runtime = input.runtime;
|
|
118
|
+
this.classifiers = input.classifiers;
|
|
119
|
+
}
|
|
120
|
+
async send(adapter, terminalControl, text, options = {}) {
|
|
121
|
+
const multiline = /[\r\n]/u.test(text.trimEnd());
|
|
122
|
+
const { exactEmptyRetryAuthority, requireExactEmptyComposerBeforeText, requireExactComposer } = terminalSendComposerRequirements(adapter.agent, multiline, options);
|
|
123
|
+
try {
|
|
124
|
+
this.runtime.preflight(terminalControl, requireExactComposer || exactEmptyRetryAuthority
|
|
125
|
+
? "send_with_composer"
|
|
126
|
+
: "send");
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw new TerminalInputNotStartedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
130
|
+
}
|
|
131
|
+
const normalized = text.trimEnd();
|
|
132
|
+
if (!normalized) {
|
|
133
|
+
throw new TerminalInputNotStartedError("terminal message is empty");
|
|
134
|
+
}
|
|
135
|
+
let verifiedForText;
|
|
136
|
+
try {
|
|
137
|
+
verifiedForText = await this.runtime.verifyIdentity(adapter.agent, terminalControl, options.runtime);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new TerminalInputNotStartedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
141
|
+
}
|
|
142
|
+
if (!verifiedForText.capabilities.includes("send_keys")) {
|
|
143
|
+
throw new TerminalInputNotStartedError(`${adapter.displayName} terminal input capability changed before injection`);
|
|
144
|
+
}
|
|
145
|
+
let composerVerifiedImmediatelyBeforeText = false;
|
|
146
|
+
if (exactEmptyRetryAuthority) {
|
|
147
|
+
try {
|
|
148
|
+
await options.beforeText?.({
|
|
149
|
+
agent: adapter.agent,
|
|
150
|
+
terminalControl: verifiedForText,
|
|
151
|
+
multiline,
|
|
152
|
+
text: normalized
|
|
153
|
+
});
|
|
154
|
+
const finalEmpty = await this.captureCodexComposerSnapshot(adapter, verifiedForText, normalized, options.runtime);
|
|
155
|
+
if (finalEmpty.state !== "exact_empty" ||
|
|
156
|
+
finalEmpty.digest !==
|
|
157
|
+
exactEmptyRetryAuthority.preliminaryComposerDigest ||
|
|
158
|
+
!this.classifiers.sameIdentity(verifiedForText, finalEmpty.terminalControl)) {
|
|
159
|
+
const reason = "reason" in finalEmpty
|
|
160
|
+
? finalEmpty.reason
|
|
161
|
+
: `Codex composer is ${finalEmpty.state}`;
|
|
162
|
+
throw new Error(`reserved Codex replacement lost its exact-empty composer: ${reason}`);
|
|
163
|
+
}
|
|
164
|
+
verifiedForText = finalEmpty.terminalControl;
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
throw new TerminalEnterDispatchReservedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
try {
|
|
172
|
+
await options.beforeText?.({
|
|
173
|
+
agent: adapter.agent,
|
|
174
|
+
terminalControl: verifiedForText,
|
|
175
|
+
multiline,
|
|
176
|
+
text: normalized
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
throw new TerminalInputNotStartedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
181
|
+
}
|
|
182
|
+
if (requireExactEmptyComposerBeforeText) {
|
|
183
|
+
try {
|
|
184
|
+
verifiedForText = await this.verifyExactEmptyComposerBeforeText(adapter, verifiedForText, normalized, options.runtime, options.allowWorkingComposerForUserExplicit === true);
|
|
185
|
+
composerVerifiedImmediatelyBeforeText = true;
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
throw new TerminalInputNotStartedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!composerVerifiedImmediatelyBeforeText) {
|
|
193
|
+
try {
|
|
194
|
+
const reverifiedForText = await this.runtime.verifyIdentity(adapter.agent, verifiedForText, options.runtime);
|
|
195
|
+
if (!this.classifiers.sameIdentity(verifiedForText, reverifiedForText)) {
|
|
196
|
+
throw new Error("terminal identity changed after the final pre-text check");
|
|
197
|
+
}
|
|
198
|
+
verifiedForText = reverifiedForText;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
202
|
+
if (exactEmptyRetryAuthority) {
|
|
203
|
+
throw new TerminalEnterDispatchReservedError(message, {
|
|
204
|
+
cause: error
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
throw new TerminalInputNotStartedError(message, { cause: error });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
await this.runtime.deliverText(verifiedForText, normalized);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
if (exactEmptyRetryAuthority) {
|
|
215
|
+
throw new TerminalEnterDispatchReservedError("reserved Codex replacement text delivery outcome is uncertain; do not retry", { cause: error });
|
|
216
|
+
}
|
|
217
|
+
if (error instanceof TerminalControlInputNotSentError) {
|
|
218
|
+
throw new TerminalInputNotStartedError(error.message, {
|
|
219
|
+
cause: error
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
const textInjectedAt = this.runtime.nowMs();
|
|
225
|
+
const preserveUserInput = options.userExplicitEnterAfterTextWithoutComposerVeto === true;
|
|
226
|
+
const allowClaudeInjectedPastePlaceholder = claudeInjectedPasteProofEligible({
|
|
227
|
+
agent: adapter.agent,
|
|
228
|
+
multiline,
|
|
229
|
+
composerVerifiedImmediatelyBeforeText,
|
|
230
|
+
terminalControl: verifiedForText
|
|
231
|
+
});
|
|
232
|
+
let postTextHookError;
|
|
233
|
+
let verifiedForEnter;
|
|
234
|
+
let claudeComposerProof;
|
|
235
|
+
try {
|
|
236
|
+
postTextHookError = await recordTerminalSendStage(options, {
|
|
237
|
+
stage: "text_injected",
|
|
238
|
+
agent: adapter.agent,
|
|
239
|
+
terminalControl: verifiedForText,
|
|
240
|
+
multiline
|
|
241
|
+
}, preserveUserInput);
|
|
242
|
+
if (adapter.agent === "codex" && requireExactComposer) {
|
|
243
|
+
verifiedForEnter = await this.settleCodexMultilineComposer(adapter, terminalControl, normalized, options.runtime, {
|
|
244
|
+
allowOpaqueLargePastePlaceholder: exactEmptyRetryAuthority === undefined,
|
|
245
|
+
allowWorkingComposer: options.allowWorkingComposerForUserExplicit === true
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
else if (allowClaudeInjectedPastePlaceholder) {
|
|
249
|
+
claudeComposerProof = await settleClaudeInjectedPasteComposer({
|
|
250
|
+
terminalControl: verifiedForText,
|
|
251
|
+
expectedText: normalized,
|
|
252
|
+
runtime: options.runtime,
|
|
253
|
+
allowWorkingComposer: options.allowWorkingComposerForUserExplicit === true,
|
|
254
|
+
ports: this.claudeInjectedPasteProofPorts(adapter)
|
|
255
|
+
});
|
|
256
|
+
verifiedForEnter = claudeComposerProof.terminalControl;
|
|
257
|
+
}
|
|
258
|
+
else if (requireExactComposer) {
|
|
259
|
+
verifiedForEnter = await this.verifyExactComposerBeforeEnter(adapter, terminalControl, normalized, options.runtime, options.allowWorkingComposerForUserExplicit === true);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
await waitForUserExplicitCodexEnter({
|
|
263
|
+
enabled: preserveUserInput,
|
|
264
|
+
textInjectedAt,
|
|
265
|
+
nowMs: this.runtime.nowMs,
|
|
266
|
+
sleep: this.runtime.sleep
|
|
267
|
+
});
|
|
268
|
+
verifiedForEnter = await this.runtime.verifyIdentity(adapter.agent, terminalControl, options.runtime);
|
|
269
|
+
}
|
|
270
|
+
postTextHookError = await runTerminalSendBeforeEnter(options, {
|
|
271
|
+
agent: adapter.agent,
|
|
272
|
+
terminalControl: verifiedForEnter,
|
|
273
|
+
multiline,
|
|
274
|
+
text: normalized
|
|
275
|
+
}, preserveUserInput, postTextHookError);
|
|
276
|
+
if (requireExactComposer) {
|
|
277
|
+
if (adapter.agent === "codex") {
|
|
278
|
+
verifiedForEnter = await this.settleCodexMultilineComposer(adapter, terminalControl, normalized, options.runtime, {
|
|
279
|
+
allowOpaqueLargePastePlaceholder: exactEmptyRetryAuthority === undefined,
|
|
280
|
+
allowWorkingComposer: options.allowWorkingComposerForUserExplicit === true
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else if (allowClaudeInjectedPastePlaceholder && claudeComposerProof) {
|
|
284
|
+
verifiedForEnter = await revalidateClaudeComposerProof({
|
|
285
|
+
proof: claudeComposerProof,
|
|
286
|
+
expectedText: normalized,
|
|
287
|
+
runtime: options.runtime,
|
|
288
|
+
allowWorkingComposer: options.allowWorkingComposerForUserExplicit === true,
|
|
289
|
+
ports: this.claudeInjectedPasteProofPorts(adapter)
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
verifiedForEnter = await this.verifyExactComposerBeforeEnter(adapter, terminalControl, normalized, options.runtime, options.allowWorkingComposerForUserExplicit === true);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else if (options.beforeEnter) {
|
|
297
|
+
verifiedForEnter = await this.runtime.verifyIdentity(adapter.agent, terminalControl, options.runtime);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
if (exactEmptyRetryAuthority) {
|
|
302
|
+
if (error instanceof TerminalEnterDispatchReservedError) {
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
throw new TerminalEnterDispatchReservedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
306
|
+
}
|
|
307
|
+
if (error instanceof TerminalEnterDispatchNotAttemptedError) {
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
throw new TerminalEnterDispatchNotAttemptedError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
await this.runtime.dispatchEnter(verifiedForEnter);
|
|
314
|
+
postTextHookError = await recordTerminalSendStage(options, {
|
|
315
|
+
stage: "enter_dispatched",
|
|
316
|
+
agent: adapter.agent,
|
|
317
|
+
terminalControl: verifiedForEnter,
|
|
318
|
+
multiline
|
|
319
|
+
}, preserveUserInput, postTextHookError);
|
|
320
|
+
throwPostTextHookFailureAfterUserEnter(preserveUserInput, postTextHookError);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
if (exactEmptyRetryAuthority) {
|
|
324
|
+
throw new TerminalEnterDispatchReservedError("reserved Codex Enter dispatch outcome is uncertain; do not retry", { cause: error });
|
|
325
|
+
}
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
stage: "enter_dispatched",
|
|
330
|
+
agent: adapter.agent,
|
|
331
|
+
terminalControl: verifiedForEnter,
|
|
332
|
+
multiline
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
async observeCodexComposer(adapter, terminalControl, expectedText, runtime) {
|
|
336
|
+
const normalized = expectedText.trimEnd();
|
|
337
|
+
if (!normalized) {
|
|
338
|
+
return {
|
|
339
|
+
state: "unavailable",
|
|
340
|
+
reason: "expected Codex draft is empty"
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
this.runtime.preflight(terminalControl, "observe_composer");
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
return {
|
|
348
|
+
state: "unavailable",
|
|
349
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
return this.settleCodexComposerObservation(adapter, terminalControl, normalized, runtime, { minimumStableMs: CODEX_MULTILINE_SETTLE_POLL_MS });
|
|
353
|
+
}
|
|
354
|
+
async settleCodexComposerObservation(adapter, terminalControl, expectedText, runtime, options) {
|
|
355
|
+
const startedAt = this.runtime.nowMs();
|
|
356
|
+
let candidate;
|
|
357
|
+
let stableSince;
|
|
358
|
+
let stableCaptures = 0;
|
|
359
|
+
let finishObservedExactCandidate = false;
|
|
360
|
+
let capturesBeyondDeadline = 0;
|
|
361
|
+
let control = terminalControl;
|
|
362
|
+
while (true) {
|
|
363
|
+
const snapshot = await this.captureCodexComposerSnapshot(adapter, control, expectedText, runtime, {
|
|
364
|
+
allowOpaqueLargePastePlaceholder: options.allowOpaqueLargePastePlaceholder === true,
|
|
365
|
+
classifyOpaqueLargePasteAsDifferent: options.classifyOpaqueLargePasteAsDifferent === true,
|
|
366
|
+
allowWorkingComposer: options.allowWorkingComposer === true
|
|
367
|
+
});
|
|
368
|
+
if (snapshot.state === "identity_drift" ||
|
|
369
|
+
(snapshot.state === "unavailable" && snapshot.retryable !== true)) {
|
|
370
|
+
return snapshot;
|
|
371
|
+
}
|
|
372
|
+
if (this.runtime.nowMs() - startedAt >
|
|
373
|
+
CODEX_MULTILINE_SETTLE_TIMEOUT_MS) {
|
|
374
|
+
capturesBeyondDeadline += 1;
|
|
375
|
+
if (capturesBeyondDeadline > CODEX_EXACT_CANDIDATE_GRACE_CAPTURES) {
|
|
376
|
+
return {
|
|
377
|
+
state: "unavailable",
|
|
378
|
+
reason: "Codex exact composer did not stabilize within its bounded capture grace"
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
control = snapshot.terminalControl;
|
|
383
|
+
const sameCandidate = candidate !== undefined &&
|
|
384
|
+
candidate.state === snapshot.state &&
|
|
385
|
+
candidate.digest === snapshot.digest &&
|
|
386
|
+
this.classifiers.sameIdentity(candidate.terminalControl, snapshot.terminalControl);
|
|
387
|
+
if (sameCandidate) {
|
|
388
|
+
stableCaptures += 1;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
candidate = snapshot;
|
|
392
|
+
stableSince = this.runtime.nowMs();
|
|
393
|
+
stableCaptures = 1;
|
|
394
|
+
finishObservedExactCandidate = snapshot.state === "exact_draft";
|
|
395
|
+
}
|
|
396
|
+
const stableForMs = stableSince === undefined
|
|
397
|
+
? 0
|
|
398
|
+
: this.runtime.nowMs() - stableSince;
|
|
399
|
+
if (stableCaptures >= CODEX_MULTILINE_STABLE_CAPTURES &&
|
|
400
|
+
stableForMs >= options.minimumStableMs &&
|
|
401
|
+
snapshot.state !== "unavailable" &&
|
|
402
|
+
(options.requiredState === undefined ||
|
|
403
|
+
snapshot.state === options.requiredState ||
|
|
404
|
+
snapshot.state === "working" ||
|
|
405
|
+
snapshot.state === "approval_or_modal")) {
|
|
406
|
+
const finalSnapshot = await this.captureCodexComposerSnapshot(adapter, snapshot.terminalControl, expectedText, runtime, {
|
|
407
|
+
allowOpaqueLargePastePlaceholder: options.allowOpaqueLargePastePlaceholder === true,
|
|
408
|
+
classifyOpaqueLargePasteAsDifferent: options.classifyOpaqueLargePasteAsDifferent === true,
|
|
409
|
+
allowWorkingComposer: options.allowWorkingComposer === true
|
|
410
|
+
});
|
|
411
|
+
if (finalSnapshot.state === snapshot.state &&
|
|
412
|
+
"digest" in finalSnapshot &&
|
|
413
|
+
finalSnapshot.digest === snapshot.digest &&
|
|
414
|
+
this.classifiers.sameIdentity(snapshot.terminalControl, finalSnapshot.terminalControl)) {
|
|
415
|
+
return {
|
|
416
|
+
...finalSnapshot,
|
|
417
|
+
stableCaptures: stableCaptures + 1
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (finalSnapshot.state === "identity_drift" ||
|
|
421
|
+
(finalSnapshot.state === "unavailable" &&
|
|
422
|
+
finalSnapshot.retryable !== true)) {
|
|
423
|
+
return finalSnapshot;
|
|
424
|
+
}
|
|
425
|
+
if (options.requiredState !== undefined &&
|
|
426
|
+
snapshot.state === options.requiredState) {
|
|
427
|
+
return {
|
|
428
|
+
state: "unavailable",
|
|
429
|
+
reason: "Codex composer changed after its stable final recapture"
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
candidate = finalSnapshot;
|
|
433
|
+
control = finalSnapshot.terminalControl;
|
|
434
|
+
stableSince = this.runtime.nowMs();
|
|
435
|
+
stableCaptures = 1;
|
|
436
|
+
finishObservedExactCandidate = finalSnapshot.state === "exact_draft";
|
|
437
|
+
}
|
|
438
|
+
const elapsed = this.runtime.nowMs() - startedAt;
|
|
439
|
+
if (elapsed > CODEX_MULTILINE_SETTLE_TIMEOUT_MS &&
|
|
440
|
+
!finishObservedExactCandidate) {
|
|
441
|
+
return {
|
|
442
|
+
state: "unavailable",
|
|
443
|
+
reason: options.requiredState
|
|
444
|
+
? `Codex composer did not become ${options.requiredState} before the bounded observation deadline`
|
|
445
|
+
: "Codex composer did not become stable before the bounded observation deadline"
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
if (elapsed > CODEX_MULTILINE_SETTLE_TIMEOUT_MS &&
|
|
449
|
+
options.requiredState !== undefined &&
|
|
450
|
+
snapshot.state !== options.requiredState) {
|
|
451
|
+
if (snapshot.state !== "unavailable") {
|
|
452
|
+
return {
|
|
453
|
+
...snapshot,
|
|
454
|
+
stableCaptures
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
state: "unavailable",
|
|
459
|
+
reason: snapshot.reason
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
const remainingStableMs = options.minimumStableMs - stableForMs;
|
|
463
|
+
await this.runtime.sleep(Math.max(1, Math.min(CODEX_MULTILINE_SETTLE_POLL_MS, remainingStableMs > 0
|
|
464
|
+
? remainingStableMs
|
|
465
|
+
: CODEX_MULTILINE_SETTLE_POLL_MS)));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async captureCodexComposerSnapshot(adapter, terminalControl, expectedText, runtime, options = {}) {
|
|
469
|
+
let verifiedBefore;
|
|
470
|
+
try {
|
|
471
|
+
verifiedBefore = await this.runtime.verifyIdentity(adapter.agent, terminalControl, runtime);
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
return {
|
|
475
|
+
state: "identity_drift",
|
|
476
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
let styledScreen;
|
|
480
|
+
try {
|
|
481
|
+
styledScreen = await this.runtime.captureStyled(verifiedBefore);
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
return {
|
|
485
|
+
state: "unavailable",
|
|
486
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const screen = this.classifiers.stripEscapes(styledScreen);
|
|
490
|
+
let inspection;
|
|
491
|
+
try {
|
|
492
|
+
inspection = adapter.inspectScreen({ screen, runtime });
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
return {
|
|
496
|
+
state: "unavailable",
|
|
497
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
let verifiedAfter;
|
|
501
|
+
try {
|
|
502
|
+
verifiedAfter = await this.runtime.verifyIdentity(adapter.agent, verifiedBefore, runtime);
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
return {
|
|
506
|
+
state: "identity_drift",
|
|
507
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
if (!this.classifiers.sameIdentity(verifiedBefore, verifiedAfter)) {
|
|
511
|
+
return {
|
|
512
|
+
state: "identity_drift",
|
|
513
|
+
reason: "terminal control identity changed across the Codex composer capture"
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
const screenDigest = createHash("sha256")
|
|
517
|
+
.update(styledScreen)
|
|
518
|
+
.digest("hex");
|
|
519
|
+
if (inspection.approval.blocked ||
|
|
520
|
+
inspection.activity.state === "awaiting_approval" ||
|
|
521
|
+
this.classifiers.codexBlockingModalVisible(screen)) {
|
|
522
|
+
return {
|
|
523
|
+
state: "approval_or_modal",
|
|
524
|
+
terminalControl: verifiedAfter,
|
|
525
|
+
digest: screenDigest
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
if (inspection.activity.state === "working" &&
|
|
529
|
+
options.allowWorkingComposer !== true) {
|
|
530
|
+
return {
|
|
531
|
+
state: "working",
|
|
532
|
+
terminalControl: verifiedAfter,
|
|
533
|
+
digest: screenDigest
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
const composer = this.classifiers.currentCodexComposer(styledScreen, expectedText, options.allowOpaqueLargePastePlaceholder === true, options.classifyOpaqueLargePasteAsDifferent === true);
|
|
537
|
+
if (!composer) {
|
|
538
|
+
return {
|
|
539
|
+
state: "unavailable",
|
|
540
|
+
reason: "the current live Codex composer could not be proven",
|
|
541
|
+
retryable: true,
|
|
542
|
+
terminalControl: verifiedAfter,
|
|
543
|
+
digest: screenDigest
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
return {
|
|
547
|
+
state: composer.state,
|
|
548
|
+
terminalControl: verifiedAfter,
|
|
549
|
+
digest: composer.digest
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
async settleCodexMultilineComposer(adapter, terminalControl, expectedText, runtime, options = {}) {
|
|
553
|
+
const observation = await this.settleCodexComposerObservation(adapter, terminalControl, expectedText, runtime, {
|
|
554
|
+
minimumStableMs: CODEX_PASTE_ENTER_SETTLE_MS,
|
|
555
|
+
requiredState: "exact_draft",
|
|
556
|
+
allowOpaqueLargePastePlaceholder: options.allowOpaqueLargePastePlaceholder === true,
|
|
557
|
+
allowWorkingComposer: options.allowWorkingComposer === true
|
|
558
|
+
});
|
|
559
|
+
if (observation.state === "exact_draft") {
|
|
560
|
+
return observation.terminalControl;
|
|
561
|
+
}
|
|
562
|
+
if (observation.state === "working" ||
|
|
563
|
+
observation.state === "approval_or_modal") {
|
|
564
|
+
throw new Error("Codex became busy or blocked while its multiline composer was settling");
|
|
565
|
+
}
|
|
566
|
+
if (observation.state === "identity_drift") {
|
|
567
|
+
throw new Error(observation.reason);
|
|
568
|
+
}
|
|
569
|
+
throw new Error("Codex multiline composer did not become exact, idle, and stable before the bounded submit deadline");
|
|
570
|
+
}
|
|
571
|
+
async verifyExactComposerBeforeEnter(adapter, terminalControl, expectedText, runtime, allowWorkingComposer = false) {
|
|
572
|
+
const captured = await this.runtime.captureInspection(adapter, terminalControl, {
|
|
573
|
+
runtime,
|
|
574
|
+
scrollbackLines: CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES
|
|
575
|
+
});
|
|
576
|
+
const exactComposer = this.classifiers.exactTerminalComposer(adapter.agent, captured.screen, expectedText);
|
|
577
|
+
if (captured.inspection.approval.blocked ||
|
|
578
|
+
!(["idle", "unknown"].includes(captured.inspection.activity.state) ||
|
|
579
|
+
(allowWorkingComposer &&
|
|
580
|
+
captured.inspection.activity.state === "working")) ||
|
|
581
|
+
!exactComposer) {
|
|
582
|
+
throw new Error(`${adapter.displayName} composer was not exact and idle immediately before Enter`);
|
|
583
|
+
}
|
|
584
|
+
const verifiedImmediatelyBeforeEnter = await this.runtime.verifyIdentity(adapter.agent, captured.terminalControl, runtime);
|
|
585
|
+
if (!this.classifiers.sameIdentity(captured.terminalControl, verifiedImmediatelyBeforeEnter)) {
|
|
586
|
+
throw new Error("terminal control identity changed after the final exact composer capture");
|
|
587
|
+
}
|
|
588
|
+
return verifiedImmediatelyBeforeEnter;
|
|
589
|
+
}
|
|
590
|
+
claudeInjectedPasteProofPorts(adapter) {
|
|
591
|
+
return {
|
|
592
|
+
nowMs: this.runtime.nowMs,
|
|
593
|
+
sleep: this.runtime.sleep,
|
|
594
|
+
capture: (terminalControl, runtime) => this.runtime.captureInspection(adapter, terminalControl, {
|
|
595
|
+
runtime,
|
|
596
|
+
scrollbackLines: CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES
|
|
597
|
+
}),
|
|
598
|
+
verifyIdentity: (terminalControl, runtime) => this.runtime.verifyIdentity(adapter.agent, terminalControl, runtime),
|
|
599
|
+
exactDraft: this.classifiers.exactClaudeComposer,
|
|
600
|
+
exactInjectedPastePlaceholder: this.classifiers.exactClaudeInjectedPastePlaceholder
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
async verifyExactEmptyComposerBeforeText(adapter, terminalControl, expectedText, runtime, allowWorkingComposer = false) {
|
|
604
|
+
if (adapter.agent === "codex") {
|
|
605
|
+
const snapshot = await this.captureCodexComposerSnapshot(adapter, terminalControl, expectedText, runtime);
|
|
606
|
+
if (snapshot.state !== "exact_empty") {
|
|
607
|
+
const reason = "reason" in snapshot
|
|
608
|
+
? snapshot.reason
|
|
609
|
+
: `Codex composer is ${snapshot.state}`;
|
|
610
|
+
throw new Error(`Codex composer was not exactly empty immediately before text: ${reason}`);
|
|
611
|
+
}
|
|
612
|
+
return snapshot.terminalControl;
|
|
613
|
+
}
|
|
614
|
+
const captured = await this.runtime.captureInspection(adapter, terminalControl, {
|
|
615
|
+
runtime,
|
|
616
|
+
scrollbackLines: CODEX_MULTILINE_SETTLE_SCROLLBACK_LINES
|
|
617
|
+
});
|
|
618
|
+
if (captured.inspection.approval.blocked ||
|
|
619
|
+
!(["idle", "unknown"].includes(captured.inspection.activity.state) ||
|
|
620
|
+
(allowWorkingComposer &&
|
|
621
|
+
captured.inspection.activity.state === "working")) ||
|
|
622
|
+
!this.classifiers.exactTerminalComposer(adapter.agent, captured.screen, "")) {
|
|
623
|
+
throw new Error(`${adapter.displayName} composer was not exactly empty immediately before text`);
|
|
624
|
+
}
|
|
625
|
+
const verified = await this.runtime.verifyIdentity(adapter.agent, captured.terminalControl, runtime);
|
|
626
|
+
if (!this.classifiers.sameIdentity(captured.terminalControl, verified)) {
|
|
627
|
+
throw new Error("terminal control identity changed after the final empty composer capture");
|
|
628
|
+
}
|
|
629
|
+
return verified;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
//# sourceMappingURL=terminal-text-submission-bridge.js.map
|