adhdev 0.9.12 → 0.9.14

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
@@ -9487,14 +9487,14 @@ async function handleOpenPanel(h, args) {
9487
9487
  success: revealState.visible || focusState.focused
9488
9488
  };
9489
9489
  }
9490
- function handlePtyInput(h, args) {
9490
+ async function handlePtyInput(h, args) {
9491
9491
  const { cliType, data, targetSessionId } = args || {};
9492
9492
  if (!data) return { success: false, error: "data required" };
9493
9493
  const adapter = h.getCliAdapter(targetSessionId || cliType);
9494
9494
  if (!adapter || typeof adapter.writeRaw !== "function") {
9495
9495
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
9496
9496
  }
9497
- adapter.writeRaw(data);
9497
+ await adapter.writeRaw(data);
9498
9498
  return { success: true };
9499
9499
  }
9500
9500
  function handlePtyResize(_h, args) {
@@ -9671,7 +9671,7 @@ async function executeProviderScript(h, args, scriptName) {
9671
9671
  if (cliCommand?.type === "send_message" && cliCommand.text) {
9672
9672
  await adapter.sendMessage(cliCommand.text);
9673
9673
  } else if (cliCommand?.type === "pty_write" && cliCommand.text && adapter.writeRaw) {
9674
- adapter.writeRaw(cliCommand.text + "\r");
9674
+ await adapter.writeRaw(cliCommand.text + "\r");
9675
9675
  }
9676
9676
  applyProviderPatch(h, args, parsed.payload);
9677
9677
  return {
@@ -13971,6 +13971,29 @@ var init_provider_cli_adapter = __esm({
13971
13971
  }
13972
13972
  await this.sendMessage(promptText);
13973
13973
  }
13974
+ async writeToPty(data) {
13975
+ if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13976
+ await this.ptyProcess.write(data);
13977
+ }
13978
+ resetPendingSendState(reason) {
13979
+ this.isWaitingForResponse = false;
13980
+ this.responseBuffer = "";
13981
+ this.currentTurnScope = null;
13982
+ this.submitPendingUntil = 0;
13983
+ this.clearIdleFinishCandidate(reason);
13984
+ if (this.responseTimeout) {
13985
+ clearTimeout(this.responseTimeout);
13986
+ this.responseTimeout = null;
13987
+ }
13988
+ if (this.submitRetryTimer) {
13989
+ clearTimeout(this.submitRetryTimer);
13990
+ this.submitRetryTimer = null;
13991
+ }
13992
+ if (this.finishRetryTimer) {
13993
+ clearTimeout(this.finishRetryTimer);
13994
+ this.finishRetryTimer = null;
13995
+ }
13996
+ }
13974
13997
  async sendMessage(text) {
13975
13998
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13976
13999
  const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
@@ -14065,19 +14088,29 @@ var init_provider_cli_adapter = __esm({
14065
14088
  if (this.isWaitingForResponse) this.finishResponse();
14066
14089
  }, this.timeouts.maxResponse);
14067
14090
  };
14068
- await new Promise((resolve18) => {
14091
+ await new Promise((resolve18, reject) => {
14069
14092
  let resolved = false;
14070
14093
  const resolveOnce = () => {
14071
14094
  if (resolved) return;
14072
14095
  resolved = true;
14073
14096
  resolve18();
14074
14097
  };
14098
+ const rejectOnce = (error48) => {
14099
+ if (resolved) return;
14100
+ this.resetPendingSendState("send_write_failed");
14101
+ resolved = true;
14102
+ reject(error48);
14103
+ };
14104
+ const writeRetryKey = (mode) => {
14105
+ void this.writeToPty(this.sendKey).catch((error48) => {
14106
+ LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error48?.message || error48}`);
14107
+ });
14108
+ };
14075
14109
  const submit = () => {
14076
14110
  if (!this.ptyProcess) {
14077
14111
  resolveOnce();
14078
14112
  return;
14079
14113
  }
14080
- commitUserTurn();
14081
14114
  this.submitPendingUntil = 0;
14082
14115
  const screenText = this.terminalScreen.getText();
14083
14116
  this.recordTrace("submit_write", {
@@ -14085,7 +14118,6 @@ var init_provider_cli_adapter = __esm({
14085
14118
  sendKey: this.sendKey,
14086
14119
  screenText: summarizeCliTraceText(screenText, 500)
14087
14120
  });
14088
- this.ptyProcess.write(this.sendKey);
14089
14121
  const retrySubmitIfStuck = (attempt) => {
14090
14122
  this.submitRetryTimer = null;
14091
14123
  if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
@@ -14105,19 +14137,21 @@ var init_provider_cli_adapter = __esm({
14105
14137
  sendKey: this.sendKey,
14106
14138
  screenText: summarizeCliTraceText(screenText2, 500)
14107
14139
  });
14108
- this.ptyProcess.write(this.sendKey);
14140
+ writeRetryKey("submit_retry");
14109
14141
  if (attempt >= 3) {
14110
14142
  this.submitRetryUsed = true;
14111
14143
  return;
14112
14144
  }
14113
14145
  this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
14114
14146
  };
14115
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
14116
- startResponseTimeout();
14117
- resolveOnce();
14147
+ void this.writeToPty(this.sendKey).then(() => {
14148
+ commitUserTurn();
14149
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
14150
+ startResponseTimeout();
14151
+ resolveOnce();
14152
+ }, rejectOnce);
14118
14153
  };
14119
14154
  if (this.submitStrategy === "immediate") {
14120
- commitUserTurn();
14121
14155
  this.submitPendingUntil = 0;
14122
14156
  this.recordTrace("submit_write", {
14123
14157
  mode: "immediate",
@@ -14125,37 +14159,38 @@ var init_provider_cli_adapter = __esm({
14125
14159
  sendKey: this.sendKey,
14126
14160
  screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
14127
14161
  });
14128
- this.ptyProcess.write(text + this.sendKey);
14129
- this.submitRetryTimer = setTimeout(() => {
14130
- this.submitRetryTimer = null;
14131
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
14132
- if (this.currentStatus === "waiting_approval") return;
14133
- if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
14134
- const screenText = this.terminalScreen.getText();
14135
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
14136
- const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
14137
- if (liveApproval) return;
14138
- const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
14139
- if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
14140
- LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
14141
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
14142
- this.recordTrace("submit_write", {
14143
- mode: "immediate_retry",
14144
- attempt: 1,
14145
- sendKey: this.sendKey,
14146
- screenText: summarizeCliTraceText(screenText, 500)
14147
- });
14148
- this.ptyProcess.write(this.sendKey);
14149
- this.submitRetryUsed = true;
14150
- }, retryDelayMs);
14151
- startResponseTimeout();
14152
- resolveOnce();
14162
+ void this.writeToPty(text + this.sendKey).then(() => {
14163
+ commitUserTurn();
14164
+ this.submitRetryTimer = setTimeout(() => {
14165
+ this.submitRetryTimer = null;
14166
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
14167
+ if (this.currentStatus === "waiting_approval") return;
14168
+ if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
14169
+ const screenText = this.terminalScreen.getText();
14170
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
14171
+ const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
14172
+ if (liveApproval) return;
14173
+ const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
14174
+ if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
14175
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
14176
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
14177
+ this.recordTrace("submit_write", {
14178
+ mode: "immediate_retry",
14179
+ attempt: 1,
14180
+ sendKey: this.sendKey,
14181
+ screenText: summarizeCliTraceText(screenText, 500)
14182
+ });
14183
+ writeRetryKey("immediate_retry");
14184
+ this.submitRetryUsed = true;
14185
+ }, retryDelayMs);
14186
+ startResponseTimeout();
14187
+ resolveOnce();
14188
+ }, rejectOnce);
14153
14189
  return;
14154
14190
  }
14155
14191
  if (submitDelayMs > 0) {
14156
14192
  this.submitPendingUntil = Date.now() + submitDelayMs;
14157
14193
  }
14158
- this.ptyProcess.write(text);
14159
14194
  this.recordTrace("submit_write", {
14160
14195
  mode: "type_then_submit",
14161
14196
  text: summarizeCliTraceText(text, 500),
@@ -14192,7 +14227,7 @@ var init_provider_cli_adapter = __esm({
14192
14227
  }
14193
14228
  setTimeout(waitForEchoAndSubmit, 50);
14194
14229
  };
14195
- waitForEchoAndSubmit();
14230
+ void this.writeToPty(text).then(() => waitForEchoAndSubmit(), rejectOnce);
14196
14231
  });
14197
14232
  }
14198
14233
  getPartialResponse() {
@@ -14347,12 +14382,12 @@ var init_provider_cli_adapter = __esm({
14347
14382
  isReady() {
14348
14383
  return this.ready;
14349
14384
  }
14350
- writeRaw(data) {
14385
+ async writeRaw(data) {
14351
14386
  this.recordTrace("write_raw", {
14352
14387
  keys: JSON.stringify(data),
14353
14388
  length: data.length
14354
14389
  });
14355
- this.ptyProcess?.write(data);
14390
+ await this.writeToPty(data);
14356
14391
  }
14357
14392
  resolveModal(buttonIndex) {
14358
14393
  let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
@@ -14898,7 +14933,7 @@ var init_cli_provider_instance = __esm({
14898
14933
  if (cliCommand?.type === "send_message" && cliCommand.text) {
14899
14934
  await this.adapter.sendMessage(cliCommand.text);
14900
14935
  } else if (cliCommand?.type === "pty_write" && cliCommand.text) {
14901
- this.adapter.writeRaw(cliCommand.text + "\r");
14936
+ await this.adapter.writeRaw(cliCommand.text + "\r");
14902
14937
  }
14903
14938
  this.applyProviderResponse(parsed.payload, { phase: "immediate" });
14904
14939
  }
@@ -38684,10 +38719,14 @@ var init_router = __esm({
38684
38719
  currentInstalled = parsed?.dependencies?.[pkgName]?.version || null;
38685
38720
  } catch {
38686
38721
  }
38687
- if (currentInstalled === latest) {
38722
+ const runningVersion = typeof this.deps.statusVersion === "string" ? this.deps.statusVersion.trim().replace(/^v/, "") : null;
38723
+ if (currentInstalled === latest && runningVersion === latest) {
38688
38724
  LOG.info("Upgrade", `Already on latest version v${latest}; skipping install`);
38689
38725
  return { success: true, upgraded: false, alreadyLatest: true, version: latest };
38690
38726
  }
38727
+ if (currentInstalled === latest && runningVersion && runningVersion !== latest) {
38728
+ LOG.info("Upgrade", `Installed package is v${latest}, but running daemon is v${runningVersion}; scheduling restart`);
38729
+ }
38691
38730
  spawnDetachedDaemonUpgradeHelper({
38692
38731
  packageName: pkgName,
38693
38732
  targetVersion: latest,
@@ -42873,7 +42912,7 @@ async function handleCliRaw(ctx, req, res) {
42873
42912
  }
42874
42913
  try {
42875
42914
  if (typeof adapter.writeRaw === "function") {
42876
- adapter.writeRaw(keys);
42915
+ await adapter.writeRaw(keys);
42877
42916
  ctx.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
42878
42917
  } else {
42879
42918
  ctx.json(res, 400, { error: "writeRaw not available on this adapter" });
@@ -45836,7 +45875,7 @@ var init_session_host_transport = __esm({
45836
45875
  this.exitCallbacks.add(callback);
45837
45876
  }
45838
45877
  write(data) {
45839
- this.enqueue(async () => {
45878
+ return this.enqueue(async () => {
45840
45879
  let response = await this.client.request({
45841
45880
  type: "send_input",
45842
45881
  payload: {
@@ -46138,9 +46177,11 @@ var init_session_host_transport = __esm({
46138
46177
  };
46139
46178
  }
46140
46179
  enqueue(action) {
46141
- this.operationChain = this.operationChain.then(() => this.ready).then(action).catch((error48) => {
46180
+ const operation = this.operationChain.then(() => this.ready).then(action);
46181
+ this.operationChain = operation.catch((error48) => {
46142
46182
  LOG.warn("CLI", `[session-host:${this.options.runtimeId}] ${error48?.message || error48}`);
46143
46183
  });
46184
+ return operation;
46144
46185
  }
46145
46186
  async closeClient(destroy = false) {
46146
46187
  if (this.closed) return;
@@ -78731,14 +78772,41 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
78731
78772
  return;
78732
78773
  }
78733
78774
  if (parsed.type === "pty_input") {
78734
- const permission = peers.get(peerId)?.sharePermission;
78775
+ const peer = peers.get(peerId);
78776
+ const permission = peer?.sharePermission;
78777
+ const sendPtyInputError = (sessionId2, reason, error48) => {
78778
+ const message = error48 instanceof Error ? error48.message : typeof error48 === "string" ? error48 : void 0;
78779
+ sendToPeer(peer, {
78780
+ type: "session_io_error",
78781
+ sessionId: sessionId2,
78782
+ reason,
78783
+ ...message ? { error: message } : {}
78784
+ });
78785
+ };
78735
78786
  if (permission) {
78736
78787
  log(`pty_input: REJECTED \u2014 permission=${permission} peer=${peerId}`);
78788
+ const sessionId2 = typeof (parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType) === "string" ? parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType : "";
78789
+ sendPtyInputError(sessionId2, "permission_denied");
78790
+ return;
78791
+ }
78792
+ const sessionIdCandidate = parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType || "";
78793
+ const sessionId = typeof sessionIdCandidate === "string" ? sessionIdCandidate : "";
78794
+ if (!sessionId || typeof parsed.data !== "string" || parsed.data.length === 0) {
78795
+ sendPtyInputError(sessionId, "invalid_payload");
78796
+ return;
78797
+ }
78798
+ if (!handlers.ptyInputHandler) {
78799
+ sendPtyInputError(sessionId, "handler_unavailable");
78737
78800
  return;
78738
78801
  }
78739
- const sessionId = parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType || "";
78740
- if (handlers.ptyInputHandler && parsed.data && sessionId) {
78741
- handlers.ptyInputHandler(sessionId, parsed.data);
78802
+ try {
78803
+ Promise.resolve(handlers.ptyInputHandler(sessionId, parsed.data)).catch((error48) => {
78804
+ log(`pty_input write failed: peer=${peerId} sessionId=${sessionId} error=${error48?.message || error48}`);
78805
+ sendPtyInputError(sessionId, "write_failed", error48);
78806
+ });
78807
+ } catch (error48) {
78808
+ log(`pty_input write failed: peer=${peerId} sessionId=${sessionId} error=${error48?.message || error48}`);
78809
+ sendPtyInputError(sessionId, "write_failed", error48);
78742
78810
  }
78743
78811
  return;
78744
78812
  }
@@ -87072,21 +87140,65 @@ function isAdhdevProcess(pid) {
87072
87140
  return true;
87073
87141
  }
87074
87142
  }
87075
- function getDaemonPid(ref = {}) {
87076
- const pidFile = getDaemonPidFile(ref);
87143
+ function getDaemonHealthPid(ref = {}) {
87144
+ const port = resolveDaemonPort(ref);
87077
87145
  try {
87078
- if (!fs23.existsSync(pidFile)) return null;
87079
- const pid = parseInt(fs23.readFileSync(pidFile, "utf-8").trim(), 10);
87146
+ const { execFileSync: execFileSync5 } = require("child_process");
87147
+ const probe = `
87148
+ const http = require('http');
87149
+ const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
87150
+ let body = '';
87151
+ res.setEncoding('utf8');
87152
+ res.on('data', (chunk) => { body += chunk; });
87153
+ res.on('end', () => {
87154
+ if (res.statusCode !== 200) return;
87155
+ try {
87156
+ const json = JSON.parse(body || '{}');
87157
+ if (Number.isFinite(json.pid)) process.stdout.write(String(json.pid));
87158
+ } catch {}
87159
+ });
87160
+ });
87161
+ req.on('error', () => {});
87162
+ req.on('timeout', () => { req.destroy(); });
87163
+ `;
87164
+ const result = execFileSync5(process.execPath, ["-e", probe], {
87165
+ encoding: "utf-8",
87166
+ timeout: 3e3,
87167
+ stdio: ["ignore", "pipe", "ignore"]
87168
+ }).trim();
87169
+ const pid = parseInt(result, 10);
87080
87170
  return Number.isFinite(pid) ? pid : null;
87081
87171
  } catch {
87082
87172
  return null;
87083
87173
  }
87084
87174
  }
87175
+ function getDaemonPid(ref = {}) {
87176
+ const pidFile = getDaemonPidFile(ref);
87177
+ try {
87178
+ if (fs23.existsSync(pidFile)) {
87179
+ const pid = parseInt(fs23.readFileSync(pidFile, "utf-8").trim(), 10);
87180
+ if (Number.isFinite(pid)) return pid;
87181
+ }
87182
+ } catch {
87183
+ }
87184
+ return getDaemonHealthPid(ref);
87185
+ }
87085
87186
  function stopDaemon(ref = {}) {
87086
87187
  const pidFile = getDaemonPidFile(ref);
87188
+ let pid = null;
87189
+ try {
87190
+ if (fs23.existsSync(pidFile)) {
87191
+ const pidFromFile = parseInt(fs23.readFileSync(pidFile, "utf-8").trim(), 10);
87192
+ if (Number.isFinite(pidFromFile)) pid = pidFromFile;
87193
+ }
87194
+ } catch {
87195
+ removeDaemonPid(ref);
87196
+ }
87197
+ if (pid === null) {
87198
+ pid = getDaemonHealthPid(ref);
87199
+ }
87200
+ if (pid === null) return false;
87087
87201
  try {
87088
- if (!fs23.existsSync(pidFile)) return false;
87089
- const pid = parseInt(fs23.readFileSync(pidFile, "utf-8").trim());
87090
87202
  process.kill(pid, "SIGTERM");
87091
87203
  removeDaemonPid(ref);
87092
87204
  return true;
@@ -87116,7 +87228,7 @@ var init_adhdev_daemon = __esm({
87116
87228
  init_version();
87117
87229
  init_src();
87118
87230
  init_runtime_defaults();
87119
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.12" });
87231
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.14" });
87120
87232
  AdhdevDaemon = class _AdhdevDaemon {
87121
87233
  localHttpServer = null;
87122
87234
  localWss = null;
@@ -87638,24 +87750,25 @@ ${err?.stack || ""}`);
87638
87750
  return { id: req.id, success: result.success, entries: result.files, error: result.error };
87639
87751
  }
87640
87752
  });
87641
- this.p2p.onPtyInput((sessionId, data) => {
87753
+ this.p2p.onPtyInput(async (sessionId, data) => {
87642
87754
  if (!this.isCliSession(sessionId)) {
87643
87755
  this.logPtyInputDrop(sessionId, "not_cli_session");
87644
- return;
87756
+ throw new Error("not_cli_session");
87645
87757
  }
87646
87758
  const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
87647
87759
  if (!found) {
87648
87760
  this.logPtyInputDrop(sessionId, "adapter_not_found");
87649
- return;
87761
+ throw new Error("adapter_not_found");
87650
87762
  }
87651
87763
  if (typeof found.adapter.writeRaw !== "function") {
87652
87764
  this.logPtyInputDrop(sessionId, "writeRaw_missing");
87653
- return;
87765
+ throw new Error("writeRaw_missing");
87654
87766
  }
87655
87767
  try {
87656
- found.adapter.writeRaw(data);
87657
- } catch {
87768
+ await found.adapter.writeRaw(data);
87769
+ } catch (error48) {
87658
87770
  this.logPtyInputDrop(sessionId, "write_failed");
87771
+ throw error48;
87659
87772
  }
87660
87773
  });
87661
87774
  this.p2p.onPtyResize((sessionId, cols, rows) => {