@rynx-ai/runtime 0.1.0 → 0.1.10-beta.2
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/claude/executor.d.ts +3 -5
- package/dist/claude/executor.js +3 -5
- package/dist/claude/native-bridge.d.ts +74 -17
- package/dist/claude/native-bridge.js +225 -30
- package/dist/claude/native-hook-main.js +327 -38
- package/dist/claude/native-hooks.d.ts +3 -2
- package/dist/claude/native-hooks.js +15 -6
- package/dist/claude/native-integration.d.ts +123 -16
- package/dist/claude/native-integration.js +624 -81
- package/dist/claude/settings.d.ts +8 -0
- package/dist/claude/settings.js +50 -0
- package/dist/claude/transcript.d.ts +2 -2
- package/dist/claude/transcript.js +14 -3
- package/dist/codex/rollout-synth.d.ts +8 -3
- package/dist/codex/rollout-synth.js +65 -32
- package/dist/codex-app-server/client.d.ts +27 -40
- package/dist/codex-app-server/client.js +1134 -99
- package/dist/codex-app-server/forwarder.d.ts +36 -10
- package/dist/codex-app-server/forwarder.js +146 -28
- package/dist/codex-app-server/mapping.d.ts +1 -1
- package/dist/codex-app-server/mapping.js +64 -5
- package/dist/codex-app-server/protocol.d.ts +269 -4
- package/dist/codex-app-server/transport.d.ts +20 -5
- package/dist/codex-app-server/transport.js +93 -40
- package/dist/codex-app-server/ws-channel.d.ts +3 -3
- package/dist/codex-app-server/ws-channel.js +23 -7
- package/dist/codex-child-env.js +33 -0
- package/dist/codex-home.d.ts +16 -6
- package/dist/codex-home.js +46 -15
- package/dist/codex-session-store.d.ts +2 -1
- package/dist/host.d.ts +38 -38
- package/dist/host.js +626 -121
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/input-resources.d.ts +13 -0
- package/dist/input-resources.js +67 -0
- package/dist/interactions.d.ts +61 -0
- package/dist/interactions.js +236 -0
- package/dist/models-catalog.d.ts +5 -13
- package/dist/models-catalog.js +60 -9
- package/dist/runner/child.d.ts +9 -1
- package/dist/runner/child.js +100 -19
- package/dist/runner/manager.d.ts +79 -11
- package/dist/runner/manager.js +423 -43
- package/dist/runner/protocol.d.ts +30 -11
- package/dist/runner-main.js +9 -6
- package/dist/runtime-status.js +1 -1
- package/dist/terminal/claude-tui.d.ts +8 -3
- package/dist/terminal/claude-tui.js +6 -2
- package/dist/terminal/codex-tui.d.ts +3 -3
- package/dist/terminal/codex-tui.js +1 -1
- package/dist/terminal/registry.d.ts +1 -1
- package/dist/terminal/registry.js +1 -1
- package/dist/terminal/tmux.d.ts +6 -6
- package/dist/terminal/tmux.js +10 -10
- package/package.json +8 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AgentEvent, TerminalCommandData, TodoItem } from "@rynx-ai/core";
|
|
1
|
+
import type { AgentEvent, SessionInteractionResolution, TerminalCommandData, TodoItem } from "@rynx-ai/core";
|
|
2
|
+
import type { ResolveInteractionResult, RuntimeInteractionEvent } from "../interactions.js";
|
|
2
3
|
/** Mirror sink — the same shape as `CodexForwarderSink` so the host reuses one
|
|
3
4
|
* per-turn normalizer wiring for both runtimes. */
|
|
4
5
|
export interface ClaudeForwarderSink {
|
|
@@ -14,6 +15,9 @@ export interface ClaudeForwarderSink {
|
|
|
14
15
|
onTodos(todos: TodoItem[]): void;
|
|
15
16
|
/** One mapped event within the current turn. */
|
|
16
17
|
onEvent(event: AgentEvent): void;
|
|
18
|
+
/** A provider-neutral question/permission requested or settled while this
|
|
19
|
+
* Turn remains active. */
|
|
20
|
+
onInteraction(event: RuntimeInteractionEvent): void;
|
|
17
21
|
/** The current turn finished (a new user prompt, or the inactivity backstop).
|
|
18
22
|
* `usage` carries the latest statusLine context/cost snapshot, when captured. */
|
|
19
23
|
onTurnEnd(usage?: Record<string, unknown>): void;
|
|
@@ -51,6 +55,10 @@ export interface ClaudeLiveSessionOptions {
|
|
|
51
55
|
* flush still join the turn (Stop and the flush race). */
|
|
52
56
|
stopGraceMs?: number;
|
|
53
57
|
now?: () => number;
|
|
58
|
+
/** Process-liveness probe for the blocking native hook (test override). */
|
|
59
|
+
isProcessAlive?: (pid: number) => boolean;
|
|
60
|
+
/** Native lease timestamp reader (test override). */
|
|
61
|
+
interactionLeaseUpdatedAt?: (interactionId: string) => number | undefined;
|
|
54
62
|
}
|
|
55
63
|
export declare class ClaudeLiveSession {
|
|
56
64
|
private readonly bridgeDir;
|
|
@@ -59,9 +67,13 @@ export declare class ClaudeLiveSession {
|
|
|
59
67
|
private readonly idleCloseMs;
|
|
60
68
|
private readonly stopGraceMs;
|
|
61
69
|
private readonly now;
|
|
70
|
+
private readonly isProcessAlive;
|
|
71
|
+
private readonly leaseUpdatedAt;
|
|
62
72
|
private started;
|
|
63
73
|
private stopped;
|
|
64
74
|
private hooksOffset;
|
|
75
|
+
private interactionsOffset;
|
|
76
|
+
private interactionAcksOffset;
|
|
65
77
|
private transcriptOffset;
|
|
66
78
|
/** Secondary dedup: source ids (record uuids) already forwarded, so a re-read
|
|
67
79
|
* (fingerprint reset / mid-poll death) doesn't re-emit. Persisted in the
|
|
@@ -76,11 +88,40 @@ export declare class ClaudeLiveSession {
|
|
|
76
88
|
private readonly seenClaudeSessionIds;
|
|
77
89
|
private turnOpen;
|
|
78
90
|
private currentTurnId?;
|
|
91
|
+
/** The Turn opened from a pre-transcript interaction. Its unique provisional
|
|
92
|
+
* id keeps responses distinct until the real prompt uuid can be adopted. */
|
|
93
|
+
private syntheticTurn;
|
|
79
94
|
private lastActivityAt;
|
|
80
95
|
/** When the Stop hook fired (null = not yet) — drives the grace-period close. */
|
|
81
96
|
private stopPendingAt;
|
|
82
97
|
/** Open tool-call ids (start seen, end not yet) — suppresses the idle backstop. */
|
|
83
98
|
private readonly openToolIds;
|
|
99
|
+
/** Transcript-backed acknowledgements for web→TUI input. A direct idle
|
|
100
|
+
* submit is recorded as `promptSource:"typed"`; a submit while Claude is busy
|
|
101
|
+
* is recorded immediately as `queue-operation:enqueue` and only later
|
|
102
|
+
* promoted to `promptSource:"queued"`. The promotion is intentionally not a
|
|
103
|
+
* second acknowledgement. */
|
|
104
|
+
private submissionSequence;
|
|
105
|
+
private readonly submissionObservations;
|
|
106
|
+
/** Enqueued type-ahead inputs awaiting their eventual role:user promotion.
|
|
107
|
+
* Claude has used both `promptSource:"queued"` and `"sdk"` for that later
|
|
108
|
+
* record, so content correlation is the stable discriminator. */
|
|
109
|
+
private readonly pendingQueuedSubmissions;
|
|
110
|
+
/** Blocking native questions/permissions. Their hook subprocess is still
|
|
111
|
+
* executing, so the Turn remains running and cannot be idle-closed. */
|
|
112
|
+
private readonly pendingInteractions;
|
|
113
|
+
private readonly settledInteractions;
|
|
114
|
+
/** Claimed response files may still contain the provider-bound, unredacted
|
|
115
|
+
* answer. Keep tracking them after canonical settlement until ACK/hook cleanup. */
|
|
116
|
+
private readonly claimedInteractions;
|
|
117
|
+
private readonly scheduledClaimScrubs;
|
|
118
|
+
/** Stop is flushed after interactions in the same poll, preventing a
|
|
119
|
+
* request+Stop race from briefly reporting this executing Turn as idle. */
|
|
120
|
+
private stopSignalPending;
|
|
121
|
+
/** StopFailure is likewise flushed after interactions. A blocking hook can
|
|
122
|
+
* append its request immediately before the failure hook lands; closing here
|
|
123
|
+
* would let the later interaction poll reopen an already-failed Turn. */
|
|
124
|
+
private turnFailurePending;
|
|
84
125
|
/** Sub-agent (Task) ids already forwarded — a Task tool_result is processed once. */
|
|
85
126
|
private readonly seenSubagents;
|
|
86
127
|
/** The agent's task list, keyed by task id in creation order (claude
|
|
@@ -90,14 +131,19 @@ export declare class ClaudeLiveSession {
|
|
|
90
131
|
* a turn's usage on close. undefined until the statusLine hook first fires. */
|
|
91
132
|
private latestStatus?;
|
|
92
133
|
private deltasOffset;
|
|
93
|
-
/** MessageDisplay
|
|
134
|
+
/** Finalized MessageDisplay ids in completion order, FIFO-mapped onto the
|
|
94
135
|
* transcript's assistant-text records so a streamed message and its final
|
|
95
136
|
* item share an itemId (message_id is absent from the transcript). */
|
|
96
137
|
private readonly messageIdQueue;
|
|
97
|
-
private readonly
|
|
138
|
+
private readonly finalizedMessageIds;
|
|
139
|
+
/** Transcript messages that arrived before their MessageDisplay stream. A
|
|
140
|
+
* matching late final consumes both sides so its id cannot shift the FIFO
|
|
141
|
+
* used by the next assistant message. */
|
|
142
|
+
private readonly unmatchedTranscriptMessages;
|
|
143
|
+
private readonly streamedMessageText;
|
|
98
144
|
constructor(opts: ClaudeLiveSessionOptions);
|
|
99
145
|
/**
|
|
100
|
-
* Restore the durable forwarder cursor for `transcriptPath` (
|
|
146
|
+
* Restore the durable forwarder cursor for `transcriptPath` (reference implementation's
|
|
101
147
|
* `_validated_transcript_state`). A cursor for a DIFFERENT file is ignored (a new
|
|
102
148
|
* session starts at 0). A matching cursor whose fingerprint still validates
|
|
103
149
|
* resumes at its `byteOffset`; a MISMATCH (the file was truncated/replaced) skips
|
|
@@ -109,14 +155,35 @@ export declare class ClaudeLiveSession {
|
|
|
109
155
|
private persistForwardState;
|
|
110
156
|
/** True once SessionStart bound the transcript (or a resume path was given). */
|
|
111
157
|
isReady(): boolean;
|
|
158
|
+
/** Drain records that predate a new injection, then return a monotonic
|
|
159
|
+
* checkpoint. This prevents a lagging, older identical prompt from
|
|
160
|
+
* acknowledging the new submit. */
|
|
161
|
+
beginSubmissionObservation(): number;
|
|
162
|
+
/** Whether Claude durably accepted `text` after `checkpoint`. Polling the
|
|
163
|
+
* transcript here makes submit confirmation independent of the background
|
|
164
|
+
* forwarder interval and covers both idle and type-ahead submissions. */
|
|
165
|
+
hasObservedSubmissionAfter(checkpoint: number, text: string): boolean;
|
|
166
|
+
private rememberSubmission;
|
|
167
|
+
private rememberQueuedSubmission;
|
|
168
|
+
private consumeQueuedPromotion;
|
|
112
169
|
start(): void;
|
|
113
170
|
stop(): void;
|
|
171
|
+
/** Phase two of runner shutdown. The caller must stop the Claude terminal
|
|
172
|
+
* first so no hook can still be opening an atomically claimed answer. This is
|
|
173
|
+
* synchronous because the runner process exits immediately afterwards. */
|
|
174
|
+
finalizeStop(): void;
|
|
114
175
|
/** One poll cycle (hooks → transcript → idle backstop). Exposed for tests to
|
|
115
176
|
* drive deterministically; the async {@link loop} just calls it on an interval. */
|
|
116
177
|
tick(): void;
|
|
117
178
|
private loop;
|
|
118
179
|
private pollHooks;
|
|
119
180
|
private handleHook;
|
|
181
|
+
/** Process a provider failure only after this tick has discovered every
|
|
182
|
+
* blocking request already appended by its hook subprocess. */
|
|
183
|
+
private flushTurnFailure;
|
|
184
|
+
/** Emit the Stop idle signal only after this tick has discovered native
|
|
185
|
+
* interactions. A pending question/permission is active execution, not idle. */
|
|
186
|
+
private flushStopSignal;
|
|
120
187
|
/** SessionStart drives discovery (first) and rotation (a later one with a NEW
|
|
121
188
|
* session id + transcript). `/clear` → source="clear"; `/fork` → source="resume"
|
|
122
189
|
* into an unseen id with a forkedFrom marker. Any other new-transcript
|
|
@@ -127,6 +194,39 @@ export declare class ClaudeLiveSession {
|
|
|
127
194
|
* rotation, so their cursors are NOT reset). */
|
|
128
195
|
private repointTranscript;
|
|
129
196
|
private pollTranscript;
|
|
197
|
+
/** Tail blocking hook requests after transcript records, so an interaction
|
|
198
|
+
* emitted in the same poll attaches to the user Turn that caused it. */
|
|
199
|
+
private pollInteractions;
|
|
200
|
+
private drainInteractionCommits;
|
|
201
|
+
/** A hook acknowledgement is the commit point: it is appended after the hook
|
|
202
|
+
* consumes the one-shot response and before it returns the native verdict. */
|
|
203
|
+
private pollInteractionAcks;
|
|
204
|
+
/** A claimed response is already consumed by the native hook. This fallback
|
|
205
|
+
* converges the interaction even if the hook exits before appending its
|
|
206
|
+
* redacted ACK. */
|
|
207
|
+
private pollInteractionClaims;
|
|
208
|
+
/** A request cannot remain actionable after its blocking hook exits. A short
|
|
209
|
+
* post-submit timeout also converges requests created by older hooks that did
|
|
210
|
+
* not publish a waiter pid, and scrubs any unacknowledged secret response. */
|
|
211
|
+
private pollAbandonedInteractions;
|
|
212
|
+
/** Deliver an answer to the blocked hook. The bridge file contains the real
|
|
213
|
+
* answer; only the canonical resolved event receives a secret-redacted copy. */
|
|
214
|
+
resolveInteraction(interactionId: string, resolution: SessionInteractionResolution): ResolveInteractionResult;
|
|
215
|
+
private cancelPendingInteractions;
|
|
216
|
+
/** Terminal cancellation may race the hook's atomic result claim. A claim
|
|
217
|
+
* always wins; otherwise the cancellation file becomes the hook's verdict. */
|
|
218
|
+
private cancelOrSettlePendingInteraction;
|
|
219
|
+
private settleClaimedInteraction;
|
|
220
|
+
/** A claim is the hook's private handoff file and can contain secret answers.
|
|
221
|
+
* ACK/finally normally removes it; process death or an expired lease is the
|
|
222
|
+
* crash fallback after the canonical interaction has already settled. */
|
|
223
|
+
private pollClaimedInteractionCleanup;
|
|
224
|
+
/** Once this forwarder stops it can no longer poll a later hook crash. Keep a
|
|
225
|
+
* short unref'd scrub deadline so unredacted claim material cannot persist for
|
|
226
|
+
* the lifetime of the daemon. */
|
|
227
|
+
private scheduleClaimedInteractionScrubs;
|
|
228
|
+
private settleCancelledInteraction;
|
|
229
|
+
private rememberSettled;
|
|
130
230
|
private handleRecord;
|
|
131
231
|
/** Fold a `TaskCreate` (new pending task) or `TaskUpdate` (status/subject/delete)
|
|
132
232
|
* record into the task list; on any change emit the whole list as a snapshot. */
|
|
@@ -140,6 +240,7 @@ export declare class ClaudeLiveSession {
|
|
|
140
240
|
* events. Guarded on an open turn — deltas belong to the turn the user record
|
|
141
241
|
* opened; the offset advances only once processed. */
|
|
142
242
|
private pollDeltas;
|
|
243
|
+
private finalizeMessageDisplay;
|
|
143
244
|
/** Refresh the latest statusLine context/cost snapshot (a last-writer-wins file
|
|
144
245
|
* the statusLine hook overwrites on every TUI render). */
|
|
145
246
|
private pollStatus;
|
|
@@ -149,7 +250,8 @@ export declare class ClaudeLiveSession {
|
|
|
149
250
|
private statusUsage;
|
|
150
251
|
/** Remap an assistant-text `message_completed` onto the FIFO-matched
|
|
151
252
|
* MessageDisplay message_id, so its streamed deltas and this final item share
|
|
152
|
-
* an itemId. No queued delta
|
|
253
|
+
* an itemId. No queued delta yet → keep the transcript id and remember its
|
|
254
|
+
* text so a late MessageDisplay final can be reconciled backward. */
|
|
153
255
|
private remapMessageItem;
|
|
154
256
|
private trackTool;
|
|
155
257
|
private ensureTurn;
|
|
@@ -172,6 +274,7 @@ export declare class ClaudeLiveSession {
|
|
|
172
274
|
isTurnOpen(): boolean;
|
|
173
275
|
private closeTurn;
|
|
174
276
|
private closeTurnError;
|
|
277
|
+
private resetMessageCorrelation;
|
|
175
278
|
private maybeIdleClose;
|
|
176
279
|
}
|
|
177
280
|
/** The tmux-pane operations claude-native injection needs (a subset of
|
|
@@ -182,16 +285,20 @@ export interface TerminalInjector {
|
|
|
182
285
|
clearInputLine(): void;
|
|
183
286
|
paste(text: string): void;
|
|
184
287
|
sendEnter(): void;
|
|
185
|
-
/** Interrupt the running turn (Escape) — the web Stop button (
|
|
288
|
+
/** Interrupt the running turn (Escape) — the web Stop button (reference implementation). */
|
|
186
289
|
interrupt(): void;
|
|
187
290
|
}
|
|
188
291
|
export interface InjectViaTerminalOptions {
|
|
189
292
|
promptGlyph?: string;
|
|
190
293
|
promptTimeoutMs?: number;
|
|
191
|
-
pasteCommitMs?: number;
|
|
192
294
|
settleMs?: number;
|
|
193
|
-
|
|
194
|
-
|
|
295
|
+
/** Transcript-backed proof that Claude accepted this exact input. When
|
|
296
|
+
* absent, injection keeps the legacy one-Enter best-effort contract. */
|
|
297
|
+
submissionObserved?: () => boolean;
|
|
298
|
+
/** Per-attempt wait for a transcript acknowledgement. */
|
|
299
|
+
submitConfirmMs?: number;
|
|
300
|
+
/** Total Enter attempts when transcript confirmation is available. */
|
|
301
|
+
maxSubmitAttempts?: number;
|
|
195
302
|
pollMs?: number;
|
|
196
303
|
now?: () => number;
|
|
197
304
|
sleep?: (ms: number) => Promise<void>;
|
|
@@ -200,14 +307,14 @@ export interface InjectViaTerminalOptions {
|
|
|
200
307
|
signal?: AbortSignal;
|
|
201
308
|
}
|
|
202
309
|
/**
|
|
203
|
-
* Deliver `text` into a claude TUI pane, the
|
|
204
|
-
* ready-gate (poll for `❯`) → clear leftover → bracketed paste
|
|
205
|
-
*
|
|
206
|
-
* draft left the box (re-send Enter while it hasn't).
|
|
310
|
+
* Deliver `text` into a claude TUI pane, the reference implementation recipe:
|
|
311
|
+
* ready-gate (poll for `❯`) → clear leftover → bracketed paste the draft
|
|
312
|
+
* → settle → submit Enter → confirm from Claude's transcript.
|
|
207
313
|
*
|
|
208
|
-
* THROWS if the prompt never appears within the ready-gate window (
|
|
314
|
+
* THROWS if the prompt never appears within the ready-gate window (reference implementation
|
|
209
315
|
* `_wait_for_claude_prompt_ready` RAISE) — a not-ready pane is a hard error the
|
|
210
|
-
* caller reports, NOT a signal to fall through to a second output path.
|
|
211
|
-
*
|
|
316
|
+
* caller reports, NOT a signal to fall through to a second output path. With a
|
|
317
|
+
* transcript observer, Enter is retried only when Claude has durably recorded
|
|
318
|
+
* neither a direct user prompt nor a type-ahead enqueue.
|
|
212
319
|
*/
|
|
213
320
|
export declare function injectViaTerminal(injector: TerminalInjector, text: string, opts?: InjectViaTerminalOptions): Promise<boolean>;
|