@adhdev/daemon-standalone 0.8.14 → 0.8.16

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
@@ -28501,19 +28501,32 @@ var require_dist2 = __commonJS({
28501
28501
  };
28502
28502
  }
28503
28503
  });
28504
+ var import_session_host_core2;
28505
+ var init_spawn_env = __esm2({
28506
+ "src/cli-adapters/spawn-env.ts"() {
28507
+ "use strict";
28508
+ import_session_host_core2 = require_dist();
28509
+ }
28510
+ });
28511
+ function loadNodePty() {
28512
+ if (cachedPty !== void 0) return cachedPty;
28513
+ try {
28514
+ cachedPty = require("node-pty");
28515
+ (0, import_session_host_core2.ensureNodePtySpawnHelperPermissions)();
28516
+ } catch {
28517
+ cachedPty = null;
28518
+ }
28519
+ return cachedPty;
28520
+ }
28504
28521
  var os7;
28505
- var pty;
28522
+ var cachedPty;
28506
28523
  var NodePtyRuntimeTransport;
28507
28524
  var NodePtyTransportFactory;
28508
28525
  var init_pty_transport = __esm2({
28509
28526
  "src/cli-adapters/pty-transport.ts"() {
28510
28527
  "use strict";
28511
28528
  os7 = __toESM2(require("os"));
28512
- try {
28513
- pty = require("node-pty");
28514
- } catch {
28515
- pty = null;
28516
- }
28529
+ init_spawn_env();
28517
28530
  NodePtyRuntimeTransport = class {
28518
28531
  constructor(handle) {
28519
28532
  this.handle = handle;
@@ -28544,6 +28557,7 @@ var require_dist2 = __commonJS({
28544
28557
  };
28545
28558
  NodePtyTransportFactory = class {
28546
28559
  spawn(command, args, options) {
28560
+ const pty = loadNodePty();
28547
28561
  if (!pty) throw new Error("node-pty is not installed");
28548
28562
  let cwd = options.cwd;
28549
28563
  if (cwd) {
@@ -28567,13 +28581,6 @@ var require_dist2 = __commonJS({
28567
28581
  };
28568
28582
  }
28569
28583
  });
28570
- var import_session_host_core2;
28571
- var init_spawn_env = __esm2({
28572
- "src/cli-adapters/spawn-env.ts"() {
28573
- "use strict";
28574
- import_session_host_core2 = require_dist();
28575
- }
28576
- });
28577
28584
  var provider_cli_adapter_exports = {};
28578
28585
  __export2(provider_cli_adapter_exports, {
28579
28586
  ProviderCliAdapter: () => ProviderCliAdapter,
@@ -28692,6 +28699,40 @@ var require_dist2 = __commonJS({
28692
28699
  function normalizeComparableMessageContent(text) {
28693
28700
  return String(text || "").replace(/\s+/g, " ").trim();
28694
28701
  }
28702
+ function trimPromptEchoPrefix(text, promptText) {
28703
+ const prompt = normalizeComparableMessageContent(String(promptText || ""));
28704
+ if (!prompt) return String(text || "");
28705
+ const lines = String(text || "").split(/\r\n|\n|\r/g);
28706
+ let dropCount = 0;
28707
+ for (let index = 0; index < Math.min(lines.length, 6); index += 1) {
28708
+ const fragment = normalizeComparableMessageContent(lines[index].replace(/^[.…]+\s*/, ""));
28709
+ if (!fragment) {
28710
+ if (dropCount === index) dropCount = index + 1;
28711
+ continue;
28712
+ }
28713
+ const fragmentWordCount = fragment ? fragment.split(/\s+/).filter(Boolean).length : 0;
28714
+ const canBePromptEcho = fragment.length >= 16 || fragmentWordCount >= 4;
28715
+ if (canBePromptEcho && prompt.includes(fragment)) {
28716
+ dropCount = index + 1;
28717
+ continue;
28718
+ }
28719
+ break;
28720
+ }
28721
+ return lines.slice(dropCount).join("\n").trim();
28722
+ }
28723
+ function getLastUserPromptText(messages) {
28724
+ const items = Array.isArray(messages) ? messages : [];
28725
+ for (let index = items.length - 1; index >= 0; index -= 1) {
28726
+ const message = items[index];
28727
+ if (message?.role === "user" && typeof message.content === "string" && message.content.trim()) {
28728
+ return message.content;
28729
+ }
28730
+ }
28731
+ return "";
28732
+ }
28733
+ function looksLikeConfirmOnlyLabel(label) {
28734
+ return /^(?:continue|confirm|ok|yes|trust|proceed|enter)$/i.test(String(label || "").trim());
28735
+ }
28695
28736
  function parsePatternEntry(x) {
28696
28737
  if (x instanceof RegExp) return x;
28697
28738
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -28719,7 +28760,6 @@ var require_dist2 = __commonJS({
28719
28760
  var os8;
28720
28761
  var path7;
28721
28762
  var import_child_process4;
28722
- var pty2;
28723
28763
  var buildCliSpawnEnv;
28724
28764
  var ProviderCliAdapter;
28725
28765
  var init_provider_cli_adapter = __esm2({
@@ -28732,12 +28772,6 @@ var require_dist2 = __commonJS({
28732
28772
  init_terminal_screen();
28733
28773
  init_pty_transport();
28734
28774
  init_spawn_env();
28735
- try {
28736
- pty2 = require("node-pty");
28737
- (0, import_session_host_core2.ensureNodePtySpawnHelperPermissions)((msg) => LOG2.info("CLI", msg));
28738
- } catch {
28739
- LOG2.error("CLI", "[ProviderCliAdapter] node-pty not found. Terminal features disabled.");
28740
- }
28741
28775
  buildCliSpawnEnv = import_session_host_core2.sanitizeSpawnEnv;
28742
28776
  ProviderCliAdapter = class _ProviderCliAdapter {
28743
28777
  constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
@@ -28839,6 +28873,8 @@ var require_dist2 = __commonJS({
28839
28873
  submitRetryUsed = false;
28840
28874
  submitRetryPromptSnippet = "";
28841
28875
  idleFinishCandidate = null;
28876
+ finishRetryTimer = null;
28877
+ finishRetryCount = 0;
28842
28878
  // Resize redraw suppression
28843
28879
  resizeSuppressUntil = 0;
28844
28880
  // Debug: status transition history
@@ -28860,6 +28896,8 @@ var require_dist2 = __commonJS({
28860
28896
  static MAX_TRACE_ENTRIES = 250;
28861
28897
  providerResolutionMeta;
28862
28898
  static IDLE_FINISH_CONFIRM_MS = 900;
28899
+ static FINISH_RETRY_DELAY_MS = 300;
28900
+ static MAX_FINISH_RETRIES = 2;
28863
28901
  syncMessageViews() {
28864
28902
  this.messages = [...this.committedMessages];
28865
28903
  this.structuredMessages = [...this.committedMessages];
@@ -28919,7 +28957,8 @@ var require_dist2 = __commonJS({
28919
28957
  recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
28920
28958
  screenText: this.terminalScreen.getText(),
28921
28959
  messages: [...baseMessages],
28922
- partialResponse
28960
+ partialResponse,
28961
+ promptText: scope?.prompt || ""
28923
28962
  };
28924
28963
  }
28925
28964
  setStatus(status, trigger) {
@@ -29162,6 +29201,11 @@ var require_dist2 = __commonJS({
29162
29201
  this.terminalScreen.reset(24, 80);
29163
29202
  this.pendingTerminalQueryTail = "";
29164
29203
  this.currentTurnScope = null;
29204
+ this.finishRetryCount = 0;
29205
+ if (this.finishRetryTimer) {
29206
+ clearTimeout(this.finishRetryTimer);
29207
+ this.finishRetryTimer = null;
29208
+ }
29165
29209
  this.ready = false;
29166
29210
  await this.ptyProcess.ready;
29167
29211
  this.recordTrace("ready", {
@@ -29208,11 +29252,12 @@ var require_dist2 = __commonJS({
29208
29252
  if (this.startupParseGate) {
29209
29253
  this.startupBuffer += cleanData;
29210
29254
  const elapsed = Date.now() - this.spawnAt;
29211
- const scriptStatus = this.runDetectStatus(this.startupBuffer);
29212
29255
  const screenText = this.terminalScreen.getText() || "";
29256
+ const startupModal = this.getStartupConfirmationModal(screenText);
29257
+ const scriptStatus = startupModal ? "waiting_approval" : this.runDetectStatus(this.startupBuffer);
29213
29258
  const hasInteractivePrompt = this.looksLikeVisibleIdlePrompt(screenText);
29214
29259
  const startupStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
29215
- const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
29260
+ const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || !!startupModal && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
29216
29261
  if (isReady) {
29217
29262
  this.startupParseGate = false;
29218
29263
  this.ready = true;
@@ -29244,7 +29289,9 @@ var require_dist2 = __commonJS({
29244
29289
  this.approvalExitTimeout = setTimeout(() => {
29245
29290
  if (this.currentStatus !== "waiting_approval") return;
29246
29291
  const tail = this.recentOutputBuffer;
29247
- const modal = this.runParseApproval(tail);
29292
+ const screenText = this.terminalScreen.getText() || "";
29293
+ const startupModal = this.getStartupConfirmationModal(screenText);
29294
+ const modal = this.runParseApproval(tail) || startupModal;
29248
29295
  const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
29249
29296
  if (stillWaiting) {
29250
29297
  this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
@@ -29264,6 +29311,63 @@ var require_dist2 = __commonJS({
29264
29311
  if (!text.trim()) return false;
29265
29312
  return /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(text) || /⏎\s+send/i.test(text) || /\?\s*for\s*shortcuts/i.test(text) || /Type your message(?:\s+or\s+@path\/to\/file)?/i.test(text) || /workspace\s*\(\/directory\)/i.test(text) || /for\s*shortcuts/i.test(text);
29266
29313
  }
29314
+ looksLikeVisibleAssistantCandidate(screenText) {
29315
+ const lines = sanitizeTerminalText(String(screenText || "")).split(/\r\n|\n|\r/g);
29316
+ for (const line of lines) {
29317
+ const trimmed = String(line || "").trim();
29318
+ if (!trimmed) continue;
29319
+ if (/^➜\s+\S+/.test(trimmed)) continue;
29320
+ if (/^Update available!/i.test(trimmed)) continue;
29321
+ if (/Claude Code v\d/i.test(trimmed)) continue;
29322
+ if (/^⏵⏵\s+accept edits on/i.test(trimmed)) continue;
29323
+ if (/^[◐◑◒◓◴◵◶◷◸◹◺◿].*\/effort/i.test(trimmed)) continue;
29324
+ if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+$/.test(trimmed)) continue;
29325
+ if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) continue;
29326
+ const assistantMatch = trimmed.match(/^⏺\s+(.+)$/);
29327
+ if (!assistantMatch) continue;
29328
+ const content = assistantMatch[1].trim();
29329
+ if (!content) continue;
29330
+ if (/^(?:Bash|Read|Write|Edit|MultiEdit|Task|Glob|Grep|LS|NotebookEdit)\(/.test(content)) continue;
29331
+ if (/This command requires approval|Do you want to proceed|Allow once|Always allow/i.test(content)) continue;
29332
+ return true;
29333
+ }
29334
+ return false;
29335
+ }
29336
+ shouldRetryFinishResponse(commitResult) {
29337
+ if (!this.currentTurnScope) return false;
29338
+ if (this.currentStatus === "waiting_approval" || this.activeModal) return false;
29339
+ if (this.finishRetryCount >= _ProviderCliAdapter.MAX_FINISH_RETRIES) return false;
29340
+ if (commitResult.hasAssistant && commitResult.assistantContent.trim()) return false;
29341
+ const screenText = this.terminalScreen.getText() || "";
29342
+ if (!this.looksLikeVisibleAssistantCandidate(screenText)) return false;
29343
+ const now = Date.now();
29344
+ const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
29345
+ const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
29346
+ return quietForMs < 1200 || screenStableMs < 1200 || !commitResult.hasAssistant;
29347
+ }
29348
+ getStartupConfirmationModal(screenText) {
29349
+ const text = sanitizeTerminalText(String(screenText || ""));
29350
+ if (!text.trim()) return null;
29351
+ if (this.cliType === "claude-cli") {
29352
+ const hasTrustPrompt = /Quick safety check/i.test(text) || /Is this a project you trust/i.test(text) || /Do you trust (?:this project|the contents of this directory|the files in this folder)/i.test(text);
29353
+ const hasConfirmFooter = /Press Enter to (?:continue|confirm)/i.test(text) || /Enter to confirm/i.test(text) || /Esc to (?:cancel|exit)/i.test(text);
29354
+ if (hasTrustPrompt || hasConfirmFooter && /trust/i.test(text)) {
29355
+ return {
29356
+ message: "Confirm Claude Code project trust",
29357
+ buttons: ["Continue"]
29358
+ };
29359
+ }
29360
+ }
29361
+ return null;
29362
+ }
29363
+ shouldResolveModalWithEnter(modal, buttonIndex) {
29364
+ if (!modal || buttonIndex !== 0) return false;
29365
+ const buttons = Array.isArray(modal.buttons) ? modal.buttons : [];
29366
+ if (buttons.length !== 1) return false;
29367
+ const buttonLabel = String(buttons[0] || "").trim();
29368
+ const modalText = `${modal.message || ""} ${buttonLabel}`.trim();
29369
+ return looksLikeConfirmOnlyLabel(buttonLabel) || /Quick safety check|project trust|trust (?:this project|the contents of this directory|the files in this folder)|Enter to confirm/i.test(modalText);
29370
+ }
29267
29371
  async waitForInteractivePrompt(maxWaitMs = 5e3) {
29268
29372
  const startedAt = Date.now();
29269
29373
  let loggedWait = false;
@@ -29313,9 +29417,10 @@ var require_dist2 = __commonJS({
29313
29417
  }
29314
29418
  const tail = this.settledBuffer;
29315
29419
  const screenText = this.terminalScreen.getText() || "";
29316
- const modal = this.runParseApproval(tail);
29420
+ const startupModal = this.getStartupConfirmationModal(screenText);
29421
+ const modal = this.runParseApproval(tail) || startupModal;
29317
29422
  const rawScriptStatus = this.runDetectStatus(tail);
29318
- const scriptStatus = rawScriptStatus;
29423
+ const scriptStatus = startupModal ? "waiting_approval" : rawScriptStatus;
29319
29424
  const parsedTranscript = this.parseCurrentTranscript(
29320
29425
  this.committedMessages,
29321
29426
  this.responseBuffer,
@@ -29510,7 +29615,24 @@ var require_dist2 = __commonJS({
29510
29615
  this.recordTrace("finish_response", {
29511
29616
  ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
29512
29617
  });
29513
- this.commitCurrentTranscript();
29618
+ const commitResult = this.commitCurrentTranscript();
29619
+ if (this.shouldRetryFinishResponse(commitResult)) {
29620
+ this.finishRetryCount += 1;
29621
+ this.recordTrace("finish_response_retry", {
29622
+ retryCount: this.finishRetryCount,
29623
+ retryDelayMs: _ProviderCliAdapter.FINISH_RETRY_DELAY_MS,
29624
+ assistantContent: this.summarizeTraceText(commitResult.assistantContent, 220),
29625
+ ...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
29626
+ });
29627
+ if (this.finishRetryTimer) clearTimeout(this.finishRetryTimer);
29628
+ this.finishRetryTimer = setTimeout(() => {
29629
+ this.finishRetryTimer = null;
29630
+ if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
29631
+ this.finishResponse();
29632
+ }
29633
+ }, _ProviderCliAdapter.FINISH_RETRY_DELAY_MS);
29634
+ return;
29635
+ }
29514
29636
  if (this.responseTimeout) {
29515
29637
  clearTimeout(this.responseTimeout);
29516
29638
  this.responseTimeout = null;
@@ -29527,11 +29649,16 @@ var require_dist2 = __commonJS({
29527
29649
  clearTimeout(this.submitRetryTimer);
29528
29650
  this.submitRetryTimer = null;
29529
29651
  }
29652
+ if (this.finishRetryTimer) {
29653
+ clearTimeout(this.finishRetryTimer);
29654
+ this.finishRetryTimer = null;
29655
+ }
29530
29656
  this.responseBuffer = "";
29531
29657
  this.isWaitingForResponse = false;
29532
29658
  this.responseSettleIgnoreUntil = 0;
29533
29659
  this.submitRetryUsed = false;
29534
29660
  this.submitRetryPromptSnippet = "";
29661
+ this.finishRetryCount = 0;
29535
29662
  this.currentTurnScope = null;
29536
29663
  this.activeModal = null;
29537
29664
  this.setStatus("idle", "response_finished");
@@ -29545,6 +29672,13 @@ var require_dist2 = __commonJS({
29545
29672
  );
29546
29673
  if (parsed && Array.isArray(parsed.messages)) {
29547
29674
  this.committedMessages = this.normalizeParsedMessages(parsed.messages);
29675
+ const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
29676
+ if (promptForTrim) {
29677
+ const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
29678
+ if (lastAssistantForTrim) {
29679
+ lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
29680
+ }
29681
+ }
29548
29682
  this.syncMessageViews();
29549
29683
  const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
29550
29684
  this.recordTrace("commit_transcript", {
@@ -29560,7 +29694,15 @@ var require_dist2 = __commonJS({
29560
29694
  `[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
29561
29695
  );
29562
29696
  }
29697
+ return {
29698
+ hasAssistant: !!lastAssistant,
29699
+ assistantContent: lastAssistant?.content || ""
29700
+ };
29563
29701
  }
29702
+ return {
29703
+ hasAssistant: false,
29704
+ assistantContent: ""
29705
+ };
29564
29706
  }
29565
29707
  // ─── Script Execution ──────────────────────────
29566
29708
  runDetectStatus(text) {
@@ -29639,7 +29781,15 @@ var require_dist2 = __commonJS({
29639
29781
  if (!this.cliScripts?.parseOutput) return null;
29640
29782
  try {
29641
29783
  const input = this.buildParseInput(baseMessages, partialResponse, scope);
29642
- return this.cliScripts.parseOutput(input);
29784
+ const parsed = this.cliScripts.parseOutput(input);
29785
+ const promptForTrim = scope?.prompt || getLastUserPromptText(baseMessages);
29786
+ if (parsed && Array.isArray(parsed.messages) && promptForTrim) {
29787
+ const lastAssistant = [...parsed.messages].reverse().find((message) => message?.role === "assistant" && typeof message.content === "string");
29788
+ if (lastAssistant) {
29789
+ lastAssistant.content = trimPromptEchoPrefix(lastAssistant.content, promptForTrim);
29790
+ }
29791
+ }
29792
+ return parsed;
29643
29793
  } catch (e) {
29644
29794
  LOG2.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
29645
29795
  return null;
@@ -29684,10 +29834,19 @@ ${data.message || ""}`.trim();
29684
29834
  if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
29685
29835
  if (this.isWaitingForResponse) return;
29686
29836
  await this.waitForInteractivePrompt();
29837
+ const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
29838
+ if (blockingModal || this.currentStatus === "waiting_approval") {
29839
+ throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
29840
+ }
29687
29841
  this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
29688
29842
  this.syncMessageViews();
29689
29843
  this.isWaitingForResponse = true;
29690
29844
  this.responseBuffer = "";
29845
+ this.finishRetryCount = 0;
29846
+ if (this.finishRetryTimer) {
29847
+ clearTimeout(this.finishRetryTimer);
29848
+ this.finishRetryTimer = null;
29849
+ }
29691
29850
  this.clearIdleFinishCandidate("send_message");
29692
29851
  this.currentTurnScope = {
29693
29852
  prompt: text,
@@ -29915,6 +30074,10 @@ ${data.message || ""}`.trim();
29915
30074
  clearTimeout(this.submitRetryTimer);
29916
30075
  this.submitRetryTimer = null;
29917
30076
  }
30077
+ if (this.finishRetryTimer) {
30078
+ clearTimeout(this.finishRetryTimer);
30079
+ this.finishRetryTimer = null;
30080
+ }
29918
30081
  if (this.responseTimeout) {
29919
30082
  clearTimeout(this.responseTimeout);
29920
30083
  this.responseTimeout = null;
@@ -29938,6 +30101,7 @@ ${data.message || ""}`.trim();
29938
30101
  this.ptyOutputFlushTimer = null;
29939
30102
  }
29940
30103
  this.ptyOutputBuffer = "";
30104
+ this.finishRetryCount = 0;
29941
30105
  if (this.ptyProcess) {
29942
30106
  this.ptyProcess.write("");
29943
30107
  setTimeout(() => {
@@ -29968,6 +30132,10 @@ ${data.message || ""}`.trim();
29968
30132
  clearTimeout(this.submitRetryTimer);
29969
30133
  this.submitRetryTimer = null;
29970
30134
  }
30135
+ if (this.finishRetryTimer) {
30136
+ clearTimeout(this.finishRetryTimer);
30137
+ this.finishRetryTimer = null;
30138
+ }
29971
30139
  if (this.responseTimeout) {
29972
30140
  clearTimeout(this.responseTimeout);
29973
30141
  this.responseTimeout = null;
@@ -29991,6 +30159,7 @@ ${data.message || ""}`.trim();
29991
30159
  this.ptyOutputFlushTimer = null;
29992
30160
  }
29993
30161
  this.ptyOutputBuffer = "";
30162
+ this.finishRetryCount = 0;
29994
30163
  if (this.ptyProcess) {
29995
30164
  try {
29996
30165
  if (typeof this.ptyProcess.detach === "function") {
@@ -30027,6 +30196,11 @@ ${data.message || ""}`.trim();
30027
30196
  this.ptyOutputFlushTimer = null;
30028
30197
  }
30029
30198
  this.ptyOutputBuffer = "";
30199
+ if (this.finishRetryTimer) {
30200
+ clearTimeout(this.finishRetryTimer);
30201
+ this.finishRetryTimer = null;
30202
+ }
30203
+ this.finishRetryCount = 0;
30030
30204
  this.terminalScreen.reset();
30031
30205
  this.ptyProcess?.clearBuffer?.();
30032
30206
  this.onStatusChange?.();
@@ -30046,10 +30220,11 @@ ${data.message || ""}`.trim();
30046
30220
  }
30047
30221
  resolveModal(buttonIndex) {
30048
30222
  if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
30223
+ const modal = this.activeModal;
30049
30224
  this.clearIdleFinishCandidate("resolve_modal");
30050
30225
  this.recordTrace("resolve_modal", {
30051
30226
  buttonIndex,
30052
- activeModal: this.activeModal
30227
+ activeModal: modal
30053
30228
  });
30054
30229
  this.activeModal = null;
30055
30230
  this.lastApprovalResolvedAt = Date.now();
@@ -30060,7 +30235,9 @@ ${data.message || ""}`.trim();
30060
30235
  }
30061
30236
  this.setStatus("generating", "approval_resolved");
30062
30237
  this.onStatusChange?.();
30063
- if (buttonIndex in this.approvalKeys) {
30238
+ if (this.shouldResolveModalWithEnter(modal, buttonIndex)) {
30239
+ this.ptyProcess.write("\r");
30240
+ } else if (buttonIndex in this.approvalKeys) {
30064
30241
  this.ptyProcess.write(this.approvalKeys[buttonIndex]);
30065
30242
  } else {
30066
30243
  const DOWN = "\x1B[B";
@@ -39394,7 +39571,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
39394
39571
  }
39395
39572
  }
39396
39573
  function getNpmExecutable() {
39397
- return process.platform === "win32" ? "npm.cmd" : "npm";
39574
+ return "npm";
39575
+ }
39576
+ function getNpmExecOptions() {
39577
+ return { shell: process.platform === "win32" };
39398
39578
  }
39399
39579
  function killPid2(pid) {
39400
39580
  try {
@@ -39456,9 +39636,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
39456
39636
  }
39457
39637
  }
39458
39638
  function cleanupStaleGlobalInstallDirs(pkgName) {
39459
- const npmRoot = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["root", "-g"], { encoding: "utf8" }).trim();
39639
+ const npmExecOpts = getNpmExecOptions();
39640
+ const npmRoot = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
39460
39641
  if (!npmRoot) return;
39461
- const npmPrefix = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8" }).trim();
39642
+ const npmPrefix = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
39462
39643
  const binDir = process.platform === "win32" ? npmPrefix : path13.join(npmPrefix, "bin");
39463
39644
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
39464
39645
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
@@ -39519,7 +39700,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
39519
39700
  {
39520
39701
  encoding: "utf8",
39521
39702
  stdio: "pipe",
39522
- maxBuffer: 20 * 1024 * 1024
39703
+ maxBuffer: 20 * 1024 * 1024,
39704
+ ...getNpmExecOptions()
39523
39705
  }
39524
39706
  );
39525
39707
  if (installOutput.trim()) {
@@ -42711,6 +42893,53 @@ async (params) => {
42711
42893
  let lastModalKey = "";
42712
42894
  let idleSince = 0;
42713
42895
  let sawBusy = false;
42896
+ const noteStatus = (status) => {
42897
+ if (status !== lastStatus) {
42898
+ statusesSeen.push(status);
42899
+ lastStatus = status;
42900
+ }
42901
+ };
42902
+ const resolveActiveModalIfNeeded = (status, modal) => {
42903
+ if (!autoResolveApprovals || status !== "waiting_approval" || !modal || !Array.isArray(modal.buttons) || modal.buttons.length === 0) {
42904
+ return false;
42905
+ }
42906
+ const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
42907
+ const modalKey = JSON.stringify({
42908
+ message: modal.message || "",
42909
+ buttons: modal.buttons,
42910
+ index: clampedIndex
42911
+ });
42912
+ if (modalKey === lastModalKey || typeof bundle?.adapter?.resolveModal !== "function") {
42913
+ return false;
42914
+ }
42915
+ lastModalKey = modalKey;
42916
+ approvalsResolved.push({
42917
+ at: Date.now(),
42918
+ buttonIndex: clampedIndex,
42919
+ label: modal.buttons[clampedIndex] || null
42920
+ });
42921
+ bundle.adapter.resolveModal(clampedIndex);
42922
+ return true;
42923
+ };
42924
+ const preflightStartedAt = Date.now();
42925
+ while (Date.now() - preflightStartedAt < Math.max(1e3, readyTimeoutMs)) {
42926
+ bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
42927
+ if (!bundle) {
42928
+ throw new Error("CLI instance disappeared before exercise send");
42929
+ }
42930
+ const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
42931
+ const trace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
42932
+ const status = String(debug?.status || bundle.target.status || "unknown");
42933
+ const modal = debug?.activeModal || trace?.activeModal || null;
42934
+ noteStatus(status);
42935
+ if (resolveActiveModalIfNeeded(status, modal)) {
42936
+ await sleep(150);
42937
+ continue;
42938
+ }
42939
+ const startupParseGate = !!debug?.startupParseGate;
42940
+ if (status === "idle" && !startupParseGate) break;
42941
+ await sleep(150);
42942
+ }
42714
42943
  ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
42715
42944
  while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
42716
42945
  await sleep(150);
@@ -42725,32 +42954,14 @@ async (params) => {
42725
42954
  const sawSendMessage = traceEntries.some((entry) => entry?.type === "send_message");
42726
42955
  const sawSubmitWrite = traceEntries.some((entry) => entry?.type === "submit_write");
42727
42956
  const hasTurnStarted = sawSendMessage || sawSubmitWrite || !!debug?.currentTurnScope;
42728
- if (status !== lastStatus) {
42729
- statusesSeen.push(status);
42730
- lastStatus = status;
42731
- }
42957
+ noteStatus(status);
42732
42958
  if (status === "generating" || status === "waiting_approval") {
42733
42959
  sawBusy = true;
42734
42960
  idleSince = 0;
42735
42961
  }
42736
42962
  const modal = debug?.activeModal || trace?.activeModal || null;
42737
- if (autoResolveApprovals && status === "waiting_approval" && modal && Array.isArray(modal.buttons) && modal.buttons.length > 0) {
42738
- const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
42739
- const modalKey = JSON.stringify({
42740
- message: modal.message || "",
42741
- buttons: modal.buttons,
42742
- index: clampedIndex
42743
- });
42744
- if (modalKey !== lastModalKey && typeof bundle.adapter.resolveModal === "function") {
42745
- lastModalKey = modalKey;
42746
- approvalsResolved.push({
42747
- at: Date.now(),
42748
- buttonIndex: clampedIndex,
42749
- label: modal.buttons[clampedIndex] || null
42750
- });
42751
- bundle.adapter.resolveModal(clampedIndex);
42752
- continue;
42753
- }
42963
+ if (resolveActiveModalIfNeeded(status, modal)) {
42964
+ continue;
42754
42965
  }
42755
42966
  const traceCount = Number(trace?.entryCount || 0);
42756
42967
  const hasProgress = hasTurnStarted && (traceCount > preTraceCount || statusesSeen.length > 1 || approvalsResolved.length > 0);
@@ -43744,10 +43955,10 @@ async (params) => {
43744
43955
  let isPty = false;
43745
43956
  const { spawn: spawnFn } = await import("child_process");
43746
43957
  try {
43747
- const pty3 = require("node-pty");
43958
+ const pty = require("node-pty");
43748
43959
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
43749
43960
  const isWin2 = os17.platform() === "win32";
43750
- child = pty3.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
43961
+ child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
43751
43962
  name: "xterm-256color",
43752
43963
  cols: 120,
43753
43964
  rows: 40,
@@ -44403,6 +44614,13 @@ async (params) => {
44403
44614
  lines.push("19. Literal string checks are allowed only for stable proper nouns or exact product chrome that cannot be expressed safely as a broader pattern. Everything else should generalize.");
44404
44615
  lines.push("20. When a bug comes from noisy PTY text, first normalize and classify the line family; do NOT just append another special-case substring to the parser.");
44405
44616
  lines.push("");
44617
+ if (verification?.focusAreas?.length) {
44618
+ lines.push("## Provider-Specific Focus Areas");
44619
+ for (const area of verification.focusAreas) {
44620
+ lines.push(`- ${area}`);
44621
+ }
44622
+ lines.push("");
44623
+ }
44406
44624
  lines.push("## Task");
44407
44625
  lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
44408
44626
  lines.push("");
@@ -47479,6 +47697,14 @@ if (pkgVersion === "unknown") {
47479
47697
  } catch {
47480
47698
  }
47481
47699
  }
47700
+ if (process.platform === "win32") {
47701
+ const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] || "0", 10);
47702
+ if (nodeMajor >= 24) {
47703
+ console.error("\n\u2717 Windows is currently unsupported on Node.js 24+ for ADHDev standalone.");
47704
+ console.error(" Install Node.js 22.x on Windows, then retry.\n");
47705
+ process.exit(1);
47706
+ }
47707
+ }
47482
47708
  var SESSION_TARGET_COMMANDS = /* @__PURE__ */ new Set([
47483
47709
  "send_chat",
47484
47710
  "read_chat",