@adhdev/daemon-core 0.9.82-rc.334 → 0.9.82-rc.335

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.334",
3
+ "version": "0.9.82-rc.335",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "author": "vilmire",
47
47
  "license": "AGPL-3.0-or-later",
48
48
  "dependencies": {
49
- "@adhdev/mesh-shared": "0.9.82-rc.334",
49
+ "@adhdev/mesh-shared": "0.9.82-rc.335",
50
50
  "@adhdev/session-host-core": "*",
51
51
  "@agentclientprotocol/sdk": "^0.16.1",
52
52
  "ajv": "^8.20.0",
@@ -118,6 +118,20 @@ export function appendBoundedText(current: string, chunk: string, maxChars: numb
118
118
  return current.slice(-keepFromCurrent) + chunk;
119
119
  }
120
120
 
121
+ // Force-send (mesh coordinator dispatch / reconcile redelivery) writes raw
122
+ // keystrokes straight into the PTY, bypassing the normal echo-wait submit
123
+ // pipeline. Historically it wrote `text + sendKey` in a single PTY write with
124
+ // zero settle time. On TUI input boxes that re-render the pasted text, the
125
+ // trailing submit key could arrive before the input line had stabilized and be
126
+ // swallowed by the input handler — leaving the prompt typed but never submitted
127
+ // ("text injected, Enter not pressed"). We now split inject from submit and let
128
+ // the input settle first. FORCE_SUBMIT_SETTLE_MS is the minimum gap after the
129
+ // text write before the submit key is sent; FORCE_SUBMIT_MAX_WAIT_MS caps the
130
+ // echo-gated wait so the submit always fires even if the echo never appears.
131
+ const FORCE_SUBMIT_SETTLE_MS = 150;
132
+ const FORCE_SUBMIT_MAX_WAIT_MS = 1500;
133
+ const FORCE_SUBMIT_POLL_MS = 50;
134
+
121
135
  // ─── Adapter ────────────────────────────────────────
122
136
 
123
137
  export class ProviderCliAdapter implements CliAdapter {
@@ -1298,10 +1312,36 @@ export class ProviderCliAdapter implements CliAdapter {
1298
1312
  return;
1299
1313
  }
1300
1314
  LOG.info('CLI', `[${this.cliType}] force-sending prompt while status=${this.engine.currentStatus}`);
1301
- await this.writeToPty(content + this.sendKey);
1315
+ // Split inject from submit. Writing `content + sendKey` in one PTY write
1316
+ // can race a TUI input box that is still absorbing/redrawing the pasted
1317
+ // text, so the trailing submit key gets eaten and the prompt sits typed
1318
+ // but unsent. Write the text first, let the input line settle (echo-gated
1319
+ // when we can verify it, otherwise a fixed minimum gap), then write the
1320
+ // submit key separately so it lands as a clean Enter on a stable prompt.
1321
+ await this.writeToPty(content);
1322
+ await this.waitForForceSubmitSettle(content);
1323
+ await this.writeToPty(this.sendKey);
1302
1324
  this.onStatusChange?.();
1303
1325
  }
1304
1326
 
1327
+ private async waitForForceSubmitSettle(content: string): Promise<void> {
1328
+ const startedAt = Date.now();
1329
+ const normalizedPromptSnippet = normalizePromptText(extractPromptRetrySnippet(content));
1330
+ // Always honor a minimum settle so the input handler has time to finish
1331
+ // ingesting the pasted text before the submit key arrives.
1332
+ await new Promise<void>(resolve => setTimeout(resolve, FORCE_SUBMIT_SETTLE_MS));
1333
+ if (!normalizedPromptSnippet) return;
1334
+ // Beyond the minimum gap, keep waiting (up to the cap) until the prompt
1335
+ // echo is visible on screen — that is the strongest signal the input line
1336
+ // has stabilized and the Enter will be applied to the typed prompt.
1337
+ while (Date.now() - startedAt < FORCE_SUBMIT_MAX_WAIT_MS) {
1338
+ if (!this.ptyProcess) return;
1339
+ const screenText = this.terminalScreen.getText();
1340
+ if (promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
1341
+ await new Promise<void>(resolve => setTimeout(resolve, FORCE_SUBMIT_POLL_MS));
1342
+ }
1343
+ }
1344
+
1305
1345
  private enqueuePendingOutboundMessage(text: string, reason: string): void {
1306
1346
  const content = String(text || '');
1307
1347
  const duplicate = this.pendingOutboundQueue.some((message) => message.content === content);