adhdev 0.9.18 → 0.9.20

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/index.js CHANGED
@@ -6675,14 +6675,14 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
6675
6675
  id: state.instanceId || state.type,
6676
6676
  parentId: null,
6677
6677
  providerType: state.type,
6678
- ...includeSessionMetadata && { providerName: state.name },
6678
+ providerName: state.name,
6679
6679
  kind: "workspace",
6680
6680
  transport: "cdp-page",
6681
6681
  status: normalizeManagedStatus(activeChat?.status || state.status, {
6682
6682
  activeModal: activeChat?.activeModal || null
6683
6683
  }),
6684
6684
  title,
6685
- ...includeSessionMetadata && { workspace: state.workspace || null },
6685
+ workspace: state.workspace || null,
6686
6686
  activeChat,
6687
6687
  ...summaryMetadata && { summaryMetadata },
6688
6688
  ...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
@@ -6707,7 +6707,7 @@ function buildExtensionAgentSession(parent, ext, options) {
6707
6707
  id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
6708
6708
  parentId: parent.instanceId || parent.type,
6709
6709
  providerType: ext.type,
6710
- ...includeSessionMetadata && { providerName: ext.name },
6710
+ providerName: ext.name,
6711
6711
  providerSessionId: ext.providerSessionId,
6712
6712
  kind: "agent",
6713
6713
  transport: "cdp-webview",
@@ -6715,7 +6715,7 @@ function buildExtensionAgentSession(parent, ext, options) {
6715
6715
  activeModal: activeChat?.activeModal || null
6716
6716
  }),
6717
6717
  title: activeChat?.title || ext.name,
6718
- ...includeSessionMetadata && { workspace: parent.workspace || null },
6718
+ workspace: parent.workspace || null,
6719
6719
  activeChat,
6720
6720
  ...summaryMetadata && { summaryMetadata },
6721
6721
  ...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
@@ -6755,7 +6755,7 @@ function buildCliSession(state, options) {
6755
6755
  id: state.instanceId,
6756
6756
  parentId: null,
6757
6757
  providerType: state.type,
6758
- ...includeSessionMetadata && { providerName: state.name },
6758
+ providerName: state.name,
6759
6759
  providerSessionId: state.providerSessionId,
6760
6760
  kind: "agent",
6761
6761
  transport: "pty",
@@ -6763,7 +6763,7 @@ function buildCliSession(state, options) {
6763
6763
  activeModal: activeChat?.activeModal || null
6764
6764
  }),
6765
6765
  title: activeChat?.title || state.name,
