@adhdev/daemon-core 0.9.82-rc.10 → 0.9.82-rc.101
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/cli-adapters/provider-cli-adapter.d.ts +13 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +10 -0
- package/dist/commands/router.d.ts +22 -0
- package/dist/config/mesh-config.d.ts +66 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +5793 -1219
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5759 -1206
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/mesh/beads-db.d.ts +18 -0
- package/dist/mesh/mesh-active-work.d.ts +60 -0
- package/dist/mesh/mesh-events.d.ts +26 -5
- package/dist/mesh/mesh-fast-forward.d.ts +39 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-ledger.d.ts +38 -1
- package/dist/mesh/mesh-work-queue.d.ts +27 -5
- package/dist/mesh/refine-config.d.ts +176 -0
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -1
- package/dist/repo-mesh-types.d.ts +46 -0
- package/dist/status/reporter.d.ts +2 -0
- package/package.json +3 -1
- package/src/boot/daemon-lifecycle.ts +1 -0
- package/src/cli-adapters/provider-cli-adapter.ts +319 -14
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +4 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -1
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +28 -10
- package/src/commands/chat-commands.ts +570 -20
- package/src/commands/cli-manager.ts +129 -1
- package/src/commands/handler.ts +8 -1
- package/src/commands/mesh-coordinator.ts +13 -143
- package/src/commands/router.ts +2820 -437
- package/src/config/chat-history.ts +9 -7
- package/src/config/mesh-config.ts +245 -1
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/index.ts +30 -4
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/beads-db.ts +176 -0
- package/src/mesh/coordinator-prompt.ts +31 -8
- package/src/mesh/mesh-active-work.ts +255 -0
- package/src/mesh/mesh-events.ts +389 -47
- package/src/mesh/mesh-fast-forward.ts +430 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger.ts +138 -1
- package/src/mesh/mesh-work-queue.ts +199 -137
- package/src/mesh/refine-config.ts +356 -0
- package/src/providers/chat-message-normalization.ts +7 -12
- package/src/providers/cli-provider-instance.ts +102 -17
- package/src/providers/ide-provider-instance.ts +17 -3
- package/src/providers/provider-loader.ts +10 -4
- package/src/providers/read-chat-contract.ts +1 -1
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +51 -0
- package/src/status/reporter.ts +15 -0
- package/src/system/host-memory.ts +29 -12
|
@@ -19,10 +19,37 @@ export interface RepoMesh {
|
|
|
19
19
|
defaultBranch?: string;
|
|
20
20
|
policy: RepoMeshPolicy;
|
|
21
21
|
coordinator: RepoMeshCoordinatorConfig;
|
|
22
|
+
meshHost?: RepoMeshHostMetadata;
|
|
22
23
|
projectContext: ProjectContextSnapshot;
|
|
23
24
|
nodes: RepoMeshNode[];
|
|
24
25
|
status: 'active' | 'archived' | 'deleted';
|
|
25
26
|
}
|
|
27
|
+
export type RepoMeshDaemonRole = 'host' | 'member';
|
|
28
|
+
export interface RepoMeshHostPairingMetadata {
|
|
29
|
+
status: 'not_configured' | 'pairing' | 'paired' | 'rejected' | 'revoked';
|
|
30
|
+
tokenId?: string;
|
|
31
|
+
joinedAt?: string;
|
|
32
|
+
lastPairedAt?: string;
|
|
33
|
+
lastRejectedAt?: string;
|
|
34
|
+
expiresAt?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RepoMeshHostMetadata {
|
|
37
|
+
/** Local daemon role for this mesh. Missing metadata defaults to host for standalone compatibility. */
|
|
38
|
+
role: RepoMeshDaemonRole;
|
|
39
|
+
/** Daemon that owns mesh truth/status/git/queue/session/ledger/coordinator ownership. */
|
|
40
|
+
hostDaemonId?: string;
|
|
41
|
+
/** Mesh node that represents the host daemon, when known. */
|
|
42
|
+
hostNodeId?: string;
|
|
43
|
+
/** Future standalone manual pairing endpoint entered by member daemons. */
|
|
44
|
+
hostAddress?: string;
|
|
45
|
+
/** Redacted pairing state only; raw join tokens must not be persisted here. */
|
|
46
|
+
pairing?: RepoMeshHostPairingMetadata;
|
|
47
|
+
}
|
|
48
|
+
export interface RepoMeshHostStatus extends RepoMeshHostMetadata {
|
|
49
|
+
canOwnCoordinator: boolean;
|
|
50
|
+
canOwnQueue: boolean;
|
|
51
|
+
defaulted: boolean;
|
|
52
|
+
}
|
|
26
53
|
export interface RepoMeshNode {
|
|
27
54
|
id: string;
|
|
28
55
|
daemonId: string;
|
|
@@ -37,6 +64,7 @@ export interface RepoMeshNode {
|
|
|
37
64
|
effectiveCapabilities: RepoMeshNodeCapabilities;
|
|
38
65
|
policy: RepoMeshNodePolicy;
|
|
39
66
|
health: RepoMeshNodeHealth;
|
|
67
|
+
role?: RepoMeshDaemonRole;
|
|
40
68
|
status: 'enabled' | 'disabled' | 'removed';
|
|
41
69
|
}
|
|
42
70
|
export type RepoMeshNodeHealth = 'online' | 'offline' | 'degraded' | 'dirty' | 'wrong_branch' | 'unknown';
|
|
@@ -46,6 +74,13 @@ export interface RepoMeshPolicy {
|
|
|
46
74
|
requirePreTaskCheckpoint: boolean;
|
|
47
75
|
requirePostTaskCheckpoint: boolean;
|
|
48
76
|
requireApprovalForPush: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Narrow Refinery opt-in: when validation and patch-equivalence have passed,
|
|
79
|
+
* allow Refinery to publish submodule gitlink commits to each submodule's
|
|
80
|
+
* configured remote main branch with a non-force push, then verify reachability.
|
|
81
|
+
* Defaults to false; root branch pushes/merges are not affected.
|
|
82
|
+
*/
|
|
83
|
+
allowAutoPublishSubmoduleMainCommits?: boolean;
|
|
49
84
|
requireApprovalForDestructiveGit: boolean;
|
|
50
85
|
dirtyWorkspaceBehavior: 'block' | 'warn' | 'checkpoint_then_continue';
|
|
51
86
|
maxParallelTasks: number;
|
|
@@ -185,6 +220,7 @@ export interface LocalMeshEntry {
|
|
|
185
220
|
defaultBranch?: string;
|
|
186
221
|
policy: RepoMeshPolicy;
|
|
187
222
|
coordinator: RepoMeshCoordinatorConfig;
|
|
223
|
+
meshHost?: RepoMeshHostMetadata;
|
|
188
224
|
nodes: LocalMeshNodeEntry[];
|
|
189
225
|
createdAt: string;
|
|
190
226
|
updatedAt: string;
|
|
@@ -206,12 +242,15 @@ export interface LocalMeshNodeEntry {
|
|
|
206
242
|
clonedFromNodeId?: string;
|
|
207
243
|
/** Optional associated/external repos configured as node metadata. */
|
|
208
244
|
relatedRepos?: RepoMeshRelatedRepo[];
|
|
245
|
+
role?: RepoMeshDaemonRole;
|
|
209
246
|
}
|
|
210
247
|
export interface RepoMeshStatus {
|
|
211
248
|
meshId: string;
|
|
212
249
|
meshName: string;
|
|
213
250
|
repoIdentity: string;
|
|
251
|
+
defaultBranch?: string;
|
|
214
252
|
refreshedAt: string;
|
|
253
|
+
meshHost?: RepoMeshHostStatus;
|
|
215
254
|
nodes: RepoMeshNodeStatus[];
|
|
216
255
|
queue?: RepoMeshQueueStatus;
|
|
217
256
|
ledger?: RepoMeshLedgerStatus;
|
|
@@ -248,11 +287,18 @@ export interface RepoMeshNodeStatus {
|
|
|
248
287
|
repoRoot?: string;
|
|
249
288
|
daemonId?: string;
|
|
250
289
|
machineId?: string;
|
|
290
|
+
role?: RepoMeshDaemonRole;
|
|
251
291
|
machineStatus?: string;
|
|
252
292
|
isLocalWorktree?: boolean;
|
|
253
293
|
worktreeBranch?: string;
|
|
254
294
|
health: RepoMeshNodeHealth;
|
|
255
295
|
git?: GitRepoStatus;
|
|
296
|
+
/**
|
|
297
|
+
* True when the selected coordinator has evidence that a peer git probe is still
|
|
298
|
+
* in flight or just timed out during initial mesh handshake, so callers should
|
|
299
|
+
* treat missing git data as pending instead of authoritative absence.
|
|
300
|
+
*/
|
|
301
|
+
gitProbePending?: boolean;
|
|
256
302
|
providers: string[];
|
|
257
303
|
activeSessions: string[];
|
|
258
304
|
activeSessionDetails?: RepoMeshSessionStatus[];
|
|
@@ -46,6 +46,8 @@ export declare class DaemonStatusReporter {
|
|
|
46
46
|
private lastStatusSentAt;
|
|
47
47
|
private statusPendingThrottle;
|
|
48
48
|
private lastP2PStatusHash;
|
|
49
|
+
private lastP2PStatusSentAt;
|
|
50
|
+
private p2pDebounceTimer;
|
|
49
51
|
private lastServerStatusHash;
|
|
50
52
|
private lastStatusSummary;
|
|
51
53
|
private statusTimer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.82-rc.
|
|
3
|
+
"version": "0.9.82-rc.101",
|
|
4
4
|
"description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@adhdev/session-host-core": "*",
|
|
50
50
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
51
51
|
"@xterm/xterm": "^6.0.0",
|
|
52
|
+
"better-sqlite3": "^12.10.0",
|
|
52
53
|
"chalk": "^5.3.0",
|
|
53
54
|
"chokidar": "^4.0.3",
|
|
54
55
|
"conf": "^13.0.0",
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
"@adhdev/ghostty-vt-node": "*"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
64
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
63
65
|
"@types/js-yaml": "^4.0.9",
|
|
64
66
|
"@types/node": "^22.0.0",
|
|
65
67
|
"@types/ws": "^8.18.1",
|
|
@@ -309,6 +309,7 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
|
|
|
309
309
|
statusInstanceId: config.statusInstanceId,
|
|
310
310
|
statusVersion: config.statusVersion,
|
|
311
311
|
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
312
|
+
dispatchMeshCommand: config.dispatchMeshCommand,
|
|
312
313
|
getCdpLogFn: config.getCdpLogFn || ((ideType: string) => LOG.forComponent(`CDP:${ideType}`).asLogFn()),
|
|
313
314
|
});
|
|
314
315
|
|
|
@@ -110,6 +110,14 @@ interface SendMessageCompletion {
|
|
|
110
110
|
rejectOnce: (error: unknown) => void;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
interface PendingOutboundMessage {
|
|
114
|
+
id: string;
|
|
115
|
+
role: 'user';
|
|
116
|
+
content: string;
|
|
117
|
+
queuedAt: number;
|
|
118
|
+
source: 'sendMessage';
|
|
119
|
+
}
|
|
120
|
+
|
|
113
121
|
export function appendBoundedText(current: string, chunk: string, maxChars: number): string {
|
|
114
122
|
if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
|
|
115
123
|
if (maxChars <= 0) return '';
|
|
@@ -186,6 +194,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
186
194
|
private idleFinishCandidate: IdleFinishCandidate | null = null;
|
|
187
195
|
private finishRetryTimer: NodeJS.Timeout | null = null;
|
|
188
196
|
private finishRetryCount = 0;
|
|
197
|
+
private pendingOutboundQueue: PendingOutboundMessage[] = [];
|
|
198
|
+
private pendingOutboundFlushTimer: NodeJS.Timeout | null = null;
|
|
199
|
+
private pendingOutboundFlushInFlight = false;
|
|
189
200
|
|
|
190
201
|
// Resize redraw suppression
|
|
191
202
|
private resizeSuppressUntil: number = 0;
|
|
@@ -761,6 +772,17 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
761
772
|
if (stableMs < 2000) return;
|
|
762
773
|
|
|
763
774
|
const startupModal = this.runParseApproval(this.recentOutputBuffer);
|
|
775
|
+
const startupStatus = this.runDetectStatus(screenText || this.recentOutputBuffer);
|
|
776
|
+
if (!startupModal && startupStatus !== 'idle') {
|
|
777
|
+
this.recordTrace('startup_settle_deferred', {
|
|
778
|
+
trigger,
|
|
779
|
+
startupStatus,
|
|
780
|
+
stableMs,
|
|
781
|
+
screenText: summarizeCliTraceText(screenText, 500),
|
|
782
|
+
});
|
|
783
|
+
this.scheduleStartupSettleCheck();
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
764
786
|
this.startupParseGate = false;
|
|
765
787
|
if (this.startupSettleTimer) {
|
|
766
788
|
clearTimeout(this.startupSettleTimer);
|
|
@@ -956,6 +978,38 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
956
978
|
return true;
|
|
957
979
|
}
|
|
958
980
|
|
|
981
|
+
private clearParsedIdleResponseGuard(reason: string, parsedStatus: any): boolean {
|
|
982
|
+
const parsedRawStatus = typeof parsedStatus?.status === 'string' ? parsedStatus.status.trim() : '';
|
|
983
|
+
const parsedModal = parsedStatus?.activeModal ?? parsedStatus?.modal ?? null;
|
|
984
|
+
const blockingModal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
|
|
985
|
+
if (
|
|
986
|
+
!this.isWaitingForResponse
|
|
987
|
+
|| parsedRawStatus !== 'idle'
|
|
988
|
+
|| !!parsedModal
|
|
989
|
+
|| !!blockingModal
|
|
990
|
+
|| !this.parsedStatusHasFinalAssistantMessage(parsedStatus)
|
|
991
|
+
) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
this.clearAllTimers();
|
|
995
|
+
this.clearIdleFinishCandidate(reason);
|
|
996
|
+
this.responseBuffer = '';
|
|
997
|
+
this.isWaitingForResponse = false;
|
|
998
|
+
this.responseSettleIgnoreUntil = 0;
|
|
999
|
+
this.submitRetryUsed = false;
|
|
1000
|
+
this.submitRetryPromptSnippet = '';
|
|
1001
|
+
this.finishRetryCount = 0;
|
|
1002
|
+
this.currentTurnScope = null;
|
|
1003
|
+
this.activeModal = null;
|
|
1004
|
+
this.setStatus('idle', reason);
|
|
1005
|
+
this.recordTrace('parsed_idle_response_cleared', {
|
|
1006
|
+
reason,
|
|
1007
|
+
parsedStatus: parsedRawStatus,
|
|
1008
|
+
parsedMessageCount: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : 0,
|
|
1009
|
+
});
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
959
1013
|
private hasMeaningfulResponseBuffer(promptSnippet: string): boolean {
|
|
960
1014
|
const raw = String(this.responseBuffer || '').trim();
|
|
961
1015
|
if (!raw) return false;
|
|
@@ -1318,6 +1372,11 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1318
1372
|
this.idleTimeout = setTimeout(() => {
|
|
1319
1373
|
if (this.isWaitingForResponse && !this.hasActionableApproval()) {
|
|
1320
1374
|
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
1375
|
+
const parsed = this.runParseSession();
|
|
1376
|
+
if (this.shouldKeepCodexTurnOpenForFinish(parsed)) {
|
|
1377
|
+
this.rescheduleCodexFinishCheck('codex_idle_timeout_not_final');
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1321
1380
|
this.clearIdleFinishCandidate('idle_timeout_finish');
|
|
1322
1381
|
this.finishResponse();
|
|
1323
1382
|
}
|
|
@@ -1327,6 +1386,11 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1327
1386
|
private finishResponse(): void {
|
|
1328
1387
|
if (this.submitPendingUntil > Date.now()) return;
|
|
1329
1388
|
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1389
|
+
const parsedBeforeFinish = this.runParseSession();
|
|
1390
|
+
if (this.shouldKeepCodexTurnOpenForFinish(parsedBeforeFinish)) {
|
|
1391
|
+
this.rescheduleCodexFinishCheck('codex_finish_not_final');
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1330
1394
|
this.clearIdleFinishCandidate('finish_response_enter');
|
|
1331
1395
|
this.recordTrace('finish_response', {
|
|
1332
1396
|
...buildCliTraceParseSnapshot({
|
|
@@ -1372,6 +1436,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1372
1436
|
this.activeModal = null;
|
|
1373
1437
|
this.setStatus('idle', 'response_finished');
|
|
1374
1438
|
this.onStatusChange?.();
|
|
1439
|
+
this.schedulePendingOutboundFlush();
|
|
1375
1440
|
}
|
|
1376
1441
|
|
|
1377
1442
|
private maybeCommitVisibleIdleTranscript(session: ParsedSession, parsedMessages: CliChatMessage[]): boolean {
|
|
@@ -1402,6 +1467,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1402
1467
|
this.activeModal = null;
|
|
1403
1468
|
this.setStatus('idle', 'script_idle_commit');
|
|
1404
1469
|
this.onStatusChange?.();
|
|
1470
|
+
this.schedulePendingOutboundFlush();
|
|
1405
1471
|
this.recordTrace('script_idle_commit', {
|
|
1406
1472
|
messageCount: parsedMessages.length,
|
|
1407
1473
|
lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320),
|
|
@@ -1489,6 +1555,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1489
1555
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1490
1556
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
1491
1557
|
terminalScreenText: parseScreenText,
|
|
1558
|
+
workingDir: this.workingDir,
|
|
1492
1559
|
baseMessages: [],
|
|
1493
1560
|
partialResponse: this.responseBuffer,
|
|
1494
1561
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
@@ -1552,6 +1619,58 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1552
1619
|
return !!(startupModal || this.activeModal);
|
|
1553
1620
|
}
|
|
1554
1621
|
|
|
1622
|
+
private parsedStatusHasFinalAssistantMessage(parsed: any): boolean {
|
|
1623
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
1624
|
+
const lastAssistant = [...messages].reverse().find((message: any) => {
|
|
1625
|
+
if (!message || message.role !== 'assistant') return false;
|
|
1626
|
+
return typeof message.content === 'string' && message.content.trim().length > 0;
|
|
1627
|
+
});
|
|
1628
|
+
return !!lastAssistant;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
private parsedStatusHasFinalStandardAssistantMessage(parsed: any): boolean {
|
|
1632
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
1633
|
+
const lastAssistant = [...messages].reverse().find((message: any) => {
|
|
1634
|
+
if (!message || message.role !== 'assistant') return false;
|
|
1635
|
+
return typeof message.content === 'string' && message.content.trim().length > 0;
|
|
1636
|
+
});
|
|
1637
|
+
if (!lastAssistant) return false;
|
|
1638
|
+
const kind = typeof lastAssistant.kind === 'string' && lastAssistant.kind.trim()
|
|
1639
|
+
? lastAssistant.kind.trim()
|
|
1640
|
+
: 'standard';
|
|
1641
|
+
return kind === 'standard' && lastAssistant.meta?.streaming !== true;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
private shouldKeepCodexTurnOpenForFinish(parsed: any): boolean {
|
|
1645
|
+
if (this.cliType !== 'codex-cli') return false;
|
|
1646
|
+
if (!this.isWaitingForResponse || !this.currentTurnScope || this.hasActionableApproval()) return false;
|
|
1647
|
+
const parsedStatus = typeof parsed?.status === 'string' ? parsed.status.trim() : '';
|
|
1648
|
+
if (parsedStatus !== 'idle') return true;
|
|
1649
|
+
if (parsed?.activeModal || parsed?.modal) return true;
|
|
1650
|
+
return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
private rescheduleCodexFinishCheck(reason: string): void {
|
|
1654
|
+
this.clearIdleFinishCandidate(reason);
|
|
1655
|
+
this.setStatus('generating', reason);
|
|
1656
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1657
|
+
this.idleTimeout = setTimeout(() => {
|
|
1658
|
+
if (!this.isWaitingForResponse || this.hasActionableApproval()) return;
|
|
1659
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
1660
|
+
this.evaluateSettled();
|
|
1661
|
+
}, this.getIdleFinishConfirmMs());
|
|
1662
|
+
this.recordTrace('codex_finish_deferred', {
|
|
1663
|
+
reason,
|
|
1664
|
+
...buildCliTraceParseSnapshot({
|
|
1665
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
1666
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1667
|
+
responseBuffer: this.responseBuffer,
|
|
1668
|
+
partialResponse: this.responseBuffer,
|
|
1669
|
+
scope: this.currentTurnScope,
|
|
1670
|
+
}),
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1555
1674
|
private projectEffectiveStatus(startupModal: { message: string; buttons: string[] } | null = null): CliSessionStatus['status'] {
|
|
1556
1675
|
if (this.parseErrorMessage) return 'error';
|
|
1557
1676
|
if (this.hasActionableApproval(startupModal)) return 'waiting_approval';
|
|
@@ -1564,8 +1683,16 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1564
1683
|
getStatus(options: { allowParse?: boolean } = {}): CliSessionStatus {
|
|
1565
1684
|
const allowParse = options.allowParse !== false;
|
|
1566
1685
|
const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
1686
|
+
const startupDetectedStatus = allowParse && this.startupParseGate && !startupModal
|
|
1687
|
+
? this.runDetectStatus(this.recentOutputBuffer || this.terminalScreen.getText())
|
|
1688
|
+
: null;
|
|
1567
1689
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
1568
1690
|
let effectiveModal = startupModal || this.activeModal;
|
|
1691
|
+
if (startupDetectedStatus === 'waiting_approval') {
|
|
1692
|
+
effectiveStatus = 'waiting_approval';
|
|
1693
|
+
} else if (startupDetectedStatus === 'idle' && !startupModal && !effectiveModal) {
|
|
1694
|
+
effectiveStatus = 'idle';
|
|
1695
|
+
}
|
|
1569
1696
|
if (allowParse && !startupModal && !effectiveModal) {
|
|
1570
1697
|
const parsed = this.getFreshParsedStatusCache();
|
|
1571
1698
|
const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
@@ -1575,6 +1702,18 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1575
1702
|
if (parsed?.status === 'waiting_approval' && parsedModal) {
|
|
1576
1703
|
effectiveStatus = 'waiting_approval';
|
|
1577
1704
|
effectiveModal = parsedModal;
|
|
1705
|
+
} else if (
|
|
1706
|
+
effectiveStatus === 'idle'
|
|
1707
|
+
&& parsed?.status === 'generating'
|
|
1708
|
+
&& !this.parsedStatusHasFinalAssistantMessage(parsed)
|
|
1709
|
+
) {
|
|
1710
|
+
effectiveStatus = 'generating';
|
|
1711
|
+
} else if (
|
|
1712
|
+
effectiveStatus === 'generating'
|
|
1713
|
+
&& parsed?.status === 'idle'
|
|
1714
|
+
&& this.parsedStatusHasFinalAssistantMessage(parsed)
|
|
1715
|
+
) {
|
|
1716
|
+
effectiveStatus = 'idle';
|
|
1578
1717
|
}
|
|
1579
1718
|
}
|
|
1580
1719
|
const bufferState = this.getBufferState();
|
|
@@ -1583,6 +1722,14 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1583
1722
|
messages: [],
|
|
1584
1723
|
workingDir: this.workingDir,
|
|
1585
1724
|
activeModal: effectiveModal,
|
|
1725
|
+
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
1726
|
+
pendingOutboundMessages: this.pendingOutboundQueue.map((message) => ({
|
|
1727
|
+
id: message.id,
|
|
1728
|
+
role: message.role,
|
|
1729
|
+
content: message.content,
|
|
1730
|
+
queuedAt: message.queuedAt,
|
|
1731
|
+
source: message.source,
|
|
1732
|
+
})),
|
|
1586
1733
|
errorMessage: this.parseErrorMessage || undefined,
|
|
1587
1734
|
errorReason: this.parseErrorMessage ? 'parse_error' : undefined,
|
|
1588
1735
|
...(bufferState ? { bufferState } : {}),
|
|
@@ -1600,7 +1747,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1600
1747
|
const cached = this.parsedStatusCache;
|
|
1601
1748
|
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
1602
1749
|
if (
|
|
1603
|
-
|
|
1750
|
+
!this.providerOwnsTranscript()
|
|
1751
|
+
&& cached
|
|
1604
1752
|
&& cached.responseBuffer === this.responseBuffer
|
|
1605
1753
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
1606
1754
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
@@ -1631,6 +1779,12 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1631
1779
|
}),
|
|
1632
1780
|
activeModal,
|
|
1633
1781
|
providerSessionId: typeof (parsed as any).providerSessionId === 'string' ? (parsed as any).providerSessionId : undefined,
|
|
1782
|
+
errorMessage: typeof (parsed as any).errorMessage === 'string' && (parsed as any).errorMessage.trim()
|
|
1783
|
+
? (parsed as any).errorMessage.trim()
|
|
1784
|
+
: undefined,
|
|
1785
|
+
errorReason: typeof (parsed as any).errorReason === 'string' && (parsed as any).errorReason.trim()
|
|
1786
|
+
? (parsed as any).errorReason.trim()
|
|
1787
|
+
: undefined,
|
|
1634
1788
|
...(bufferState ? { bufferState } : {}),
|
|
1635
1789
|
...((parsed as any).transcriptAuthority === 'provider' || (parsed as any).transcriptAuthority === 'daemon'
|
|
1636
1790
|
? { transcriptAuthority: (parsed as any).transcriptAuthority }
|
|
@@ -1665,6 +1819,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1665
1819
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1666
1820
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
1667
1821
|
terminalScreenText: this.getParseScreenText(this.terminalScreen.getText()),
|
|
1822
|
+
workingDir: this.workingDir,
|
|
1668
1823
|
baseMessages: [],
|
|
1669
1824
|
partialResponse: this.responseBuffer,
|
|
1670
1825
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
@@ -1925,6 +2080,104 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1925
2080
|
}
|
|
1926
2081
|
|
|
1927
2082
|
async sendMessage(text: string): Promise<void> {
|
|
2083
|
+
await this.sendMessageNow(text, true);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
private enqueuePendingOutboundMessage(text: string, reason: string): void {
|
|
2087
|
+
const content = String(text || '');
|
|
2088
|
+
const duplicate = this.pendingOutboundQueue.some((message) => message.content === content);
|
|
2089
|
+
if (duplicate) {
|
|
2090
|
+
this.recordTrace('send_message_queued_duplicate_suppressed', {
|
|
2091
|
+
reason,
|
|
2092
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2093
|
+
text: summarizeCliTraceText(content, 500),
|
|
2094
|
+
});
|
|
2095
|
+
return;
|
|
2096
|
+
}
|
|
2097
|
+
const queuedAt = Date.now();
|
|
2098
|
+
const message: PendingOutboundMessage = {
|
|
2099
|
+
id: `${queuedAt}:${this.pendingOutboundQueue.length}:${Math.random().toString(36).slice(2, 10)}`,
|
|
2100
|
+
role: 'user',
|
|
2101
|
+
content,
|
|
2102
|
+
queuedAt,
|
|
2103
|
+
source: 'sendMessage',
|
|
2104
|
+
};
|
|
2105
|
+
this.pendingOutboundQueue.push(message);
|
|
2106
|
+
this.recordTrace('send_message_queued', {
|
|
2107
|
+
reason,
|
|
2108
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2109
|
+
queuedAt,
|
|
2110
|
+
text: summarizeCliTraceText(content, 500),
|
|
2111
|
+
});
|
|
2112
|
+
LOG.info('CLI', `[${this.cliType}] queued outbound message while busy (${reason}); queue=${this.pendingOutboundQueue.length}`);
|
|
2113
|
+
this.onStatusChange?.();
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
private shouldQueuePendingOutboundMessage(parsedStatusBeforeSend: any | null = null): string | null {
|
|
2117
|
+
if (this.provider.allowInputDuringGeneration === true) return null;
|
|
2118
|
+
if (this.hasActionableApproval()) return null;
|
|
2119
|
+
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === 'string'
|
|
2120
|
+
? String(parsedStatusBeforeSend.status)
|
|
2121
|
+
: '';
|
|
2122
|
+
if (parsedSessionStatus === 'idle' && this.parsedStatusHasFinalAssistantMessage(parsedStatusBeforeSend)) return null;
|
|
2123
|
+
if (this.currentStatus === 'generating') return 'current_status_generating';
|
|
2124
|
+
if (parsedSessionStatus === 'generating' || parsedSessionStatus === 'long_generating') {
|
|
2125
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
2126
|
+
const parsedHasActionableModal = Boolean(
|
|
2127
|
+
parsedModal
|
|
2128
|
+
&& Array.isArray(parsedModal.buttons)
|
|
2129
|
+
&& parsedModal.buttons.some((candidate: unknown) => typeof candidate === 'string' && candidate.trim()),
|
|
2130
|
+
);
|
|
2131
|
+
const terminalLooksIdle = this.currentStatus === 'idle'
|
|
2132
|
+
&& this.runDetectStatus(this.recentOutputBuffer) === 'idle'
|
|
2133
|
+
&& !this.isWaitingForResponse
|
|
2134
|
+
&& !this.currentTurnScope
|
|
2135
|
+
&& !this.hasActionableApproval()
|
|
2136
|
+
&& !parsedHasActionableModal;
|
|
2137
|
+
return terminalLooksIdle ? null : `parsed_status_${parsedSessionStatus}`;
|
|
2138
|
+
}
|
|
2139
|
+
if (this.isWaitingForResponse && this.currentTurnScope) return 'active_turn_in_progress';
|
|
2140
|
+
return null;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
private schedulePendingOutboundFlush(delayMs = 0): void {
|
|
2144
|
+
if (this.pendingOutboundFlushTimer) clearTimeout(this.pendingOutboundFlushTimer);
|
|
2145
|
+
this.pendingOutboundFlushTimer = setTimeout(() => {
|
|
2146
|
+
this.pendingOutboundFlushTimer = null;
|
|
2147
|
+
void this.flushPendingOutboundQueue();
|
|
2148
|
+
}, Math.max(0, delayMs));
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
private async flushPendingOutboundQueue(): Promise<void> {
|
|
2152
|
+
if (this.pendingOutboundFlushInFlight || this.pendingOutboundQueue.length === 0) return;
|
|
2153
|
+
if (this.currentStatus !== 'idle' || this.isWaitingForResponse || this.hasActionableApproval()) return;
|
|
2154
|
+
this.pendingOutboundFlushInFlight = true;
|
|
2155
|
+
try {
|
|
2156
|
+
while (this.pendingOutboundQueue.length > 0) {
|
|
2157
|
+
if (this.currentStatus !== 'idle' || this.isWaitingForResponse || this.hasActionableApproval()) break;
|
|
2158
|
+
const next = this.pendingOutboundQueue[0];
|
|
2159
|
+
this.recordTrace('send_message_queue_flush', {
|
|
2160
|
+
id: next.id,
|
|
2161
|
+
queuedAt: next.queuedAt,
|
|
2162
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2163
|
+
text: summarizeCliTraceText(next.content, 500),
|
|
2164
|
+
});
|
|
2165
|
+
try {
|
|
2166
|
+
await this.sendMessageNow(next.content, false);
|
|
2167
|
+
this.pendingOutboundQueue.shift();
|
|
2168
|
+
this.onStatusChange?.();
|
|
2169
|
+
} catch (error: any) {
|
|
2170
|
+
LOG.warn('CLI', `[${this.cliType}] queued outbound flush failed: ${error?.message || error}`);
|
|
2171
|
+
this.schedulePendingOutboundFlush(1000);
|
|
2172
|
+
break;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
} finally {
|
|
2176
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
private async sendMessageNow(text: string, allowQueue: boolean): Promise<void> {
|
|
1928
2181
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
1929
2182
|
const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
|
|
1930
2183
|
const allowInterventionPrompt = allowInputDuringGeneration
|
|
@@ -1937,27 +2190,33 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1937
2190
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
1938
2191
|
}
|
|
1939
2192
|
}
|
|
2193
|
+
const parsedStatusBeforeSend = !allowInputDuringGeneration
|
|
2194
|
+
? (() => {
|
|
2195
|
+
try {
|
|
2196
|
+
return this.getScriptParsedStatus?.() || null;
|
|
2197
|
+
} catch {
|
|
2198
|
+
return null;
|
|
2199
|
+
}
|
|
2200
|
+
})()
|
|
2201
|
+
: null;
|
|
2202
|
+
const queueReason = this.shouldQueuePendingOutboundMessage(parsedStatusBeforeSend);
|
|
2203
|
+
if (allowQueue && queueReason) {
|
|
2204
|
+
this.enqueuePendingOutboundMessage(text, queueReason);
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
1940
2207
|
if (!allowInterventionPrompt) {
|
|
1941
2208
|
await this.waitForInteractivePrompt();
|
|
1942
2209
|
}
|
|
1943
2210
|
if (!this.ready) {
|
|
1944
2211
|
this.resolveStartupState('send_precheck');
|
|
1945
|
-
if (this.runDetectStatus(this.recentOutputBuffer) === 'idle'
|
|
2212
|
+
if (this.runDetectStatus(this.recentOutputBuffer) === 'idle') {
|
|
1946
2213
|
this.ready = true;
|
|
1947
2214
|
this.startupParseGate = false;
|
|
2215
|
+
this.setStatus('idle', 'send_message_idle_prompt_recovery');
|
|
1948
2216
|
LOG.info('CLI', `[${this.cliType}] sendMessage recovered idle prompt readiness`);
|
|
1949
2217
|
}
|
|
1950
2218
|
}
|
|
1951
2219
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
1952
|
-
const parsedStatusBeforeSend = !allowInputDuringGeneration
|
|
1953
|
-
? (() => {
|
|
1954
|
-
try {
|
|
1955
|
-
return this.getScriptParsedStatus?.() || null;
|
|
1956
|
-
} catch {
|
|
1957
|
-
return null;
|
|
1958
|
-
}
|
|
1959
|
-
})()
|
|
1960
|
-
: null;
|
|
1961
2220
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === 'string'
|
|
1962
2221
|
? String(parsedStatusBeforeSend.status)
|
|
1963
2222
|
: '';
|
|
@@ -1975,11 +2234,22 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1975
2234
|
&& !this.hasActionableApproval()
|
|
1976
2235
|
&& !parsedHasActionableModal;
|
|
1977
2236
|
if (!terminalLooksIdle) {
|
|
2237
|
+
if (allowQueue) {
|
|
2238
|
+
this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`);
|
|
2239
|
+
return;
|
|
2240
|
+
}
|
|
1978
2241
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
1979
2242
|
}
|
|
1980
2243
|
}
|
|
1981
2244
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
1982
|
-
if (
|
|
2245
|
+
if (
|
|
2246
|
+
!this.clearStaleIdleResponseGuard('send_message_guard')
|
|
2247
|
+
&& !this.clearParsedIdleResponseGuard('send_message_parsed_idle_guard', parsedStatusBeforeSend)
|
|
2248
|
+
) {
|
|
2249
|
+
if (allowQueue) {
|
|
2250
|
+
this.enqueuePendingOutboundMessage(text, 'waiting_for_response');
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
1983
2253
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
1984
2254
|
}
|
|
1985
2255
|
}
|
|
@@ -2230,6 +2500,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2230
2500
|
this.pendingTerminalQueryTail = '';
|
|
2231
2501
|
this.ptyOutputChunks = [];
|
|
2232
2502
|
this.finishRetryCount = 0;
|
|
2503
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2504
|
+
this.pendingOutboundQueue = [];
|
|
2505
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2233
2506
|
if (this.ptyProcess) {
|
|
2234
2507
|
this.ptyProcess.write('\x03');
|
|
2235
2508
|
setTimeout(() => {
|
|
@@ -2251,6 +2524,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2251
2524
|
this.pendingTerminalQueryTail = '';
|
|
2252
2525
|
this.ptyOutputChunks = [];
|
|
2253
2526
|
this.finishRetryCount = 0;
|
|
2527
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2528
|
+
this.pendingOutboundQueue = [];
|
|
2529
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2254
2530
|
if (this.ptyProcess) {
|
|
2255
2531
|
try {
|
|
2256
2532
|
if (typeof this.ptyProcess.detach === 'function') {
|
|
@@ -2281,6 +2557,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2281
2557
|
this.ptyOutputChunks = [];
|
|
2282
2558
|
if (this.finishRetryTimer) { clearTimeout(this.finishRetryTimer); this.finishRetryTimer = null; }
|
|
2283
2559
|
this.finishRetryCount = 0;
|
|
2560
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2561
|
+
this.pendingOutboundQueue = [];
|
|
2562
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2284
2563
|
this.resetTerminalScreen();
|
|
2285
2564
|
this.ptyProcess?.clearBuffer?.();
|
|
2286
2565
|
this.onStatusChange?.();
|
|
@@ -2369,10 +2648,26 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2369
2648
|
getDebugState(): Record<string, any> {
|
|
2370
2649
|
const screenText = sanitizeTerminalText(this.terminalScreen.getText());
|
|
2371
2650
|
const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2651
|
+
const startupDetectedStatus = this.startupParseGate && !startupModal
|
|
2652
|
+
? this.runDetectStatus(this.recentOutputBuffer || screenText)
|
|
2653
|
+
: null;
|
|
2654
|
+
const effectiveReady = this.ready || !!startupModal || startupDetectedStatus === 'waiting_approval';
|
|
2374
2655
|
const parsedDebugState = this.getParsedDebugState();
|
|
2375
2656
|
const parsedMessages = Array.isArray(parsedDebugState?.messages) ? parsedDebugState.messages : [];
|
|
2657
|
+
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
2658
|
+
if (parsedDebugState?.status === 'error') {
|
|
2659
|
+
effectiveStatus = 'error';
|
|
2660
|
+
}
|
|
2661
|
+
if (startupDetectedStatus === 'waiting_approval') {
|
|
2662
|
+
effectiveStatus = 'waiting_approval';
|
|
2663
|
+
}
|
|
2664
|
+
if (
|
|
2665
|
+
effectiveStatus === 'idle'
|
|
2666
|
+
&& parsedDebugState?.status === 'generating'
|
|
2667
|
+
&& !this.parsedStatusHasFinalAssistantMessage(parsedDebugState)
|
|
2668
|
+
) {
|
|
2669
|
+
effectiveStatus = 'generating';
|
|
2670
|
+
}
|
|
2376
2671
|
return {
|
|
2377
2672
|
type: this.cliType,
|
|
2378
2673
|
name: this.cliName,
|
|
@@ -2394,6 +2689,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2394
2689
|
providerSessionId: parsedDebugState.providerSessionId,
|
|
2395
2690
|
transcriptAuthority: parsedDebugState.transcriptAuthority,
|
|
2396
2691
|
coverage: parsedDebugState.coverage,
|
|
2692
|
+
errorMessage: parsedDebugState.errorMessage,
|
|
2693
|
+
errorReason: parsedDebugState.errorReason,
|
|
2397
2694
|
activeModal: parsedDebugState.activeModal,
|
|
2398
2695
|
messageCount: parsedMessages.length,
|
|
2399
2696
|
} : null,
|
|
@@ -2407,6 +2704,14 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2407
2704
|
rawBufferPreview: this.accumulatedRawBuffer.slice(-1000),
|
|
2408
2705
|
sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1000),
|
|
2409
2706
|
responseBuffer: this.responseBuffer.slice(-1000),
|
|
2707
|
+
pendingOutboundQueue: this.pendingOutboundQueue.map((message) => ({
|
|
2708
|
+
id: message.id,
|
|
2709
|
+
role: message.role,
|
|
2710
|
+
content: message.content,
|
|
2711
|
+
queuedAt: message.queuedAt,
|
|
2712
|
+
source: message.source,
|
|
2713
|
+
})),
|
|
2714
|
+
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
2410
2715
|
lastOutputAt: this.lastOutputAt,
|
|
2411
2716
|
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
2412
2717
|
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
@@ -15,6 +15,7 @@ export declare function buildCliParseInput(options: {
|
|
|
15
15
|
accumulatedRawBuffer: string;
|
|
16
16
|
recentOutputBuffer: string;
|
|
17
17
|
terminalScreenText: string;
|
|
18
|
+
workingDir?: string;
|
|
18
19
|
baseMessages: CliChatMessage[];
|
|
19
20
|
partialResponse: string;
|
|
20
21
|
isWaitingForResponse?: boolean;
|