@adhdev/daemon-core 0.8.33 → 0.8.35

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.
Files changed (89) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +127 -102
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +127 -102
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/shared-types.d.ts +38 -0
  7. package/dist/status/reporter.d.ts +3 -0
  8. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  9. package/package.json +1 -1
  10. package/src/agent-stream/forward.d.ts +8 -0
  11. package/src/agent-stream/index.d.ts +6 -0
  12. package/src/agent-stream/manager.d.ts +60 -0
  13. package/src/agent-stream/poller.d.ts +41 -0
  14. package/src/agent-stream/provider-adapter.d.ts +36 -0
  15. package/src/agent-stream/types.d.ts +68 -0
  16. package/src/boot/daemon-lifecycle.d.ts +100 -0
  17. package/src/cdp/devtools.d.ts +51 -0
  18. package/src/cdp/initializer.d.ts +50 -0
  19. package/src/cdp/manager.d.ts +147 -0
  20. package/src/cdp/scanner.d.ts +58 -0
  21. package/src/cdp/setup.d.ts +58 -0
  22. package/src/cli-adapter-types.d.ts +57 -0
  23. package/src/cli-adapters/provider-cli-adapter.d.ts +177 -0
  24. package/src/cli-adapters/provider-cli-adapter.ts +115 -91
  25. package/src/cli-adapters/provider-cli-config.d.ts +30 -0
  26. package/src/cli-adapters/provider-cli-parse.d.ts +42 -0
  27. package/src/cli-adapters/provider-cli-runtime.d.ts +29 -0
  28. package/src/cli-adapters/provider-cli-shared.d.ts +158 -0
  29. package/src/cli-adapters/pty-transport.d.ts +48 -0
  30. package/src/cli-adapters/session-host-transport.d.ts +20 -0
  31. package/src/cli-adapters/spawn-env.d.ts +8 -0
  32. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +16 -0
  33. package/src/cli-adapters/terminal-backends/types.d.ts +18 -0
  34. package/src/cli-adapters/terminal-backends/xterm-backend.d.ts +17 -0
  35. package/src/cli-adapters/terminal-screen.d.ts +33 -0
  36. package/src/commands/cdp-commands.d.ts +15 -0
  37. package/src/commands/chat-commands.d.ts +15 -0
  38. package/src/commands/cli-manager.d.ts +94 -0
  39. package/src/commands/handler.d.ts +103 -0
  40. package/src/commands/router.d.ts +98 -0
  41. package/src/commands/stream-commands.d.ts +14 -0
  42. package/src/commands/upgrade-helper.d.ts +10 -0
  43. package/src/commands/workspace-commands.d.ts +11 -0
  44. package/src/config/chat-history.d.ts +99 -0
  45. package/src/config/config.d.ts +14 -0
  46. package/src/config/recent-activity.d.ts +29 -0
  47. package/src/config/saved-sessions.d.ts +22 -0
  48. package/src/config/state-store.d.ts +32 -0
  49. package/src/config/workspaces.d.ts +0 -1
  50. package/src/daemon/dev-auto-implement.d.ts +43 -0
  51. package/src/daemon/dev-cdp-handlers.d.ts +22 -0
  52. package/src/daemon/dev-cli-debug.d.ts +106 -0
  53. package/src/daemon/dev-server-types.d.ts +43 -0
  54. package/src/daemon/dev-server.d.ts +140 -0
  55. package/src/daemon/scaffold-template.d.ts +32 -0
  56. package/src/daemon-core.d.ts +36 -0
  57. package/src/detection/cli-detector.d.ts +31 -0
  58. package/src/detection/ide-detector.d.ts +35 -0
  59. package/src/index.d.ts +83 -0
  60. package/src/index.ts +2 -0
  61. package/src/installer.d.ts +50 -0
  62. package/src/ipc-protocol.d.ts +111 -0
  63. package/src/launch.d.ts +46 -0
  64. package/src/logging/command-log.d.ts +31 -0
  65. package/src/logging/logger.d.ts +89 -0
  66. package/src/providers/acp-provider-instance.d.ts +102 -0
  67. package/src/providers/approval-utils.d.ts +7 -0
  68. package/src/providers/cli-provider-instance.d.ts +86 -0
  69. package/src/providers/contracts.d.ts +193 -1
  70. package/src/providers/control-effects.d.ts +4 -0
  71. package/src/providers/extension-provider-instance.d.ts +61 -0
  72. package/src/providers/ide-provider-instance.d.ts +70 -0
  73. package/src/providers/provider-instance-manager.d.ts +84 -0
  74. package/src/providers/provider-instance.d.ts +7 -1
  75. package/src/providers/provider-loader.d.ts +299 -0
  76. package/src/providers/status-monitor.d.ts +48 -0
  77. package/src/providers/version-archive.d.ts +52 -0
  78. package/src/session-host/runtime-support.d.ts +8 -0
  79. package/src/sessions/reconcile.d.ts +22 -0
  80. package/src/sessions/registry.d.ts +24 -0
  81. package/src/shared-types-extra.d.ts +29 -0
  82. package/src/shared-types.d.ts +79 -22
  83. package/src/shared-types.ts +40 -0
  84. package/src/status/builders.d.ts +33 -0
  85. package/src/status/reporter.d.ts +69 -0
  86. package/src/status/reporter.ts +16 -13
  87. package/src/status/snapshot.d.ts +58 -0
  88. package/src/system/host-memory.d.ts +19 -0
  89. package/src/types.d.ts +3 -7