6766
- ...includeSessionMetadata && { workspace: state.workspace || null },
6766
+ workspace: state.workspace || null,
6767
6767
  ...includeRuntimeMetadata && {
6768
6768
  runtimeKey: state.runtime?.runtimeKey,
6769
6769
  runtimeDisplayName: state.runtime?.displayName,
@@ -6802,14 +6802,14 @@ function buildAcpSession(state, options) {
6802
6802
  id: state.instanceId,
6803
6803
  parentId: null,
6804
6804
  providerType: state.type,
6805
- ...includeSessionMetadata && { providerName: state.name },
6805
+ providerName: state.name,
6806
6806
  kind: "agent",
6807
6807
  transport: "acp",
6808
6808
  status: normalizeManagedStatus(activeChat?.status || state.status, {
6809
6809
  activeModal: activeChat?.activeModal || null
6810
6810
  }),
6811
6811
  title: activeChat?.title || state.name,
6812
- ...includeSessionMetadata && { workspace: state.workspace || null },
6812
+ workspace: state.workspace || null,
6813
6813
  activeChat,
6814
6814
  ...summaryMetadata && { summaryMetadata },
6815
6815
  ...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
@@ -7354,26 +7354,26 @@ function buildReadChatReplayCollapseSignature(message) {
7354
7354
  function shouldCollapseReadChatReplayDuplicate(message) {
7355
7355
  if (!message) return false;
7356
7356
  const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7357
- if (role !== "assistant" && role !== "system") return false;
7358
- const kind = typeof message.kind === "string" ? message.kind.trim().toLowerCase() : "standard";
7359
- return kind === "tool" || kind === "terminal" || kind === "thought" || kind === "system";
7357
+ return role === "assistant" || role === "system";
7360
7358
  }
7361
7359
  function collapseReplayDuplicatesFromReadChat(messages) {
7362
7360
  const collapsed = [];
7363
- let lastReplayTurnSignature = "";
7361
+ const replaySignaturesInCurrentTurn = /* @__PURE__ */ new Set();
7364
7362
  for (const message of messages) {
7363
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7364
+ if (role === "user") {
7365
+ replaySignaturesInCurrentTurn.clear();
7366
+ }
7365
7367
  const signature = buildReadChatReplayCollapseSignature(message);
7366
7368
  const previous = collapsed[collapsed.length - 1];
7367
7369
  const previousSignature = buildReadChatReplayCollapseSignature(previous);
7368
7370
  if (shouldCollapseReadChatReplayDuplicate(message) && signature) {
7369
7371
  if (previousSignature === signature) continue;
7370
- if (lastReplayTurnSignature === signature) continue;
7372
+ if (replaySignaturesInCurrentTurn.has(signature)) continue;
7371
7373
  }
7372
7374
  collapsed.push(message);
7373
7375
  if (shouldCollapseReadChatReplayDuplicate(message) && signature) {
7374
- lastReplayTurnSignature = signature;
7375
- } else if ((message.role || "").toLowerCase() === "user") {
7376
- lastReplayTurnSignature = "";
7376
+ replaySignaturesInCurrentTurn.add(signature);
7377
7377
  }
7378
7378
  }
7379
7379
  return collapsed;
@@ -11580,6 +11580,7 @@ var init_provider_cli_runtime = __esm({
11580
11580
  var provider_cli_adapter_exports = {};
11581
11581
  __export(provider_cli_adapter_exports, {
11582
11582
  ProviderCliAdapter: () => ProviderCliAdapter,
11583
+ appendBoundedText: () => appendBoundedText,
11583
11584
  normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
11584
11585
  });
11585
11586
  function normalizeComparableTranscriptText(value) {
@@ -11612,6 +11613,14 @@ function parsedTranscriptIsRicherThanCommitted(parsedMessages, committedMessages
11612
11613
  }
11613
11614
  return false;
11614
11615
  }
11616
+ function appendBoundedText(current, chunk, maxChars) {
11617
+ if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
11618
+ if (maxChars <= 0) return "";
11619
+ if (chunk.length >= maxChars) return chunk.slice(-maxChars);
11620
+ const keepFromCurrent = maxChars - chunk.length;
11621
+ if (current.length <= keepFromCurrent) return current + chunk;
11622
+ return current.slice(-keepFromCurrent) + chunk;
11623
+ }
11615
11624
  var os12, ProviderCliAdapter;
11616
11625
  var init_provider_cli_adapter = __esm({
11617
11626
  "../../oss/packages/daemon-core/src/cli-adapters/provider-cli-adapter.ts"() {
@@ -11689,15 +11698,17 @@ var init_provider_cli_adapter = __esm({
11689
11698
  startupFirstOutputAt = 0;
11690
11699
  // PTY I/O
11691
11700
  onPtyDataCallback = null;
11692
- pendingOutputParseBuffer = "";
11701
+ pendingOutputParseChunks = [];
11693
11702
  pendingOutputParseTimer = null;
11694
- ptyOutputBuffer = "";
11703
+ ptyOutputChunks = [];
11695
11704
  ptyOutputFlushTimer = null;
11696
11705
  pendingTerminalQueryTail = "";
11697
11706
  lastOutputAt = 0;
11698
11707
  lastNonEmptyOutputAt = 0;
11699
11708
  lastScreenChangeAt = 0;
11700
11709
  lastScreenSnapshot = "";
11710
+ lastScreenText = "";
11711
+ lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
11701
11712
  // Server log forwarding
11702
11713
  serverConn = null;
11703
11714
  logBuffer = [];
@@ -11743,6 +11754,9 @@ var init_provider_cli_adapter = __esm({
11743
11754
  traceSeq = 0;
11744
11755
  traceSessionId = "";
11745
11756
  parsedStatusCache = null;
11757
+ lastStatusHotPathParseAt = Number.NEGATIVE_INFINITY;
11758
+ static STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1e3;
11759
+ static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
11746
11760
  static MAX_TRACE_ENTRIES = 250;
11747
11761
  providerResolutionMeta;
11748
11762
  static FINISH_RETRY_DELAY_MS = 300;
@@ -11751,6 +11765,30 @@ var init_provider_cli_adapter = __esm({
11751
11765
  this.messages = [...this.committedMessages];
11752
11766
  this.structuredMessages = [...this.committedMessages];
11753
11767
  }
11768
+ readTerminalScreenText(now = Date.now()) {
11769
+ const screenText = this.terminalScreen.getText() || "";
11770
+ this.lastScreenText = screenText;
11771
+ this.lastScreenSnapshotReadAt = now;
11772
+ return screenText;
11773
+ }
11774
+ shouldReadTerminalScreenSnapshot(now) {
11775
+ if (!this.lastScreenText) return true;
11776
+ return now - this.lastScreenSnapshotReadAt >= _ProviderCliAdapter.SCREEN_SNAPSHOT_MIN_INTERVAL_MS;
11777
+ }
11778
+ resetTerminalScreen(rows, cols) {
11779
+ this.terminalScreen.reset(rows, cols);
11780
+ this.lastScreenText = "";
11781
+ this.lastScreenSnapshot = "";
11782
+ this.lastScreenChangeAt = 0;
11783
+ this.lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
11784
+ }
11785
+ getFreshParsedStatusCache() {
11786
+ const cached2 = this.parsedStatusCache;
11787
+ if (cached2 && cached2.committedMessagesRef === this.committedMessages && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBuffer === this.accumulatedRawBuffer && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName && cached2.lastOutputAt === this.lastOutputAt) {
11788
+ return cached2.result;
11789
+ }
11790
+ return null;
11791
+ }
11754
11792
  getIdleFinishConfirmMs() {
11755
11793
  return this.timeouts.idleFinishConfirm;
11756
11794
  }
@@ -11865,9 +11903,9 @@ var init_provider_cli_adapter = __esm({
11865
11903
  clearTimeout(this.pendingOutputParseTimer);
11866
11904
  this.pendingOutputParseTimer = null;
11867
11905
  }
11868
- if (!this.pendingOutputParseBuffer) return;
11869
- const rawData = this.pendingOutputParseBuffer;
11870
- this.pendingOutputParseBuffer = "";
11906
+ if (this.pendingOutputParseChunks.length === 0) return;
11907
+ const rawData = this.pendingOutputParseChunks.join("");
11908
+ this.pendingOutputParseChunks = [];
11871
11909
  this.handleOutput(rawData);
11872
11910
  }
11873
11911
  async spawn() {
@@ -11922,7 +11960,7 @@ var init_provider_cli_adapter = __esm({
11922
11960
  terminalScreen: this.terminalScreen
11923
11961
  });
11924
11962
  }
11925
- this.pendingOutputParseBuffer += data;
11963
+ this.pendingOutputParseChunks.push(data);
11926
11964
  if (!this.pendingOutputParseTimer) {
11927
11965
  this.pendingOutputParseTimer = setTimeout(() => {
11928
11966
  this.pendingOutputParseTimer = null;
@@ -11930,13 +11968,13 @@ var init_provider_cli_adapter = __esm({
11930
11968
  }, this.timeouts.ptyFlush);
11931
11969
  }
11932
11970
  if (this.onPtyDataCallback) {
11933
- this.ptyOutputBuffer += data;
11971
+ this.ptyOutputChunks.push(data);
11934
11972
  if (!this.ptyOutputFlushTimer) {
11935
11973
  this.ptyOutputFlushTimer = setTimeout(() => {
11936
- if (this.ptyOutputBuffer && this.onPtyDataCallback) {
11937
- this.onPtyDataCallback(this.ptyOutputBuffer);
11974
+ if (this.ptyOutputChunks.length > 0 && this.onPtyDataCallback) {
11975
+ this.onPtyDataCallback(this.ptyOutputChunks.join(""));
11938
11976
  }
11939
- this.ptyOutputBuffer = "";
11977
+ this.ptyOutputChunks = [];
11940
11978
  this.ptyOutputFlushTimer = null;
11941
11979
  }, this.timeouts.ptyFlush);
11942
11980
  }
@@ -11961,7 +11999,7 @@ var init_provider_cli_adapter = __esm({
11961
11999
  clearTimeout(this.startupSettleTimer);
11962
12000
  this.startupSettleTimer = null;
11963
12001
  }
11964
- this.terminalScreen.reset(24, 80);
12002
+ this.resetTerminalScreen(24, 80);
11965
12003
  this.pendingTerminalQueryTail = "";
11966
12004
  this.currentTurnScope = null;
11967
12005
  this.finishRetryCount = 0;
@@ -11983,11 +12021,12 @@ var init_provider_cli_adapter = __esm({
11983
12021
  this.terminalScreen.write(rawData);
11984
12022
  const cleanData = sanitizeTerminalText(rawData);
11985
12023
  const now = Date.now();
11986
- const screenText = this.terminalScreen.getText();
11987
- const normalizedScreenSnapshot = normalizeScreenSnapshot(screenText);
12024
+ const shouldReadScreen = this.shouldReadTerminalScreenSnapshot(now);
12025
+ const screenText = shouldReadScreen ? this.readTerminalScreenText(now) : this.lastScreenText;
12026
+ const normalizedScreenSnapshot = shouldReadScreen ? normalizeScreenSnapshot(screenText) : this.lastScreenSnapshot;
11988
12027
  this.lastOutputAt = now;
11989
12028
  if (cleanData.trim()) this.lastNonEmptyOutputAt = now;
11990
- if (normalizedScreenSnapshot !== this.lastScreenSnapshot) {
12029
+ if (shouldReadScreen && normalizedScreenSnapshot !== this.lastScreenSnapshot) {
11991
12030
  this.lastScreenSnapshot = normalizedScreenSnapshot;
11992
12031
  this.lastScreenChangeAt = now;
11993
12032
  }
@@ -12009,7 +12048,7 @@ var init_provider_cli_adapter = __esm({
12009
12048
  this.scheduleStartupSettleCheck();
12010
12049
  }
12011
12050
  if (this.isWaitingForResponse && cleanData) {
12012
- this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
12051
+ this.responseBuffer = appendBoundedText(this.responseBuffer, cleanData, 8e3);
12013
12052
  }
12014
12053
  if (cleanData.trim()) {
12015
12054
  if (this.serverConn) {
@@ -12018,11 +12057,11 @@ var init_provider_cli_adapter = __esm({
12018
12057
  this.logBuffer.push({ message: cleanData.trim(), level: "info" });
12019
12058
  }
12020
12059
  }
12021
- this.recentOutputBuffer = (this.recentOutputBuffer + cleanData).slice(-1e3);
12022
12060
  const prevAccumulatedLen = this.accumulatedBuffer.length;
12023
12061
  const prevAccumulatedRawLen = this.accumulatedRawBuffer.length;
12024
- this.accumulatedBuffer = (this.accumulatedBuffer + cleanData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
12025
- this.accumulatedRawBuffer = (this.accumulatedRawBuffer + rawData).slice(-_ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
12062
+ this.recentOutputBuffer = appendBoundedText(this.recentOutputBuffer, cleanData, 1e3);
12063
+ this.accumulatedBuffer = appendBoundedText(this.accumulatedBuffer, cleanData, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
12064
+ this.accumulatedRawBuffer = appendBoundedText(this.accumulatedRawBuffer, rawData, _ProviderCliAdapter.MAX_ACCUMULATED_BUFFER);
12026
12065
  if (this.currentTurnScope) {
12027
12066
  const droppedClean = prevAccumulatedLen + cleanData.length - this.accumulatedBuffer.length;
12028
12067
  const droppedRaw = prevAccumulatedRawLen + rawData.length - this.accumulatedRawBuffer.length;
@@ -12033,14 +12072,14 @@ var init_provider_cli_adapter = __esm({
12033
12072
  this.currentTurnScope.rawBufferStart = Math.max(0, this.currentTurnScope.rawBufferStart - droppedRaw);
12034
12073
  }
12035
12074
  }
12036
- this.resolveStartupState("output");
12075
+ this.resolveStartupState("output", screenText, normalizedScreenSnapshot, now);
12037
12076
  this.scheduleSettle();
12038
12077
  }
12039
- resolveStartupState(trigger) {
12078
+ resolveStartupState(trigger, screenTextOverride, normalizedScreenOverride, nowOverride) {
12040
12079
  if (!this.startupParseGate) return;
12041
- const now = Date.now();
12042
- const screenText = this.terminalScreen.getText() || "";
12043
- const normalizedScreen = normalizeScreenSnapshot(screenText);
12080
+ const now = typeof nowOverride === "number" ? nowOverride : Date.now();
12081
+ const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.readTerminalScreenText();
12082
+ const normalizedScreen = typeof normalizedScreenOverride === "string" ? normalizedScreenOverride : normalizeScreenSnapshot(screenText);
12044
12083
  const hasStartupOutput = !!this.startupFirstOutputAt || !!normalizedScreen.trim();
12045
12084
  if (!hasStartupOutput) return;
12046
12085
  const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
@@ -12275,40 +12314,28 @@ var init_provider_cli_adapter = __esm({
12275
12314
  }, delayTime);
12276
12315
  return;
12277
12316
  }
12278
- const tail = this.settledBuffer;
12279
- const screenText = this.terminalScreen.getText() || "";
12280
12317
  this.resolveStartupState("settled");
12281
- if (this.startupParseGate) {
12282
- return;
12283
- }
12284
- const parsedTranscript = this.parseCurrentTranscript(
12285
- this.committedMessages,
12286
- this.responseBuffer,
12287
- this.currentTurnScope
12288
- );
12289
- const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsedTranscript.activeModal : null;
12290
- const modal = this.runParseApproval(tail) || parsedModal;
12291
- const rawScriptStatus = this.runDetectStatus(tail);
12292
- const scriptStatus = parsedTranscript?.status === "waiting_approval" && modal ? "waiting_approval" : rawScriptStatus;
12293
- const parsedMessages = Array.isArray(parsedTranscript?.messages) ? normalizeCliParsedMessages(parsedTranscript.messages, {
12318
+ if (this.startupParseGate) return;
12319
+ const session = this.runParseSession();
12320
+ if (!session) return;
12321
+ const { status, messages, modal, parsedStatus } = session;
12322
+ const parsedMessages = normalizeCliParsedMessages(messages, {
12294
12323
  committedMessages: this.committedMessages,
12295
12324
  scope: this.currentTurnScope,
12296
12325
  lastOutputAt: this.lastOutputAt
12297
- }) : [];
12298
- if (this.maybeCommitVisibleIdleTranscript(parsedTranscript)) {
12299
- return;
12300
- }
12301
- const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
12302
- const parsedShowsLiveAssistantProgress = parsedTranscript?.status === "generating" && !!lastParsedAssistant && parsedMessages.length > this.committedMessages.length;
12326
+ });
12327
+ if (this.maybeCommitVisibleIdleTranscript(session, parsedMessages)) return;
12328
+ const lastParsedAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant");
12303
12329
  const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet || this.currentTurnScope?.prompt || "");
12330
+ const screenText = this.terminalScreen.getText() || "";
12304
12331
  this.recordTrace("settled", {
12305
- tail: summarizeCliTraceText(tail, 500),
12332
+ tail: summarizeCliTraceText(this.settledBuffer, 500),
12306
12333
  screenText: summarizeCliTraceText(screenText, 1200),
12307
- detectStatus: scriptStatus,
12308
- parsedStatus: parsedTranscript?.status || null,
12334
+ detectStatus: status,
12335
+ parsedStatus: parsedStatus || null,
12309
12336
  parsedMessageCount: parsedMessages.length,
12310
12337
  parsedLastAssistant: lastParsedAssistant ? summarizeCliTraceText(lastParsedAssistant.content, 280) : "",
12311
- parsedActiveModal: parsedTranscript?.activeModal ?? null,
12338
+ parsedActiveModal: modal,
12312
12339
  approval: modal,
12313
12340
  ...buildCliTraceParseSnapshot({
12314
12341
  accumulatedBuffer: this.accumulatedBuffer,
@@ -12342,36 +12369,36 @@ var init_provider_cli_adapter = __esm({
12342
12369
  `[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
12343
12370
  );
12344
12371
  }
12345
- if (!scriptStatus) return;
12372
+ if (!status) return;
12346
12373
  const prevStatus = this.currentStatus;
12347
- const ctx = { now, screenText, modal, scriptStatus, parsedTranscript, parsedMessages, lastParsedAssistant, parsedShowsLiveAssistantProgress, prevStatus };
12374
+ const ctx = { now, modal, status, parsedMessages, lastParsedAssistant, parsedStatus: parsedStatus || null, prevStatus };
12348
12375
  if (!this.applyPendingScriptStatusDebounce(ctx)) return;
12349
12376
  const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
12350
12377
  LOG.info(
12351
12378
  "CLI",
12352
- `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 140)} scriptStatus=${String(scriptStatus || "")} parsedStatus=${String(parsedTranscript?.status || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
12379
+ `[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 140)} status=${String(status || "")} parsedStatus=${String(parsedStatus || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
12353
12380
  );
12354
- const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(parsedTranscript?.status === "idle" && !!lastParsedAssistant);
12381
+ const shouldHoldGenerating = status === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(parsedStatus === "idle" && !!lastParsedAssistant);
12355
12382
  if (shouldHoldGenerating) {
12356
12383
  this.applyHoldGenerating(ctx, recentInteractiveActivity);
12357
12384
  return;
12358
12385
  }
12359
- if (scriptStatus === "waiting_approval") {
12386
+ if (status === "waiting_approval") {
12360
12387
  this.applyWaitingApproval(ctx);
12361
12388
  return;
12362
12389
  }
12363
- if (scriptStatus === "generating") {
12390
+ if (status === "generating") {
12364
12391
  this.applyGenerating(ctx);
12365
12392
  return;
12366
12393
  }
12367
- if (scriptStatus === "idle") {
12394
+ if (status === "idle") {
12368
12395
  this.applyIdle(ctx, now);
12369
12396
  }
12370
12397
  }
12371
12398
  // Returns false if the caller should bail out (debounce pending).
12372
12399
  applyPendingScriptStatusDebounce(ctx) {
12373
- const { now, scriptStatus, prevStatus } = ctx;
12374
- const shouldDebounce = prevStatus === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && (scriptStatus === "generating" || scriptStatus === "waiting_approval");
12400
+ const { now, status, prevStatus } = ctx;
12401
+ const shouldDebounce = prevStatus === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && (status === "generating" || status === "waiting_approval");
12375
12402
  if (!shouldDebounce) {
12376
12403
  this.pendingScriptStatus = null;
12377
12404
  this.pendingScriptStatusSince = 0;
@@ -12389,8 +12416,8 @@ var init_provider_cli_adapter = __esm({
12389
12416
  this.evaluateSettled();
12390
12417
  }, delayMs);
12391
12418
  };
12392
- if (this.pendingScriptStatus !== scriptStatus) {
12393
- this.pendingScriptStatus = scriptStatus;
12419
+ if (this.pendingScriptStatus !== status) {
12420
+ this.pendingScriptStatus = status;
12394
12421
  this.pendingScriptStatusSince = now;
12395
12422
  armPending(_ProviderCliAdapter.SCRIPT_STATUS_DEBOUNCE_MS);
12396
12423
  return false;
@@ -12403,7 +12430,7 @@ var init_provider_cli_adapter = __esm({
12403
12430
  return true;
12404
12431
  }
12405
12432
  applyHoldGenerating(ctx, recentInteractiveActivity) {
12406
- const { scriptStatus } = ctx;
12433
+ const { status } = ctx;
12407
12434
  this.clearIdleFinishCandidate("hold_generating_recent_activity");
12408
12435
  this.setStatus("generating", "recent_activity_hold");
12409
12436
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
@@ -12414,7 +12441,7 @@ var init_provider_cli_adapter = __esm({
12414
12441
  }
12415
12442
  }, this.timeouts.generatingIdle);
12416
12443
  this.recordTrace("hold_generating_recent_activity", {
12417
- scriptStatus,
12444
+ scriptStatus: status,
12418
12445
  recentInteractiveActivity,
12419
12446
  lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
12420
12447
  lastScreenChangeAt: this.lastScreenChangeAt,
@@ -12468,11 +12495,13 @@ var init_provider_cli_adapter = __esm({
12468
12495
  }
12469
12496
  }
12470
12497
  applyGenerating(ctx) {
12471
- const { screenText, modal, parsedShowsLiveAssistantProgress, prevStatus } = ctx;
12498
+ const { modal, parsedMessages, lastParsedAssistant, parsedStatus, prevStatus } = ctx;
12472
12499
  this.clearIdleFinishCandidate("generating");
12500
+ const screenText = this.terminalScreen.getText() || "";
12473
12501
  const effectiveScreenText = screenText || this.accumulatedBuffer;
12474
12502
  const noActiveTurn = !this.currentTurnScope;
12475
12503
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText) || /accept edits on/i.test(effectiveScreenText) && (/Update available!/i.test(screenText) || /\/effort/i.test(screenText) || /^.*➜\s+\S+/m.test(effectiveScreenText));
12504
+ const parsedShowsLiveAssistantProgress = parsedStatus === "generating" && !!lastParsedAssistant && parsedMessages.length > this.committedMessages.length;
12476
12505
  if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
12477
12506
  return;
12478
12507
  }
@@ -12499,7 +12528,7 @@ var init_provider_cli_adapter = __esm({
12499
12528
  this.onStatusChange?.();
12500
12529
  }
12501
12530
  applyIdle(ctx, now) {
12502
- const { screenText, modal, lastParsedAssistant, prevStatus } = ctx;
12531
+ const { modal, lastParsedAssistant, prevStatus } = ctx;
12503
12532
  if (prevStatus === "waiting_approval") {
12504
12533
  if (this.approvalExitTimeout) {
12505
12534
  clearTimeout(this.approvalExitTimeout);
@@ -12621,20 +12650,15 @@ var init_provider_cli_adapter = __esm({
12621
12650
  this.setStatus("idle", "response_finished");
12622
12651
  this.onStatusChange?.();
12623
12652
  }
12624
- maybeCommitVisibleIdleTranscript(parsed) {
12653
+ maybeCommitVisibleIdleTranscript(session, parsedMessages) {
12625
12654
  const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
12626
12655
  if (!allowImmediateScriptIdleCommit) return false;
12627
- if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
12656
+ if (!session || session.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || session.modal) {
12628
12657
  return false;
12629
12658
  }
12630
- const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
12631
- committedMessages: this.committedMessages,
12632
- scope: this.currentTurnScope,
12633
- lastOutputAt: this.lastOutputAt
12634
- });
12635
- const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
12659
+ const visibleAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant" && m.content.trim());
12636
12660
  if (!visibleAssistant) return false;
12637
- this.committedMessages = hydratedForIdleCommit;
12661
+ this.committedMessages = parsedMessages;
12638
12662
  this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
12639
12663
  this.clearAllTimers();
12640
12664
  this.syncMessageViews();
@@ -12712,6 +12736,59 @@ var init_provider_cli_adapter = __esm({
12712
12736
  };
12713
12737
  }
12714
12738
  // ─── Script Execution ──────────────────────────
12739
+ runParseSession() {
12740
+ if (typeof this.cliScripts?.parseSession === "function") {
12741
+ try {
12742
+ const screenText = this.terminalScreen.getText();
12743
+ const tail = this.recentOutputBuffer.slice(-500);
12744
+ const input = buildCliParseInput({
12745
+ accumulatedBuffer: this.accumulatedBuffer,
12746
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
12747
+ recentOutputBuffer: this.recentOutputBuffer,
12748
+ terminalScreenText: screenText,
12749
+ baseMessages: this.committedMessages,
12750
+ partialResponse: this.responseBuffer,
12751
+ isWaitingForResponse: this.isWaitingForResponse,
12752
+ scope: this.currentTurnScope,
12753
+ runtimeSettings: this.runtimeSettings
12754
+ });
12755
+ const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
12756
+ this.parseErrorMessage = null;
12757
+ return session && typeof session === "object" ? session : null;
12758
+ } catch (e) {
12759
+ const message = e?.message || String(e);
12760
+ this.parseErrorMessage = message;
12761
+ LOG.warn("CLI", `[${this.cliType}] parseSession error: ${message}`);
12762
+ return null;
12763
+ }
12764
+ }
12765
+ if (!this.cliScripts?.detectStatus && !this.cliScripts?.parseOutput) return null;
12766
+ try {
12767
+ const tail = this.settledBuffer;
12768
+ const parsedTranscript = this.parseCurrentTranscript(
12769
+ this.committedMessages,
12770
+ this.responseBuffer,
12771
+ this.currentTurnScope
12772
+ );
12773
+ const parsedModal = parsedTranscript?.activeModal && Array.isArray(parsedTranscript.activeModal.buttons) && parsedTranscript.activeModal.buttons.some((b) => typeof b === "string" && b.trim()) ? parsedTranscript.activeModal : null;
12774
+ const approval = this.runParseApproval(tail);
12775
+ const modal = approval || parsedModal;
12776
+ const rawStatus = this.runDetectStatus(tail);
12777
+ const parsedStatus = typeof parsedTranscript?.status === "string" ? parsedTranscript.status : null;
12778
+ const effectiveStatus = parsedStatus === "waiting_approval" && modal ? "waiting_approval" : rawStatus || parsedStatus || "idle";
12779
+ return {
12780
+ status: effectiveStatus,
12781
+ messages: Array.isArray(parsedTranscript?.messages) ? parsedTranscript.messages : [],
12782
+ modal,
12783
+ parsedStatus
12784
+ };
12785
+ } catch (e) {
12786
+ const message = e?.message || String(e);
12787
+ this.parseErrorMessage = message;
12788
+ LOG.warn("CLI", `[${this.cliType}] parseSession fallback error: ${message}`);
12789
+ return null;
12790
+ }
12791
+ }
12715
12792
  runDetectStatus(text) {
12716
12793
  if (!this.cliScripts?.detectStatus) return null;
12717
12794
  try {
@@ -12785,14 +12862,21 @@ var init_provider_cli_adapter = __esm({
12785
12862
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
12786
12863
  let effectiveModal = startupModal || this.activeModal;
12787
12864
  if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === "function") {
12788
- try {
12789
- const parsed = this.getScriptParsedStatus();
12790
- const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
12791
- if (parsed?.status === "waiting_approval" && parsedModal) {
12792
- effectiveStatus = "waiting_approval";
12793
- effectiveModal = parsedModal;
12865
+ let parsed = this.getFreshParsedStatusCache();
12866
+ if (!parsed && effectiveStatus !== "idle") {
12867
+ const now = Date.now();
12868
+ if (now - this.lastStatusHotPathParseAt >= _ProviderCliAdapter.STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS) {
12869
+ this.lastStatusHotPathParseAt = now;
12870
+ try {
12871
+ parsed = this.getScriptParsedStatus();
12872
+ } catch {
12873
+ }
12794
12874
  }
12795
- } catch {
12875
+ }
12876
+ const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons) && parsed.activeModal.buttons.some((button) => typeof button === "string" && button.trim()) ? parsed.activeModal : null;
12877
+ if (parsed?.status === "waiting_approval" && parsedModal) {
12878
+ effectiveStatus = "waiting_approval";
12879
+ effectiveModal = parsedModal;
12796
12880
  }
12797
12881
  }
12798
12882
  return {
@@ -12824,7 +12908,7 @@ var init_provider_cli_adapter = __esm({
12824
12908
  * Called by command handler / dashboard for rich content rendering.
12825
12909
  */
12826
12910
  getScriptParsedStatus() {
12827
- const screenText = this.terminalScreen.getText();
12911
+ const screenText = this.readTerminalScreenText();
12828
12912
  const cached2 = this.parsedStatusCache;
12829
12913
  if (cached2 && cached2.committedMessagesRef === this.committedMessages && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBuffer === this.accumulatedRawBuffer && cached2.screenText === screenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName && cached2.lastOutputAt === this.lastOutputAt) {
12830
12914
  return cached2.result;
@@ -12844,8 +12928,21 @@ var init_provider_cli_adapter = __esm({
12844
12928
  this.onStatusChange?.();
12845
12929
  }
12846
12930
  }
12847
- if (this.maybeCommitVisibleIdleTranscript(parsed)) {
12848
- return this.getScriptParsedStatus();
12931
+ if (parsed && Array.isArray(parsed.messages)) {
12932
+ const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
12933
+ committedMessages: this.committedMessages,
12934
+ scope: this.currentTurnScope,
12935
+ lastOutputAt: this.lastOutputAt
12936
+ });
12937
+ const fakeSession = {
12938
+ status: parsed.status || "idle",
12939
+ messages: parsed.messages,
12940
+ modal: parsedModal,
12941
+ parsedStatus: parsed.status || null
12942
+ };
12943
+ if (this.maybeCommitVisibleIdleTranscript(fakeSession, hydratedForCommit)) {
12944
+ return this.getScriptParsedStatus();
12945
+ }
12849
12946
  }
12850
12947
  const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
12851
12948
  let result;
@@ -13027,6 +13124,17 @@ var init_provider_cli_adapter = __esm({
13027
13124
  }
13028
13125
  await this.sendMessage(promptText);
13029
13126
  }
13127
+ isSubmitStuck(normalizedPromptSnippet) {
13128
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return false;
13129
+ if (this.hasActionableApproval()) return false;
13130
+ if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return false;
13131
+ const screenText = this.terminalScreen.getText();
13132
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return false;
13133
+ const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
13134
+ if (liveApproval) return false;
13135
+ const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
13136
+ return liveStatus !== "generating" && liveStatus !== "waiting_approval";
13137
+ }
13030
13138
  async writeToPty(data) {
13031
13139
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13032
13140
  await this.ptyProcess.write(data);
@@ -13050,6 +13158,121 @@ var init_provider_cli_adapter = __esm({
13050
13158
  this.finishRetryTimer = null;
13051
13159
  }
13052
13160
  }
13161
+ commitSendUserTurn(state) {
13162
+ if (state.didCommitUserTurn) return;
13163
+ state.didCommitUserTurn = true;
13164
+ this.committedMessages.push({ role: "user", content: state.text, timestamp: Date.now() });
13165
+ this.syncMessageViews();
13166
+ }
13167
+ armResponseTimeout() {
13168
+ if (this.responseTimeout) clearTimeout(this.responseTimeout);
13169
+ this.responseTimeout = setTimeout(() => {
13170
+ if (this.isWaitingForResponse) this.finishResponse();
13171
+ }, this.timeouts.maxResponse);
13172
+ }
13173
+ writeSubmitKeyForRetry(mode) {
13174
+ void this.writeToPty(this.sendKey).catch((error48) => {
13175
+ LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error48?.message || error48}`);
13176
+ });
13177
+ }
13178
+ retrySubmitIfStuck(state, attempt) {
13179
+ this.submitRetryTimer = null;
13180
+ if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
13181
+ const screenText = this.terminalScreen.getText();
13182
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13183
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
13184
+ this.recordTrace("submit_write", {
13185
+ mode: "submit_retry",
13186
+ attempt,
13187
+ sendKey: this.sendKey,
13188
+ screenText: summarizeCliTraceText(screenText, 500)
13189
+ });
13190
+ this.writeSubmitKeyForRetry("submit_retry");
13191
+ if (attempt >= 3) {
13192
+ this.submitRetryUsed = true;
13193
+ return;
13194
+ }
13195
+ this.submitRetryTimer = setTimeout(() => this.retrySubmitIfStuck(state, attempt + 1), state.retryDelayMs);
13196
+ }
13197
+ retryImmediateSubmitIfStuck(state) {
13198
+ this.submitRetryTimer = null;
13199
+ if (!this.isSubmitStuck(state.normalizedPromptSnippet)) return;
13200
+ const screenText = this.terminalScreen.getText();
13201
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13202
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
13203
+ this.recordTrace("submit_write", {
13204
+ mode: "immediate_retry",
13205
+ attempt: 1,
13206
+ sendKey: this.sendKey,
13207
+ screenText: summarizeCliTraceText(screenText, 500)
13208
+ });
13209
+ this.writeSubmitKeyForRetry("immediate_retry");
13210
+ this.submitRetryUsed = true;
13211
+ }
13212
+ submitSendKey(state, completion) {
13213
+ if (!this.ptyProcess) {
13214
+ completion.resolveOnce();
13215
+ return;
13216
+ }
13217
+ this.submitPendingUntil = 0;
13218
+ const screenText = this.terminalScreen.getText();
13219
+ this.recordTrace("submit_write", {
13220
+ mode: "submit_key",
13221
+ sendKey: this.sendKey,
13222
+ screenText: summarizeCliTraceText(screenText, 500)
13223
+ });
13224
+ void this.writeToPty(this.sendKey).then(() => {
13225
+ this.commitSendUserTurn(state);
13226
+ this.submitRetryTimer = setTimeout(() => this.retrySubmitIfStuck(state, 1), state.retryDelayMs);
13227
+ this.armResponseTimeout();
13228
+ completion.resolveOnce();
13229
+ }, completion.rejectOnce);
13230
+ }
13231
+ submitImmediatePrompt(state, completion) {
13232
+ this.submitPendingUntil = 0;
13233
+ this.recordTrace("submit_write", {
13234
+ mode: "immediate",
13235
+ text: summarizeCliTraceText(state.text, 500),
13236
+ sendKey: this.sendKey,
13237
+ screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
13238
+ });
13239
+ void this.writeToPty(state.text + this.sendKey).then(() => {
13240
+ this.commitSendUserTurn(state);
13241
+ this.submitRetryTimer = setTimeout(() => this.retryImmediateSubmitIfStuck(state), state.retryDelayMs);
13242
+ this.armResponseTimeout();
13243
+ completion.resolveOnce();
13244
+ }, completion.rejectOnce);
13245
+ }
13246
+ waitForEchoAndSubmit(state, completion, submitStartedAt, lastNormalizedScreen = "", lastScreenChangeAt = submitStartedAt) {
13247
+ if (!this.ptyProcess) {
13248
+ completion.resolveOnce();
13249
+ return;
13250
+ }
13251
+ const now = Date.now();
13252
+ const elapsed = now - submitStartedAt;
13253
+ const screenText = this.terminalScreen.getText();
13254
+ const normalizedScreen = normalizePromptText(screenText);
13255
+ const nextScreenChangeAt = normalizedScreen !== lastNormalizedScreen ? now : lastScreenChangeAt;
13256
+ const echoVisible = !state.normalizedPromptSnippet || promptLikelyVisible(screenText, state.normalizedPromptSnippet);
13257
+ if (echoVisible) {
13258
+ const screenSettled = now - nextScreenChangeAt >= 500;
13259
+ if (elapsed >= state.submitDelayMs && screenSettled) {
13260
+ this.submitSendKey(state, completion);
13261
+ return;
13262
+ }
13263
+ }
13264
+ if (elapsed >= state.maxEchoWaitMs) {
13265
+ this.submitSendKey(state, completion);
13266
+ return;
13267
+ }
13268
+ setTimeout(() => this.waitForEchoAndSubmit(
13269
+ state,
13270
+ completion,
13271
+ submitStartedAt,
13272
+ normalizedScreen,
13273
+ nextScreenChangeAt
13274
+ ), 50);
13275
+ }
13053
13276
  async sendMessage(text) {
13054
13277
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13055
13278
  const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
@@ -13125,12 +13348,13 @@ var init_provider_cli_adapter = __esm({
13125
13348
  const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
13126
13349
  const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
13127
13350
  const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
13128
- let didCommitUserTurn = false;
13129
- const commitUserTurn = () => {
13130
- if (didCommitUserTurn) return;
13131
- didCommitUserTurn = true;
13132
- this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
13133
- this.syncMessageViews();
13351
+ const sendState = {
13352
+ text,
13353
+ normalizedPromptSnippet,
13354
+ submitDelayMs,
13355
+ maxEchoWaitMs,
13356
+ retryDelayMs,
13357
+ didCommitUserTurn: false
13134
13358
  };
13135
13359
  if (this.settleTimer) {
13136
13360
  clearTimeout(this.settleTimer);
@@ -13138,110 +13362,23 @@ var init_provider_cli_adapter = __esm({
13138
13362
  }
13139
13363
  this.responseEpoch += 1;
13140
13364
  this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
13141
- const startResponseTimeout = () => {
13142
- if (this.responseTimeout) clearTimeout(this.responseTimeout);
13143
- this.responseTimeout = setTimeout(() => {
13144
- if (this.isWaitingForResponse) this.finishResponse();
13145
- }, this.timeouts.maxResponse);
13146
- };
13147
13365
  await new Promise((resolve16, reject) => {
13148
13366
  let resolved = false;
13149
- const resolveOnce = () => {
13150
- if (resolved) return;
13151
- resolved = true;
13152
- resolve16();
13153
- };
13154
- const rejectOnce = (error48) => {
13155
- if (resolved) return;
13156
- this.resetPendingSendState("send_write_failed");
13157
- resolved = true;
13158
- reject(error48);
13159
- };
13160
- const writeRetryKey = (mode) => {
13161
- void this.writeToPty(this.sendKey).catch((error48) => {
13162
- LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error48?.message || error48}`);
13163
- });
13164
- };
13165
- const submit = () => {
13166
- if (!this.ptyProcess) {
13167
- resolveOnce();
13168
- return;
13367
+ const completion = {
13368
+ resolveOnce: () => {
13369
+ if (resolved) return;
13370
+ resolved = true;
13371
+ resolve16();
13372
+ },
13373
+ rejectOnce: (error48) => {
13374
+ if (resolved) return;
13375
+ this.resetPendingSendState("send_write_failed");
13376
+ resolved = true;
13377
+ reject(error48);
13169
13378
  }
13170
- this.submitPendingUntil = 0;
13171
- const screenText = this.terminalScreen.getText();
13172
- this.recordTrace("submit_write", {
13173
- mode: "submit_key",
13174
- sendKey: this.sendKey,
13175
- screenText: summarizeCliTraceText(screenText, 500)
13176
- });
13177
- const retrySubmitIfStuck = (attempt) => {
13178
- this.submitRetryTimer = null;
13179
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
13180
- if (this.hasActionableApproval()) return;
13181
- if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
13182
- const screenText2 = this.terminalScreen.getText();
13183
- if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
13184
- const liveApproval = this.runParseApproval(screenText2) || this.runParseApproval(this.recentOutputBuffer);
13185
- if (liveApproval) return;
13186
- const liveStatus = this.runDetectStatus(screenText2) || this.runDetectStatus(this.recentOutputBuffer);
13187
- if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
13188
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13189
- LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
13190
- this.recordTrace("submit_write", {
13191
- mode: "submit_retry",
13192
- attempt,
13193
- sendKey: this.sendKey,
13194
- screenText: summarizeCliTraceText(screenText2, 500)
13195
- });
13196
- writeRetryKey("submit_retry");
13197
- if (attempt >= 3) {
13198
- this.submitRetryUsed = true;
13199
- return;
13200
- }
13201
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
13202
- };
13203
- void this.writeToPty(this.sendKey).then(() => {
13204
- commitUserTurn();
13205
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
13206
- startResponseTimeout();
13207
- resolveOnce();
13208
- }, rejectOnce);
13209
13379
  };
13210
13380
  if (this.submitStrategy === "immediate") {
13211
- this.submitPendingUntil = 0;
13212
- this.recordTrace("submit_write", {
13213
- mode: "immediate",
13214
- text: summarizeCliTraceText(text, 500),
13215
- sendKey: this.sendKey,
13216
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
13217
- });
13218
- void this.writeToPty(text + this.sendKey).then(() => {
13219
- commitUserTurn();
13220
- this.submitRetryTimer = setTimeout(() => {
13221
- this.submitRetryTimer = null;
13222
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
13223
- if (this.hasActionableApproval()) return;
13224
- if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
13225
- const screenText = this.terminalScreen.getText();
13226
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
13227
- const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
13228
- if (liveApproval) return;
13229
- const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
13230
- if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
13231
- LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
13232
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13233
- this.recordTrace("submit_write", {
13234
- mode: "immediate_retry",
13235
- attempt: 1,
13236
- sendKey: this.sendKey,
13237
- screenText: summarizeCliTraceText(screenText, 500)
13238
- });
13239
- writeRetryKey("immediate_retry");
13240
- this.submitRetryUsed = true;
13241
- }, retryDelayMs);
13242
- startResponseTimeout();
13243
- resolveOnce();
13244
- }, rejectOnce);
13381
+ this.submitImmediatePrompt(sendState, completion);
13245
13382
  return;
13246
13383
  }
13247
13384
  if (submitDelayMs > 0) {
@@ -13254,36 +13391,10 @@ var init_provider_cli_adapter = __esm({
13254
13391
  screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
13255
13392
  });
13256
13393
  const submitStartedAt = Date.now();
13257
- let lastNormalizedScreen = "";
13258
- let lastScreenChangeAt = submitStartedAt;
13259
- const waitForEchoAndSubmit = () => {
13260
- if (!this.ptyProcess) {
13261
- resolveOnce();
13262
- return;
13263
- }
13264
- const now = Date.now();
13265
- const elapsed = now - submitStartedAt;
13266
- const screenText = this.terminalScreen.getText();
13267
- const normalizedScreen = normalizePromptText(screenText);
13268
- if (normalizedScreen !== lastNormalizedScreen) {
13269
- lastNormalizedScreen = normalizedScreen;
13270
- lastScreenChangeAt = now;
13271
- }
13272
- const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
13273
- if (echoVisible) {
13274
- const screenSettled = now - lastScreenChangeAt >= 500;
13275
- if (elapsed >= submitDelayMs && screenSettled) {
13276
- submit();
13277
- return;
13278
- }
13279
- }
13280
- if (elapsed >= maxEchoWaitMs) {
13281
- submit();
13282
- return;
13283
- }
13284
- setTimeout(waitForEchoAndSubmit, 50);
13285
- };
13286
- void this.writeToPty(text).then(() => waitForEchoAndSubmit(), rejectOnce);
13394
+ void this.writeToPty(text).then(
13395
+ () => this.waitForEchoAndSubmit(sendState, completion, submitStartedAt),
13396
+ completion.rejectOnce
13397
+ );
13287
13398
  });
13288
13399
  }
13289
13400
  getPartialResponse() {
@@ -13360,9 +13471,9 @@ var init_provider_cli_adapter = __esm({
13360
13471
  shutdown() {
13361
13472
  this.clearIdleFinishCandidate("shutdown");
13362
13473
  this.clearAllTimers();
13363
- this.pendingOutputParseBuffer = "";
13474
+ this.pendingOutputParseChunks = [];
13364
13475
  this.pendingTerminalQueryTail = "";
13365
- this.ptyOutputBuffer = "";
13476
+ this.ptyOutputChunks = [];
13366
13477
  this.finishRetryCount = 0;
13367
13478
  if (this.ptyProcess) {
13368
13479
  this.ptyProcess.write("");
@@ -13383,9 +13494,9 @@ var init_provider_cli_adapter = __esm({
13383
13494
  detach() {
13384
13495
  this.clearIdleFinishCandidate("detach");
13385
13496
  this.clearAllTimers();
13386
- this.pendingOutputParseBuffer = "";
13497
+ this.pendingOutputParseChunks = [];
13387
13498
  this.pendingTerminalQueryTail = "";
13388
- this.ptyOutputBuffer = "";
13499
+ this.ptyOutputChunks = [];
13389
13500
  this.finishRetryCount = 0;
13390
13501
  if (this.ptyProcess) {
13391
13502
  try {
@@ -13416,19 +13527,19 @@ var init_provider_cli_adapter = __esm({
13416
13527
  clearTimeout(this.pendingOutputParseTimer);
13417
13528
  this.pendingOutputParseTimer = null;
13418
13529
  }
13419
- this.pendingOutputParseBuffer = "";
13530
+ this.pendingOutputParseChunks = [];
13420
13531
  this.pendingTerminalQueryTail = "";
13421
13532
  if (this.ptyOutputFlushTimer) {
13422
13533
  clearTimeout(this.ptyOutputFlushTimer);
13423
13534
  this.ptyOutputFlushTimer = null;
13424
13535
  }
13425
- this.ptyOutputBuffer = "";
13536
+ this.ptyOutputChunks = [];
13426
13537
  if (this.finishRetryTimer) {
13427
13538
  clearTimeout(this.finishRetryTimer);
13428
13539
  this.finishRetryTimer = null;
13429
13540
  }
13430
13541
  this.finishRetryCount = 0;
13431
- this.terminalScreen.reset();
13542
+ this.resetTerminalScreen();
13432
13543
  this.ptyProcess?.clearBuffer?.();
13433
13544
  this.onStatusChange?.();
13434
13545
  }
@@ -13545,7 +13656,7 @@ var init_provider_cli_adapter = __esm({
13545
13656
  traceEntryCount: this.traceEntries.length,
13546
13657
  statusHistory: this.statusHistory.slice(-30),
13547
13658
  timeouts: this.timeouts,
13548
- pendingOutputParseBufferLength: this.pendingOutputParseBuffer.length,
13659
+ pendingOutputParseBufferLength: this.pendingOutputParseChunks.reduce((total, chunk) => total + chunk.length, 0),
13549
13660
  pendingOutputParseScheduled: !!this.pendingOutputParseTimer,
13550
13661
  ptyAlive: !!this.ptyProcess
13551
13662
  };
@@ -36695,6 +36806,18 @@ function getUnreadState(hasContentChange, status, lastUsedAt, lastSeenAt, lastRo
36695
36806
  const unread = completionMarker ? completionMarker !== seenCompletionMarker : hasContentChange && lastUsedAt > lastSeenAt && lastRole !== "user" && lastRole !== "human" && lastRole !== "system";
36696
36807
  return { unread, inboxBucket: unread ? "task_complete" : "idle" };
36697
36808
  }
36809
+ function projectLiveSessionFromFull(session) {
36810
+ const {
36811
+ capabilities: _capabilities,
36812
+ controlValues: _controlValues,
36813
+ providerControls: _providerControls,
36814
+ ...rest
36815
+ } = session;
36816
+ return {
36817
+ ...rest,
36818
+ activeChat: normalizeActiveChatData(session.activeChat, LIVE_STATUS_ACTIVE_CHAT_OPTIONS)
36819
+ };
36820
+ }
36698
36821
  function buildRecentLaunches(recentActivity) {
36699
36822
  return recentActivity.map((item) => ({
36700
36823
  id: item.id,
@@ -36719,7 +36842,7 @@ function buildStatusSnapshot(options) {
36719
36842
  options.cdpManagers,
36720
36843
  { profile: "full" }
36721
36844
  );
36722
- const sessions = profile === "full" ? unreadSourceSessions : buildSessionEntries(
36845
+ const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
36723
36846
  options.allStates,
36724
36847
  options.cdpManagers,
36725
36848
  { profile }
@@ -36823,6 +36946,7 @@ var init_snapshot = __esm({
36823
36946
  init_terminal_screen();
36824
36947
  init_logger();
36825
36948
  init_builders();
36949
+ init_normalize();
36826
36950
  init_recent_activity();
36827
36951
  READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
36828
36952
  recentReadDebugSignatureBySession = /* @__PURE__ */ new Map();
@@ -37888,7 +38012,6 @@ var init_reporter = __esm({
37888
38012
  "use strict";
37889
38013
  init_logger();
37890
38014
  init_runtime_defaults();
37891
- init_builders();
37892
38015
  init_snapshot();
37893
38016
  DaemonStatusReporter = class {
37894
38017
  deps;
@@ -38062,10 +38185,6 @@ var init_reporter = __esm({
38062
38185
  LOG.info("StatusReport", `\u2192${target} ${baseSummary}`);
38063
38186
  }
38064
38187
  }
38065
- const sessions = buildSessionEntries(
38066
- allStates,
38067
- this.deps.cdpManagers
38068
- );
38069
38188
  const payload = {
38070
38189
  ...buildStatusSnapshot({
38071
38190
  allStates,
@@ -38085,9 +38204,9 @@ var init_reporter = __esm({
38085
38204
  }),
38086
38205
  screenshotUsage: this.deps.getScreenshotUsage?.() || null
38087
38206
  };
38088
- const payloadBytes = JSON.stringify(payload).length;
38089
38207
  const p2pSent = this.sendP2PPayload(payload);
38090
38208
  if (p2pSent) {
38209
+ const payloadBytes = JSON.stringify(payload).length;
38091
38210
  LOG.debug("P2P", `sent (${payloadBytes} bytes)`);
38092
38211
  if (payloadBytes > 256 * 1024) {
38093
38212
  LOG.warn(
@@ -38097,8 +38216,10 @@ var init_reporter = __esm({
38097
38216
  }
38098
38217
  }
38099
38218
  if (opts?.p2pOnly) return;
38219
+ if (!serverConnected || !serverConn) return;
38220
+ const payloadSessions = Array.isArray(payload.sessions) ? payload.sessions : [];
38100
38221
  const wsPayload = {
38101
- sessions: sessions.map((session) => ({
38222
+ sessions: payloadSessions.map((session) => ({
38102
38223
  id: session.id,
38103
38224
  parentId: session.parentId,
38104
38225
  providerType: session.providerType,
@@ -38124,8 +38245,9 @@ var init_reporter = __esm({
38124
38245
  return;
38125
38246
  }
38126
38247
  this.lastServerStatusHash = wsHash;
38248
+ const wsPayloadBytes = JSON.stringify(wsPayload).length;
38127
38249
  serverConn.sendMessage("status_report", wsPayload);
38128
- LOG.debug("Server", `sent status_report (${JSON.stringify(wsPayload).length} bytes)${opts?.reason ? ` [${opts.reason}]` : ""}`);
38250
+ LOG.debug("Server", `sent status_report (${wsPayloadBytes} bytes)${opts?.reason ? ` [${opts.reason}]` : ""}`);
38129
38251
  }
38130
38252
  // ─── P2P ─────────────────────────────────────────
38131
38253
  sendP2PPayload(payload) {
@@ -46626,53 +46748,63 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
46626
46748
  function handleSubscribe(peerId, msg, peers, handlers) {
46627
46749
  const peer = peers.get(peerId);
46628
46750
  if (!peer) return;
46629
- if (msg.topic === "session.chat_tail") {
46630
- const targetSessionId = typeof msg.params?.targetSessionId === "string" ? msg.params.targetSessionId.trim() : "";
46751
+ const topic = msg.topic;
46752
+ const params = msg.params || {};
46753
+ if (topic === "session.chat_tail") {
46754
+ const targetSessionId = typeof params?.targetSessionId === "string" ? params.targetSessionId.trim() : "";
46631
46755
  if (!targetSessionId) return;
46632
46756
  if (!peer.chatSubscriptions) peer.chatSubscriptions = /* @__PURE__ */ new Map();
46633
46757
  peer.chatSubscriptions.set(msg.key, {
46634
46758
  key: msg.key,
46635
- params: msg.params,
46759
+ params,
46636
46760
  seq: 0,
46637
46761
  cursor: {
46638
- knownMessageCount: Math.max(0, Number(msg.params.knownMessageCount || 0)),
46639
- lastMessageSignature: typeof msg.params.lastMessageSignature === "string" ? msg.params.lastMessageSignature : "",
46640
- tailLimit: Math.max(0, Number(msg.params.tailLimit || 0))
46762
+ knownMessageCount: Math.max(0, Number(params.knownMessageCount || 0)),
46763
+ lastMessageSignature: typeof params.lastMessageSignature === "string" ? params.lastMessageSignature : "",
46764
+ tailLimit: Math.max(0, Number(params.tailLimit || 0))
46641
46765
  },
46642
46766
  lastDeliveredSignature: ""
46643
46767
  });
46644
- } else if (msg.topic === "machine.runtime") {
46768
+ } else if (topic === "session.runtime_output") {
46769
+ const targetSessionId = typeof params?.targetSessionId === "string" ? params.targetSessionId.trim() : "";
46770
+ if (!targetSessionId) return;
46771
+ if (!peer.runtimeOutputSubscriptions) peer.runtimeOutputSubscriptions = /* @__PURE__ */ new Map();
46772
+ peer.runtimeOutputSubscriptions.set(msg.key, {
46773
+ key: msg.key,
46774
+ params: { targetSessionId }
46775
+ });
46776
+ } else if (topic === "machine.runtime") {
46645
46777
  if (!peer.machineRuntimeSubscriptions) peer.machineRuntimeSubscriptions = /* @__PURE__ */ new Map();
46646
46778
  peer.machineRuntimeSubscriptions.set(msg.key, {
46647
46779
  key: msg.key,
46648
- params: msg.params,
46780
+ params,
46649
46781
  seq: 0,
46650
46782
  lastSentAt: 0
46651
46783
  });
46652
- } else if (msg.topic === "session_host.diagnostics") {
46784
+ } else if (topic === "session_host.diagnostics") {
46653
46785
  if (!peer.sessionHostDiagnosticsSubscriptions) peer.sessionHostDiagnosticsSubscriptions = /* @__PURE__ */ new Map();
46654
46786
  peer.sessionHostDiagnosticsSubscriptions.set(msg.key, {
46655
46787
  key: msg.key,
46656
- params: msg.params,
46788
+ params,
46657
46789
  seq: 0,
46658
46790
  lastSentAt: 0
46659
46791
  });
46660
- } else if (msg.topic === "session.modal") {
46661
- const targetSessionId = typeof msg.params?.targetSessionId === "string" ? msg.params.targetSessionId.trim() : "";
46792
+ } else if (topic === "session.modal") {
46793
+ const targetSessionId = typeof params?.targetSessionId === "string" ? params.targetSessionId.trim() : "";
46662
46794
  if (!targetSessionId) return;
46663
46795
  if (!peer.sessionModalSubscriptions) peer.sessionModalSubscriptions = /* @__PURE__ */ new Map();
46664
46796
  peer.sessionModalSubscriptions.set(msg.key, {
46665
46797
  key: msg.key,
46666
- params: msg.params,
46798
+ params,
46667
46799
  seq: 0,
46668
46800
  lastSentAt: 0,
46669
46801
  lastDeliveredSignature: ""
46670
46802
  });
46671
- } else if (msg.topic === "daemon.metadata") {
46803
+ } else if (topic === "daemon.metadata") {
46672
46804
  if (!peer.daemonMetadataSubscriptions) peer.daemonMetadataSubscriptions = /* @__PURE__ */ new Map();
46673
46805
  peer.daemonMetadataSubscriptions.set(msg.key, {
46674
46806
  key: msg.key,
46675
- params: msg.params,
46807
+ params,
46676
46808
  seq: 0,
46677
46809
  lastSentAt: 0
46678
46810
  });
@@ -46684,23 +46816,28 @@ function handleSubscribe(peerId, msg, peers, handlers) {
46684
46816
  function handleUnsubscribe(peerId, msg, peers) {
46685
46817
  const peer = peers.get(peerId);
46686
46818
  if (!peer) return;
46687
- if (msg.topic === "session.chat_tail") {
46819
+ const topic = msg.topic;
46820
+ if (topic === "session.chat_tail") {
46688
46821
  peer.chatSubscriptions?.delete(msg.key);
46689
46822
  return;
46690
46823
  }
46691
- if (msg.topic === "machine.runtime") {
46824
+ if (topic === "session.runtime_output") {
46825
+ peer.runtimeOutputSubscriptions?.delete(msg.key);
46826
+ return;
46827
+ }
46828
+ if (topic === "machine.runtime") {
46692
46829
  peer.machineRuntimeSubscriptions?.delete(msg.key);
46693
46830
  return;
46694
46831
  }
46695
- if (msg.topic === "session_host.diagnostics") {
46832
+ if (topic === "session_host.diagnostics") {
46696
46833
  peer.sessionHostDiagnosticsSubscriptions?.delete(msg.key);
46697
46834
  return;
46698
46835
  }
46699
- if (msg.topic === "session.modal") {
46836
+ if (topic === "session.modal") {
46700
46837
  peer.sessionModalSubscriptions?.delete(msg.key);
46701
46838
  return;
46702
46839
  }
46703
- if (msg.topic === "daemon.metadata") {
46840
+ if (topic === "daemon.metadata") {
46704
46841
  peer.daemonMetadataSubscriptions?.delete(msg.key);
46705
46842
  }
46706
46843
  }
@@ -47453,7 +47590,24 @@ ${e?.stack || ""}`);
47453
47590
  return this.screenshotSender.sendStatusEvent(this.peers, event);
47454
47591
  }
47455
47592
  broadcastSessionOutput(sessionId, data) {
47456
- return this.screenshotSender.broadcastSessionOutput(this.peers, sessionId, data);
47593
+ if (!sessionId || typeof data !== "string" || data.length === 0) return false;
47594
+ const targetPeers = /* @__PURE__ */ new Map();
47595
+ for (const [peerId, peer] of this.peers.entries()) {
47596
+ if (peer.state !== "connected") continue;
47597
+ const subscriptions = peer.runtimeOutputSubscriptions;
47598
+ if (!subscriptions || subscriptions.size === 0) continue;
47599
+ let matches = false;
47600
+ for (const subscription of subscriptions.values()) {
47601
+ if (subscription.params.targetSessionId === sessionId) {
47602
+ matches = true;
47603
+ break;
47604
+ }
47605
+ }
47606
+ if (!matches) continue;
47607
+ targetPeers.set(peerId, peer);
47608
+ }
47609
+ if (targetPeers.size === 0) return false;
47610
+ return this.screenshotSender.broadcastSessionOutput(targetPeers, sessionId, data);
47457
47611
  }
47458
47612
  sendScreenshot(base64Data) {
47459
47613
  return this.screenshotSender.sendScreenshot(this.peers, base64Data);
@@ -55526,7 +55680,7 @@ var init_adhdev_daemon = __esm({
55526
55680
  init_version();
55527
55681
  init_src();
55528
55682
  init_runtime_defaults();
55529
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.18" });
55683
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.20" });
55530
55684
  AdhdevDaemon = class _AdhdevDaemon {
55531
55685
  localHttpServer = null;
55532
55686
  localWss = null;