adhdev 0.6.56 → 0.6.57

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/index.js CHANGED
@@ -16480,6 +16480,38 @@ function shSingleQuote(arg) {
16480
16480
  if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
16481
16481
  return `'${arg.replace(/'/g, `'\\''`)}'`;
16482
16482
  }
16483
+ function estimatePromptDisplayLines(text, cols = 100) {
16484
+ const normalized = String(text || "").replace(/\r/g, "");
16485
+ if (!normalized) return 1;
16486
+ return normalized.split("\n").reduce((sum, line) => sum + Math.max(1, Math.ceil(Math.max(1, line.length) / cols)), 0);
16487
+ }
16488
+ function extractPromptRetrySnippet(text) {
16489
+ const lines = String(text || "").replace(/\r/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
16490
+ const candidate = lines[lines.length - 1] || lines[0] || "";
16491
+ return candidate.slice(-120);
16492
+ }
16493
+ function normalizePromptText(text) {
16494
+ return String(text || "").replace(/\s+/g, " ").trim();
16495
+ }
16496
+ function compactPromptText(text) {
16497
+ return String(text || "").replace(/\s+/g, "").trim();
16498
+ }
16499
+ function promptLikelyVisible(screenText, promptSnippet) {
16500
+ const snippet = normalizePromptText(promptSnippet);
16501
+ if (!snippet) return false;
16502
+ const normalizedScreen = normalizePromptText(screenText);
16503
+ if (normalizedScreen.includes(snippet)) return true;
16504
+ const compactScreen = compactPromptText(screenText);
16505
+ const compactSnippet = compactPromptText(promptSnippet);
16506
+ if (compactSnippet && compactScreen.includes(compactSnippet)) return true;
16507
+ const tokens = snippet.split(/[^A-Za-z0-9_.:/-]+/).map((token) => token.trim()).filter((token) => token.length >= 4);
16508
+ if (tokens.length === 0) return false;
16509
+ const required2 = Math.min(tokens.length, 3);
16510
+ const matched = tokens.filter(
16511
+ (token) => normalizedScreen.includes(token) || compactScreen.includes(compactPromptText(token))
16512
+ ).length;
16513
+ return matched >= required2;
16514
+ }
16483
16515
  function parsePatternEntry(x) {
16484
16516
  if (x instanceof RegExp) return x;
16485
16517
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -16599,6 +16631,11 @@ var init_provider_cli_adapter = __esm({
16599
16631
  settleTimer = null;
16600
16632
  settledBuffer = "";
16601
16633
  submitPendingUntil = 0;
16634
+ responseSettleIgnoreUntil = 0;
16635
+ responseEpoch = 0;
16636
+ submitRetryTimer = null;
16637
+ submitRetryUsed = false;
16638
+ submitRetryPromptSnippet = "";
16602
16639
  // Resize redraw suppression
16603
16640
  resizeSuppressUntil = 0;
16604
16641
  // Debug: status transition history
@@ -16722,7 +16759,7 @@ var init_provider_cli_adapter = __esm({
16722
16759
  this.startupParseGate = true;
16723
16760
  this.startupBuffer = "";
16724
16761
  this.terminalScreen.reset(40, 120);
16725
- this.ready = true;
16762
+ this.ready = false;
16726
16763
  this.setStatus("idle", "pty_ready");
16727
16764
  this.onStatusChange?.();
16728
16765
  }
@@ -16767,7 +16804,9 @@ var init_provider_cli_adapter = __esm({
16767
16804
  const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
16768
16805
  if (isReady) {
16769
16806
  this.startupParseGate = false;
16807
+ this.ready = true;
16770
16808
  LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
16809
+ this.onStatusChange?.();
16771
16810
  } else {
16772
16811
  return;
16773
16812
  }
@@ -16776,19 +16815,45 @@ var init_provider_cli_adapter = __esm({
16776
16815
  }
16777
16816
  scheduleSettle() {
16778
16817
  if (this.settleTimer) clearTimeout(this.settleTimer);
16818
+ const settleEpoch = this.responseEpoch;
16779
16819
  const delay = Math.max(
16780
16820
  this.timeouts.outputSettle,
16781
16821
  this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
16782
16822
  );
16783
16823
  this.settleTimer = setTimeout(() => {
16784
16824
  this.settleTimer = null;
16825
+ if (settleEpoch !== this.responseEpoch) return;
16785
16826
  this.settledBuffer = this.recentOutputBuffer;
16786
16827
  this.evaluateSettled();
16787
16828
  }, delay);
16788
16829
  }
16830
+ armApprovalExitTimeout() {
16831
+ if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
16832
+ this.approvalExitTimeout = setTimeout(() => {
16833
+ if (this.currentStatus !== "waiting_approval") return;
16834
+ const tail = this.recentOutputBuffer;
16835
+ const modal = this.runParseApproval(tail);
16836
+ const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
16837
+ if (stillWaiting) {
16838
+ this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
16839
+ this.onStatusChange?.();
16840
+ this.armApprovalExitTimeout();
16841
+ return;
16842
+ }
16843
+ LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
16844
+ this.activeModal = null;
16845
+ this.lastApprovalResolvedAt = Date.now();
16846
+ this.setStatus("idle", "approval_timeout");
16847
+ this.onStatusChange?.();
16848
+ }, 6e4);
16849
+ }
16789
16850
  evaluateSettled() {
16851
+ if (this.submitPendingUntil > Date.now()) return;
16852
+ if (this.responseSettleIgnoreUntil > Date.now()) return;
16790
16853
  const tail = this.settledBuffer;
16791
- const scriptStatus = this.runDetectStatus(tail);
16854
+ const modal = this.runParseApproval(tail);
16855
+ const rawScriptStatus = this.runDetectStatus(tail);
16856
+ const scriptStatus = rawScriptStatus === "waiting_approval" || modal ? "waiting_approval" : rawScriptStatus;
16792
16857
  if (!scriptStatus) return;
16793
16858
  const prevStatus = this.currentStatus;
16794
16859
  if (scriptStatus === "waiting_approval") {
@@ -16796,19 +16861,9 @@ var init_provider_cli_adapter = __esm({
16796
16861
  if (!inCooldown) {
16797
16862
  this.isWaitingForResponse = true;
16798
16863
  this.setStatus("waiting_approval", "script_detect");
16799
- const modal = this.runParseApproval(tail);
16800
16864
  this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
16801
16865
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
16802
- if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
16803
- this.approvalExitTimeout = setTimeout(() => {
16804
- if (this.currentStatus === "waiting_approval") {
16805
- LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
16806
- this.activeModal = null;
16807
- this.lastApprovalResolvedAt = Date.now();
16808
- this.setStatus("idle", "approval_timeout");
16809
- this.onStatusChange?.();
16810
- }
16811
- }, 6e4);
16866
+ this.armApprovalExitTimeout();
16812
16867
  this.onStatusChange?.();
16813
16868
  return;
16814
16869
  }
@@ -16844,7 +16899,12 @@ var init_provider_cli_adapter = __esm({
16844
16899
  this.lastApprovalResolvedAt = Date.now();
16845
16900
  }
16846
16901
  if (this.isWaitingForResponse) {
16847
- this.finishResponse();
16902
+ if (this.idleTimeout) clearTimeout(this.idleTimeout);
16903
+ this.idleTimeout = setTimeout(() => {
16904
+ if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
16905
+ this.finishResponse();
16906
+ }
16907
+ }, this.timeouts.idleFinish);
16848
16908
  } else if (prevStatus !== "idle") {
16849
16909
  this.setStatus("idle", "script_detect");
16850
16910
  this.onStatusChange?.();
@@ -16852,6 +16912,8 @@ var init_provider_cli_adapter = __esm({
16852
16912
  }
16853
16913
  }
16854
16914
  finishResponse() {
16915
+ if (this.submitPendingUntil > Date.now()) return;
16916
+ if (this.responseSettleIgnoreUntil > Date.now()) return;
16855
16917
  if (this.responseTimeout) {
16856
16918
  clearTimeout(this.responseTimeout);
16857
16919
  this.responseTimeout = null;
@@ -16864,8 +16926,15 @@ var init_provider_cli_adapter = __esm({
16864
16926
  clearTimeout(this.approvalExitTimeout);
16865
16927
  this.approvalExitTimeout = null;
16866
16928
  }
16929
+ if (this.submitRetryTimer) {
16930
+ clearTimeout(this.submitRetryTimer);
16931
+ this.submitRetryTimer = null;
16932
+ }
16867
16933
  this.responseBuffer = "";
16868
16934
  this.isWaitingForResponse = false;
16935
+ this.responseSettleIgnoreUntil = 0;
16936
+ this.submitRetryUsed = false;
16937
+ this.submitRetryPromptSnippet = "";
16869
16938
  this.activeModal = null;
16870
16939
  this.setStatus("idle", "response_finished");
16871
16940
  this.onStatusChange?.();
@@ -16980,29 +17049,95 @@ ${data.message || ""}`.trim();
16980
17049
  }
