@adhdev/daemon-core 0.9.82-rc.377 → 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.
@@ -133,6 +133,30 @@ interface DeliverTaskContext {
133
133
  sourceCoordinatorDaemonId?: string;
134
134
  }
135
135
 
136
+ // Readiness barrier for the LOCAL auto-launch path. A just-spawned CLI session is
137
+ // not interactive until its PTY prints the input prompt (the adapter flips
138
+ // isReady() / settles to idle ~2-6s later). Poll the local adapter until it reports
139
+ // ready (or idle), bounded by a generous timeout so a slow/contended boot still
140
+ // lands, and a hard cap so a session that never becomes interactive doesn't block the
141
+ // reconcile loop forever (the adapter's queue-until-ready path is the backstop then).
142
+ const LOCAL_LAUNCH_READY_TIMEOUT_MS = 15_000;
143
+ const LOCAL_LAUNCH_READY_POLL_MS = 100;
144
+
145
+ async function waitForLocalSessionReady(components: DaemonComponents, sessionId: string): Promise<void> {
146
+ const adapter = components.cliManager?.adapters?.get(sessionId) as
147
+ | { isReady?: () => boolean; currentStatus?: string }
148
+ | undefined;
149
+ // No locally-resolvable adapter (e.g. a remote/forwarded session that somehow
150
+ // reached this branch) → nothing to wait on; let dispatch proceed.
151
+ if (!adapter || typeof adapter.isReady !== 'function') return;
152
+ const deadline = Date.now() + LOCAL_LAUNCH_READY_TIMEOUT_MS;
153
+ while (Date.now() < deadline) {
154
+ if (adapter.isReady() || adapter.currentStatus === 'idle') return;
155
+ await new Promise<void>(resolve => setTimeout(resolve, LOCAL_LAUNCH_READY_POLL_MS));
156
+ }
157
+ LOG.warn('MeshQueue', `Auto-launched session ${sessionId} not interactive after ${LOCAL_LAUNCH_READY_TIMEOUT_MS}ms; dispatching anyway (adapter queue-until-ready will buffer)`);
158
+ }
159
+
136
160
  // CONS scope 3: the SINGLE source of truth for dispatching a claimed task to its
137
161
  // session. The remote (P2P dispatchMeshCommand) and local (cliManager.handleCliCommand)
138
162
  // branches differ ONLY in the transport call — the delivery record, the delivered/failed
@@ -1130,6 +1154,16 @@ async function maybeAutoLaunchOneQueueSession(components: DaemonComponents, mesh
1130
1154
  return false;
1131
1155
  }
1132
1156
  markAutoLaunch(meshId, task.id, { status: 'completed', nodeId, providerType: resolved.providerType, sessionId });
1157
+ // Readiness barrier: a freshly-spawned local CLI session is NOT yet
1158
+ // interactive — its PTY prints the input prompt (and the adapter flips
1159
+ // isReady()) only ~2-6s after launch. Dispatching the task immediately
1160
+ // pushes the first (often large) message into a not-yet-ready PTY, which
1161
+ // could throw "not ready" and bounce the task through requeue (on win32
1162
+ // this raced the auto-launch cooldown and stranded the worker idle).
1163
+ // Await interactive readiness before claiming/dispatching so the very
1164
+ // first message lands cleanly. The adapter's queue-until-ready path is the
1165
+ // backstop if readiness is reported late; this just avoids the churn.
1166
+ await waitForLocalSessionReady(components, sessionId);
1133
1167
  tryAssignQueueTask(components, meshId, nodeId, sessionId, resolved.providerType);
1134
1168
  return true;
1135
1169
  } catch (e: any) {