@adhdev/daemon-core 0.9.82-rc.378 → 0.9.82-rc.379

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.
@@ -169,6 +169,11 @@ export declare class ProviderCliAdapter implements CliAdapter {
169
169
  private isSubmitStuck;
170
170
  private hasMeaningfulResponseBufferLocal;
171
171
  private writeToPty;
172
+ /** Write `data` to the PTY in bounded, surrogate-safe chunks with a short
173
+ * inter-chunk gap (win32 paced write). Awaits each chunk's write and the gap
174
+ * so the returned promise resolves only after the FINAL chunk (carrying any
175
+ * trailing submit key) has been written. */
176
+ private writeWin32Chunked;
172
177
  private resetPendingSendState;
173
178
  private commitSendUserTurn;
174
179
  private armResponseTimeout;
@@ -0,0 +1,34 @@
1
+ export declare const WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
2
+ export declare const WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
3
+ /** Split `text` into chunks of at most `size` UTF-16 units without ever cutting
4
+ * between a high and low surrogate (which would corrupt an astral char — emoji,
5
+ * etc. — on the UTF-8 PTY write). */
6
+ export declare function chunkPreservingSurrogates(text: string, size: number): string[];
7
+ /** True when a body of `length` UTF-16 units should be paced into multiple
8
+ * chunks on win32 rather than written in a single PTY write. */
9
+ export declare function shouldChunkWin32Write(length: number): boolean;
10
+ /**
11
+ * Drive a paced, surrogate-safe chunked write of `text` over a `write(chunk)`
12
+ * sink, calling `onChunkWritten` after each chunk (e.g. to advance an input-
13
+ * activity timestamp) and `onDone` once the final chunk is out. The optional
14
+ * `setTimer` lets the caller own the timer handle (so it can be cleared on
15
+ * shutdown) and supply a custom scheduler in tests; it defaults to setTimeout.
16
+ *
17
+ * Bodies at or below the chunk threshold are written in a SINGLE write — the
18
+ * common case — so this is a no-op pacing wrapper for normal-sized prompts.
19
+ *
20
+ * Returns the chunks that will be written (useful for assertions/logging).
21
+ */
22
+ export interface PacedWin32WriteOptions {
23
+ write: (chunk: string) => void;
24
+ onChunkWritten?: () => void;
25
+ onDone?: () => void;
26
+ /** Schedule the next chunk; must return a handle the caller can clear.
27
+ * Defaults to setTimeout. */
28
+ setTimer?: (fn: () => void, delayMs: number) => ReturnType<typeof setTimeout>;
29
+ /** Store the pending timer handle so the caller can clear it on shutdown. */
30
+ onTimer?: (handle: ReturnType<typeof setTimeout> | null) => void;
31
+ chunkChars?: number;
32
+ gapMs?: number;
33
+ }
34
+ export declare function writeWin32Paced(text: string, opts: PacedWin32WriteOptions): string[];
package/dist/index.js CHANGED
@@ -316,10 +316,10 @@ function readInjected(value) {
316
316
  }
317
317
  function getDaemonBuildInfo() {
318
318
  if (cached) return cached;
319
- const commit = readInjected(true ? "3920b23e979544d74c4024a0ff18e5deab7b2932" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "3920b23e" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.378" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-25T07:59:13.420Z" : void 0);
319
+ const commit = readInjected(true ? "7b74c2c74e315b3fa6eb9f18d694b79eeb561184" : void 0) ?? "unknown";
320
+ const commitShort = readInjected(true ? "7b74c2c7" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
+ const version = readInjected(true ? "0.9.82-rc.379" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
+ const builtAt = readInjected(true ? "2026-06-25T09:33:17.234Z" : void 0);
323
323
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
324
  return cached;
325
325
  }
@@ -10371,6 +10371,16 @@ function warnDispatchWarmupGetterMissingOnce(daemonId) {
10371
10371
  dispatchWarmupGetterMissingWarned.add(daemonId);
10372
10372
  LOG.warn("MeshQueue", `Mesh peer connection getter unavailable for ${String(daemonId).slice(0, 12)}; remote task-dispatch warmup deadline degraded to the combined connect+response window. Avoids a cold-open false-timeout but loses warm/cold precision \u2014 wire getMeshPeerConnectionStatus on this daemon.`);
10373
10373
  }
10374
+ async function waitForLocalSessionReady(components, sessionId) {
10375
+ const adapter = components.cliManager?.adapters?.get(sessionId);
10376
+ if (!adapter || typeof adapter.isReady !== "function") return;
10377
+ const deadline = Date.now() + LOCAL_LAUNCH_READY_TIMEOUT_MS;
10378
+ while (Date.now() < deadline) {
10379
+ if (adapter.isReady() || adapter.currentStatus === "idle") return;
10380
+ await new Promise((resolve24) => setTimeout(resolve24, LOCAL_LAUNCH_READY_POLL_MS));
10381
+ }
10382
+ LOG.warn("MeshQueue", `Auto-launched session ${sessionId} not interactive after ${LOCAL_LAUNCH_READY_TIMEOUT_MS}ms; dispatching anyway (adapter queue-until-ready will buffer)`);
10383
+ }
10374
10384
  function deliverTaskToSession(dispatchThunk, ctx, warmup) {
10375
10385
  const delivery = createSessionDelivery({
10376
10386
  meshId: ctx.meshId,
@@ -10967,6 +10977,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
10967
10977
  return false;
10968
10978
  }
10969
10979
  markAutoLaunch(meshId, task.id, { status: "completed", nodeId, providerType: resolved.providerType, sessionId });
10980
+ await waitForLocalSessionReady(components, sessionId);
10970
10981
  tryAssignQueueTask(components, meshId, nodeId, sessionId, resolved.providerType);
10971
10982
  return true;
10972
10983
  } catch (e) {
@@ -11188,7 +11199,7 @@ function runIdleMaintenanceThenAssignQueue(components, args) {
11188
11199
  });
11189
11200
  });
11190
11201
  }
11191
- var import_fs12, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX;
11202
+ var import_fs12, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX;
11192
11203
  var init_mesh_queue_assignment = __esm({
11193
11204
  "src/mesh/mesh-queue-assignment.ts"() {
11194
11205
  "use strict";
@@ -11214,6 +11225,8 @@ var init_mesh_queue_assignment = __esm({
11214
11225
  DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
11215
11226
  DISPATCH_CONNECT_TIMEOUT_MS = MESH_CONNECT_TIMEOUT_MS;
11216
11227
  dispatchWarmupGetterMissingWarned = /* @__PURE__ */ new Set();
11228
+ LOCAL_LAUNCH_READY_TIMEOUT_MS = 15e3;
11229
+ LOCAL_LAUNCH_READY_POLL_MS = 100;
11217
11230
  autoLaunchInProgress = /* @__PURE__ */ new Set();
11218
11231
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
11219
11232
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -16997,6 +17010,34 @@ var init_pty_transport = __esm({
16997
17010
  }
16998
17011
  });
16999
17012
 
17013
+ // src/cli-adapters/pty-write-chunking.ts
17014
+ function chunkPreservingSurrogates(text, size) {
17015
+ const chunks = [];
17016
+ let offset = 0;
17017
+ while (offset < text.length) {
17018
+ let end = Math.min(text.length, offset + size);
17019
+ if (end < text.length) {
17020
+ const code = text.charCodeAt(end - 1);
17021
+ if (code >= 55296 && code <= 56319) end -= 1;
17022
+ }
17023
+ if (end <= offset) end = Math.min(text.length, offset + size);
17024
+ chunks.push(text.slice(offset, end));
17025
+ offset = end;
17026
+ }
17027
+ return chunks;
17028
+ }
17029
+ function shouldChunkWin32Write(length) {
17030
+ return length > WIN32_PTY_WRITE_CHUNK_CHARS;
17031
+ }
17032
+ var WIN32_PTY_WRITE_CHUNK_CHARS, WIN32_PTY_WRITE_CHUNK_GAP_MS;
17033
+ var init_pty_write_chunking = __esm({
17034
+ "src/cli-adapters/pty-write-chunking.ts"() {
17035
+ "use strict";
17036
+ WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
17037
+ WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
17038
+ }
17039
+ });
17040
+
17000
17041
  // src/providers/sdk/v1/builders/cli/visible-region.ts
17001
17042
  function compile(re, flags) {
17002
17043
  try {
@@ -18948,6 +18989,7 @@ var init_provider_cli_adapter = __esm({
18948
18989
  init_terminal_screen();
18949
18990
  import_session_host_core5 = require("@adhdev/session-host-core");
18950
18991
  init_pty_transport();
18992
+ init_pty_write_chunking();
18951
18993
  init_provider_cli_shared();
18952
18994
  init_cli_script_runner();
18953
18995
  init_cli_state_engine();
@@ -19426,6 +19468,7 @@ ${lastSnapshot}`;
19426
19468
  `[${this.cliType}] Startup settled (${trigger}, stableMs=${stableMs}, modal=${!!startupModal}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
19427
19469
  );
19428
19470
  this.onStatusChange?.();
19471
+ if (!startupModal) this.schedulePendingOutboundFlush();
19429
19472
  }
19430
19473
  scheduleStartupSettleCheck() {
19431
19474
  if (!this.startupParseGate) return;
@@ -19746,8 +19789,26 @@ ${lastSnapshot}`;
19746
19789
  }
19747
19790
  async writeToPty(data) {
19748
19791
  if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
19792
+ if (process.platform === "win32" && shouldChunkWin32Write(data.length)) {
19793
+ await this.writeWin32Chunked(data);
19794
+ return;
19795
+ }
19749
19796
  await this.ptyProcess.write(data);
19750
19797
  }
19798
+ /** Write `data` to the PTY in bounded, surrogate-safe chunks with a short
19799
+ * inter-chunk gap (win32 paced write). Awaits each chunk's write and the gap
19800
+ * so the returned promise resolves only after the FINAL chunk (carrying any
19801
+ * trailing submit key) has been written. */
19802
+ async writeWin32Chunked(data) {
19803
+ const chunks = chunkPreservingSurrogates(data, WIN32_PTY_WRITE_CHUNK_CHARS);
19804
+ for (let i = 0; i < chunks.length; i += 1) {
19805
+ if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
19806
+ await this.ptyProcess.write(chunks[i]);
19807
+ if (i + 1 < chunks.length) {
19808
+ await new Promise((resolve24) => setTimeout(resolve24, WIN32_PTY_WRITE_CHUNK_GAP_MS));
19809
+ }
19810
+ }
19811
+ }
19751
19812
  resetPendingSendState(reason) {
19752
19813
  this.responseBuffer = "";
19753
19814
  if (this.responseTimeout) {
@@ -19995,7 +20056,13 @@ ${lastSnapshot}`;
19995
20056
  LOG.info("CLI", `[${this.cliType}] sendMessage recovered idle prompt readiness`);
19996
20057
  }
19997
20058
  }
19998
- if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
20059
+ if (!this.ready) {
20060
+ if (allowQueue) {
20061
+ this.enqueuePendingOutboundMessage(text, "not_ready_pending_prompt");
20062
+ return;
20063
+ }
20064
+ throw new Error(`${this.cliName} not ready (status: ${this.engine.currentStatus})`);
20065
+ }
19999
20066
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
20000
20067
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "no_progress" || parsedSessionStatus === "long_generating")) {
20001
20068
  const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
@@ -35606,6 +35673,7 @@ function applyPreLaunchTrust(trust, workingDir) {
35606
35673
 
35607
35674
  // src/providers/spec/fsm-driver.ts
35608
35675
  init_logger();
35676
+ init_pty_write_chunking();
35609
35677
  function countNewlines(s2) {
35610
35678
  let n = 0;
35611
35679
  for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
@@ -35616,8 +35684,6 @@ var WIN32_SUBMIT_RESEND_GAP_MS = 350;
35616
35684
  var WIN32_SUBMIT_MAX_RESENDS = 14;
35617
35685
  var WIN32_SUBMIT_SETTLE_MS = 500;
35618
35686
  var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
35619
- var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
35620
- var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
35621
35687
  var WIN32_ECHO_PROBE_CHARS = 16;
35622
35688
  var WIN32_ECHO_MAX_WAIT_MS = 2e4;
35623
35689
  function normalizeForEcho(s2) {
@@ -35629,21 +35695,7 @@ function resolveSubmitDelayMs(specBeforeSubmit, text) {
35629
35695
  const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
35630
35696
  return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
35631
35697
  }
35632
- function chunkPreservingSurrogates(text, size) {
35633
- const chunks = [];
35634
- let offset = 0;
35635
- while (offset < text.length) {
35636
- let end = Math.min(text.length, offset + size);
35637
- if (end < text.length) {
35638
- const code = text.charCodeAt(end - 1);
35639
- if (code >= 55296 && code <= 56319) end -= 1;
35640
- }
35641
- if (end <= offset) end = Math.min(text.length, offset + size);
35642
- chunks.push(text.slice(offset, end));
35643
- offset = end;
35644
- }
35645
- return chunks;
35646
- }
35698
+ var chunkPreservingSurrogates2 = chunkPreservingSurrogates;
35647
35699
  function guessExt(mime) {
35648
35700
  if (/png/i.test(mime)) return ".png";
35649
35701
  if (/jpe?g/i.test(mime)) return ".jpg";
@@ -36314,7 +36366,7 @@ var FsmDriver = class {
36314
36366
  this.adapter.send_keys(text);
36315
36367
  return;
36316
36368
  }
36317
- const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
36369
+ const chunks = chunkPreservingSurrogates2(text, WIN32_PTY_WRITE_CHUNK_CHARS);
36318
36370
  let idx = 0;
36319
36371
  const writeNext = () => {
36320
36372
  this.win32WriteTimer = null;
@@ -47148,8 +47200,9 @@ var meshCrudHandlers = {
47148
47200
  };
47149
47201
  }
47150
47202
  }
47203
+ const explicitCleanupMode = args?.sessionCleanupMode ?? args?.session_cleanup_mode;
47151
47204
  const sessionCleanupMode = ctx.normalizeMeshSessionCleanupMode(
47152
- args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
47205
+ explicitCleanupMode ?? (node?.isLocalWorktree === true ? "stop_and_delete" : void 0) ?? mesh?.policy?.sessionCleanupOnNodeRemove
47153
47206
  );
47154
47207
  const explicitSessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
47155
47208
  let sessionCleanup;
@@ -47221,12 +47274,16 @@ var meshCrudHandlers = {
47221
47274
  }
47222
47275
  }
47223
47276
  const residueWarning = worktreeCleanup?.residue === true && typeof worktreeCleanup?.residueWarning === "string" ? worktreeCleanup.residueWarning : void 0;
47277
+ const skippedLiveSessionIds = Array.isArray(sessionCleanup?.skippedLiveSessionIds) ? sessionCleanup.skippedLiveSessionIds.filter((v) => typeof v === "string") : [];
47278
+ const orphanedSessionsRemaining = skippedLiveSessionIds.length > 0;
47279
+ const orphanNextAction = orphanedSessionsRemaining ? `Live session(s) [${skippedLiveSessionIds.join(", ")}] were skipped and still survive this node removal. Run mesh_cleanup_sessions with mode:'stop_and_delete' and sessionIds:[${skippedLiveSessionIds.map((id) => `'${id}'`).join(", ")}] to release them.` : void 0;
47224
47280
  return {
47225
47281
  success: true,
47226
47282
  removed,
47227
47283
  ...residueWarning ? { residueWarning } : {},
47228
47284
  ...sessionCleanup ? { sessionCleanup } : {},
47229
- ...worktreeCleanup ? { worktreeCleanup } : {}
47285
+ ...worktreeCleanup ? { worktreeCleanup } : {},
47286
+ ...orphanedSessionsRemaining ? { orphanedSessionsRemaining: true, nextAction: orphanNextAction } : {}
47230
47287
  };
47231
47288
  } catch (e) {
47232
47289
  return { success: false, error: e.message };
@@ -52690,14 +52747,19 @@ var DaemonCommandRouter = class {
52690
52747
  skippedCoordinatorSessionIds.push(sessionId);
52691
52748
  continue;
52692
52749
  }
52693
- if (!hasExplicitSessionIds && liveRuntime && !delegateBoundToThisNode) {
52750
+ const matchedByWorkspaceOnly = !recordNodeId;
52751
+ const isWorktreeNodeRemoval = cleanupSource === "mesh_remove_node" && args.node?.isLocalWorktree === true;
52752
+ const cleanWorkspaceOnlyForWorktree = isWorktreeNodeRemoval && matchedByWorkspaceOnly;
52753
+ if (!hasExplicitSessionIds && liveRuntime && !delegateBoundToThisNode && !cleanWorkspaceOnlyForWorktree) {
52694
52754
  skippedSessionIds.push(sessionId);
52695
52755
  skippedLiveSessionIds.push(sessionId);
52696
- const matchedByWorkspaceOnly = !recordNodeId;
52697
52756
  const reason = recordNodeId && recordNodeId !== args.nodeId ? `live_delegate_bound_to_other_node:${recordNodeId}` : matchedByWorkspaceOnly ? "live_session_matched_by_workspace_only_no_node_binding" : "live_session_not_bound_to_this_node";
52698
52757
  skippedLiveSessionReasons.push({ sessionId, reason });
52699
52758
  continue;
52700
52759
  }
52760
+ if (cleanWorkspaceOnlyForWorktree && !delegateBoundToThisNode) {
52761
+ actedLiveDelegateSessionIds.push(sessionId);
52762
+ }
52701
52763
  if (!hasExplicitSessionIds && liveRuntime && delegateBoundToThisNode && args.mode === "delete_stopped") {
52702
52764
  skippedSessionIds.push(sessionId);
52703
52765
  skippedLiveSessionIds.push(sessionId);