16981
17050
  async sendMessage(text) {
16982
17051
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
17052
+ if (this.startupParseGate) {
17053
+ const deadline = Date.now() + 1e4;
17054
+ while (this.startupParseGate && Date.now() < deadline) {
17055
+ await new Promise((resolve8) => setTimeout(resolve8, 50));
17056
+ }
17057
+ }
16983
17058
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
16984
17059
  if (this.isWaitingForResponse) return;
16985
17060
  this.messages.push({ role: "user", content: text, timestamp: Date.now() });
16986
17061
  this.structuredMessages.push({ role: "user", content: text, timestamp: Date.now() });
16987
17062
  this.isWaitingForResponse = true;
16988
17063
  this.responseBuffer = "";
17064
+ this.submitRetryUsed = false;
17065
+ this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
17066
+ const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
17067
+ if (this.submitRetryTimer) {
17068
+ clearTimeout(this.submitRetryTimer);
17069
+ this.submitRetryTimer = null;
17070
+ }
17071
+ const estimatedLines = estimatePromptDisplayLines(text);
17072
+ const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
17073
+ const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
17074
+ const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
17075
+ if (this.settleTimer) {
17076
+ clearTimeout(this.settleTimer);
17077
+ this.settleTimer = null;
17078
+ }
17079
+ this.responseEpoch += 1;
17080
+ this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
16989
17081
  this.setStatus("generating", "sendMessage");
16990
17082
  this.onStatusChange?.();
17083
+ if (submitDelayMs > 0) {
17084
+ this.submitPendingUntil = Date.now() + submitDelayMs;
17085
+ }
16991
17086
  this.ptyProcess.write(text);
16992
17087
  const submit = () => {
16993
17088
  if (!this.ptyProcess) return;
16994
17089
  this.submitPendingUntil = 0;
16995
17090
  this.ptyProcess.write(this.sendKey);
17091
+ const retrySubmitIfStuck = (attempt) => {
17092
+ this.submitRetryTimer = null;
17093
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
17094
+ if (this.currentStatus !== "generating") return;
17095
+ if ((this.responseBuffer || "").trim()) return;
17096
+ const screenText = this.terminalScreen.getText();
17097
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
17098
+ if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
17099
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
17100
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
17101
+ this.ptyProcess.write(this.sendKey);
17102
+ if (attempt >= 3) {
17103
+ this.submitRetryUsed = true;
17104
+ return;
17105
+ }
17106
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
17107
+ };
17108
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
16996
17109
  this.responseTimeout = setTimeout(() => {
16997
17110
  if (this.isWaitingForResponse) this.finishResponse();
16998
17111
  }, this.timeouts.maxResponse);
16999
17112
  };
17000
- if (this.sendDelayMs > 0) {
17001
- this.submitPendingUntil = Date.now() + this.sendDelayMs;
17002
- setTimeout(submit, this.sendDelayMs);
17003
- } else {
17004
- submit();
17005
- }
17113
+ const submitStartedAt = Date.now();
17114
+ let lastNormalizedScreen = "";
17115
+ let lastScreenChangeAt = submitStartedAt;
17116
+ const waitForEchoAndSubmit = () => {
17117
+ if (!this.ptyProcess) return;
17118
+ const now = Date.now();
17119
+ const elapsed = now - submitStartedAt;
17120
+ const screenText = this.terminalScreen.getText();
17121
+ const normalizedScreen = normalizePromptText(screenText);
17122
+ if (normalizedScreen !== lastNormalizedScreen) {
17123
+ lastNormalizedScreen = normalizedScreen;
17124
+ lastScreenChangeAt = now;
17125
+ }
17126
+ const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
17127
+ if (echoVisible) {
17128
+ const screenSettled = now - lastScreenChangeAt >= 500;
17129
+ if (elapsed >= submitDelayMs && screenSettled) {
17130
+ submit();
17131
+ return;
17132
+ }
17133
+ }
17134
+ if (elapsed >= maxEchoWaitMs) {
17135
+ submit();
17136
+ return;
17137
+ }
17138
+ setTimeout(waitForEchoAndSubmit, 50);
17139
+ };
17140
+ waitForEchoAndSubmit();
17006
17141
  }