@@ -0,0 +1,58 @@
1
+ /**
2
+ * DaemonCdpScanner — Periodic CDP port scanning & auto-connect
3
+ *
4
+ * Periodic CDP port scanning and auto-connect for IDE discovery.
5
+ * Provides a unified approach to:
6
+ * 1. Initial CDP port discovery
7
+ * 2. Periodic scanning for newly launched IDEs
8
+ * 3. Multi-window support (multiple pages on same port)
9
+ */
10
+ import { DaemonCdpManager } from './manager.js';
11
+ import { type CdpSetupContext } from './setup.js';
12
+ export interface CdpScannerOptions {
13
+ /** Context for setup operations */
14
+ ctx: CdpSetupContext;
15
+ /** Log function for per-IDE CDP logs */
16
+ logFn?: (ideType: string) => (msg: string) => void;
17
+ /** Whether to support multi-window (multiple pages per port) */
18
+ multiWindow?: boolean;
19
+ /** Scan interval in ms (default: 30000) */
20
+ scanIntervalMs?: number;
21
+ /** Callback when a new CDP connection is established */
22
+ onConnected?: (ideType: string, managerKey: string, manager: DaemonCdpManager) => void;
23
+ }
24
+ export declare class DaemonCdpScanner {
25
+ private ctx;
26
+ private opts;
27
+ private scanTimer;
28
+ private discoveryTimer;
29
+ constructor(opts: CdpScannerOptions);
30
+ /**
31
+ * Initial CDP discovery — connect to all available IDEs.
32
+ * Supports both single-window and multi-window modes.
33
+ */
34
+ initialScan(enabledIdes?: string[]): Promise<void>;
35
+ /**
36
+ * Start periodic scanning for newly launched IDEs.
37
+ */
38
+ startPeriodicScan(): void;
39
+ /**
40
+ * Start periodic agent webview discovery on all connected CDPs.
41
+ */
42
+ startWebviewDiscovery(intervalMs?: number): void;
43
+ /**
44
+ * Stop all timers.
45
+ */
46
+ stop(): void;
47
+ private getLogFn;
48
+ /**
49
+ * Single-window connection (standalone mode).
50
+ * One CDP manager per IDE, first working port wins.
51
+ */
52
+ private connectSingleWindow;
53
+ /**
54
+ * Multi-window connection.
55
+ * Multiple CDP managers per IDE — one per workbench page.
56
+ */
57
+ private connectMultiWindow;
58
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * DaemonCdpSetup — Shared CDP initialization helpers
3
+ *
4
+ * Common CDP setup logic for consistent
5
+ * CDP → ProviderInstance registration.
6
+ */
7
+ import { DaemonCdpManager } from './manager.js';
8
+ import { ProviderLoader } from '../providers/provider-loader.js';
9
+ import { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
10
+ import { IdeProviderInstance } from '../providers/ide-provider-instance.js';
11
+ import { SessionRegistry } from '../sessions/registry.js';
12
+ export interface CdpSetupContext {
13
+ providerLoader: ProviderLoader;
14
+ instanceManager: ProviderInstanceManager;
15
+ cdpManagers: Map<string, DaemonCdpManager>;
16
+ sessionRegistry: SessionRegistry;
17
+ /** Server connection (optional) */
18
+ serverConn?: any;
19
+ }
20
+ export interface SetupIdeInstanceOptions {
21
+ /** Provider-based IDE type (e.g., 'antigravity', 'cursor') */
22
+ ideType: string;
23
+ /** Connected CDP manager */
24
+ manager: DaemonCdpManager;
25
+ /** CDP manager key (for multi-window: 'antigravity_remote_vs', single: 'antigravity') */
26
+ managerKey?: string;
27
+ /** Provider settings override */
28
+ settings?: Record<string, any>;
29
+ }
30
+ /**
31
+ * Register extension providers on a CDP manager.
32
+ * Common pattern used during CDP init and periodic scans.
33
+ */
34
+ export declare function registerExtensionProviders(providerLoader: ProviderLoader, manager: DaemonCdpManager, ideType: string): void;
35
+ /**
36
+ * Setup a CDP-connected IDE as a ProviderInstance.
37
+ *
38
+ * Performs:
39
+ * 1. providerLoader.resolve() to get scripts
40
+ * 2. Create IdeProviderInstance
41
+ * 3. Register in InstanceManager
42
+ * 4. Register enabled extensions
43
+ * 5. Register runtime sessions (workspace + extension children)
44
+ *
45
+ * @returns The created IdeProviderInstance, or null if provider not found
46
+ */
47
+ export declare function setupIdeInstance(ctx: CdpSetupContext, opts: SetupIdeInstanceOptions): Promise<IdeProviderInstance | null>;
48
+ /**
49
+ * Create and connect a DaemonCdpManager for a given port.
50
+ *
51
+ * @returns Connected manager or null if connection failed
52
+ */
53
+ export declare function connectCdpManager(port: number, ideType: string, logFn: (msg: string) => void, providerLoader: ProviderLoader, targetId?: string): Promise<DaemonCdpManager | null>;
54
+ /**
55
+ * Probe a CDP port to check if it's listening.
56
+ * @returns true if CDP is available on this port
57
+ */
58
+ export declare function probeCdpPort(port: number, timeoutMs?: number): Promise<boolean>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * CliAdapter — common interface for CLI agents
3
+ *
4
+ * Contract implemented by all CLI adapters (ProviderCliAdapter etc).
5
+ */
6
+ import type { ChatMessage } from './types.js';
7
+ export interface CliAdapterStatus {
8
+ status?: string;
9
+ messages?: ChatMessage[];
10
+ activeModal?: {
11
+ message: string;
12
+ buttons: string[];
13
+ } | null;
14
+ }
15
+ export interface AcpAdapterHandle {
16
+ onEvent(event: string, data?: unknown): void;
17
+ getState(): {
18
+ status: string;
19
+ activeChat?: {
20
+ messages?: ChatMessage[];
21
+ activeModal?: {
22
+ message: string;
23
+ buttons: string[];
24
+ } | null;
25
+ } | null;
26
+ };
27
+ setMode?(mode: string): Promise<void>;
28
+ setConfigOption?(configId: string, value: string): Promise<void>;
29
+ resolvePermission?(approved: boolean): Promise<void>;
30
+ }
31
+ export interface CliAdapter {
32
+ cliType: string;
33
+ cliName: string;
34
+ workingDir: string;
35
+ _acpInstance?: AcpAdapterHandle;
36
+ spawn(): Promise<void>;
37
+ sendMessage(text: string): Promise<void>;
38
+ getStatus(): CliAdapterStatus;
39
+ getScriptParsedStatus?(): unknown;
40
+ invokeScript?(scriptName: string, args?: Record<string, unknown>): Promise<unknown>;
41
+ getPartialResponse(): string;
42
+ saveAndStop?(): Promise<void>;
43
+ shutdown(): void;
44
+ detach?(): void;
45
+ cancel(): void;
46
+ isProcessing(): boolean;
47
+ isReady(): boolean;
48
+ setOnStatusChange(callback: () => void): void;
49
+ updateRuntimeSettings?(settings: Record<string, unknown>): void;
50
+ setServerConn?(serverConn: unknown): void;
51
+ clearHistory?(): void;
52
+ resolveAction?(data: unknown): Promise<void>;
53
+ resolveModal?(buttonIndex: number): void;
54
+ setOnPtyData?(callback: (data: string) => void): void;
55
+ writeRaw?(data: string): void;
56
+ resize?(cols: number, rows: number): void;
57
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * ProviderCliAdapter — Script-based CLI Adapter
3
+ *
4
+ * All CLI providers use versioned scripts (like IDE providers).
5
+ * Scripts are Node.js functions that receive PTY buffer data and return structured results.
6
+ *
7
+ * Required scripts in scripts/{version}/scripts.js:
8
+ * - detectStatus(input) → AgentStatus string ('idle' | 'generating' | 'waiting_approval')
9
+ * - parseOutput(input) → ReadChatResult { messages, status, activeModal, ... }
10
+ * - parseApproval(input) → ModalInfo | null
11
+ *
12
+ * provider.json contract:
13
+ * type, name, category: 'cli', binary, spawn, approvalKeys
14
+ * compatibility: [{ ideVersion, scriptDir }] ← versioned scripts
15
+ */
16
+ import type { CliAdapter } from '../cli-adapter-types.js';
17
+ import { type PtyRuntimeMetadata, type PtyTransportFactory } from './pty-transport.js';
18
+ import { type CliChatMessage, type CliProviderModule, type CliScripts, type CliSessionStatus } from './provider-cli-shared.js';
19
+ import { type ProviderResolutionMeta } from './provider-cli-config.js';
20
+ export { normalizeCliProviderForRuntime, type CliApprovalInput, type CliChatMessage, type CliProviderModule, type CliScreenLine, type CliScreenSnapshot, type CliScriptInput, type CliScripts, type CliSessionStatus, type CliStatusInput, type CliTraceEntry, } from './provider-cli-shared.js';
21
+ type SeedCliChatMessage = Omit<Partial<CliChatMessage>, 'role'> & {
22
+ role?: string;
23
+ content?: string;
24
+ };
25
+ export declare class ProviderCliAdapter implements CliAdapter {
26
+ private extraArgs;
27
+ readonly cliType: string;
28
+ readonly cliName: string;
29
+ workingDir: string;
30
+ private provider;
31
+ private ptyProcess;
32
+ private transportFactory;
33
+ private messages;
34
+ private committedMessages;
35
+ private structuredMessages;
36
+ private currentStatus;
37
+ private onStatusChange;
38
+ private responseBuffer;
39
+ private recentOutputBuffer;
40
+ private isWaitingForResponse;
41
+ private activeModal;
42
+ private responseTimeout;
43
+ private idleTimeout;
44
+ private ready;
45
+ private startupBuffer;
46
+ private startupParseGate;
47
+ private startupSettleTimer;
48
+ private spawnAt;
49
+ private startupFirstOutputAt;
50
+ private onPtyDataCallback;
51
+ private pendingOutputParseBuffer;
52
+ private pendingOutputParseTimer;
53
+ private ptyOutputBuffer;
54
+ private ptyOutputFlushTimer;
55
+ private pendingTerminalQueryTail;
56
+ private lastOutputAt;
57
+ private lastNonEmptyOutputAt;
58
+ private lastScreenChangeAt;
59
+ private lastScreenSnapshot;
60
+ private serverConn;
61
+ private logBuffer;
62
+ private lastApprovalResolvedAt;
63
+ private approvalTransitionBuffer;
64
+ private approvalExitTimeout;
65
+ private pendingScriptStatus;
66
+ private pendingScriptStatusSince;
67
+ private pendingScriptStatusTimer;
68
+ private settleTimer;
69
+ private settledBuffer;
70
+ private submitPendingUntil;
71
+ private responseSettleIgnoreUntil;
72
+ private responseEpoch;
73
+ private submitRetryTimer;
74
+ private submitRetryUsed;
75
+ private submitRetryPromptSnippet;
76
+ private idleFinishCandidate;
77
+ private finishRetryTimer;
78
+ private finishRetryCount;
79
+ private resizeSuppressUntil;
80
+ private statusHistory;
81
+ private cliScripts;
82
+ private runtimeSettings;
83
+ /** Full accumulated ANSI-stripped PTY output */
84
+ private accumulatedBuffer;
85
+ /** Full accumulated raw PTY output (with ANSI) */
86
+ private accumulatedRawBuffer;
87
+ /** Current visible terminal screen snapshot */
88
+ private terminalScreen;
89
+ /** Max accumulated buffer size (last 50KB) */
90
+ private static readonly MAX_ACCUMULATED_BUFFER;
91
+ private currentTurnScope;
92
+ private traceEntries;
93
+ private traceSeq;
94
+ private traceSessionId;
95
+ private static readonly MAX_TRACE_ENTRIES;
96
+ private readonly providerResolutionMeta;
97
+ private static readonly IDLE_FINISH_CONFIRM_MS;
98
+ private static readonly STATUS_ACTIVITY_HOLD_MS;
99
+ private static readonly FINISH_RETRY_DELAY_MS;
100
+ private static readonly MAX_FINISH_RETRIES;
101
+ private syncMessageViews;
102
+ private setStatus;
103
+ private clearIdleFinishCandidate;
104
+ private armIdleFinishCandidate;
105
+ private recordTrace;
106
+ private resetTraceSession;
107
+ private readonly timeouts;
108
+ private readonly approvalKeys;
109
+ private readonly sendDelayMs;
110
+ private readonly sendKey;
111
+ private readonly submitStrategy;
112
+ private static readonly SCRIPT_STATUS_DEBOUNCE_MS;
113
+ constructor(provider: CliProviderModule, workingDir: string, extraArgs?: string[], transportFactory?: PtyTransportFactory);
114
+ /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
115
+ setCliScripts(scripts: CliScripts): void;
116
+ updateRuntimeSettings(settings: Record<string, any>): void;
117
+ setServerConn(serverConn: any): void;
118
+ setOnStatusChange(callback: () => void): void;
119
+ setOnPtyData(callback: (data: string) => void): void;
120
+ private flushPendingOutputParse;
121
+ spawn(): Promise<void>;
122
+ private handleOutput;
123
+ private resolveStartupState;
124
+ private scheduleStartupSettleCheck;
125
+ private scheduleSettle;
126
+ private armApprovalExitTimeout;
127
+ private looksLikeVisibleIdlePrompt;
128
+ private findLastMatchingLineIndex;
129
+ private looksLikeClaudeGeneratingLine;
130
+ private detectClaudeGeneratingOverride;
131
+ private refineDetectedStatus;
132
+ private looksLikeVisibleAssistantCandidate;
133
+ private shouldRetryFinishResponse;
134
+ private hasRecentInteractiveActivity;
135
+ private getStartupConfirmationModal;
136
+ private shouldResolveModalWithEnter;
137
+ private waitForInteractivePrompt;
138
+ private evaluateSettled;
139
+ private finishResponse;
140
+ private commitCurrentTranscript;
141
+ private runDetectStatus;
142
+ private runParseApproval;
143
+ getStatus(): CliSessionStatus;
144
+ seedCommittedMessages(messages: SeedCliChatMessage[]): void;
145
+ /**
146
+ * Script-based full parse — returns ReadChatResult.
147
+ * Called by command handler / dashboard for rich content rendering.
148
+ */
149
+ getScriptParsedStatus(): any;
150
+ invokeScript(scriptName: string, args?: Record<string, any>): Promise<any>;
151
+ private parseCurrentTranscript;
152
+ /** Whether this adapter has CLI scripts loaded */
153
+ hasCliScripts(): boolean;
154
+ /**
155
+ * Resolves an action (like 'fix' lint error) from the dashboard.
156
+ * Uses resolveAction script if available, otherwise falls back to standard text.
157
+ */
158
+ resolveAction(data: any): Promise<void>;
159
+ sendMessage(text: string): Promise<void>;
160
+ getPartialResponse(): string;
161
+ getRuntimeMetadata(): PtyRuntimeMetadata | null;
162
+ updateRuntimeMeta(meta: Record<string, unknown>, replace?: boolean): void;
163
+ cancel(): void;
164
+ saveAndStop(): Promise<void>;
165
+ private waitForStopped;
166
+ shutdown(): void;
167
+ detach(): void;
168
+ clearHistory(): void;
169
+ isProcessing(): boolean;
170
+ isReady(): boolean;
171
+ writeRaw(data: string): void;
172
+ resolveModal(buttonIndex: number): void;
173
+ resize(cols: number, rows: number): void;
174
+ getDebugState(): Record<string, any>;
175
+ getTraceState(limit?: number): Record<string, any>;
176
+ getProviderResolutionMeta(): ProviderResolutionMeta;
177
+ }
@@ -1428,8 +1428,6 @@ export class ProviderCliAdapter implements CliAdapter {
1428
1428
  throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
1429
1429
  }
1430
1430
 
1431
- this.committedMessages.push({ role: 'user', content: text, timestamp: Date.now() });
1432
- this.syncMessageViews();
1433
1431
  this.isWaitingForResponse = true;
1434
1432
  this.responseBuffer = '';
1435
1433
  this.finishRetryCount = 0;
@@ -1458,6 +1456,13 @@ export class ProviderCliAdapter implements CliAdapter {
1458
1456
  const submitDelayMs = this.sendDelayMs + Math.min(2000, Math.max(0, estimatedLines - 1) * 350);
1459
1457
  const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5000, estimatedLines * 500));
1460
1458
  const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
1459
+ let didCommitUserTurn = false;
1460
+ const commitUserTurn = () => {
1461
+ if (didCommitUserTurn) return;
1462
+ didCommitUserTurn = true;
1463
+ this.committedMessages.push({ role: 'user', content: text, timestamp: Date.now() });
1464
+ this.syncMessageViews();
1465
+ };
1461
1466
  if (this.settleTimer) {
1462
1467
  clearTimeout(this.settleTimer);
1463
1468
  this.settleTimer = null;
@@ -1470,115 +1475,134 @@ export class ProviderCliAdapter implements CliAdapter {
1470
1475
  if (this.isWaitingForResponse) this.finishResponse();
1471
1476
  }, this.timeouts.maxResponse);
1472
1477
  };
1478
+ await new Promise<void>((resolve) => {
1479
+ let resolved = false;
1480
+ const resolveOnce = () => {
1481
+ if (resolved) return;
1482
+ resolved = true;
1483
+ resolve();
1484
+ };
1473
1485
 
1474
- const submit = () => {
1475
- if (!this.ptyProcess) return;
1476
- this.submitPendingUntil = 0;
1477
- this.recordTrace('submit_write', {
1478
- mode: 'submit_key',
1479
- sendKey: this.sendKey,
1480
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500),
1481
- });
1482
- this.ptyProcess.write(this.sendKey);
1483
- const retrySubmitIfStuck = (attempt: number) => {
1484
- this.submitRetryTimer = null;
1485
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
1486
- if (this.currentStatus === 'waiting_approval') return;
1487
- if ((this.responseBuffer || '').trim()) return;
1486
+ const submit = () => {
1487
+ if (!this.ptyProcess) {
1488
+ resolveOnce();
1489
+ return;
1490
+ }
1491
+ commitUserTurn();
1492
+ this.submitPendingUntil = 0;
1488
1493
  const screenText = this.terminalScreen.getText();
1489
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
1490
- if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
1491
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
1492
- LOG.info('CLI', `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
1493
1494
  this.recordTrace('submit_write', {
1494
- mode: 'submit_retry',
1495
- attempt,
1495
+ mode: 'submit_key',
1496
1496
  sendKey: this.sendKey,
1497
1497
  screenText: summarizeCliTraceText(screenText, 500),
1498
1498
  });
1499
- this.ptyProcess.write(this.sendKey);
1500
- if (attempt >= 3) {
1501
- this.submitRetryUsed = true;
1502
- return;
1503
- }
1504
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
1499
+ this.ptyProcess!.write(this.sendKey);
1500
+ const retrySubmitIfStuck = (attempt: number) => {
1501
+ this.submitRetryTimer = null;
1502
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
1503
+ if (this.currentStatus === 'waiting_approval') return;
1504
+ if ((this.responseBuffer || '').trim()) return;
1505
+ const screenText = this.terminalScreen.getText();
1506
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
1507
+ if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
1508
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
1509
+ LOG.info('CLI', `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
1510
+ this.recordTrace('submit_write', {
1511
+ mode: 'submit_retry',
1512
+ attempt,
1513
+ sendKey: this.sendKey,
1514
+ screenText: summarizeCliTraceText(screenText, 500),
1515
+ });
1516
+ this.ptyProcess.write(this.sendKey);
1517
+ if (attempt >= 3) {
1518
+ this.submitRetryUsed = true;
1519
+ return;
1520
+ }
1521
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
1522
+ };
1523
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
1524
+ startResponseTimeout();
1525
+ resolveOnce();
1505
1526
  };
1506
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
1507
- startResponseTimeout();
1508
- };
1509
1527
 
1510
- if (this.submitStrategy === 'immediate') {
1511
- this.submitPendingUntil = 0;
1528
+ if (this.submitStrategy === 'immediate') {
1529
+ commitUserTurn();
1530
+ this.submitPendingUntil = 0;
1531
+ this.recordTrace('submit_write', {
1532
+ mode: 'immediate',
1533
+ text: summarizeCliTraceText(text, 500),
1534
+ sendKey: this.sendKey,
1535
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500),
1536
+ });
1537
+ this.ptyProcess!.write(text + this.sendKey);
1538
+ this.submitRetryTimer = setTimeout(() => {
1539
+ this.submitRetryTimer = null;
1540
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
1541
+ if (this.currentStatus === 'waiting_approval') return;
1542
+ if ((this.responseBuffer || '').trim()) return;
1543
+ const screenText = this.terminalScreen.getText();
1544
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
1545
+ LOG.info('CLI', `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
1546
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
1547
+ this.recordTrace('submit_write', {
1548
+ mode: 'immediate_retry',
1549
+ attempt: 1,
1550
+ sendKey: this.sendKey,
1551
+ screenText: summarizeCliTraceText(screenText, 500),
1552
+ });
1553
+ this.ptyProcess.write(this.sendKey);
1554
+ this.submitRetryUsed = true;
1555
+ }, retryDelayMs);
1556
+ startResponseTimeout();
1557
+ resolveOnce();
1558
+ return;
1559
+ }
1560
+
1561
+ if (submitDelayMs > 0) {
1562
+ this.submitPendingUntil = Date.now() + submitDelayMs;
1563
+ }
1564
+ this.ptyProcess!.write(text);
1512
1565
  this.recordTrace('submit_write', {
1513
- mode: 'immediate',
1566
+ mode: 'type_then_submit',
1514
1567
  text: summarizeCliTraceText(text, 500),
1515
1568
  sendKey: this.sendKey,
1516
1569
  screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500),
1517
1570
  });
1518
- this.ptyProcess.write(text + this.sendKey);
1519
- this.submitRetryTimer = setTimeout(() => {
1520
- this.submitRetryTimer = null;
1521
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
1522
- if (this.currentStatus === 'waiting_approval') return;
1523
- if ((this.responseBuffer || '').trim()) return;
1571
+ const submitStartedAt = Date.now();
1572
+ let lastNormalizedScreen = '';
1573
+ let lastScreenChangeAt = submitStartedAt;
1574
+ const waitForEchoAndSubmit = () => {
1575
+ if (!this.ptyProcess) {
1576
+ resolveOnce();
1577
+ return;
1578
+ }
1579
+ const now = Date.now();
1580
+ const elapsed = now - submitStartedAt;
1524
1581
  const screenText = this.terminalScreen.getText();
1525
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
1526
- LOG.info('CLI', `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
1527
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
1528
- this.recordTrace('submit_write', {
1529
- mode: 'immediate_retry',
1530
- attempt: 1,
1531
- sendKey: this.sendKey,
1532
- screenText: summarizeCliTraceText(screenText, 500),
1533
- });
1534
- this.ptyProcess.write(this.sendKey);
1535
- this.submitRetryUsed = true;
1536
- }, retryDelayMs);
1537
- startResponseTimeout();
1538
- return;
1539
- }
1582
+ const normalizedScreen = normalizePromptText(screenText);
1583
+ if (normalizedScreen !== lastNormalizedScreen) {
1584
+ lastNormalizedScreen = normalizedScreen;
1585
+ lastScreenChangeAt = now;
1586
+ }
1587
+ const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
1540
1588
 
1541
- if (submitDelayMs > 0) {
1542
- this.submitPendingUntil = Date.now() + submitDelayMs;
1543
- }
1544
- this.ptyProcess.write(text);
1545
- this.recordTrace('submit_write', {
1546
- mode: 'type_then_submit',
1547
- text: summarizeCliTraceText(text, 500),
1548
- sendKey: this.sendKey,
1549
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500),
1550
- });
1551
- const submitStartedAt = Date.now();
1552
- let lastNormalizedScreen = '';
1553
- let lastScreenChangeAt = submitStartedAt;
1554
- const waitForEchoAndSubmit = () => {
1555
- if (!this.ptyProcess) return;
1556
- const now = Date.now();
1557
- const elapsed = now - submitStartedAt;
1558
- const screenText = this.terminalScreen.getText();
1559
- const normalizedScreen = normalizePromptText(screenText);
1560
- if (normalizedScreen !== lastNormalizedScreen) {
1561
- lastNormalizedScreen = normalizedScreen;
1562
- lastScreenChangeAt = now;
1563
- }
1564
- const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
1589
+ if (echoVisible) {
1590
+ const screenSettled = (now - lastScreenChangeAt) >= 500;
1591
+ if (elapsed >= submitDelayMs && screenSettled) {
1592
+ submit();
1593
+ return;
1594
+ }
1595
+ }
1565
1596
 
1566
- if (echoVisible) {
1567
- const screenSettled = (now - lastScreenChangeAt) >= 500;
1568
- if (elapsed >= submitDelayMs && screenSettled) {
1597
+ if (elapsed >= maxEchoWaitMs) {
1569
1598
  submit();
1570
1599
  return;
1571
1600
  }
1572
- }
1573
1601
 
1574
- if (elapsed >= maxEchoWaitMs) {
1575
- submit();
1576
- return;
1577
- }
1578
-
1579
- setTimeout(waitForEchoAndSubmit, 50);
1580
- };
1581
- waitForEchoAndSubmit();
1602
+ setTimeout(waitForEchoAndSubmit, 50);
1603
+ };
1604
+ waitForEchoAndSubmit();
1605
+ });
1582
1606
  }
