@parall/claude-agent 1.58.2 → 1.60.0

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.
@@ -0,0 +1,56 @@
1
+ import type { RuntimeBusyState } from '@parall/agent-core';
2
+ import type { ClaudeRuntimeTaskEvent } from './output-parser.js';
3
+ export type ClaudeBackgroundTask = {
4
+ taskId: string;
5
+ description?: string;
6
+ /** Ambient tasks (e.g. Monitor) never finish on their own. */
7
+ ambient: boolean;
8
+ };
9
+ export type ClaudeTaskNotification = {
10
+ taskId?: string;
11
+ status?: string;
12
+ summary?: string;
13
+ description?: string;
14
+ at: number;
15
+ };
16
+ /** Default follow-up hold after a background task finishes (ms). */
17
+ export declare const DEFAULT_FOLLOW_UP_HOLD_MS = 30000;
18
+ /**
19
+ * Per-process background-work ledger fed by the CLI's task frames
20
+ * (`system/background_tasks_changed`, `task_started`, `task_notification`).
21
+ *
22
+ * `busy` is: a turn is running, OR a background task finished within the
23
+ * follow-up hold and the CLI has not yet started (or folded) the follow-up
24
+ * turn it usually runs on that notification. Outstanding background tasks by
25
+ * themselves are NOT busy — a `make dev` may run forever and must never
26
+ * block a restart or a shutdown drain.
27
+ */
28
+ export declare class ClaudeBusyTracker {
29
+ private readonly holdMs;
30
+ readonly backgroundTasks: Map<string, ClaudeBackgroundTask>;
31
+ followUpHoldUntil: number | null;
32
+ lastNotification: ClaudeTaskNotification | undefined;
33
+ /**
34
+ * Descriptions of tasks that already left the live set: the REPLACE frame
35
+ * arrives BEFORE the task_notification for the task it removed, and the
36
+ * notification itself carries only a summary.
37
+ */
38
+ private readonly finishedDescriptions;
39
+ constructor(holdMs?: number);
40
+ onTaskFrame(frame: ClaudeRuntimeTaskEvent, now?: number): void;
41
+ /** A turn started (dispatch or runtime-initiated): the hold did its job. */
42
+ clearHold(): void;
43
+ holdActive(now?: number): boolean;
44
+ /** The hold's expiry while it is still pending, else undefined. */
45
+ activeHoldUntil(now?: number): number | undefined;
46
+ /** The notification a runtime-initiated turn most plausibly follows. */
47
+ takeRecentNotification(now?: number): ClaudeTaskNotification | undefined;
48
+ outstanding(): {
49
+ total: number;
50
+ ambient: number;
51
+ };
52
+ /** Background shells die with the process. */
53
+ reset(): void;
54
+ }
55
+ export declare function aggregateBusyState(states: RuntimeBusyState[]): RuntimeBusyState;
56
+ //# sourceMappingURL=busy-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"busy-state.d.ts","sourceRoot":"","sources":["../src/busy-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAWhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVnC,QAAQ,CAAC,eAAe,oCAA2C;IACnE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,gBAAgB,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACrD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA0D;gBAElE,MAAM,GAAE,MAAkC;IAEvE,WAAW,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,SAAa,GAAG,IAAI;IA6DlE,4EAA4E;IAC5E,SAAS,IAAI,IAAI;IAIjB,UAAU,CAAC,GAAG,SAAa,GAAG,OAAO;IAIrC,mEAAmE;IACnE,eAAe,CAAC,GAAG,SAAa,GAAG,MAAM,GAAG,SAAS;IAMrD,wEAAwE;IACxE,sBAAsB,CAAC,GAAG,SAAa,GAAG,sBAAsB,GAAG,SAAS;IAS5E,WAAW,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAMjD,8CAA8C;IAC9C,KAAK,IAAI,IAAI;CAMd;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,CAY/E"}
@@ -0,0 +1,140 @@
1
+ /** Default follow-up hold after a background task finishes (ms). */
2
+ export const DEFAULT_FOLLOW_UP_HOLD_MS = 30_000;
3
+ /**
4
+ * Per-process background-work ledger fed by the CLI's task frames
5
+ * (`system/background_tasks_changed`, `task_started`, `task_notification`).
6
+ *
7
+ * `busy` is: a turn is running, OR a background task finished within the
8
+ * follow-up hold and the CLI has not yet started (or folded) the follow-up
9
+ * turn it usually runs on that notification. Outstanding background tasks by
10
+ * themselves are NOT busy — a `make dev` may run forever and must never
11
+ * block a restart or a shutdown drain.
12
+ */
13
+ export class ClaudeBusyTracker {
14
+ holdMs;
15
+ backgroundTasks = new Map();
16
+ followUpHoldUntil = null;
17
+ lastNotification;
18
+ /**
19
+ * Descriptions of tasks that already left the live set: the REPLACE frame
20
+ * arrives BEFORE the task_notification for the task it removed, and the
21
+ * notification itself carries only a summary.
22
+ */
23
+ finishedDescriptions = new Map();
24
+ constructor(holdMs = DEFAULT_FOLLOW_UP_HOLD_MS) {
25
+ this.holdMs = holdMs;
26
+ }
27
+ onTaskFrame(frame, now = Date.now()) {
28
+ switch (frame.subtype) {
29
+ case 'background_tasks_changed': {
30
+ // REPLACE semantics: the frame lists every live task after the change.
31
+ const next = new Map();
32
+ for (const task of frame.tasks ?? []) {
33
+ const prior = this.backgroundTasks.get(task.taskId);
34
+ next.set(task.taskId, {
35
+ taskId: task.taskId,
36
+ description: task.description ?? prior?.description,
37
+ ambient: task.ambient ?? prior?.ambient ?? false,
38
+ });
39
+ }
40
+ for (const [id, task] of this.backgroundTasks) {
41
+ if (!next.has(id) && task.description) {
42
+ this.finishedDescriptions.set(id, { description: task.description, at: now });
43
+ }
44
+ }
45
+ // Nothing older than takeRecentNotification's horizon is ever read
46
+ // again: tasks that ended without a notification must not accumulate.
47
+ for (const [id, entry] of this.finishedDescriptions) {
48
+ if (now - entry.at > this.holdMs * 2)
49
+ this.finishedDescriptions.delete(id);
50
+ }
51
+ this.backgroundTasks.clear();
52
+ for (const [id, task] of next)
53
+ this.backgroundTasks.set(id, task);
54
+ return;
55
+ }
56
+ case 'task_started': {
57
+ if (!frame.taskId || frame.isBackgrounded === false)
58
+ return;
59
+ const prior = this.backgroundTasks.get(frame.taskId);
60
+ this.backgroundTasks.set(frame.taskId, {
61
+ taskId: frame.taskId,
62
+ description: frame.description ?? prior?.description,
63
+ ambient: prior?.ambient ?? false,
64
+ });
65
+ return;
66
+ }
67
+ case 'task_notification': {
68
+ const prior = frame.taskId ? this.backgroundTasks.get(frame.taskId) : undefined;
69
+ const finished = frame.taskId ? this.finishedDescriptions.get(frame.taskId) : undefined;
70
+ if (frame.taskId) {
71
+ this.backgroundTasks.delete(frame.taskId);
72
+ this.finishedDescriptions.delete(frame.taskId);
73
+ }
74
+ this.lastNotification = {
75
+ taskId: frame.taskId,
76
+ status: frame.status,
77
+ summary: frame.summary,
78
+ description: prior?.description ?? finished?.description ?? frame.description,
79
+ at: now,
80
+ };
81
+ // Unconditional: if the notification folds into a running turn the
82
+ // hold expires harmlessly (bounded by holdMs).
83
+ this.followUpHoldUntil = now + this.holdMs;
84
+ return;
85
+ }
86
+ default:
87
+ return;
88
+ }
89
+ }
90
+ /** A turn started (dispatch or runtime-initiated): the hold did its job. */
91
+ clearHold() {
92
+ this.followUpHoldUntil = null;
93
+ }
94
+ holdActive(now = Date.now()) {
95
+ return this.activeHoldUntil(now) !== undefined;
96
+ }
97
+ /** The hold's expiry while it is still pending, else undefined. */
98
+ activeHoldUntil(now = Date.now()) {
99
+ return this.followUpHoldUntil !== null && this.followUpHoldUntil > now
100
+ ? this.followUpHoldUntil
101
+ : undefined;
102
+ }
103
+ /** The notification a runtime-initiated turn most plausibly follows. */
104
+ takeRecentNotification(now = Date.now()) {
105
+ const notification = this.lastNotification;
106
+ this.lastNotification = undefined;
107
+ if (!notification)
108
+ return undefined;
109
+ // A notification older than two hold windows is not "recent" — the
110
+ // turn opening now is more likely unrelated; report it as such.
111
+ return now - notification.at <= this.holdMs * 2 ? notification : undefined;
112
+ }
113
+ outstanding() {
114
+ let ambient = 0;
115
+ for (const task of this.backgroundTasks.values())
116
+ if (task.ambient)
117
+ ambient += 1;
118
+ return { total: this.backgroundTasks.size, ambient };
119
+ }
120
+ /** Background shells die with the process. */
121
+ reset() {
122
+ this.backgroundTasks.clear();
123
+ this.finishedDescriptions.clear();
124
+ this.followUpHoldUntil = null;
125
+ this.lastNotification = undefined;
126
+ }
127
+ }
128
+ export function aggregateBusyState(states) {
129
+ let activeTurns = 0;
130
+ let backgroundWork = 0;
131
+ let holdUntil;
132
+ for (const state of states) {
133
+ activeTurns += state.activeTurns;
134
+ backgroundWork += state.backgroundWork;
135
+ if (state.holdUntil !== undefined && (holdUntil === undefined || state.holdUntil > holdUntil)) {
136
+ holdUntil = state.holdUntil;
137
+ }
138
+ }
139
+ return { activeTurns, backgroundWork, ...(holdUntil !== undefined ? { holdUntil } : {}) };
140
+ }
@@ -0,0 +1,29 @@
1
+ import type { CompactOpts, CompactResult, GatewayLogger } from '@parall/agent-core';
2
+ import type { ProcessState } from './dispatch.js';
3
+ import type { ClaudeProcessHandle } from './session-manager.js';
4
+ /**
5
+ * Idle auto-compact on the Claude bridge (idle-auto-compact-design.md §3.4):
6
+ * write a `/compact` user frame into the long-lived process — the Agent
7
+ * SDK's documented way to run the built-in — and wait for that command's
8
+ * lifecycle to settle. The process pump (process-pump.ts) is the only
9
+ * stdout reader: the command is registered like a dispatch delivery, the
10
+ * pump routes its frames into the delivery's sink and records the evidence
11
+ * on it — a `system/compact_boundary` means the CLI folded history (`done`);
12
+ * a result without one is the CLI declining ("Not enough messages to
13
+ * compact." — `noop`). The gateway holds the lane, so no dispatch shares the
14
+ * process while this runs. Nothing here persists steps, sends messages or
15
+ * touches session status.
16
+ *
17
+ * The host is the narrow slice of ClaudeCodeAdapter's process bookkeeping
18
+ * this needs; the adapter's `compact()` is a thin delegate.
19
+ */
20
+ export interface ClaudeCompactHost {
21
+ ensureRuntimeCapability(log: GatewayLogger | undefined): Promise<void>;
22
+ ensureProcess(sessionKey: string, log: GatewayLogger | undefined): ProcessState;
23
+ killProcess(sessionKey: string, state: ProcessState): void;
24
+ writeUserMessage(handle: ClaudeProcessHandle, text: string, commandUuid: string): void;
25
+ /** Lazy restart re-check once the command settled (the adapter's own gate). */
26
+ applyPendingRestart(sessionKey: string, state: ProcessState): void;
27
+ }
28
+ export declare function runClaudeCompact(host: ClaudeCompactHost, { sessionKey, signal, log }: CompactOpts): Promise<CompactResult>;
29
+ //# sourceMappingURL=compact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact.d.ts","sourceRoot":"","sources":["../src/compact.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;IAChF,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3D,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACvF,+EAA+E;IAC/E,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CACpE;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,iBAAiB,EACvB,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,WAAW,GACvC,OAAO,CAAC,aAAa,CAAC,CA4BxB"}
@@ -0,0 +1,98 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export async function runClaudeCompact(host, { sessionKey, signal, log }) {
3
+ if (signal.aborted)
4
+ return { status: 'timeout' };
5
+ let state;
6
+ try {
7
+ await host.ensureRuntimeCapability(log);
8
+ state = host.ensureProcess(sessionKey, log);
9
+ }
10
+ catch (err) {
11
+ return { status: 'failed', detail: `Claude spawn failed: ${String(err)}` };
12
+ }
13
+ // Defensive: an injection still owing bookkeeping means a dispatch is
14
+ // not actually settled on this session — the gateway never gets here in
15
+ // that state, but a compaction must not steal its frames.
16
+ if (state.inputs.hasPendingInjections() || state.inputs.hasUnsettledInjections()) {
17
+ return { status: 'failed', detail: 'injections still pending on the session' };
18
+ }
19
+ const delivery = state.inputs.register(`compact:${randomUUID()}`, undefined, false);
20
+ try {
21
+ host.writeUserMessage(state.handle, '/compact', delivery.commandUuid);
22
+ }
23
+ catch (err) {
24
+ state.inputs.remove(delivery);
25
+ host.killProcess(sessionKey, state);
26
+ return { status: 'failed', detail: `Claude stdin write failed: ${String(err)}` };
27
+ }
28
+ try {
29
+ return await consumeCompact(host, sessionKey, state, delivery, signal, log);
30
+ }
31
+ finally {
32
+ state.inputs.remove(delivery);
33
+ }
34
+ }
35
+ /**
36
+ * Drain the command's sink until its lifecycle settles. The pump already
37
+ * did the process bookkeeping (init, lifecycle, EOF); this only reads the
38
+ * evidence it left on the delivery. On abort the process is SIGTERMed — the
39
+ * session survives via --resume on the next spawn — and the pump's `killed`
40
+ * envelope reports `timeout`.
41
+ */
42
+ async function consumeCompact(host, sessionKey, state, target, signal, log) {
43
+ const onAbort = () => host.killProcess(sessionKey, state);
44
+ signal.addEventListener('abort', onAbort, { once: true });
45
+ // The budget may have expired while the process was being spawned or the
46
+ // frame written; an abort that already fired never reaches the listener,
47
+ // and without the kill the sink drain below would never settle — and the
48
+ // gateway's main-lane hold would leak with it.
49
+ if (signal.aborted)
50
+ onAbort();
51
+ try {
52
+ while (true) {
53
+ const next = await target.sink.next();
54
+ if (next.done)
55
+ break;
56
+ const envelope = next.value;
57
+ if (envelope.kind === 'runtime')
58
+ continue; // the summary's own frames: progress only
59
+ if (envelope.kind === 'terminal')
60
+ break;
61
+ // The process is gone (eof / killed) or the pump ended this window.
62
+ const detail = state.handle.stderrChunks.join('').trim();
63
+ if (detail)
64
+ log?.warn?.(`subprocess stderr: ${detail}`);
65
+ if (signal.aborted)
66
+ return { status: 'timeout', detail: detail || undefined };
67
+ const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null }));
68
+ return {
69
+ status: 'failed',
70
+ detail: detail ||
71
+ envelope.message ||
72
+ `Claude exited with code ${exit.code ?? 'unknown'}${exit.signal ? ` (${exit.signal})` : ''}`,
73
+ };
74
+ }
75
+ }
76
+ finally {
77
+ signal.removeEventListener('abort', onAbort);
78
+ }
79
+ host.applyPendingRestart(sessionKey, state);
80
+ const { compactBoundary, zeroTurnResultMeta, lastResultMeta } = target.evidence;
81
+ // The /compact result frame reports num_turns 0 (no model turn ran on the
82
+ // user's behalf): it is this command's boundary, not the resume poison
83
+ // frame, so it is read from the zero-turn slot first.
84
+ const result = zeroTurnResultMeta ?? lastResultMeta;
85
+ if (compactBoundary) {
86
+ return {
87
+ status: 'done',
88
+ ...(compactBoundary.preTokens !== undefined ? { preTokens: compactBoundary.preTokens } : {}),
89
+ };
90
+ }
91
+ if (result?.isError) {
92
+ return { status: 'failed', detail: result.resultText || 'compact result reported an error' };
93
+ }
94
+ if (target.terminal !== 'completed') {
95
+ return { status: 'failed', detail: `compact command ${target.terminal}` };
96
+ }
97
+ return { status: 'noop', detail: result?.resultText || 'no compact boundary emitted' };
98
+ }
@@ -1,6 +1,8 @@
1
- import type { CleanupForkOpts, DispatchAdapter, DispatchInputLifecycle, DispatchOpts, ForkOpts, RuntimeEvent } from '@parall/agent-core';
1
+ import type { CleanupForkOpts, CompactOpts, CompactResult, DispatchAdapter, DispatchInputLifecycle, DispatchOpts, ForkOpts, GatewayLogger, RuntimeActivityEvent, RuntimeBusyState, RuntimeEvent } from '@parall/agent-core';
2
2
  import type { ClaudeAgentConfig } from './config.js';
