openryoko 2026.7.3 → 2026.7.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/dist/package.json +1 -1
- package/dist/src/engines/__tests__/claude-interactive-transcript-recovery.test.d.ts +2 -0
- package/dist/src/engines/__tests__/claude-interactive-transcript-recovery.test.d.ts.map +1 -0
- package/dist/src/engines/__tests__/claude-interactive-transcript-recovery.test.js +84 -0
- package/dist/src/engines/__tests__/claude-interactive-transcript-recovery.test.js.map +1 -0
- package/dist/src/engines/__tests__/claude-interactive.test.js +107 -1
- package/dist/src/engines/__tests__/claude-interactive.test.js.map +1 -1
- package/dist/src/engines/claude-interactive.d.ts +45 -0
- package/dist/src/engines/claude-interactive.d.ts.map +1 -1
- package/dist/src/engines/claude-interactive.js +308 -15
- package/dist/src/engines/claude-interactive.js.map +1 -1
- package/dist/src/engines/sse-pty-proxy.d.ts +3 -0
- package/dist/src/engines/sse-pty-proxy.d.ts.map +1 -1
- package/dist/src/engines/sse-pty-proxy.js +5 -0
- package/dist/src/engines/sse-pty-proxy.js.map +1 -1
- package/dist/src/gateway/__tests__/status-reconciler.test.d.ts +2 -0
- package/dist/src/gateway/__tests__/status-reconciler.test.d.ts.map +1 -0
- package/dist/src/gateway/__tests__/status-reconciler.test.js +100 -0
- package/dist/src/gateway/__tests__/status-reconciler.test.js.map +1 -0
- package/dist/src/gateway/server.d.ts.map +1 -1
- package/dist/src/gateway/server.js +8 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/status-reconciler.d.ts +32 -0
- package/dist/src/gateway/status-reconciler.d.ts.map +1 -0
- package/dist/src/gateway/status-reconciler.js +74 -0
- package/dist/src/gateway/status-reconciler.js.map +1 -0
- package/dist/src/sessions/manager.d.ts.map +1 -1
- package/dist/src/sessions/manager.js +8 -2
- package/dist/src/sessions/manager.js.map +1 -1
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-interactive-transcript-recovery.test.d.ts","sourceRoot":"","sources":["../../../../src/engines/__tests__/claude-interactive-transcript-recovery.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
vi.mock("node-pty", () => ({ spawn: vi.fn() }));
|
|
6
|
+
import { findTranscriptForSession, lastAssistantTextFromTranscript, stripReasoningBlocks } from "../claude-interactive.js";
|
|
7
|
+
// Lost-Stop recovery reads the turn's final assistant message straight from
|
|
8
|
+
// Claude Code's on-disk transcript (~/.claude/projects/<cwd-slug>/<sid>.jsonl).
|
|
9
|
+
let tmp;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "transcript-recovery-"));
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
15
|
+
});
|
|
16
|
+
function writeTranscript(projectsDir, slugDir, sid, lines) {
|
|
17
|
+
const dir = path.join(projectsDir, slugDir);
|
|
18
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
19
|
+
const p = path.join(dir, `${sid}.jsonl`);
|
|
20
|
+
fs.writeFileSync(p, lines.map((l) => JSON.stringify(l)).join("\n"));
|
|
21
|
+
return p;
|
|
22
|
+
}
|
|
23
|
+
const assistantLine = (text, ts) => ({
|
|
24
|
+
type: "assistant",
|
|
25
|
+
...(ts ? { timestamp: ts } : {}),
|
|
26
|
+
message: { content: [{ type: "text", text }] },
|
|
27
|
+
});
|
|
28
|
+
describe("findTranscriptForSession", () => {
|
|
29
|
+
it("resolves the direct cwd-slug path", () => {
|
|
30
|
+
const projects = path.join(tmp, "projects");
|
|
31
|
+
const home = "/home/user/.ryoko";
|
|
32
|
+
const expected = writeTranscript(projects, "-home-user--ryoko", "sid-1", [assistantLine("hi")]);
|
|
33
|
+
expect(findTranscriptForSession("sid-1", home, projects)).toBe(expected);
|
|
34
|
+
});
|
|
35
|
+
it("falls back to scanning project dirs when the slug misses", () => {
|
|
36
|
+
const projects = path.join(tmp, "projects");
|
|
37
|
+
const expected = writeTranscript(projects, "-some-other-dir", "sid-2", [assistantLine("hi")]);
|
|
38
|
+
expect(findTranscriptForSession("sid-2", "/home/user/.ryoko", projects)).toBe(expected);
|
|
39
|
+
});
|
|
40
|
+
it("returns undefined for a missing session or projects dir", () => {
|
|
41
|
+
expect(findTranscriptForSession("nope", "/home/user/.ryoko", path.join(tmp, "absent"))).toBeUndefined();
|
|
42
|
+
expect(findTranscriptForSession("", "/home/user/.ryoko", tmp)).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("lastAssistantTextFromTranscript", () => {
|
|
46
|
+
it("returns the LAST assistant text block", () => {
|
|
47
|
+
const p = writeTranscript(path.join(tmp, "projects"), "-x", "sid-3", [
|
|
48
|
+
{ type: "user", message: { content: "question" } },
|
|
49
|
+
assistantLine("first"),
|
|
50
|
+
{ type: "system", subtype: "turn_duration" },
|
|
51
|
+
assistantLine("final answer"),
|
|
52
|
+
]);
|
|
53
|
+
expect(lastAssistantTextFromTranscript(p)).toBe("final answer");
|
|
54
|
+
});
|
|
55
|
+
it("honors the afterMs filter — pre-turn history is not 'recovered'", () => {
|
|
56
|
+
const p = writeTranscript(path.join(tmp, "projects"), "-x", "sid-4", [
|
|
57
|
+
assistantLine("stale previous turn", "2026-07-01T00:00:00Z"),
|
|
58
|
+
assistantLine("this turn's answer", "2026-07-02T12:00:00Z"),
|
|
59
|
+
]);
|
|
60
|
+
const afterMs = Date.parse("2026-07-02T00:00:00Z");
|
|
61
|
+
expect(lastAssistantTextFromTranscript(p, afterMs)).toBe("this turn's answer");
|
|
62
|
+
const tooLate = Date.parse("2026-07-03T00:00:00Z");
|
|
63
|
+
expect(lastAssistantTextFromTranscript(p, tooLate)).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
it("skips unparseable lines and non-text content", () => {
|
|
66
|
+
const dir = path.join(tmp, "projects", "-x");
|
|
67
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
68
|
+
const p = path.join(dir, "sid-5.jsonl");
|
|
69
|
+
fs.writeFileSync(p, [
|
|
70
|
+
"not json at all",
|
|
71
|
+
JSON.stringify({ type: "assistant", message: { content: [{ type: "tool_use", name: "Bash" }] } }),
|
|
72
|
+
JSON.stringify(assistantLine("real text")),
|
|
73
|
+
].join("\n"));
|
|
74
|
+
expect(lastAssistantTextFromTranscript(p)).toBe("real text");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("stripReasoningBlocks", () => {
|
|
78
|
+
it("removes thinking/reasoning tags and fenced thinking blocks", () => {
|
|
79
|
+
expect(stripReasoningBlocks("<thinking>secret</thinking>\n\nanswer")).toBe("answer");
|
|
80
|
+
expect(stripReasoningBlocks("```thinking\nsecret\n```\nanswer")).toBe("answer");
|
|
81
|
+
expect(stripReasoningBlocks("plain answer")).toBe("plain answer");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=claude-interactive-transcript-recovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-interactive-transcript-recovery.test.js","sourceRoot":"","sources":["../../../../src/engines/__tests__/claude-interactive-transcript-recovery.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { describe, it, expect, vi } from "vitest";
|
|
|
5
5
|
// pure-JS class with zero PTY dependency, so mocking the module keeps the test
|
|
6
6
|
// focused and CI-portable.
|
|
7
7
|
vi.mock("node-pty", () => ({ spawn: vi.fn() }));
|
|
8
|
-
import { TurnResolver } from "../claude-interactive.js";
|
|
8
|
+
import { TurnResolver, isNativeClaudeCommand } from "../claude-interactive.js";
|
|
9
9
|
describe("TurnResolver", () => {
|
|
10
10
|
it("resolves only after BOTH SessionStart and Stop", async () => {
|
|
11
11
|
const r = new TurnResolver({ fallbackSessionId: "old" });
|
|
@@ -51,4 +51,110 @@ describe("TurnResolver", () => {
|
|
|
51
51
|
expect(r.stopFailure?.error).toBe("rate_limit");
|
|
52
52
|
});
|
|
53
53
|
});
|
|
54
|
+
describe("TurnResolver — StopFailure grace window (upstream port)", () => {
|
|
55
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
56
|
+
it("holds a server_error StopFailure in grace and settles with the error after expiry", async () => {
|
|
57
|
+
const r = new TurnResolver({ fallbackSessionId: "s", stopFailureGraceMs: 20 });
|
|
58
|
+
let resolved;
|
|
59
|
+
r.promise.then((v) => { resolved = v; });
|
|
60
|
+
r.onHook({ hook_event_name: "StopFailure", error: "server_error" });
|
|
61
|
+
await sleep(5);
|
|
62
|
+
expect(resolved).toBeUndefined(); // held in grace, not settled yet
|
|
63
|
+
await sleep(40);
|
|
64
|
+
expect(resolved?.error).toMatch(/server_error/);
|
|
65
|
+
expect(resolved?.numTurns).toBe(1);
|
|
66
|
+
});
|
|
67
|
+
it("a later Stop supersedes the graced failure — the CLI retried and finished", async () => {
|
|
68
|
+
const r = new TurnResolver({ fallbackSessionId: "s", assumeStarted: true, stopFailureGraceMs: 50 });
|
|
69
|
+
r.onHook({ hook_event_name: "StopFailure", error: "server_error" });
|
|
70
|
+
await sleep(5);
|
|
71
|
+
r.onHook({ hook_event_name: "Stop", last_assistant_message: "recovered answer" });
|
|
72
|
+
const v = await r.promise;
|
|
73
|
+
expect(v.error).toBeUndefined();
|
|
74
|
+
expect(v.result).toBe("recovered answer");
|
|
75
|
+
expect(r.stopFailure).toBeUndefined(); // superseded, not exposed
|
|
76
|
+
});
|
|
77
|
+
it("tool-hook activity re-arms the grace window", async () => {
|
|
78
|
+
const r = new TurnResolver({ fallbackSessionId: "s", stopFailureGraceMs: 30 });
|
|
79
|
+
let resolved;
|
|
80
|
+
r.promise.then((v) => { resolved = v; });
|
|
81
|
+
r.onHook({ hook_event_name: "StopFailure", error: "server_error" });
|
|
82
|
+
// Keep feeding activity past the original 30ms window.
|
|
83
|
+
for (let i = 0; i < 4; i++) {
|
|
84
|
+
await sleep(15);
|
|
85
|
+
r.onHook({ hook_event_name: "PostToolUse", tool_name: "Bash" });
|
|
86
|
+
}
|
|
87
|
+
expect(resolved).toBeUndefined(); // still alive well past 30ms
|
|
88
|
+
await sleep(60); // quiet — grace finally expires
|
|
89
|
+
expect(resolved?.error).toMatch(/server_error/);
|
|
90
|
+
});
|
|
91
|
+
it("defers settling while shouldDeferStopFailure reports in-flight work", async () => {
|
|
92
|
+
let busy = true;
|
|
93
|
+
const r = new TurnResolver({ fallbackSessionId: "s", stopFailureGraceMs: 10, shouldDeferStopFailure: () => busy });
|
|
94
|
+
let resolved;
|
|
95
|
+
r.promise.then((v) => { resolved = v; });
|
|
96
|
+
r.onHook({ hook_event_name: "StopFailure", error: "server_error" });
|
|
97
|
+
await sleep(40);
|
|
98
|
+
expect(resolved).toBeUndefined(); // deferred — sub-agent still streaming
|
|
99
|
+
busy = false;
|
|
100
|
+
await sleep(30);
|
|
101
|
+
expect(resolved?.error).toMatch(/server_error/);
|
|
102
|
+
});
|
|
103
|
+
it("rate_limit / authentication_failed still settle immediately", async () => {
|
|
104
|
+
for (const error of ["rate_limit", "authentication_failed", "billing_error", "max_output_tokens"]) {
|
|
105
|
+
const r = new TurnResolver({ fallbackSessionId: "s", stopFailureGraceMs: 10_000 });
|
|
106
|
+
r.onHook({ hook_event_name: "StopFailure", error });
|
|
107
|
+
const v = await r.promise; // resolves without waiting for any grace
|
|
108
|
+
expect(v.error).toContain(error);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
it("PTY death with a pending graced failure reports the API error, not 'process exited'", async () => {
|
|
112
|
+
const r = new TurnResolver({ fallbackSessionId: "s", stopFailureGraceMs: 10_000 });
|
|
113
|
+
r.onHook({ hook_event_name: "StopFailure", error: "server_error" });
|
|
114
|
+
r.interrupt("Interrupted: claude process exited");
|
|
115
|
+
const v = await r.promise;
|
|
116
|
+
expect(v.error).toMatch(/server_error/);
|
|
117
|
+
});
|
|
118
|
+
it("strips leaked thinking blocks from Stop hook assistant text", async () => {
|
|
119
|
+
const r = new TurnResolver({ fallbackSessionId: "warm-sid", assumeStarted: true });
|
|
120
|
+
r.onHook({
|
|
121
|
+
hook_event_name: "Stop",
|
|
122
|
+
last_assistant_message: "<thinking>private reasoning</thinking>\n\nVisible answer.",
|
|
123
|
+
});
|
|
124
|
+
const v = await r.promise;
|
|
125
|
+
expect(v.result).toBe("Visible answer.");
|
|
126
|
+
});
|
|
127
|
+
it("can recover-complete a turn when the Stop hook is missing", async () => {
|
|
128
|
+
const r = new TurnResolver({ fallbackSessionId: "old" });
|
|
129
|
+
r.onHook({ hook_event_name: "SessionStart", session_id: "c1" });
|
|
130
|
+
r.completeRecovered("transcript final", "c1");
|
|
131
|
+
const v = await r.promise;
|
|
132
|
+
expect(v.result).toBe("transcript final");
|
|
133
|
+
expect(v.sessionId).toBe("c1");
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe("native Claude command handling (upstream port)", () => {
|
|
137
|
+
it("classifies native local commands", () => {
|
|
138
|
+
expect(isNativeClaudeCommand("/compact")).toBe(true);
|
|
139
|
+
expect(isNativeClaudeCommand("/usage")).toBe(true);
|
|
140
|
+
expect(isNativeClaudeCommand(" /model opus")).toBe(true);
|
|
141
|
+
expect(isNativeClaudeCommand("/init")).toBe(false); // real-turn command
|
|
142
|
+
expect(isNativeClaudeCommand("hello /compact")).toBe(false);
|
|
143
|
+
expect(isNativeClaudeCommand("")).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
it("a native turn's Stop settles EMPTY — stale last_assistant_message is not persisted", async () => {
|
|
146
|
+
const r = new TurnResolver({ fallbackSessionId: "warm-sid", assumeStarted: true, native: true });
|
|
147
|
+
r.onHook({ hook_event_name: "Stop", last_assistant_message: "PREVIOUS turn's text" });
|
|
148
|
+
const v = await r.promise;
|
|
149
|
+
expect(v.result).toBe("");
|
|
150
|
+
expect(v.error).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
it("completeNativeCommand settles empty (context mutators fire no Stop at all)", async () => {
|
|
153
|
+
const r = new TurnResolver({ fallbackSessionId: "warm-sid", assumeStarted: true, native: true });
|
|
154
|
+
r.completeNativeCommand();
|
|
155
|
+
const v = await r.promise;
|
|
156
|
+
expect(v.result).toBe("");
|
|
157
|
+
expect(v.numTurns).toBe(1);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
54
160
|
//# sourceMappingURL=claude-interactive.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-interactive.test.js","sourceRoot":"","sources":["../../../../src/engines/__tests__/claude-interactive.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,2BAA2B;AAC3B,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-interactive.test.js","sourceRoot":"","sources":["../../../../src/engines/__tests__/claude-interactive.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,21 @@ import type { PtyControlEvent, PtyViewEngine, PtyIdleSpawnOpts } from "./pty-vie
|
|
|
4
4
|
import type { HookRegistry, HookPayload } from "../gateway/hook-registry.js";
|
|
5
5
|
import { type SseDataEvent } from "./sse-pty-proxy.js";
|
|
6
6
|
export type { PtyControlEvent } from "./pty-view-engine.js";
|
|
7
|
+
/** Claude Code stores per-project transcripts at
|
|
8
|
+
* ~/.claude/projects/<cwd-slug>/<claudeSessionId>.jsonl, where the slug is the
|
|
9
|
+
* cwd with every "/" and "." replaced by "-". Derive that path; fall back to a
|
|
10
|
+
* scan across project dirs if the slug heuristic misses (defensive). Exported
|
|
11
|
+
* for the transcript-recovery unit test. (Ported from upstream jinn.) */
|
|
12
|
+
export declare function findTranscriptForSession(claudeSessionId: string, homeDir?: string, projectsDir?: string): string | undefined;
|
|
13
|
+
/** Last assistant text block from a Claude transcript — the turn's final
|
|
14
|
+
* message. Used to recover result text when the Stop hook (which normally
|
|
15
|
+
* carries last_assistant_message) was lost (gateway restart deleting
|
|
16
|
+
* gateway.json mid-turn, PTY crash, or relay drop), so the reply shows real
|
|
17
|
+
* output instead of "(no output)". Exported for tests. */
|
|
18
|
+
export declare function lastAssistantTextFromTranscript(transcriptPath: string, afterMs?: number): string | undefined;
|
|
19
|
+
/** Strip model reasoning blocks that occasionally leak into
|
|
20
|
+
* last_assistant_message / transcript text — they are never user-facing. */
|
|
21
|
+
export declare function stripReasoningBlocks(text: string): string;
|
|
7
22
|
/**
|
|
8
23
|
* Translate one parsed Anthropic SSE `data:` event into StreamDeltas. This is the
|
|
9
24
|
* live streaming source (replacing the old transcript tailer): word-by-word text
|
|
@@ -23,6 +38,15 @@ export interface TurnResolverOpts {
|
|
|
23
38
|
* SessionStart (it already fired once at process start) and pre-fills the
|
|
24
39
|
* Claude session id from fallbackSessionId. */
|
|
25
40
|
assumeStarted?: boolean;
|
|
41
|
+
/** Test override for the StopFailure grace window (default 20s). */
|
|
42
|
+
stopFailureGraceMs?: number;
|
|
43
|
+
/** While true, a graced StopFailure keeps waiting instead of settling. */
|
|
44
|
+
shouldDeferStopFailure?: () => boolean;
|
|
45
|
+
/** This turn is a Claude-native local command (see isNativeClaudeCommand). Such
|
|
46
|
+
* commands produce no new assistant message, so a Stop hook's
|
|
47
|
+
* last_assistant_message is the PREVIOUS turn's stale text — maybeComplete must
|
|
48
|
+
* settle empty rather than re-persist it as a duplicate. */
|
|
49
|
+
native?: boolean;
|
|
26
50
|
}
|
|
27
51
|
/** State machine for one interactive turn: resolves after BOTH SessionStart + Stop, or on StopFailure/interrupt. */
|
|
28
52
|
export declare class TurnResolver {
|
|
@@ -34,18 +58,31 @@ export declare class TurnResolver {
|
|
|
34
58
|
private gotSessionStart;
|
|
35
59
|
private stopPayload;
|
|
36
60
|
private stopFailurePayload;
|
|
61
|
+
private graceTimer;
|
|
37
62
|
constructor(opts: TurnResolverOpts);
|
|
38
63
|
onHook(h: HookPayload): void;
|
|
39
64
|
/** Claude session id learned so far (for engineSessionId persistence on warm-PTY turns). */
|
|
40
65
|
get sessionId(): string | undefined;
|
|
66
|
+
get isSettled(): boolean;
|
|
41
67
|
/** The StopFailure payload, if the turn ended in an API error (Task 5.3 maps it to rateLimit). */
|
|
42
68
|
get stopFailure(): HookPayload | undefined;
|
|
43
69
|
/** transcript_path from whichever hook carried it. */
|
|
44
70
|
get transcriptPath(): string | undefined;
|
|
45
71
|
private maybeComplete;
|
|
46
72
|
interrupt(reason: string): void;
|
|
73
|
+
/** Settle a native local command (no Stop hook fires for context mutators). */
|
|
74
|
+
completeNativeCommand(): void;
|
|
75
|
+
/** Settle with text recovered from the transcript (the Stop hook was lost). */
|
|
76
|
+
completeRecovered(text: string, sessionId?: string): void;
|
|
77
|
+
/** Proof of life (SSE delta / tool hook) while a StopFailure is pending —
|
|
78
|
+
* re-arms the grace window. No-op when no failure is pending. */
|
|
79
|
+
noteActivity(): void;
|
|
80
|
+
private armGrace;
|
|
81
|
+
private clearGrace;
|
|
82
|
+
private settleWithFailure;
|
|
47
83
|
private settle;
|
|
48
84
|
}
|
|
85
|
+
export declare function isNativeClaudeCommand(prompt: string): boolean;
|
|
49
86
|
export declare class InteractiveClaudeEngine implements InterruptibleEngine, PtyViewEngine {
|
|
50
87
|
private lifecycle;
|
|
51
88
|
private hookRegistry;
|
|
@@ -69,6 +106,9 @@ export declare class InteractiveClaudeEngine implements InterruptibleEngine, Pty
|
|
|
69
106
|
* `onStream` is the current turn's delta callback; the per-PTY SSE proxy routes
|
|
70
107
|
* parsed events here (a PTY outlives its turn, so the proxy looks this up live). */
|
|
71
108
|
private active;
|
|
109
|
+
/** Epoch ms of the most recent PTY output per session — the quiet-window
|
|
110
|
+
* signal for native-command settle and lost-Stop recovery. */
|
|
111
|
+
private lastOutputAt;
|
|
72
112
|
/** Sessions with an in-flight async idle-spawn (proxy.start awaited) — prevents
|
|
73
113
|
* a second ensureIdleSpawn from racing in a duplicate PTY during that gap. */
|
|
74
114
|
private idleSpawning;
|
|
@@ -173,6 +213,11 @@ export declare class InteractiveClaudeEngine implements InterruptibleEngine, Pty
|
|
|
173
213
|
* PtyLifecycleManager.isBusy so the keep-warm reaper / LRU eviction never
|
|
174
214
|
* kills a PTY mid-work. */
|
|
175
215
|
isEngineBusy(sessionId: string): boolean;
|
|
216
|
+
/** True while an upstream API request is streaming through the session's SSE
|
|
217
|
+
* proxy RIGHT NOW (no recency window — strictly in-flight). Used to defer a
|
|
218
|
+
* graced StopFailure (a sub-agent error while the main agent still works)
|
|
219
|
+
* and to hold lost-Stop recovery while the model is mid-request. */
|
|
220
|
+
private hasInflightUpstream;
|
|
176
221
|
/** Out-of-turn engine activity observed via an orphan hook (a background
|
|
177
222
|
* continuation firing PreToolUse/PostToolUse/Stop after its turn settled).
|
|
178
223
|
* Restarts the PTY keep-warm grace window so active background work — which
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-interactive.d.ts","sourceRoot":"","sources":["../../../src/engines/claude-interactive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"claude-interactive.d.ts","sourceRoot":"","sources":["../../../src/engines/claude-interactive.ts"],"names":[],"mappings":"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"}
|