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/index.js CHANGED
@@ -8967,14 +8967,14 @@ async function handleOpenPanel(h, args) {
8967
8967
  success: revealState.visible || focusState.focused
8968
8968
  };
8969
8969
  }
8970
- function handlePtyInput(h, args) {
8970
+ async function handlePtyInput(h, args) {
8971
8971
  const { cliType, data, targetSessionId } = args || {};
8972
8972
  if (!data) return { success: false, error: "data required" };
8973
8973
  const adapter = h.getCliAdapter(targetSessionId || cliType);
8974
8974
  if (!adapter || typeof adapter.writeRaw !== "function") {
8975
8975
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
8976
8976
  }
8977
- adapter.writeRaw(data);
8977
+ await adapter.writeRaw(data);
8978
8978
  return { success: true };
8979
8979
  }
8980
8980
  function handlePtyResize(_h, args) {
@@ -9151,7 +9151,7 @@ async function executeProviderScript(h, args, scriptName) {
9151
9151
  if (cliCommand?.type === "send_message" && cliCommand.text) {
9152
9152
  await adapter.sendMessage(cliCommand.text);
9153
9153
  } else if (cliCommand?.type === "pty_write" && cliCommand.text && adapter.writeRaw) {
9154
- adapter.writeRaw(cliCommand.text + "\r");
9154
+ await adapter.writeRaw(cliCommand.text + "\r");
9155
9155
  }
9156
9156
  applyProviderPatch(h, args, parsed.payload);
9157
9157
  return {
@@ -13015,6 +13015,29 @@ var init_provider_cli_adapter = __esm({
13015
13015
  }
13016
13016
  await this.sendMessage(promptText);
13017
13017
  }
13018
+ async writeToPty(data) {
13019
+ if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13020
+ await this.ptyProcess.write(data);
13021
+ }
13022
+ resetPendingSendState(reason) {
13023
+ this.isWaitingForResponse = false;
13024
+ this.responseBuffer = "";
13025
+ this.currentTurnScope = null;
13026
+ this.submitPendingUntil = 0;
13027
+ this.clearIdleFinishCandidate(reason);
13028
+ if (this.responseTimeout) {
13029
+ clearTimeout(this.responseTimeout);
13030
+ this.responseTimeout = null;
13031
+ }
13032
+ if (this.submitRetryTimer) {
13033
+ clearTimeout(this.submitRetryTimer);
13034
+ this.submitRetryTimer = null;
13035
+ }
13036
+ if (this.finishRetryTimer) {
13037
+ clearTimeout(this.finishRetryTimer);
13038
+ this.finishRetryTimer = null;
13039
+ }
13040
+ }
13018
13041
  async sendMessage(text) {
13019
13042
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
13020
13043
  const allowInputDuringGeneration = this.provider.allowInputDuringGeneration === true;
@@ -13109,19 +13132,29 @@ var init_provider_cli_adapter = __esm({
13109
13132
  if (this.isWaitingForResponse) this.finishResponse();
13110
13133
  }, this.timeouts.maxResponse);
13111
13134
  };
13112
- await new Promise((resolve16) => {
13135
+ await new Promise((resolve16, reject) => {
13113
13136
  let resolved = false;
13114
13137
  const resolveOnce = () => {
13115
13138
  if (resolved) return;
13116
13139
  resolved = true;
13117
13140
  resolve16();
13118
13141
  };
13142
+ const rejectOnce = (error48) => {
13143
+ if (resolved) return;
13144
+ this.resetPendingSendState("send_write_failed");
13145
+ resolved = true;
13146
+ reject(error48);
13147
+ };
13148
+ const writeRetryKey = (mode) => {
13149
+ void this.writeToPty(this.sendKey).catch((error48) => {
13150
+ LOG.warn("CLI", `[${this.cliType}] ${mode} write failed: ${error48?.message || error48}`);
13151
+ });
13152
+ };
13119
13153
  const submit = () => {
13120
13154
  if (!this.ptyProcess) {
13121
13155
  resolveOnce();
13122
13156
  return;
13123
13157
  }
13124
- commitUserTurn();
13125
13158
  this.submitPendingUntil = 0;
13126
13159
  const screenText = this.terminalScreen.getText();
13127
13160
  this.recordTrace("submit_write", {
@@ -13129,7 +13162,6 @@ var init_provider_cli_adapter = __esm({
13129
13162
  sendKey: this.sendKey,
13130
13163
  screenText: summarizeCliTraceText(screenText, 500)
13131
13164
  });
13132
- this.ptyProcess.write(this.sendKey);
13133
13165
  const retrySubmitIfStuck = (attempt) => {
13134
13166
  this.submitRetryTimer = null;
13135
13167
  if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
@@ -13149,19 +13181,21 @@ var init_provider_cli_adapter = __esm({
13149
13181
  sendKey: this.sendKey,
13150
13182
  screenText: summarizeCliTraceText(screenText2, 500)
13151
13183
  });
13152
- this.ptyProcess.write(this.sendKey);
13184
+ writeRetryKey("submit_retry");
13153
13185
  if (attempt >= 3) {
13154
13186
  this.submitRetryUsed = true;
13155
13187
  return;
13156
13188
  }
13157
13189
  this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
13158
13190
  };
13159
- this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
13160
- startResponseTimeout();
13161
- resolveOnce();
13191
+ void this.writeToPty(this.sendKey).then(() => {
13192
+ commitUserTurn();
13193
+ this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
13194
+ startResponseTimeout();
13195
+ resolveOnce();
13196
+ }, rejectOnce);
13162
13197
  };
13163
13198
  if (this.submitStrategy === "immediate") {
13164
- commitUserTurn();
13165
13199
  this.submitPendingUntil = 0;
13166
13200
  this.recordTrace("submit_write", {
13167
13201
  mode: "immediate",
@@ -13169,37 +13203,38 @@ var init_provider_cli_adapter = __esm({
13169
13203
  sendKey: this.sendKey,
13170
13204
  screenText: summarizeCliTraceText(this.terminalScreen.getText(), 500)
13171
13205
  });
13172
- this.ptyProcess.write(text + this.sendKey);
13173
- this.submitRetryTimer = setTimeout(() => {
13174
- this.submitRetryTimer = null;
13175
- if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
13176
- if (this.currentStatus === "waiting_approval") return;
13177
- if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
13178
- const screenText = this.terminalScreen.getText();
13179
- if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
13180
- const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
13181
- if (liveApproval) return;
13182
- const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
13183
- if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
13184
- LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
13185
- this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13186
- this.recordTrace("submit_write", {
13187
- mode: "immediate_retry",
13188
- attempt: 1,
13189
- sendKey: this.sendKey,
13190
- screenText: summarizeCliTraceText(screenText, 500)
13191
- });
13192
- this.ptyProcess.write(this.sendKey);
13193
- this.submitRetryUsed = true;
13194
- }, retryDelayMs);
13195
- startResponseTimeout();
13196
- resolveOnce();
13206
+ void this.writeToPty(text + this.sendKey).then(() => {
13207
+ commitUserTurn();
13208
+ this.submitRetryTimer = setTimeout(() => {
13209
+ this.submitRetryTimer = null;
13210
+ if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
13211
+ if (this.currentStatus === "waiting_approval") return;
13212
+ if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
13213
+ const screenText = this.terminalScreen.getText();
13214
+ if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
13215
+ const liveApproval = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
13216
+ if (liveApproval) return;
13217
+ const liveStatus = this.runDetectStatus(screenText) || this.runDetectStatus(this.recentOutputBuffer);
13218
+ if (liveStatus === "generating" || liveStatus === "waiting_approval") return;
13219
+ LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
13220
+ this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
13221
+ this.recordTrace("submit_write", {
13222
+ mode: "immediate_retry",
13223
+ attempt: 1,
13224
+ sendKey: this.sendKey,
13225
+ screenText: summarizeCliTraceText(screenText, 500)
13226
+ });
13227
+ writeRetryKey("immediate_retry");
13228
+ this.submitRetryUsed = true;
13229
+ }, retryDelayMs);
13230
+ startResponseTimeout();
13231
+ resolveOnce();
13232
+ }, rejectOnce);
13197
13233
  return;
13198
13234
  }
13199
13235
  if (submitDelayMs > 0) {
13200
13236
  this.submitPendingUntil = Date.now() + submitDelayMs;
13201
13237
  }
13202
- this.ptyProcess.write(text);
13203
13238
  this.recordTrace("submit_write", {
13204
13239
  mode: "type_then_submit",
13205
13240
  text: summarizeCliTraceText(text, 500),
@@ -13236,7 +13271,7 @@ var init_provider_cli_adapter = __esm({
13236
13271
  }
13237
13272
  setTimeout(waitForEchoAndSubmit, 50);
13238
13273
  };
13239
- waitForEchoAndSubmit();
13274
+ void this.writeToPty(text).then(() => waitForEchoAndSubmit(), rejectOnce);
13240
13275
  });
13241
13276
  }
13242
13277
  getPartialResponse() {
@@ -13391,12 +13426,12 @@ var init_provider_cli_adapter = __esm({
13391
13426
  isReady() {
13392
13427
  return this.ready;
13393
13428
  }
13394
- writeRaw(data) {
13429
+ async writeRaw(data) {
13395
13430
  this.recordTrace("write_raw", {
13396
13431
  keys: JSON.stringify(data),
13397
13432
  length: data.length
13398
13433
  });
13399
- this.ptyProcess?.write(data);
13434
+ await this.writeToPty(data);
13400
13435
  }
13401
13436
  resolveModal(buttonIndex) {
13402
13437
  let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
@@ -13942,7 +13977,7 @@ var init_cli_provider_instance = __esm({
13942
13977
  if (cliCommand?.type === "send_message" && cliCommand.text) {
13943
13978
  await this.adapter.sendMessage(cliCommand.text);
13944
13979
  } else if (cliCommand?.type === "pty_write" && cliCommand.text) {
13945
- this.adapter.writeRaw(cliCommand.text + "\r");
13980
+ await this.adapter.writeRaw(cliCommand.text + "\r");
13946
13981
  }
13947
13982
  this.applyProviderResponse(parsed.payload, { phase: "immediate" });
13948
13983
  }
@@ -37728,10 +37763,14 @@ var init_router = __esm({
37728
37763
  currentInstalled = parsed?.dependencies?.[pkgName]?.version || null;
37729
37764
  } catch {
37730
37765
  }
37731
- if (currentInstalled === latest) {
37766
+ const runningVersion = typeof this.deps.statusVersion === "string" ? this.deps.statusVersion.trim().replace(/^v/, "") : null;
37767
+ if (currentInstalled === latest && runningVersion === latest) {
37732
37768
  LOG.info("Upgrade", `Already on latest version v${latest}; skipping install`);
37733
37769
  return { success: true, upgraded: false, alreadyLatest: true, version: latest };
37734
37770
  }
37771
+ if (currentInstalled === latest && runningVersion && runningVersion !== latest) {
37772
+ LOG.info("Upgrade", `Installed package is v${latest}, but running daemon is v${runningVersion}; scheduling restart`);
37773
+ }
37735
37774
  spawnDetachedDaemonUpgradeHelper({
37736
37775
  packageName: pkgName,
37737
37776
  targetVersion: latest,
@@ -41917,7 +41956,7 @@ async function handleCliRaw(ctx, req, res) {
41917
41956
  }
41918
41957
  try {
41919
41958
  if (typeof adapter.writeRaw === "function") {
41920
- adapter.writeRaw(keys);
41959
+ await adapter.writeRaw(keys);
41921
41960
  ctx.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
41922
41961
  } else {
41923
41962
  ctx.json(res, 400, { error: "writeRaw not available on this adapter" });
@@ -44880,7 +44919,7 @@ var init_session_host_transport = __esm({
44880
44919
  this.exitCallbacks.add(callback);
44881
44920
  }
44882
44921
  write(data) {
44883
- this.enqueue(async () => {
44922
+ return this.enqueue(async () => {
44884
44923
  let response = await this.client.request({
44885
44924
  type: "send_input",
44886
44925
  payload: {
@@ -45182,9 +45221,11 @@ var init_session_host_transport = __esm({
45182
45221
  };
45183
45222
  }
45184
45223
  enqueue(action) {
45185
- this.operationChain = this.operationChain.then(() => this.ready).then(action).catch((error48) => {
45224
+ const operation = this.operationChain.then(() => this.ready).then(action);
45225
+ this.operationChain = operation.catch((error48) => {
45186
45226
  LOG.warn("CLI", `[session-host:${this.options.runtimeId}] ${error48?.message || error48}`);
45187
45227
  });
45228
+ return operation;
45188
45229
  }
45189
45230
  async closeClient(destroy = false) {
45190
45231
  if (this.closed) return;
@@ -46517,14 +46558,41 @@ function routeDataChannelMessage(peerId, msg, peers, handlers) {
46517
46558
  return;
46518
46559
  }
46519
46560
  if (parsed.type === "pty_input") {
46520
- const permission = peers.get(peerId)?.sharePermission;
46561
+ const peer = peers.get(peerId);
46562
+ const permission = peer?.sharePermission;
46563
+ const sendPtyInputError = (sessionId2, reason, error48) => {
46564
+ const message = error48 instanceof Error ? error48.message : typeof error48 === "string" ? error48 : void 0;
46565
+ sendToPeer(peer, {
46566
+ type: "session_io_error",
46567
+ sessionId: sessionId2,
46568
+ reason,
46569
+ ...message ? { error: message } : {}
46570
+ });
46571
+ };
46521
46572
  if (permission) {
46522
46573
  log(`pty_input: REJECTED \u2014 permission=${permission} peer=${peerId}`);
46574
+ const sessionId2 = typeof (parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType) === "string" ? parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType : "";
46575
+ sendPtyInputError(sessionId2, "permission_denied");
46576
+ return;
46577
+ }
46578
+ const sessionIdCandidate = parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType || "";
46579
+ const sessionId = typeof sessionIdCandidate === "string" ? sessionIdCandidate : "";
46580
+ if (!sessionId || typeof parsed.data !== "string" || parsed.data.length === 0) {
46581
+ sendPtyInputError(sessionId, "invalid_payload");
46523
46582
  return;
46524
46583
  }
46525
- const sessionId = parsed.sessionId || parsed.targetSessionId || parsed.cliId || parsed.cliType || "";
46526
- if (handlers.ptyInputHandler && parsed.data && sessionId) {
46527
- handlers.ptyInputHandler(sessionId, parsed.data);
46584
+ if (!handlers.ptyInputHandler) {
46585
+ sendPtyInputError(sessionId, "handler_unavailable");
46586
+ return;
46587
+ }
46588
+ try {
46589
+ Promise.resolve(handlers.ptyInputHandler(sessionId, parsed.data)).catch((error48) => {
46590
+ log(`pty_input write failed: peer=${peerId} sessionId=${sessionId} error=${error48?.message || error48}`);
46591
+ sendPtyInputError(sessionId, "write_failed", error48);
46592
+ });
46593
+ } catch (error48) {
46594
+ log(`pty_input write failed: peer=${peerId} sessionId=${sessionId} error=${error48?.message || error48}`);
46595
+ sendPtyInputError(sessionId, "write_failed", error48);
46528
46596
  }
46529
46597
  return;
46530
46598
  }
@@ -55352,21 +55420,65 @@ function isAdhdevProcess(pid) {
55352
55420
  return true;
55353
55421
  }
55354
55422
  }
55355
- function getDaemonPid(ref = {}) {
55356
- const pidFile = getDaemonPidFile(ref);
55423
+ function getDaemonHealthPid(ref = {}) {
55424
+ const port = resolveDaemonPort(ref);
55357
55425
  try {
55358
- if (!fs18.existsSync(pidFile)) return null;
55359
- const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim(), 10);
55426
+ const { execFileSync: execFileSync4 } = require("child_process");
55427
+ const probe = `
55428
+ const http = require('http');
55429
+ const req = http.get('http://127.0.0.1:${port}/health', { timeout: 1500 }, (res) => {
55430
+ let body = '';
55431
+ res.setEncoding('utf8');
55432
+ res.on('data', (chunk) => { body += chunk; });
55433
+ res.on('end', () => {
55434
+ if (res.statusCode !== 200) return;
55435
+ try {
55436
+ const json = JSON.parse(body || '{}');
55437
+ if (Number.isFinite(json.pid)) process.stdout.write(String(json.pid));
55438
+ } catch {}
55439
+ });
55440
+ });
55441
+ req.on('error', () => {});
55442
+ req.on('timeout', () => { req.destroy(); });
55443
+ `;
55444
+ const result = execFileSync4(process.execPath, ["-e", probe], {
55445
+ encoding: "utf-8",
55446
+ timeout: 3e3,
55447
+ stdio: ["ignore", "pipe", "ignore"]
55448
+ }).trim();
55449
+ const pid = parseInt(result, 10);
55360
55450
  return Number.isFinite(pid) ? pid : null;
55361
55451
  } catch {
55362
55452
  return null;
55363
55453
  }
55364
55454
  }
55455
+ function getDaemonPid(ref = {}) {
55456
+ const pidFile = getDaemonPidFile(ref);
55457
+ try {
55458
+ if (fs18.existsSync(pidFile)) {
55459
+ const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim(), 10);
55460
+ if (Number.isFinite(pid)) return pid;
55461
+ }
55462
+ } catch {
55463
+ }
55464
+ return getDaemonHealthPid(ref);
55465
+ }
55365
55466
  function stopDaemon(ref = {}) {
55366
55467
  const pidFile = getDaemonPidFile(ref);
55468
+ let pid = null;
55469
+ try {
55470
+ if (fs18.existsSync(pidFile)) {
55471
+ const pidFromFile = parseInt(fs18.readFileSync(pidFile, "utf-8").trim(), 10);
55472
+ if (Number.isFinite(pidFromFile)) pid = pidFromFile;
55473
+ }
55474
+ } catch {
55475
+ removeDaemonPid(ref);
55476
+ }
55477
+ if (pid === null) {
55478
+ pid = getDaemonHealthPid(ref);
55479
+ }
55480
+ if (pid === null) return false;
55367
55481
  try {
55368
- if (!fs18.existsSync(pidFile)) return false;
55369
- const pid = parseInt(fs18.readFileSync(pidFile, "utf-8").trim());
55370
55482
  process.kill(pid, "SIGTERM");
55371
55483
  removeDaemonPid(ref);
55372
55484
  return true;
@@ -55396,7 +55508,7 @@ var init_adhdev_daemon = __esm({
55396
55508
  init_version();
55397
55509
  init_src();
55398
55510
  init_runtime_defaults();
55399
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.12" });
55511
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.14" });
55400
55512
  AdhdevDaemon = class _AdhdevDaemon {
55401
55513
  localHttpServer = null;
55402
55514
  localWss = null;
@@ -55918,24 +56030,25 @@ ${err?.stack || ""}`);
55918
56030
  return { id: req.id, success: result.success, entries: result.files, error: result.error };
55919
56031
  }
55920
56032
  });
55921
- this.p2p.onPtyInput((sessionId, data) => {
56033
+ this.p2p.onPtyInput(async (sessionId, data) => {
55922
56034
  if (!this.isCliSession(sessionId)) {
55923
56035
  this.logPtyInputDrop(sessionId, "not_cli_session");
55924
- return;
56036
+ throw new Error("not_cli_session");
55925
56037
  }
55926
56038
  const found = this.components.cliManager.findAdapter(sessionId, { instanceKey: sessionId });
55927
56039
  if (!found) {
55928
56040
  this.logPtyInputDrop(sessionId, "adapter_not_found");
55929
- return;
56041
+ throw new Error("adapter_not_found");
55930
56042
  }
55931
56043
  if (typeof found.adapter.writeRaw !== "function") {
55932
56044
  this.logPtyInputDrop(sessionId, "writeRaw_missing");
55933
- return;
56045
+ throw new Error("writeRaw_missing");
55934
56046
  }
55935
56047
  try {
55936
- found.adapter.writeRaw(data);
55937
- } catch {
56048
+ await found.adapter.writeRaw(data);
56049
+ } catch (error48) {
55938
56050
  this.logPtyInputDrop(sessionId, "write_failed");
56051
+ throw error48;
55939
56052
  }
55940
56053
  });
55941
56054
  this.p2p.onPtyResize((sessionId, cols, rows) => {