3
- import type { ClaudeSessionManager } from './session-manager.js';
3
+ import { ClaudeInputRegistry } from './input-lifecycle.js';
4
+ import { ClaudeProcessPump } from './process-pump.js';
5
+ import type { ClaudeProcessHandle, ClaudeSessionManager } from './session-manager.js';
4
6
  import { buildSpawnEnv } from './spawn-env.js';
5
7
  export { buildSpawnEnv };
6
8
  type ClaudeCodeAdapterOptions = Pick<ClaudeAgentConfig, 'additionalDirs' | 'allowApiKey' | 'allowedTools' | 'appendSystemPrompt' | 'claudeBin' | 'claudeHome' | 'disallowedTools' | 'model' | 'permissionMode' | 'workspaceDir'> & {
@@ -32,14 +34,43 @@ type ClaudeCodeAdapterOptions = Pick<ClaudeAgentConfig, 'additionalDirs' | 'allo
32
34
  * subprocess on its next shell command — no respawn needed.
33
35
  */
34
36
  capabilityBinDir?: string;
37
+ /**
38
+ * How long the bridge stays busy after a background task finishes,
39
+ * waiting for the follow-up turn the CLI usually runs on that
40
+ * notification (busy-state.ts). Default 30 s.
41
+ */
42
+ followUpHoldMs?: number;
43
+ /** Test port. */
44
+ now?: () => number;
45
+ };
46
+ /**
47
+ * Per-sessionKey long-lived process state. The process stays alive across
48
+ * dispatches; each dispatch writes one NDJSON user message to stdin and
49
+ * drains the envelopes the stdout pump routes to that delivery until its
50
+ * lifecycle terminal. The pump (process-pump.ts) is the ONLY stdout reader:
51
+ * between dispatches it keeps reading, so turns the CLI starts on its own
52
+ * (background-task follow-ups) are observed instead of piling up in the
53
+ * pipe. Gateway's `drainMainBuffer` serializes dispatch calls per
54
+ * sessionKey, so no two drains compete for the same delivery.
55
+ */
56
+ export type ProcessState = {
57
+ handle: ClaudeProcessHandle;
58
+ pump: ClaudeProcessPump;
59
+ done: boolean;
60
+ needsRestart: boolean;
61
+ inputs: ClaudeInputRegistry;
62
+ log?: GatewayLogger;
35
63
  };