17007
17142
  getPartialResponse() {
17008
17143
  if (!this.isWaitingForResponse) return "";
@@ -17020,6 +17155,10 @@ ${data.message || ""}`.trim();
17020
17155
  clearTimeout(this.approvalExitTimeout);
17021
17156
  this.approvalExitTimeout = null;
17022
17157
  }
17158
+ if (this.submitRetryTimer) {
17159
+ clearTimeout(this.submitRetryTimer);
17160
+ this.submitRetryTimer = null;
17161
+ }
17023
17162
  if (this.ptyProcess) {
17024
17163
  this.ptyProcess.write("");
17025
17164
  setTimeout(() => {
@@ -17041,6 +17180,8 @@ ${data.message || ""}`.trim();
17041
17180
  this.structuredMessages = [];
17042
17181
  this.accumulatedBuffer = "";
17043
17182
  this.accumulatedRawBuffer = "";
17183
+ this.submitRetryUsed = false;
17184
+ this.submitRetryPromptSnippet = "";
17044
17185
  this.terminalScreen.reset();
17045
17186
  this.onStatusChange?.();
17046
17187
  }
@@ -17054,7 +17195,16 @@ ${data.message || ""}`.trim();
17054
17195
  this.ptyProcess?.write(data);
17055
17196
  }
17056
17197
  resolveModal(buttonIndex) {
17057
- if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
17198
+ if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
17199
+ this.activeModal = null;
17200
+ this.lastApprovalResolvedAt = Date.now();
17201
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
17202
+ if (this.approvalExitTimeout) {
17203
+ clearTimeout(this.approvalExitTimeout);
17204
+ this.approvalExitTimeout = null;
17205
+ }
17206
+ this.setStatus("generating", "approval_resolved");
17207
+ this.onStatusChange?.();
17058
17208
  if (buttonIndex in this.approvalKeys) {
17059
17209
  this.ptyProcess.write(this.approvalKeys[buttonIndex]);
17060
17210
  } else {
@@ -17096,6 +17246,10 @@ ${data.message || ""}`.trim();
17096
17246
  isWaitingForResponse: this.isWaitingForResponse,
17097
17247
  activeModal: this.activeModal,
17098
17248
  lastApprovalResolvedAt: this.lastApprovalResolvedAt,
17249
+ sendDelayMs: this.sendDelayMs,
17250
+ sendKey: this.sendKey,
17251
+ submitPendingUntil: this.submitPendingUntil,
17252
+ responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
17099
17253
  resizeSuppressUntil: this.resizeSuppressUntil,
17100
17254
  hasCliScripts: this.hasCliScripts(),
17101
17255
  scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
@@ -40872,7 +41026,7 @@ var init_adhdev_daemon = __esm({
40872
41026
  fs12 = __toESM(require("fs"));
40873
41027
  path14 = __toESM(require("path"));
40874
41028
  import_chalk2 = __toESM(require("chalk"));
40875
- pkgVersion = "0.6.56";
41029
+ pkgVersion = "0.6.57";
40876
41030
  if (pkgVersion === "unknown") {
40877
41031
  try {
40878
41032
  const possiblePaths = [