1583
1607
 
1584
1608
  getPartialResponse(): string {
@@ -0,0 +1,30 @@
1
+ import type { CliProviderModule } from './provider-cli-shared.js';
2
+ export interface ProviderResolutionMeta {
3
+ type: string;
4
+ name: string;
5
+ resolvedVersion: string | null;
6
+ resolvedOs: string | null;
7
+ providerDir: string | null;
8
+ scriptDir: string | null;
9
+ scriptsPath: string | null;
10
+ scriptsSource: string | null;
11
+ versionWarning: string | null;
12
+ }
13
+ export interface ResolvedCliAdapterConfig {
14
+ timeouts: {
15
+ ptyFlush: number;
16
+ dialogAccept: number;
17
+ approvalCooldown: number;
18
+ generatingIdle: number;
19
+ idleFinish: number;
20
+ maxResponse: number;
21
+ shutdownGrace: number;
22
+ outputSettle: number;
23
+ };
24
+ approvalKeys: Record<number, string>;
25
+ sendDelayMs: number;
26
+ sendKey: string;
27
+ submitStrategy: 'wait_for_echo' | 'immediate';
28
+ providerResolutionMeta: ProviderResolutionMeta;
29
+ }
30
+ export declare function resolveCliAdapterConfig(provider: CliProviderModule): ResolvedCliAdapterConfig;
@@ -0,0 +1,42 @@
1
+ import { type CliChatMessage, type CliScriptInput } from './provider-cli-shared.js';
2
+ export interface TurnParseScope {
3
+ prompt: string;
4
+ startedAt: number;
5
+ bufferStart: number;
6
+ rawBufferStart: number;
7
+ }
8
+ export declare function hydrateCliParsedMessages(parsedMessages: any[], options: {
9
+ committedMessages: CliChatMessage[];
10
+ scope?: TurnParseScope | null;
11
+ lastOutputAt: number;
12
+ now?: number;
13
+ }): any[];
14
+ export declare function normalizeCliParsedMessages(parsedMessages: any[], options: {
15
+ committedMessages: CliChatMessage[];
16
+ scope?: TurnParseScope | null;
17
+ lastOutputAt: number;
18
+ now?: number;
19
+ }): CliChatMessage[];
20
+ export declare function buildCliParseInput(options: {
21
+ accumulatedBuffer: string;
22
+ accumulatedRawBuffer: string;
23
+ recentOutputBuffer: string;
24
+ terminalScreenText: string;
25
+ baseMessages: CliChatMessage[];
26
+ partialResponse: string;
27
+ scope?: TurnParseScope | null;
28
+ runtimeSettings: Record<string, any>;
29
+ }): CliScriptInput;
30
+ export declare function summarizeCliTraceText(text: string, max?: number): string;
31
+ export declare function summarizeCliTraceMessages(messages: CliChatMessage[], limit?: number): {
32
+ role: string;
33
+ content: string;
34
+ timestamp?: number;
35
+ }[];
36
+ export declare function buildCliTraceParseSnapshot(options: {
37
+ accumulatedBuffer: string;
38
+ accumulatedRawBuffer: string;
39
+ responseBuffer: string;
40
+ partialResponse?: string;
41
+ scope?: TurnParseScope | null;
42
+ }): Record<string, any>;