@adhdev/daemon-core 0.9.82-rc.489 → 0.9.82-rc.490

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.489",
3
+ "version": "0.9.82-rc.490",
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",
@@ -47,8 +47,8 @@
47
47
  "author": "vilmire",
48
48
  "license": "AGPL-3.0-or-later",
49
49
  "dependencies": {
50
- "@adhdev/mesh-shared": "0.9.82-rc.489",
51
- "@adhdev/session-host-core": "0.9.82-rc.489",
50
+ "@adhdev/mesh-shared": "0.9.82-rc.490",
51
+ "@adhdev/session-host-core": "0.9.82-rc.490",
52
52
  "@agentclientprotocol/sdk": "^0.16.1",
53
53
  "ajv": "^8.20.0",
54
54
  "ajv-formats": "^3.0.1",
@@ -226,6 +226,17 @@ export class ProviderCliAdapter implements CliAdapter {
226
226
  // Submit retry timer — PTY-level, not state machine
227
227
  private submitRetryTimer: NodeJS.Timeout | null = null;
228
228
 
229
+ // PTY-WRITE-SERIALIZE: a single per-session tail promise that serializes every
230
+ // PTY write. Each writeToPty() call chains its actual write after the previous
231
+ // one and returns a promise that resolves only after ITS write completes, so
232
+ // two consecutive sends (e.g. mesh force-dispatch burst → forceSendMessage, or
233
+ // a retry-timer's bare CR interleaving a fresh body) can never write into the
234
+ // same input line: message A's (body + sendKey/CR) is fully written to the PTY
235
+ // before message B's body write starts. The chain is kept alive across errors
236
+ // (each link swallows/logs its own failure) so one failed write never wedges
237
+ // all later writes behind a permanently-rejected tail.
238
+ private ptyWriteChain: Promise<void> = Promise.resolve();
239
+
229
240
  // Resize redraw suppression
230
241
  private resizeSuppressUntil: number = 0;
231
242
 
@@ -1292,7 +1303,22 @@ export class ProviderCliAdapter implements CliAdapter {
1292
1303
  return true;
1293
1304
  }
1294
1305
 
1295
- private async writeToPty(data: string): Promise<void> {
1306
+ /** Serialize `data` onto the per-session PTY write chain. Returns a promise
1307
+ * that resolves (or rejects) with THIS write's own outcome, so callers keep
1308
+ * their existing "await my write completion" semantics. The underlying chain
1309
+ * link swallows its own error before releasing the next write, so a failed
1310
+ * write surfaces to its caller but never wedges subsequent writes behind a
1311
+ * permanently-rejected tail (FIFO order preserved). */
1312
+ private writeToPty(data: string): Promise<void> {
1313
+ const run = this.ptyWriteChain.then(() => this.doWriteToPty(data));
1314
+ // Keep the tail resolved so the next writeToPty() always chains onto a
1315
+ // settled promise (never a rejected one). The caller still sees run's
1316
+ // rejection; only the shared chain is insulated from it.
1317
+ this.ptyWriteChain = run.catch(() => {});
1318
+ return run;
1319
+ }
1320
+
1321
+ private async doWriteToPty(data: string): Promise<void> {
1296
1322
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
1297
1323
  // win32 ConPTY paced write: a single unbounded write beyond ~1KB overflows
1298
1324
  // the console input pipe and drops LEADING bytes (the "long message gets