@adhdev/daemon-core 0.9.82-rc.416 → 0.9.82-rc.417

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.416",
3
+ "version": "0.9.82-rc.417",
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.416",
49
+ "@adhdev/mesh-shared": "0.9.82-rc.417",
50
50
  "@adhdev/session-host-core": "*",
51
51
  "@agentclientprotocol/sdk": "^0.16.1",
52
52
  "ajv": "^8.20.0",
@@ -1041,15 +1041,36 @@ export class FsmDriver implements ISpecDriver {
1041
1041
  if (this.win32SubmitTimer) { clearTimeout(this.win32SubmitTimer); this.win32SubmitTimer = null; }
1042
1042
  const startedAt = Date.now();
1043
1043
 
1044
- // Distinctive whitespace-collapsed TAIL of the body what we look for in the
1045
- // composer to confirm the body landed. The tail (not the head) because a long
1046
- // multiline body scrolls its leading lines out of the composer viewport while
1047
- // the cursor and therefore the body's end stays visible. Empty body
1048
- // nothing to confirm.
1049
- const probe = normalizeForEcho(body).slice(-WIN32_ECHO_PROBE_CHARS);
1044
+ // FULL-BODY echo confirmation. A tail-only probe (slice(-N)) was insufficient
1045
+ // for multi-line prompts: a multiline body echoes line-by-line, so its TAIL can
1046
+ // appear in the composer (and the screen settle) while the HEAD / middle is still
1047
+ // arriving. Releasing the first CR on the tail alone then submits a PARTIAL body:
1048
+ // the early CR commits whatever has accumulated and the remainder is lost, so only
1049
+ // the trailing segment survives (the cross-machine MAGI replica receiving only the
1050
+ // prompt's boilerplate suffix). We now require BOTH the head probe AND the tail
1051
+ // probe to be present in the echo before releasing the CR.
1052
+ //
1053
+ // Crucially, the head check runs against snapshotWithScrollback(), NOT the visible
1054
+ // viewport: a tall body scrolls its leading lines off-screen (the very reason the
1055
+ // original gate used the tail), so the head is only ever observable in the
1056
+ // scrollback-inclusive buffer. The tail check stays on the visible snapshot (the
1057
+ // cursor / body end is always on screen). Both present ⇒ the whole body, head
1058
+ // through tail, has echoed — not just its end with a still-streaming middle.
1059
+ // Single-line / short bodies have overlapping head and tail probes and the
1060
+ // scrollback buffer is a superset of the viewport, so behaviour is unchanged. The
1061
+ // WIN32_ECHO_MAX_WAIT_MS blind-fire backstop below still bounds the wait so a body
1062
+ // that never fully confirms cannot hang.
1063
+ const normBody = normalizeForEcho(body);
1064
+ const headProbe = normBody.slice(0, WIN32_ECHO_PROBE_CHARS);
1065
+ const tailProbe = normBody.slice(-WIN32_ECHO_PROBE_CHARS);
1050
1066
  const bodyEchoed = (): boolean => {
1051
- if (!probe) return true;
1052
- return normalizeForEcho(this.adapter.snapshot()).includes(probe);
1067
+ if (!normBody) return true;
1068
+ // Tail on the visible viewport (cursor end is always on screen); head on the
1069
+ // scrollback-inclusive buffer (leading lines of a tall body scroll off-screen).
1070
+ const visible = normalizeForEcho(this.adapter.snapshot());
1071
+ if (!visible.includes(tailProbe)) return false;
1072
+ const full = normalizeForEcho(this.adapter.snapshotWithScrollback());
1073
+ return full.includes(headProbe);
1053
1074
  };
1054
1075
 
1055
1076
  const fire = (attempt: number): void => {