36
64
  export declare class ClaudeCodeAdapter implements DispatchAdapter {
37
65
  private readonly opts;
38
66
  readonly inputLifecycleMode: "explicit";
39
67
  private readonly processes;
68
+ /** Retired by abortDispatch while the CLI still had its own work: busy until idle, then terminated. */
69
+ private readonly retiring;
40
70
  private capabilityProbe?;
41
71
  private capabilityProbeHandle?;
42
72
  private shuttingDown;
73
+ private readonly activity;
43
74
  private _model;
44
75
  private _effortLevel;
45
76
  private _contextWindow;
@@ -54,9 +85,14 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
54
85
  maxTokens?: number | null;
55
86
  }): void;
56
87
  requestProcessRestart(): void;
88
+ subscribeRuntimeActivity(handler: (event: RuntimeActivityEvent) => void): () => void;
89
+ busyState(now?: number): RuntimeBusyState;
90
+ isBusy(now?: number): boolean;
57
91
  enqueueDuringDispatch(sessionKey: string, body: string, inputLifecycle?: DispatchInputLifecycle): boolean;
58
92
  abortDispatch(sessionKey: string): void;
59
93
  hasPendingInjections(sessionKey: string): boolean;
94
+ hasUnsettledInjections(sessionKey: string): boolean;
95
+ acknowledgeDiscardedInjection(sessionKey: string, deliveryKey: string): void;
60
96
  dispatch({ event, bodyForAgent, sessionKey, context, inputLifecycle, noteActivity, }: DispatchOpts): AsyncIterable<RuntimeEvent>;
