@adhdev/daemon-core 0.9.82-rc.11 → 0.9.82-rc.110
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 +18 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +14 -0
- package/dist/commands/router.d.ts +22 -0
- package/dist/config/chat-history.d.ts +4 -0
- package/dist/config/mesh-config.d.ts +66 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +5936 -1225
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5902 -1212
- 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 +45 -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 +379 -17
- 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 +32 -10
- package/src/commands/chat-commands.ts +626 -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 +37 -9
- 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 +143 -18
- 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 +50 -0
- package/src/status/reporter.ts +15 -0
- package/src/system/host-memory.ts +29 -12
|
@@ -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 '';
|
|
@@ -137,6 +145,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
137
145
|
private isWaitingForResponse = false;
|
|
138
146
|
private activeModal: { message: string; buttons: string[] } | null = null;
|
|
139
147
|
private parseErrorMessage: string | null = null;
|
|
148
|
+
private providerSessionId: string | null = null;
|
|
149
|
+
private providerErrorMessage: string | null = null;
|
|
150
|
+
private providerErrorReason: string | null = null;
|
|
140
151
|
private responseTimeout: NodeJS.Timeout | null = null;
|
|
141
152
|
private idleTimeout: NodeJS.Timeout | null = null;
|
|
142
153
|
private ready = false;
|
|
@@ -186,6 +197,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
186
197
|
private idleFinishCandidate: IdleFinishCandidate | null = null;
|
|
187
198
|
private finishRetryTimer: NodeJS.Timeout | null = null;
|
|
188
199
|
private finishRetryCount = 0;
|
|
200
|
+
private pendingOutboundQueue: PendingOutboundMessage[] = [];
|
|
201
|
+
private pendingOutboundFlushTimer: NodeJS.Timeout | null = null;
|
|
202
|
+
private pendingOutboundFlushInFlight = false;
|
|
189
203
|
|
|
190
204
|
// Resize redraw suppression
|
|
191
205
|
private resizeSuppressUntil: number = 0;
|
|
@@ -761,6 +775,17 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
761
775
|
if (stableMs < 2000) return;
|
|
762
776
|
|
|
763
777
|
const startupModal = this.runParseApproval(this.recentOutputBuffer);
|
|
778
|
+
const startupStatus = this.runDetectStatus(screenText || this.recentOutputBuffer);
|
|
779
|
+
if (!startupModal && startupStatus !== 'idle') {
|
|
780
|
+
this.recordTrace('startup_settle_deferred', {
|
|
781
|
+
trigger,
|
|
782
|
+
startupStatus,
|
|
783
|
+
stableMs,
|
|
784
|
+
screenText: summarizeCliTraceText(screenText, 500),
|
|
785
|
+
});
|
|
786
|
+
this.scheduleStartupSettleCheck();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
764
789
|
this.startupParseGate = false;
|
|
765
790
|
if (this.startupSettleTimer) {
|
|
766
791
|
clearTimeout(this.startupSettleTimer);
|
|
@@ -956,6 +981,38 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
956
981
|
return true;
|
|
957
982
|
}
|
|
958
983
|
|
|
984
|
+
private clearParsedIdleResponseGuard(reason: string, parsedStatus: any): boolean {
|
|
985
|
+
const parsedRawStatus = typeof parsedStatus?.status === 'string' ? parsedStatus.status.trim() : '';
|
|
986
|
+
const parsedModal = parsedStatus?.activeModal ?? parsedStatus?.modal ?? null;
|
|
987
|
+
const blockingModal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
|
|
988
|
+
if (
|
|
989
|
+
!this.isWaitingForResponse
|
|
990
|
+
|| parsedRawStatus !== 'idle'
|
|
991
|
+
|| !!parsedModal
|
|
992
|
+
|| !!blockingModal
|
|
993
|
+
|| !this.parsedStatusHasFinalAssistantMessage(parsedStatus)
|
|
994
|
+
) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
this.clearAllTimers();
|
|
998
|
+
this.clearIdleFinishCandidate(reason);
|
|
999
|
+
this.responseBuffer = '';
|
|
1000
|
+
this.isWaitingForResponse = false;
|
|
1001
|
+
this.responseSettleIgnoreUntil = 0;
|
|
1002
|
+
this.submitRetryUsed = false;
|
|
1003
|
+
this.submitRetryPromptSnippet = '';
|
|
1004
|
+
this.finishRetryCount = 0;
|
|
1005
|
+
this.currentTurnScope = null;
|
|
1006
|
+
this.activeModal = null;
|
|
1007
|
+
this.setStatus('idle', reason);
|
|
1008
|
+
this.recordTrace('parsed_idle_response_cleared', {
|
|
1009
|
+
reason,
|
|
1010
|
+
parsedStatus: parsedRawStatus,
|
|
1011
|
+
parsedMessageCount: Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : 0,
|
|
1012
|
+
});
|
|
1013
|
+
return true;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
959
1016
|
private hasMeaningfulResponseBuffer(promptSnippet: string): boolean {
|
|
960
1017
|
const raw = String(this.responseBuffer || '').trim();
|
|
961
1018
|
if (!raw) return false;
|
|
@@ -1097,6 +1154,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1097
1154
|
&& !(parsedStatus === 'idle' && !!lastParsedAssistant);
|
|
1098
1155
|
|
|
1099
1156
|
if (shouldHoldGenerating) { this.applyHoldGenerating(ctx, recentInteractiveActivity); return; }
|
|
1157
|
+
if (status === 'error') { this.applyError(ctx, session); return; }
|
|
1100
1158
|
if (status === 'waiting_approval') { this.applyWaitingApproval(ctx); return; }
|
|
1101
1159
|
if (status === 'generating') { this.applyGenerating(ctx); return; }
|
|
1102
1160
|
if (status === 'idle') { this.applyIdle(ctx, now); }
|
|
@@ -1240,6 +1298,41 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1240
1298
|
this.onStatusChange?.();
|
|
1241
1299
|
}
|
|
1242
1300
|
|
|
1301
|
+
private applyError(ctx: SettledEvalContext, session: ParsedSession): void {
|
|
1302
|
+
this.clearIdleFinishCandidate('provider_error');
|
|
1303
|
+
if (this.responseTimeout) { clearTimeout(this.responseTimeout); this.responseTimeout = null; }
|
|
1304
|
+
if (this.idleTimeout) { clearTimeout(this.idleTimeout); this.idleTimeout = null; }
|
|
1305
|
+
if (this.approvalExitTimeout) { clearTimeout(this.approvalExitTimeout); this.approvalExitTimeout = null; }
|
|
1306
|
+
this.isWaitingForResponse = false;
|
|
1307
|
+
this.responseSettleIgnoreUntil = 0;
|
|
1308
|
+
this.submitRetryUsed = false;
|
|
1309
|
+
this.submitRetryPromptSnippet = '';
|
|
1310
|
+
this.finishRetryCount = 0;
|
|
1311
|
+
this.currentTurnScope = null;
|
|
1312
|
+
this.activeModal = null;
|
|
1313
|
+
this.providerErrorMessage = typeof session.errorMessage === 'string' && session.errorMessage.trim()
|
|
1314
|
+
? session.errorMessage.trim()
|
|
1315
|
+
: 'Provider reported an error';
|
|
1316
|
+
this.providerErrorReason = typeof session.errorReason === 'string' && session.errorReason.trim()
|
|
1317
|
+
? session.errorReason.trim()
|
|
1318
|
+
: 'provider_error';
|
|
1319
|
+
this.setStatus('error', this.providerErrorReason);
|
|
1320
|
+
this.recordTrace('provider_error', {
|
|
1321
|
+
errorMessage: this.providerErrorMessage,
|
|
1322
|
+
errorReason: this.providerErrorReason,
|
|
1323
|
+
parsedStatus: ctx.parsedStatus || ctx.status,
|
|
1324
|
+
messageCount: ctx.parsedMessages.length,
|
|
1325
|
+
...buildCliTraceParseSnapshot({
|
|
1326
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
1327
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1328
|
+
responseBuffer: this.responseBuffer,
|
|
1329
|
+
partialResponse: this.responseBuffer,
|
|
1330
|
+
scope: this.currentTurnScope,
|
|
1331
|
+
}),
|
|
1332
|
+
});
|
|
1333
|
+
this.onStatusChange?.();
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1243
1336
|
private applyIdle(ctx: SettledEvalContext, now: number): void {
|
|
1244
1337
|
const { modal, lastParsedAssistant, prevStatus } = ctx;
|
|
1245
1338
|
if (prevStatus === 'waiting_approval') {
|
|
@@ -1318,6 +1411,11 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1318
1411
|
this.idleTimeout = setTimeout(() => {
|
|
1319
1412
|
if (this.isWaitingForResponse && !this.hasActionableApproval()) {
|
|
1320
1413
|
if (this.shouldDeferIdleTimeoutFinish()) return;
|
|
1414
|
+
const parsed = this.runParseSession();
|
|
1415
|
+
if (this.shouldKeepCodexTurnOpenForFinish(parsed)) {
|
|
1416
|
+
this.rescheduleCodexFinishCheck('codex_idle_timeout_not_final');
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1321
1419
|
this.clearIdleFinishCandidate('idle_timeout_finish');
|
|
1322
1420
|
this.finishResponse();
|
|
1323
1421
|
}
|
|
@@ -1327,6 +1425,11 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1327
1425
|
private finishResponse(): void {
|
|
1328
1426
|
if (this.submitPendingUntil > Date.now()) return;
|
|
1329
1427
|
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1428
|
+
const parsedBeforeFinish = this.runParseSession();
|
|
1429
|
+
if (this.shouldKeepCodexTurnOpenForFinish(parsedBeforeFinish)) {
|
|
1430
|
+
this.rescheduleCodexFinishCheck('codex_finish_not_final');
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1330
1433
|
this.clearIdleFinishCandidate('finish_response_enter');
|
|
1331
1434
|
this.recordTrace('finish_response', {
|
|
1332
1435
|
...buildCliTraceParseSnapshot({
|
|
@@ -1372,6 +1475,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1372
1475
|
this.activeModal = null;
|
|
1373
1476
|
this.setStatus('idle', 'response_finished');
|
|
1374
1477
|
this.onStatusChange?.();
|
|
1478
|
+
this.schedulePendingOutboundFlush();
|
|
1375
1479
|
}
|
|
1376
1480
|
|
|
1377
1481
|
private maybeCommitVisibleIdleTranscript(session: ParsedSession, parsedMessages: CliChatMessage[]): boolean {
|
|
@@ -1402,6 +1506,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1402
1506
|
this.activeModal = null;
|
|
1403
1507
|
this.setStatus('idle', 'script_idle_commit');
|
|
1404
1508
|
this.onStatusChange?.();
|
|
1509
|
+
this.schedulePendingOutboundFlush();
|
|
1405
1510
|
this.recordTrace('script_idle_commit', {
|
|
1406
1511
|
messageCount: parsedMessages.length,
|
|
1407
1512
|
lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320),
|
|
@@ -1489,6 +1594,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1489
1594
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1490
1595
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
1491
1596
|
terminalScreenText: parseScreenText,
|
|
1597
|
+
workingDir: this.workingDir,
|
|
1492
1598
|
baseMessages: [],
|
|
1493
1599
|
partialResponse: this.responseBuffer,
|
|
1494
1600
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
@@ -1500,6 +1606,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1500
1606
|
{ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) },
|
|
1501
1607
|
);
|
|
1502
1608
|
this.parseErrorMessage = null;
|
|
1609
|
+
if (session && typeof session === 'object') this.applyParsedSessionMetadata(session);
|
|
1503
1610
|
return session && typeof session === 'object' ? session : null;
|
|
1504
1611
|
} catch (e: any) {
|
|
1505
1612
|
const message = e?.message || String(e);
|
|
@@ -1552,6 +1659,74 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1552
1659
|
return !!(startupModal || this.activeModal);
|
|
1553
1660
|
}
|
|
1554
1661
|
|
|
1662
|
+
private parsedStatusHasFinalAssistantMessage(parsed: any): boolean {
|
|
1663
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
1664
|
+
const lastAssistant = [...messages].reverse().find((message: any) => {
|
|
1665
|
+
if (!message || message.role !== 'assistant') return false;
|
|
1666
|
+
return typeof message.content === 'string' && message.content.trim().length > 0;
|
|
1667
|
+
});
|
|
1668
|
+
return !!lastAssistant;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
private applyParsedSessionMetadata(parsed: any): void {
|
|
1672
|
+
const providerSessionId = typeof parsed?.providerSessionId === 'string' && parsed.providerSessionId.trim()
|
|
1673
|
+
? parsed.providerSessionId.trim()
|
|
1674
|
+
: '';
|
|
1675
|
+
if (providerSessionId) {
|
|
1676
|
+
this.providerSessionId = providerSessionId;
|
|
1677
|
+
this.updateRuntimeMeta({ providerSessionId });
|
|
1678
|
+
}
|
|
1679
|
+
this.providerErrorMessage = typeof parsed?.errorMessage === 'string' && parsed.errorMessage.trim()
|
|
1680
|
+
? parsed.errorMessage.trim()
|
|
1681
|
+
: null;
|
|
1682
|
+
this.providerErrorReason = typeof parsed?.errorReason === 'string' && parsed.errorReason.trim()
|
|
1683
|
+
? parsed.errorReason.trim()
|
|
1684
|
+
: null;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
private parsedStatusHasFinalStandardAssistantMessage(parsed: any): boolean {
|
|
1688
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
1689
|
+
const lastAssistant = [...messages].reverse().find((message: any) => {
|
|
1690
|
+
if (!message || message.role !== 'assistant') return false;
|
|
1691
|
+
return typeof message.content === 'string' && message.content.trim().length > 0;
|
|
1692
|
+
});
|
|
1693
|
+
if (!lastAssistant) return false;
|
|
1694
|
+
const kind = typeof lastAssistant.kind === 'string' && lastAssistant.kind.trim()
|
|
1695
|
+
? lastAssistant.kind.trim()
|
|
1696
|
+
: 'standard';
|
|
1697
|
+
return kind === 'standard' && lastAssistant.meta?.streaming !== true;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
private shouldKeepCodexTurnOpenForFinish(parsed: any): boolean {
|
|
1701
|
+
if (this.cliType !== 'codex-cli') return false;
|
|
1702
|
+
if (!this.isWaitingForResponse || !this.currentTurnScope || this.hasActionableApproval()) return false;
|
|
1703
|
+
const parsedStatus = typeof parsed?.status === 'string' ? parsed.status.trim() : '';
|
|
1704
|
+
if (parsedStatus !== 'idle') return true;
|
|
1705
|
+
if (parsed?.activeModal || parsed?.modal) return true;
|
|
1706
|
+
return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
private rescheduleCodexFinishCheck(reason: string): void {
|
|
1710
|
+
this.clearIdleFinishCandidate(reason);
|
|
1711
|
+
this.setStatus('generating', reason);
|
|
1712
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1713
|
+
this.idleTimeout = setTimeout(() => {
|
|
1714
|
+
if (!this.isWaitingForResponse || this.hasActionableApproval()) return;
|
|
1715
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
1716
|
+
this.evaluateSettled();
|
|
1717
|
+
}, this.getIdleFinishConfirmMs());
|
|
1718
|
+
this.recordTrace('codex_finish_deferred', {
|
|
1719
|
+
reason,
|
|
1720
|
+
...buildCliTraceParseSnapshot({
|
|
1721
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
1722
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1723
|
+
responseBuffer: this.responseBuffer,
|
|
1724
|
+
partialResponse: this.responseBuffer,
|
|
1725
|
+
scope: this.currentTurnScope,
|
|
1726
|
+
}),
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1555
1730
|
private projectEffectiveStatus(startupModal: { message: string; buttons: string[] } | null = null): CliSessionStatus['status'] {
|
|
1556
1731
|
if (this.parseErrorMessage) return 'error';
|
|
1557
1732
|
if (this.hasActionableApproval(startupModal)) return 'waiting_approval';
|
|
@@ -1564,8 +1739,16 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1564
1739
|
getStatus(options: { allowParse?: boolean } = {}): CliSessionStatus {
|
|
1565
1740
|
const allowParse = options.allowParse !== false;
|
|
1566
1741
|
const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
1742
|
+
const startupDetectedStatus = allowParse && this.startupParseGate && !startupModal
|
|
1743
|
+
? this.runDetectStatus(this.recentOutputBuffer || this.terminalScreen.getText())
|
|
1744
|
+
: null;
|
|
1567
1745
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
1568
1746
|
let effectiveModal = startupModal || this.activeModal;
|
|
1747
|
+
if (startupDetectedStatus === 'waiting_approval') {
|
|
1748
|
+
effectiveStatus = 'waiting_approval';
|
|
1749
|
+
} else if (startupDetectedStatus === 'idle' && !startupModal && !effectiveModal) {
|
|
1750
|
+
effectiveStatus = 'idle';
|
|
1751
|
+
}
|
|
1569
1752
|
if (allowParse && !startupModal && !effectiveModal) {
|
|
1570
1753
|
const parsed = this.getFreshParsedStatusCache();
|
|
1571
1754
|
const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
@@ -1575,6 +1758,18 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1575
1758
|
if (parsed?.status === 'waiting_approval' && parsedModal) {
|
|
1576
1759
|
effectiveStatus = 'waiting_approval';
|
|
1577
1760
|
effectiveModal = parsedModal;
|
|
1761
|
+
} else if (
|
|
1762
|
+
effectiveStatus === 'idle'
|
|
1763
|
+
&& parsed?.status === 'generating'
|
|
1764
|
+
&& !this.parsedStatusHasFinalAssistantMessage(parsed)
|
|
1765
|
+
) {
|
|
1766
|
+
effectiveStatus = 'generating';
|
|
1767
|
+
} else if (
|
|
1768
|
+
effectiveStatus === 'generating'
|
|
1769
|
+
&& parsed?.status === 'idle'
|
|
1770
|
+
&& this.parsedStatusHasFinalAssistantMessage(parsed)
|
|
1771
|
+
) {
|
|
1772
|
+
effectiveStatus = 'idle';
|
|
1578
1773
|
}
|
|
1579
1774
|
}
|
|
1580
1775
|
const bufferState = this.getBufferState();
|
|
@@ -1583,8 +1778,17 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1583
1778
|
messages: [],
|
|
1584
1779
|
workingDir: this.workingDir,
|
|
1585
1780
|
activeModal: effectiveModal,
|
|
1586
|
-
|
|
1587
|
-
|
|
1781
|
+
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
1782
|
+
pendingOutboundMessages: this.pendingOutboundQueue.map((message) => ({
|
|
1783
|
+
id: message.id,
|
|
1784
|
+
role: message.role,
|
|
1785
|
+
content: message.content,
|
|
1786
|
+
queuedAt: message.queuedAt,
|
|
1787
|
+
source: message.source,
|
|
1788
|
+
})),
|
|
1789
|
+
errorMessage: this.parseErrorMessage || this.providerErrorMessage || undefined,
|
|
1790
|
+
errorReason: this.parseErrorMessage ? 'parse_error' : (this.providerErrorReason || undefined),
|
|
1791
|
+
providerSessionId: this.providerSessionId || undefined,
|
|
1588
1792
|
...(bufferState ? { bufferState } : {}),
|
|
1589
1793
|
};
|
|
1590
1794
|
}
|
|
@@ -1600,7 +1804,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1600
1804
|
const cached = this.parsedStatusCache;
|
|
1601
1805
|
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
1602
1806
|
if (
|
|
1603
|
-
|
|
1807
|
+
!this.providerOwnsTranscript()
|
|
1808
|
+
&& cached
|
|
1604
1809
|
&& cached.responseBuffer === this.responseBuffer
|
|
1605
1810
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
1606
1811
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
@@ -1630,7 +1835,13 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1630
1835
|
lastOutputAt: this.lastOutputAt,
|
|
1631
1836
|
}),
|
|
1632
1837
|
activeModal,
|
|
1633
|
-
providerSessionId: typeof (parsed as any).providerSessionId === 'string' ? (parsed as any).providerSessionId : undefined,
|
|
1838
|
+
providerSessionId: this.providerSessionId || (typeof (parsed as any).providerSessionId === 'string' ? (parsed as any).providerSessionId : undefined),
|
|
1839
|
+
errorMessage: typeof (parsed as any).errorMessage === 'string' && (parsed as any).errorMessage.trim()
|
|
1840
|
+
? (parsed as any).errorMessage.trim()
|
|
1841
|
+
: undefined,
|
|
1842
|
+
errorReason: typeof (parsed as any).errorReason === 'string' && (parsed as any).errorReason.trim()
|
|
1843
|
+
? (parsed as any).errorReason.trim()
|
|
1844
|
+
: undefined,
|
|
1634
1845
|
...(bufferState ? { bufferState } : {}),
|
|
1635
1846
|
...((parsed as any).transcriptAuthority === 'provider' || (parsed as any).transcriptAuthority === 'daemon'
|
|
1636
1847
|
? { transcriptAuthority: (parsed as any).transcriptAuthority }
|
|
@@ -1665,6 +1876,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1665
1876
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1666
1877
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
1667
1878
|
terminalScreenText: this.getParseScreenText(this.terminalScreen.getText()),
|
|
1879
|
+
workingDir: this.workingDir,
|
|
1668
1880
|
baseMessages: [],
|
|
1669
1881
|
partialResponse: this.responseBuffer,
|
|
1670
1882
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
@@ -1925,6 +2137,104 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1925
2137
|
}
|
|
1926
2138
|
|
|
1927
2139
|
async sendMessage(text: string): Promise<void> {
|
|
2140
|
+
await this.sendMessageNow(text, true);
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
private enqueuePendingOutboundMessage(text: string, reason: string): void {
|
|
2144
|
+
const content = String(text || '');
|
|
2145
|
+
const duplicate = this.pendingOutboundQueue.some((message) => message.content === content);
|
|
2146
|
+
if (duplicate) {
|
|
2147
|
+
this.recordTrace('send_message_queued_duplicate_suppressed', {
|
|
2148
|
+
reason,
|
|
2149
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2150
|
+
text: summarizeCliTraceText(content, 500),
|
|
2151
|
+
});
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
const queuedAt = Date.now();
|
|
2155
|
+
const message: PendingOutboundMessage = {
|
|
2156
|
+
id: `${queuedAt}:${this.pendingOutboundQueue.length}:${Math.random().toString(36).slice(2, 10)}`,
|
|
2157
|
+
role: 'user',
|
|
2158
|
+
content,
|
|
2159
|
+
queuedAt,
|
|
2160
|
+
source: 'sendMessage',
|
|
2161
|
+
};
|
|
2162
|
+
this.pendingOutboundQueue.push(message);
|
|
2163
|
+
this.recordTrace('send_message_queued', {
|
|
2164
|
+
reason,
|
|
2165
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2166
|
+
queuedAt,
|
|
2167
|
+
text: summarizeCliTraceText(content, 500),
|
|
2168
|
+
});
|
|
2169
|
+
LOG.info('CLI', `[${this.cliType}] queued outbound message while busy (${reason}); queue=${this.pendingOutboundQueue.length}`);
|
|
2170
|
+
this.onStatusChange?.();
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
private shouldQueuePendingOutboundMessage(parsedStatusBeforeSend: any | null = null): string | null {
|
|
2174
|
+
if (this.provider.allowInputDuringGeneration === true) return null;
|
|
2175
|
+
if (this.hasActionableApproval()) return null;
|
|
2176
|
+
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === 'string'
|
|
2177
|
+
? String(parsedStatusBeforeSend.status)
|
|
2178
|
+
: '';
|
|
2179
|
+
if (parsedSessionStatus === 'idle' && this.parsedStatusHasFinalAssistantMessage(parsedStatusBeforeSend)) return null;
|
|
2180
|
+
if (this.currentStatus === 'generating') return 'current_status_generating';
|
|
2181
|
+
if (parsedSessionStatus === 'generating' || parsedSessionStatus === 'long_generating') {
|
|
2182
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
2183
|
+
const parsedHasActionableModal = Boolean(
|
|
2184
|
+
parsedModal
|
|
2185
|
+
&& Array.isArray(parsedModal.buttons)
|
|
2186
|
+
&& parsedModal.buttons.some((candidate: unknown) => typeof candidate === 'string' && candidate.trim()),
|
|
2187
|
+
);
|
|
2188
|
+
const terminalLooksIdle = this.currentStatus === 'idle'
|
|
2189
|
+
&& this.runDetectStatus(this.recentOutputBuffer) === 'idle'
|
|
2190
|
+
&& !this.isWaitingForResponse
|
|
2191
|
+
&& !this.currentTurnScope
|
|
2192
|
+
&& !this.hasActionableApproval()
|
|
2193
|
+
&& !parsedHasActionableModal;
|
|
2194
|
+
return terminalLooksIdle ? null : `parsed_status_${parsedSessionStatus}`;
|
|
2195
|
+
}
|
|
2196
|
+
if (this.isWaitingForResponse && this.currentTurnScope) return 'active_turn_in_progress';
|
|
2197
|
+
return null;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
private schedulePendingOutboundFlush(delayMs = 0): void {
|
|
2201
|
+
if (this.pendingOutboundFlushTimer) clearTimeout(this.pendingOutboundFlushTimer);
|
|
2202
|
+
this.pendingOutboundFlushTimer = setTimeout(() => {
|
|
2203
|
+
this.pendingOutboundFlushTimer = null;
|
|
2204
|
+
void this.flushPendingOutboundQueue();
|
|
2205
|
+
}, Math.max(0, delayMs));
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
private async flushPendingOutboundQueue(): Promise<void> {
|
|
2209
|
+
if (this.pendingOutboundFlushInFlight || this.pendingOutboundQueue.length === 0) return;
|
|
2210
|
+
if (this.currentStatus !== 'idle' || this.isWaitingForResponse || this.hasActionableApproval()) return;
|
|
2211
|
+
this.pendingOutboundFlushInFlight = true;
|
|
2212
|
+
try {
|
|
2213
|
+
while (this.pendingOutboundQueue.length > 0) {
|
|
2214
|
+
if (this.currentStatus !== 'idle' || this.isWaitingForResponse || this.hasActionableApproval()) break;
|
|
2215
|
+
const next = this.pendingOutboundQueue[0];
|
|
2216
|
+
this.recordTrace('send_message_queue_flush', {
|
|
2217
|
+
id: next.id,
|
|
2218
|
+
queuedAt: next.queuedAt,
|
|
2219
|
+
queueLength: this.pendingOutboundQueue.length,
|
|
2220
|
+
text: summarizeCliTraceText(next.content, 500),
|
|
2221
|
+
});
|
|
2222
|
+
try {
|
|
2223
|
+
await this.sendMessageNow(next.content, false);
|
|
2224
|
+
this.pendingOutboundQueue.shift();
|
|
2225
|
+
this.onStatusChange?.();
|
|
2226
|
+
} catch (error: any) {
|
|
2227
|
+
LOG.warn('CLI', `[${this.cliType}] queued outbound flush failed: ${error?.message || error}`);
|
|
2228
|
+
this.schedulePendingOutboundFlush(1000);
|
|
2229
|
+
break;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
} finally {
|
|
2233
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
private async sendMessageNow(text: string, allowQueue: boolean): Promise<void> {
|
|
1928
2238
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
1929
2239
|
const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
|
|
1930
2240
|
const allowInterventionPrompt = allowInputDuringGeneration
|
|
@@ -1937,27 +2247,33 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1937
2247
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
1938
2248
|
}
|
|
1939
2249
|
}
|
|
2250
|
+
const parsedStatusBeforeSend = !allowInputDuringGeneration
|
|
2251
|
+
? (() => {
|
|
2252
|
+
try {
|
|
2253
|
+
return this.getScriptParsedStatus?.() || null;
|
|
2254
|
+
} catch {
|
|
2255
|
+
return null;
|
|
2256
|
+
}
|
|
2257
|
+
})()
|
|
2258
|
+
: null;
|
|
2259
|
+
const queueReason = this.shouldQueuePendingOutboundMessage(parsedStatusBeforeSend);
|
|
2260
|
+
if (allowQueue && queueReason) {
|
|
2261
|
+
this.enqueuePendingOutboundMessage(text, queueReason);
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
1940
2264
|
if (!allowInterventionPrompt) {
|
|
1941
2265
|
await this.waitForInteractivePrompt();
|
|
1942
2266
|
}
|
|
1943
2267
|
if (!this.ready) {
|
|
1944
2268
|
this.resolveStartupState('send_precheck');
|
|
1945
|
-
if (this.runDetectStatus(this.recentOutputBuffer) === 'idle'
|
|
2269
|
+
if (this.runDetectStatus(this.recentOutputBuffer) === 'idle') {
|
|
1946
2270
|
this.ready = true;
|
|
1947
2271
|
this.startupParseGate = false;
|
|
2272
|
+
this.setStatus('idle', 'send_message_idle_prompt_recovery');
|
|
1948
2273
|
LOG.info('CLI', `[${this.cliType}] sendMessage recovered idle prompt readiness`);
|
|
1949
2274
|
}
|
|
1950
2275
|
}
|
|
1951
2276
|
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
2277
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === 'string'
|
|
1962
2278
|
? String(parsedStatusBeforeSend.status)
|
|
1963
2279
|
: '';
|
|
@@ -1975,11 +2291,22 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1975
2291
|
&& !this.hasActionableApproval()
|
|
1976
2292
|
&& !parsedHasActionableModal;
|
|
1977
2293
|
if (!terminalLooksIdle) {
|
|
2294
|
+
if (allowQueue) {
|
|
2295
|
+
this.enqueuePendingOutboundMessage(text, `parsed_status_${parsedSessionStatus}`);
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
1978
2298
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
1979
2299
|
}
|
|
1980
2300
|
}
|
|
1981
2301
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
1982
|
-
if (
|
|
2302
|
+
if (
|
|
2303
|
+
!this.clearStaleIdleResponseGuard('send_message_guard')
|
|
2304
|
+
&& !this.clearParsedIdleResponseGuard('send_message_parsed_idle_guard', parsedStatusBeforeSend)
|
|
2305
|
+
) {
|
|
2306
|
+
if (allowQueue) {
|
|
2307
|
+
this.enqueuePendingOutboundMessage(text, 'waiting_for_response');
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
1983
2310
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
1984
2311
|
}
|
|
1985
2312
|
}
|
|
@@ -2230,6 +2557,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2230
2557
|
this.pendingTerminalQueryTail = '';
|
|
2231
2558
|
this.ptyOutputChunks = [];
|
|
2232
2559
|
this.finishRetryCount = 0;
|
|
2560
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2561
|
+
this.pendingOutboundQueue = [];
|
|
2562
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2233
2563
|
if (this.ptyProcess) {
|
|
2234
2564
|
this.ptyProcess.write('\x03');
|
|
2235
2565
|
setTimeout(() => {
|
|
@@ -2251,6 +2581,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2251
2581
|
this.pendingTerminalQueryTail = '';
|
|
2252
2582
|
this.ptyOutputChunks = [];
|
|
2253
2583
|
this.finishRetryCount = 0;
|
|
2584
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2585
|
+
this.pendingOutboundQueue = [];
|
|
2586
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2254
2587
|
if (this.ptyProcess) {
|
|
2255
2588
|
try {
|
|
2256
2589
|
if (typeof this.ptyProcess.detach === 'function') {
|
|
@@ -2281,6 +2614,9 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2281
2614
|
this.ptyOutputChunks = [];
|
|
2282
2615
|
if (this.finishRetryTimer) { clearTimeout(this.finishRetryTimer); this.finishRetryTimer = null; }
|
|
2283
2616
|
this.finishRetryCount = 0;
|
|
2617
|
+
if (this.pendingOutboundFlushTimer) { clearTimeout(this.pendingOutboundFlushTimer); this.pendingOutboundFlushTimer = null; }
|
|
2618
|
+
this.pendingOutboundQueue = [];
|
|
2619
|
+
this.pendingOutboundFlushInFlight = false;
|
|
2284
2620
|
this.resetTerminalScreen();
|
|
2285
2621
|
this.ptyProcess?.clearBuffer?.();
|
|
2286
2622
|
this.onStatusChange?.();
|
|
@@ -2369,10 +2705,26 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2369
2705
|
getDebugState(): Record<string, any> {
|
|
2370
2706
|
const screenText = sanitizeTerminalText(this.terminalScreen.getText());
|
|
2371
2707
|
const startupModal = this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
2372
|
-
const
|
|
2373
|
-
|
|
2708
|
+
const startupDetectedStatus = this.startupParseGate && !startupModal
|
|
2709
|
+
? this.runDetectStatus(this.recentOutputBuffer || screenText)
|
|
2710
|
+
: null;
|
|
2711
|
+
const effectiveReady = this.ready || !!startupModal || startupDetectedStatus === 'waiting_approval';
|
|
2374
2712
|
const parsedDebugState = this.getParsedDebugState();
|
|
2375
2713
|
const parsedMessages = Array.isArray(parsedDebugState?.messages) ? parsedDebugState.messages : [];
|
|
2714
|
+
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
2715
|
+
if (parsedDebugState?.status === 'error') {
|
|
2716
|
+
effectiveStatus = 'error';
|
|
2717
|
+
}
|
|
2718
|
+
if (startupDetectedStatus === 'waiting_approval') {
|
|
2719
|
+
effectiveStatus = 'waiting_approval';
|
|
2720
|
+
}
|
|
2721
|
+
if (
|
|
2722
|
+
effectiveStatus === 'idle'
|
|
2723
|
+
&& parsedDebugState?.status === 'generating'
|
|
2724
|
+
&& !this.parsedStatusHasFinalAssistantMessage(parsedDebugState)
|
|
2725
|
+
) {
|
|
2726
|
+
effectiveStatus = 'generating';
|
|
2727
|
+
}
|
|
2376
2728
|
return {
|
|
2377
2729
|
type: this.cliType,
|
|
2378
2730
|
name: this.cliName,
|
|
@@ -2394,6 +2746,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2394
2746
|
providerSessionId: parsedDebugState.providerSessionId,
|
|
2395
2747
|
transcriptAuthority: parsedDebugState.transcriptAuthority,
|
|
2396
2748
|
coverage: parsedDebugState.coverage,
|
|
2749
|
+
errorMessage: parsedDebugState.errorMessage,
|
|
2750
|
+
errorReason: parsedDebugState.errorReason,
|
|
2397
2751
|
activeModal: parsedDebugState.activeModal,
|
|
2398
2752
|
messageCount: parsedMessages.length,
|
|
2399
2753
|
} : null,
|
|
@@ -2407,6 +2761,14 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2407
2761
|
rawBufferPreview: this.accumulatedRawBuffer.slice(-1000),
|
|
2408
2762
|
sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1000),
|
|
2409
2763
|
responseBuffer: this.responseBuffer.slice(-1000),
|
|
2764
|
+
pendingOutboundQueue: this.pendingOutboundQueue.map((message) => ({
|
|
2765
|
+
id: message.id,
|
|
2766
|
+
role: message.role,
|
|
2767
|
+
content: message.content,
|
|
2768
|
+
queuedAt: message.queuedAt,
|
|
2769
|
+
source: message.source,
|
|
2770
|
+
})),
|
|
2771
|
+
pendingOutboundCount: this.pendingOutboundQueue.length,
|
|
2410
2772
|
lastOutputAt: this.lastOutputAt,
|
|
2411
2773
|
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
2412
2774
|
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;
|
|
@@ -35,6 +35,7 @@ export function buildCliParseInput(options: {
|
|
|
35
35
|
accumulatedRawBuffer: string;
|
|
36
36
|
recentOutputBuffer: string;
|
|
37
37
|
terminalScreenText: string;
|
|
38
|
+
workingDir?: string;
|
|
38
39
|
baseMessages: CliChatMessage[];
|
|
39
40
|
partialResponse: string;
|
|
40
41
|
isWaitingForResponse?: boolean;
|
|
@@ -46,6 +47,7 @@ export function buildCliParseInput(options: {
|
|
|
46
47
|
accumulatedRawBuffer,
|
|
47
48
|
recentOutputBuffer,
|
|
48
49
|
terminalScreenText,
|
|
50
|
+
workingDir,
|
|
49
51
|
baseMessages,
|
|
50
52
|
partialResponse,
|
|
51
53
|
isWaitingForResponse,
|
|
@@ -66,6 +68,8 @@ export function buildCliParseInput(options: {
|
|
|
66
68
|
rawBuffer,
|
|
67
69
|
recentBuffer,
|
|
68
70
|
screenText,
|
|
71
|
+
workspace: workingDir,
|
|
72
|
+
workingDir,
|
|
69
73
|
screen: buildCliScreenSnapshot(screenText),
|
|
70
74
|
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
71
75
|
recentScreen: buildCliScreenSnapshot(recentBuffer),
|
|
@@ -36,7 +36,9 @@ export function resolveCliSpawnPlan(options: {
|
|
|
36
36
|
: spawnConfig.command;
|
|
37
37
|
const binaryPath = findBinary(configuredCommand);
|
|
38
38
|
const isWin = os.platform() === 'win32';
|
|
39
|
-
const allArgs = [...spawnConfig.args, ...extraArgs]
|
|
39
|
+
const allArgs = [...spawnConfig.args, ...extraArgs].map((arg) =>
|
|
40
|
+
typeof arg === 'string' ? arg.replace(/\{\{workingDir\}\}/g, workingDir) : arg,
|
|
41
|
+
);
|
|
40
42
|
|
|
41
43
|
let shellCmd: string;
|
|
42
44
|
let shellArgs: string[];
|