61
97
  getBranchPoint(_sessionKey: string): string | undefined;
62
98
  getSessionHistoryPath(sessionKey: string): string | undefined;
@@ -64,7 +100,10 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
64
100
  cleanupFork({ fork }: CleanupForkOpts): void;
65
101
  resetProcesses(): void;
66
102
  shutdown(): Promise<void>;
103
+ private now;
67
104
  private runTurn;
105
+ /** Idle auto-compact (compact.ts): a `/compact` frame into the long-lived process. */
106
+ compact(opts: CompactOpts): Promise<CompactResult>;
68
107
  private ensureRuntimeCapability;
69
108
  /**
70
109
  * Claude does not emit system.init until it receives its first stdin
@@ -74,15 +113,24 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
74
113
  */
75
114
  private probeRuntimeCapability;
76
115
  /**
77
- * Drain the shared stdout stream until the exact UUID written for target
78
- * reaches a terminal lifecycle state. Other injected inputs may start and
79
- * finish while this drain is active; their callbacks advance independently
80
- * and their later bookkeeping dispatch becomes a no-op.
116
+ * Drain the envelopes the pump routed to `target` until its exact stdin
117
+ * UUID reaches a terminal lifecycle state. Other injected inputs may start
118
+ * and finish while this drain is active; their callbacks advance in the
119
+ * pump independently and their later bookkeeping dispatch becomes a no-op.
81
120
  */
82
121
  private consumeDelivery;
122
+ /**
123
+ * Lazy restart: kill the process so the next dispatch respawns it (the
124
+ * session survives via --resume). Waits for every injection to settle, for
125
+ * an open runtime-initiated turn and for a follow-up hold — but NOT for
126
+ * outstanding background tasks (a `make dev` would defer a config change
127
+ * forever); those die with the process, logged.
128
+ */
129
+ private maybeApplyRestart;
83
130
  private ensureProcess;
84
131
  private spawnProcess;
85
132
  private killProcess;
133
+ private endStdin;
86
134
  private terminateHandle;
87
135
  private writeCapabilityProbe;
88
136
  private writeUserMessage;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}