@adhdev/daemon-standalone 0.9.82-rc.196 → 0.9.82-rc.198

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/dist/index.js CHANGED
@@ -38227,6 +38227,49 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
38227
38227
  metadata TEXT,
38228
38228
  PRIMARY KEY (node_id, session_id)
38229
38229
  );
38230
+
38231
+ CREATE TABLE IF NOT EXISTS mesh_session_delivery (
38232
+ id TEXT PRIMARY KEY,
38233
+ mesh_id TEXT NOT NULL,
38234
+ node_id TEXT,
38235
+ session_id TEXT,
38236
+ provider_type TEXT,
38237
+ task_id TEXT,
38238
+ kind TEXT NOT NULL,
38239
+ priority INTEGER NOT NULL DEFAULT 0,
38240
+ message TEXT NOT NULL,
38241
+ status TEXT NOT NULL DEFAULT 'queued',
38242
+ deliver_after TEXT,
38243
+ expires_at TEXT,
38244
+ attempt_count INTEGER NOT NULL DEFAULT 0,
38245
+ source_coordinator_session_id TEXT,
38246
+ source_coordinator_daemon_id TEXT,
38247
+ last_error TEXT,
38248
+ created_at TEXT NOT NULL,
38249
+ updated_at TEXT NOT NULL
38250
+ );
38251
+
38252
+ CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_mesh_status
38253
+ ON mesh_session_delivery(mesh_id, status, created_at);
38254
+ CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_session
38255
+ ON mesh_session_delivery(mesh_id, session_id, status);
38256
+ CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_task
38257
+ ON mesh_session_delivery(mesh_id, task_id);
38258
+
38259
+ CREATE TABLE IF NOT EXISTS mesh_completion_conflicts (
38260
+ id TEXT PRIMARY KEY,
38261
+ mesh_id TEXT NOT NULL,
38262
+ fingerprint TEXT NOT NULL,
38263
+ conflicting_task_id TEXT,
38264
+ conflicting_session_id TEXT,
38265
+ original_task_id TEXT,
38266
+ original_session_id TEXT,
38267
+ event TEXT NOT NULL,
38268
+ created_at TEXT NOT NULL
38269
+ );
38270
+
38271
+ CREATE INDEX IF NOT EXISTS idx_mesh_completion_conflicts_mesh
38272
+ ON mesh_completion_conflicts(mesh_id, created_at);
38230
38273
  `);
38231
38274
  }
38232
38275
  hasCompletionFingerprint(fingerprint) {
@@ -38551,6 +38594,131 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
38551
38594
  pruneExpiredRemoteIdleSessions() {
38552
38595
  this.db.prepare("DELETE FROM remote_idle_sessions WHERE expires_at <= ?").run(Date.now());
38553
38596
  }
38597
+ // ── Session Delivery Queue ───────────────────────────────────────────────
38598
+ insertSessionDelivery(entry) {
38599
+ this.db.prepare(`
38600
+ INSERT OR REPLACE INTO mesh_session_delivery (
38601
+ id, mesh_id, node_id, session_id, provider_type, task_id, kind, priority,
38602
+ message, status, deliver_after, expires_at, attempt_count,
38603
+ source_coordinator_session_id, source_coordinator_daemon_id,
38604
+ last_error, created_at, updated_at
38605
+ ) VALUES (
38606
+ @id, @meshId, @nodeId, @sessionId, @providerType, @taskId, @kind, @priority,
38607
+ @message, @status, @deliverAfter, @expiresAt, 0,
38608
+ @sourceCoordinatorSessionId, @sourceCoordinatorDaemonId,
38609
+ NULL, @createdAt, @updatedAt
38610
+ )
38611
+ `).run({
38612
+ id: entry.id,
38613
+ meshId: entry.meshId,
38614
+ nodeId: entry.nodeId ?? null,
38615
+ sessionId: entry.sessionId ?? null,
38616
+ providerType: entry.providerType ?? null,
38617
+ taskId: entry.taskId ?? null,
38618
+ kind: entry.kind,
38619
+ priority: entry.priority ?? 0,
38620
+ message: entry.message,
38621
+ status: entry.status,
38622
+ deliverAfter: entry.deliverAfter ?? null,
38623
+ expiresAt: entry.expiresAt ?? null,
38624
+ sourceCoordinatorSessionId: entry.sourceCoordinatorSessionId ?? null,
38625
+ sourceCoordinatorDaemonId: entry.sourceCoordinatorDaemonId ?? null,
38626
+ createdAt: entry.createdAt,
38627
+ updatedAt: entry.updatedAt
38628
+ });
38629
+ this.maybeCheckpointWal();
38630
+ }
38631
+ updateSessionDeliveryStatus(id, status, opts) {
38632
+ const now = (/* @__PURE__ */ new Date()).toISOString();
38633
+ if (opts?.incrementAttempt) {
38634
+ this.db.prepare(`
38635
+ UPDATE mesh_session_delivery
38636
+ SET status = @status, last_error = @lastError, attempt_count = attempt_count + 1, updated_at = @updatedAt
38637
+ WHERE id = @id
38638
+ `).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
38639
+ } else {
38640
+ this.db.prepare(`
38641
+ UPDATE mesh_session_delivery
38642
+ SET status = @status, last_error = @lastError, updated_at = @updatedAt
38643
+ WHERE id = @id
38644
+ `).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
38645
+ }
38646
+ }
38647
+ getActiveSessionDeliveries(meshId, sessionId) {
38648
+ const now = (/* @__PURE__ */ new Date()).toISOString();
38649
+ const sql = sessionId ? `SELECT * FROM mesh_session_delivery WHERE mesh_id = ? AND session_id = ? AND status NOT IN ('delivered','completed','failed','expired','cancelled') AND (expires_at IS NULL OR expires_at > ?) ORDER BY priority DESC, created_at ASC` : `SELECT * FROM mesh_session_delivery WHERE mesh_id = ? AND status NOT IN ('delivered','completed','failed','expired','cancelled') AND (expires_at IS NULL OR expires_at > ?) ORDER BY priority DESC, created_at ASC`;
38650
+ const rows = sessionId ? this.db.prepare(sql).all(meshId, sessionId, now) : this.db.prepare(sql).all(meshId, now);
38651
+ return rows.map((r) => ({
38652
+ id: r.id,
38653
+ meshId: r.mesh_id,
38654
+ nodeId: r.node_id,
38655
+ sessionId: r.session_id,
38656
+ providerType: r.provider_type,
38657
+ taskId: r.task_id,
38658
+ kind: r.kind,
38659
+ priority: r.priority,
38660
+ message: r.message,
38661
+ status: r.status,
38662
+ deliverAfter: r.deliver_after,
38663
+ expiresAt: r.expires_at,
38664
+ attemptCount: r.attempt_count,
38665
+ sourceCoordinatorSessionId: r.source_coordinator_session_id,
38666
+ sourceCoordinatorDaemonId: r.source_coordinator_daemon_id,
38667
+ lastError: r.last_error,
38668
+ createdAt: r.created_at,
38669
+ updatedAt: r.updated_at
38670
+ }));
38671
+ }
38672
+ expireStaleSessionDeliveries(meshId) {
38673
+ const now = (/* @__PURE__ */ new Date()).toISOString();
38674
+ this.db.prepare(`
38675
+ UPDATE mesh_session_delivery
38676
+ SET status = 'expired', updated_at = ?
38677
+ WHERE mesh_id = ? AND expires_at IS NOT NULL AND expires_at <= ?
38678
+ AND status NOT IN ('delivered','completed','failed','expired','cancelled')
38679
+ `).run(now, meshId, now);
38680
+ }
38681
+ deleteSessionDeliveries(meshId) {
38682
+ this.db.prepare("DELETE FROM mesh_session_delivery WHERE mesh_id = ?").run(meshId);
38683
+ }
38684
+ // ── Completion Conflict Diagnostics ──────────────────────────────────────
38685
+ recordCompletionConflict(entry) {
38686
+ this.db.prepare(`
38687
+ INSERT OR IGNORE INTO mesh_completion_conflicts
38688
+ (id, mesh_id, fingerprint, conflicting_task_id, conflicting_session_id,
38689
+ original_task_id, original_session_id, event, created_at)
38690
+ VALUES (@id, @meshId, @fingerprint, @conflictingTaskId, @conflictingSessionId,
38691
+ @originalTaskId, @originalSessionId, @event, @createdAt)
38692
+ `).run({
38693
+ id: entry.id,
38694
+ meshId: entry.meshId,
38695
+ fingerprint: entry.fingerprint,
38696
+ conflictingTaskId: entry.conflictingTaskId ?? null,
38697
+ conflictingSessionId: entry.conflictingSessionId ?? null,
38698
+ originalTaskId: entry.originalTaskId ?? null,
38699
+ originalSessionId: entry.originalSessionId ?? null,
38700
+ event: entry.event,
38701
+ createdAt: entry.createdAt
38702
+ });
38703
+ this.maybeCheckpointWal();
38704
+ }
38705
+ getRecentCompletionConflicts(meshId, limitMs = 60 * 60 * 1e3) {
38706
+ const cutoff = new Date(Date.now() - limitMs).toISOString();
38707
+ const rows = this.db.prepare(
38708
+ "SELECT * FROM mesh_completion_conflicts WHERE mesh_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 50"
38709
+ ).all(meshId, cutoff);
38710
+ return rows.map((r) => ({
38711
+ id: r.id,
38712
+ meshId: r.mesh_id,
38713
+ fingerprint: r.fingerprint,
38714
+ conflictingTaskId: r.conflicting_task_id,
38715
+ conflictingSessionId: r.conflicting_session_id,
38716
+ originalTaskId: r.original_task_id,
38717
+ originalSessionId: r.original_session_id,
38718
+ event: r.event,
38719
+ createdAt: r.created_at
38720
+ }));
38721
+ }
38554
38722
  };
38555
38723
  }
38556
38724
  });
@@ -38967,6 +39135,168 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
38967
39135
  import_fs8 = require("fs");
38968
39136
  }
38969
39137
  });
39138
+ function resolveDeliveryDecision(sessionStatus, opts) {
39139
+ const status = (sessionStatus || "").trim().toLowerCase();
39140
+ if (!status) {
39141
+ return {
39142
+ decision: "rejected",
39143
+ reason: "unknown_session_status",
39144
+ message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
39145
+ };
39146
+ }
39147
+ if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
39148
+ return {
39149
+ decision: "immediate",
39150
+ reason: `session_${status}`,
39151
+ message: `Session is ${status} \u2014 delivery allowed immediately.`
39152
+ };
39153
+ }
39154
+ if (BUSY_DELIVERY_STATUSES.has(status)) {
39155
+ if (opts?.allowBusyInjection) {
39156
+ return {
39157
+ decision: "immediate",
39158
+ reason: `session_${status}_busy_injection_allowed`,
39159
+ message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
39160
+ };
39161
+ }
39162
+ if (status === "waiting_approval" && opts?.kind === "approval") {
39163
+ return {
39164
+ decision: "immediate",
39165
+ reason: "session_waiting_approval_approval_message",
39166
+ message: "Session is waiting for approval \u2014 approval message delivered immediately."
39167
+ };
39168
+ }
39169
+ return {
39170
+ decision: "queued",
39171
+ reason: `session_${status}_busy`,
39172
+ message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
39173
+ };
39174
+ }
39175
+ if (TERMINAL_DELIVERY_STATUSES.has(status)) {
39176
+ return {
39177
+ decision: "rejected",
39178
+ reason: `session_${status}_terminal`,
39179
+ message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
39180
+ };
39181
+ }
39182
+ return {
39183
+ decision: "rejected",
39184
+ reason: "unrecognized_session_status",
39185
+ message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
39186
+ };
39187
+ }
39188
+ function createSessionDelivery(opts) {
39189
+ const now = (/* @__PURE__ */ new Date()).toISOString();
39190
+ const id = (0, import_crypto6.randomUUID)();
39191
+ const record2 = {
39192
+ id,
39193
+ meshId: opts.meshId,
39194
+ nodeId: opts.nodeId,
39195
+ sessionId: opts.sessionId,
39196
+ providerType: opts.providerType,
39197
+ taskId: opts.taskId,
39198
+ kind: opts.kind,
39199
+ priority: opts.priority ?? 0,
39200
+ message: opts.message,
39201
+ status: opts.status,
39202
+ deliverAfter: opts.deliverAfter,
39203
+ expiresAt: opts.expiresAt,
39204
+ attemptCount: 0,
39205
+ sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
39206
+ sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
39207
+ createdAt: now,
39208
+ updatedAt: now
39209
+ };
39210
+ MeshRuntimeStore.getInstance().insertSessionDelivery({
39211
+ id,
39212
+ meshId: opts.meshId,
39213
+ nodeId: opts.nodeId,
39214
+ sessionId: opts.sessionId,
39215
+ providerType: opts.providerType,
39216
+ taskId: opts.taskId,
39217
+ kind: opts.kind,
39218
+ priority: opts.priority ?? 0,
39219
+ message: opts.message,
39220
+ status: opts.status,
39221
+ deliverAfter: opts.deliverAfter,
39222
+ expiresAt: opts.expiresAt,
39223
+ sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
39224
+ sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
39225
+ createdAt: now,
39226
+ updatedAt: now
39227
+ });
39228
+ return record2;
39229
+ }
39230
+ function updateSessionDeliveryStatus(id, status, opts) {
39231
+ try {
39232
+ MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
39233
+ } catch {
39234
+ }
39235
+ }
39236
+ function getActiveSessionDeliveries(meshId, sessionId) {
39237
+ try {
39238
+ return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
39239
+ } catch {
39240
+ return [];
39241
+ }
39242
+ }
39243
+ function recordCompletionConflict(opts) {
39244
+ try {
39245
+ MeshRuntimeStore.getInstance().recordCompletionConflict({
39246
+ id: (0, import_crypto6.randomUUID)(),
39247
+ meshId: opts.meshId,
39248
+ fingerprint: opts.fingerprint,
39249
+ conflictingTaskId: opts.conflictingTaskId,
39250
+ conflictingSessionId: opts.conflictingSessionId,
39251
+ originalTaskId: opts.originalTaskId,
39252
+ originalSessionId: opts.originalSessionId,
39253
+ event: opts.event,
39254
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
39255
+ });
39256
+ } catch {
39257
+ }
39258
+ }
39259
+ function getRecentCompletionConflicts(meshId, limitMs) {
39260
+ try {
39261
+ return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
39262
+ } catch {
39263
+ return [];
39264
+ }
39265
+ }
39266
+ var import_crypto6;
39267
+ var IMMEDIATE_DELIVERY_STATUSES;
39268
+ var BUSY_DELIVERY_STATUSES;
39269
+ var TERMINAL_DELIVERY_STATUSES;
39270
+ var init_mesh_delivery_policy = __esm2({
39271
+ "src/mesh/mesh-delivery-policy.ts"() {
39272
+ "use strict";
39273
+ import_crypto6 = require("crypto");
39274
+ init_mesh_runtime_store();
39275
+ IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
39276
+ "idle",
39277
+ "waiting_input",
39278
+ "ready"
39279
+ ]);
39280
+ BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
39281
+ "generating",
39282
+ "running",
39283
+ "streaming",
39284
+ "busy",
39285
+ "starting",
39286
+ "initializing",
39287
+ "waiting_approval"
39288
+ ]);
39289
+ TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
39290
+ "stopped",
39291
+ "failed",
39292
+ "terminated",
39293
+ "exited",
39294
+ "closed",
39295
+ "deleted",
39296
+ "error"
39297
+ ]);
39298
+ }
39299
+ });
38970
39300
  var mesh_events_exports = {};
38971
39301
  __export2(mesh_events_exports, {
38972
39302
  __resetIdleAutoFastForwardForTests: () => __resetIdleAutoFastForwardForTests,
@@ -39310,7 +39640,18 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
39310
39640
  function isDuplicateMeshCompletionEvent(args) {
39311
39641
  const fingerprint = buildMeshCompletionFingerprint(args);
39312
39642
  if (!fingerprint) return false;
39313
- if (hasFingerprintSeen(fingerprint)) return true;
39643
+ if (hasFingerprintSeen(fingerprint)) {
39644
+ if (args.taskId) {
39645
+ recordCompletionConflict({
39646
+ meshId: args.meshId,
39647
+ fingerprint,
39648
+ conflictingTaskId: args.taskId,
39649
+ conflictingSessionId: args.sessionId,
39650
+ event: args.event
39651
+ });
39652
+ }
39653
+ return true;
39654
+ }
39314
39655
  recordFingerprintSeen(fingerprint);
39315
39656
  return false;
39316
39657
  }
@@ -39561,20 +39902,33 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
39561
39902
  if (node?.daemonId && components.dispatchMeshCommand) {
39562
39903
  const isLocalNode = components.cliManager.adapters.has(sessionId);
39563
39904
  if (!isLocalNode) {
39905
+ const delivery2 = createSessionDelivery({
39906
+ meshId,
39907
+ nodeId,
39908
+ sessionId,
39909
+ providerType,
39910
+ taskId: task.id,
39911
+ kind: "task",
39912
+ message: task.message,
39913
+ status: "delivering"
39914
+ });
39564
39915
  components.dispatchMeshCommand(node.daemonId, "agent_command", {
39565
39916
  targetSessionId: sessionId,
39566
39917
  cliType: providerType,
39567
39918
  action: "send_chat",
39568
39919
  message: task.message
39920
+ }).then(() => {
39921
+ updateSessionDeliveryStatus(delivery2.id, "delivered");
39569
39922
  }).catch((e) => {
39570
39923
  LOG2.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
39924
+ updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
39571
39925
  updateTaskStatus(meshId, task.id, "pending");
39572
39926
  try {
39573
39927
  appendLedgerEntry(meshId, {
39574
39928
  kind: "dispatch_failed",
39575
39929
  nodeId,
39576
39930
  sessionId,
39577
- payload: { taskId: task.id, error: e?.message, retryable: true }
39931
+ payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
39578
39932
  });
39579
39933
  } catch {
39580
39934
  }
@@ -39582,13 +39936,26 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
39582
39936
  return true;
39583
39937
  }
39584
39938
  }
39939
+ const delivery = createSessionDelivery({
39940
+ meshId,
39941
+ nodeId,
39942
+ sessionId,
39943
+ providerType,
39944
+ taskId: task.id,
39945
+ kind: "task",
39946
+ message: task.message,
39947
+ status: "delivering"
39948
+ });
39585
39949
  components.cliManager.handleCliCommand("agent_command", {
39586
39950
  targetSessionId: sessionId,
39587
39951
  cliType: providerType,
39588
39952
  action: "send_chat",
39589
39953
  message: task.message
39954
+ }).then(() => {
39955
+ updateSessionDeliveryStatus(delivery.id, "delivered");
39590
39956
  }).catch((e) => {
39591
39957
  LOG2.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
39958
+ updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
39592
39959
  updateTaskStatus(meshId, task.id, "failed");
39593
39960
  });
39594
39961
  return true;
@@ -40193,7 +40560,9 @@ Next step: ${nextStep}`;
40193
40560
  finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
40194
40561
  // Scope dedup to the coordinator daemon so two coordinators for the same mesh
40195
40562
  // don't suppress each other's completion events via shared fingerprint table.
40196
- coordinatorDaemonId: workerCoordinatorDaemonId || void 0
40563
+ coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
40564
+ taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
40565
+ nodeId: eventNodeId || void 0
40197
40566
  });
40198
40567
  if (duplicateCompletion) {
40199
40568
  LOG2.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
@@ -40209,7 +40578,9 @@ Next step: ${nextStep}`;
40209
40578
  providerSessionId: readNonEmptyString2(args.metadataEvent.providerSessionId) || void 0,
40210
40579
  timestamp: eventTimestamp,
40211
40580
  finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
40212
- coordinatorDaemonId: workerCoordinatorDaemonId || void 0
40581
+ coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
40582
+ taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
40583
+ nodeId: eventNodeId || void 0
40213
40584
  });
40214
40585
  if (duplicateStopped) {
40215
40586
  LOG2.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
@@ -40602,6 +40973,7 @@ Next step: ${nextStep}`;
40602
40973
  init_mesh_work_queue();
40603
40974
  init_mesh_runtime_store();
40604
40975
  init_mesh_fast_forward();
40976
+ init_mesh_delivery_policy();
40605
40977
  REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
40606
40978
  meshByWorkspaceCache = /* @__PURE__ */ new Map();
40607
40979
  MESH_WORKSPACE_CACHE_TTL_MS = 5e3;
@@ -46160,6 +46532,7 @@ ${lastSnapshot}`;
46160
46532
  createInteractionId: () => createInteractionId,
46161
46533
  createMesh: () => createMesh,
46162
46534
  createNativeHistoryDispatcher: () => createNativeHistoryDispatcher,
46535
+ createSessionDelivery: () => createSessionDelivery,
46163
46536
  createWorktree: () => createWorktree,
46164
46537
  deleteMesh: () => deleteMesh,
46165
46538
  detectAllVersions: () => detectAllVersions,
@@ -46183,6 +46556,7 @@ ${lastSnapshot}`;
46183
46556
  forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance2,
46184
46557
  getAIExtensions: () => getAIExtensions,
46185
46558
  getActiveDirectDispatches: () => getActiveDirectDispatches,
46559
+ getActiveSessionDeliveries: () => getActiveSessionDeliveries,
46186
46560
  getAvailableIdeIds: () => getAvailableIdeIds,
46187
46561
  getCoordinatorForSession: () => getCoordinatorForSession,
46188
46562
  getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
@@ -46205,6 +46579,7 @@ ${lastSnapshot}`;
46205
46579
  getQueue: () => getQueue,
46206
46580
  getRecentActivity: () => getRecentActivity,
46207
46581
  getRecentCommands: () => getRecentCommands,
46582
+ getRecentCompletionConflicts: () => getRecentCompletionConflicts,
46208
46583
  getRecentDebugTrace: () => getRecentDebugTrace,
46209
46584
  getRecentLogs: () => getRecentLogs,
46210
46585
  getSavedProviderSessions: () => getSavedProviderSessions,
@@ -46292,6 +46667,7 @@ ${lastSnapshot}`;
46292
46667
  readLedgerEntries: () => readLedgerEntries,
46293
46668
  readLedgerSlice: () => readLedgerSlice,
46294
46669
  reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
46670
+ recordCompletionConflict: () => recordCompletionConflict,
46295
46671
  recordDebugTrace: () => recordDebugTrace,
46296
46672
  registerExtensionProviders: () => registerExtensionProviders,
46297
46673
  registerMeshCoordinator: () => registerMeshCoordinator,
@@ -46305,6 +46681,7 @@ ${lastSnapshot}`;
46305
46681
  resolveChatMessageKind: () => resolveChatMessageKind,
46306
46682
  resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
46307
46683
  resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
46684
+ resolveDeliveryDecision: () => resolveDeliveryDecision,
46308
46685
  resolveGitRepository: () => resolveGitRepository,
46309
46686
  resolveMeshHostStatus: () => resolveMeshHostStatus,
46310
46687
  resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
@@ -46334,6 +46711,7 @@ ${lastSnapshot}`;
46334
46711
  updateDirectDispatchStatus: () => updateDirectDispatchStatus,
46335
46712
  updateMesh: () => updateMesh,
46336
46713
  updateNode: () => updateNode,
46714
+ updateSessionDeliveryStatus: () => updateSessionDeliveryStatus,
46337
46715
  updateSessionTaskStatus: () => updateSessionTaskStatus,
46338
46716
  updateTaskStatus: () => updateTaskStatus,
46339
46717
  upsertSavedProviderSession: () => upsertSavedProviderSession,
@@ -49133,6 +49511,7 @@ ${lastSnapshot}`;
49133
49511
  }
49134
49512
  init_mesh_host_ownership();
49135
49513
  init_mesh_events();
49514
+ init_mesh_delivery_policy();
49136
49515
  var NO_FALLBACK_REASON = "Repo Mesh command/data-plane is P2P-only; WS/REST command fallback is intentionally disabled to preserve the transport boundary.";
49137
49516
  var P2P_NEXT_ACTION = "Check daemon/P2P health, wait briefly for connection establishment, then do one bounded retry or requeue the mesh task after clearing stale target session metadata.";
49138
49517
  var NON_P2P_NEXT_ACTION = "Inspect the provider/command error and fix the underlying logic or configuration before retrying.";
@@ -49396,8 +49775,8 @@ ${lastSnapshot}`;
49396
49775
  if ((0, import_fs11.existsSync)(bundledCli)) resolvedCli = bundledCli;
49397
49776
  }
49398
49777
  if (!resolvedCli && appPath && os29 === "win32") {
49399
- const { dirname: dirname11 } = await import("path");
49400
- const appDir = dirname11(appPath);
49778
+ const { dirname: dirname12 } = await import("path");
49779
+ const appDir = dirname12(appPath);
49401
49780
  const candidates = [
49402
49781
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
49403
49782
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -61768,7 +62147,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
61768
62147
  * explicit wake-up there's nothing to trigger the busy → idle
61769
62148
  * downshift. */
61770
62149
  busyExpiryTimer = null;
62150
+ /** Pending idle-commit timer. Armed when the evaluator first returns idle;
62151
+ * fires after idle_hold_ms if no non-idle reading has cancelled it. */
62152
+ idleHoldTimer = null;
62153
+ /** State snapshot captured when the idle hold was armed — emitted on commit. */
62154
+ pendingIdleState = null;
61771
62155
  specWatcher = null;
62156
+ /** Ring buffer of committed state transitions (max 50). */
62157
+ stateHistory = [];
62158
+ prevStateAt = 0;
61772
62159
  /** Subscribe to outbound events. Returns an unsubscribe fn. */
61773
62160
  subscribe(listener) {
61774
62161
  this.listeners.add(listener);
@@ -61819,9 +62206,40 @@ ${formatManifestValidationIssues2(validation.issues)}`,
61819
62206
  shutdown() {
61820
62207
  for (const t of this.delegateTimers.values()) clearTimeout(t);
61821
62208
  this.delegateTimers.clear();
62209
+ this.cancelIdleHold();
62210
+ if (this.busyExpiryTimer) {
62211
+ clearTimeout(this.busyExpiryTimer);
62212
+ this.busyExpiryTimer = null;
62213
+ }
61822
62214
  this.specWatcher?.close();
61823
62215
  this.adapter.kill();
61824
62216
  }
62217
+ cancelIdleHold() {
62218
+ if (this.idleHoldTimer) {
62219
+ clearTimeout(this.idleHoldTimer);
62220
+ this.idleHoldTimer = null;
62221
+ }
62222
+ this.pendingIdleState = null;
62223
+ }
62224
+ pushHistory(stateId, label) {
62225
+ const now = Date.now();
62226
+ const durationMs = this.prevStateAt > 0 ? now - this.prevStateAt : 0;
62227
+ this.prevStateAt = now;
62228
+ this.stateHistory.push({ stateId, label, at: now, durationMs });
62229
+ if (this.stateHistory.length > 50) this.stateHistory.shift();
62230
+ }
62231
+ getStateHistory() {
62232
+ return this.stateHistory;
62233
+ }
62234
+ getLastBusyAt() {
62235
+ return this.lastBusyAt;
62236
+ }
62237
+ hasIdleHoldPending() {
62238
+ return this.idleHoldTimer !== null;
62239
+ }
62240
+ getSpecPath() {
62241
+ return this.opts.specPath;
62242
+ }
61825
62243
  // ────────────────────────────────────────────────────────────────────
61826
62244
  // Loading & adapter wiring
61827
62245
  // ────────────────────────────────────────────────────────────────────
@@ -61845,7 +62263,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
61845
62263
  }
61846
62264
  armSpecWatcher() {
61847
62265
  try {
61848
- this.specWatcher = fs10.watch(this.opts.specPath, { persistent: false }, () => {
62266
+ const dir = path19.dirname(this.opts.specPath);
62267
+ const base = path19.basename(this.opts.specPath);
62268
+ this.specWatcher = fs10.watch(dir, { persistent: false }, (_event, filename) => {
62269
+ if (filename && filename !== base) return;
61849
62270
  const res = loadSpec(this.opts.specPath);
61850
62271
  if (!res.ok) {
61851
62272
  this.emit({ kind: "spec_error", errors: res.errors });
@@ -61929,7 +62350,46 @@ ${formatManifestValidationIssues2(validation.issues)}`,
61929
62350
  if (evState.id === "busy") {
61930
62351
  this.lastBusyAt = Date.now();
61931
62352
  this.lastBusyState = evState;
62353
+ this.cancelIdleHold();
61932
62354
  this.scheduleBusyExpiry(busyWakeMs);
62355
+ } else if (evState.id !== this.currentStateId && evState.id !== "busy") {
62356
+ if (evState.id !== (this.spec.default_state ?? "idle")) {
62357
+ this.cancelIdleHold();
62358
+ }
62359
+ }
62360
+ const idleHoldMs = this.spec.debounce?.idle_hold_ms ?? 0;
62361
+ const isIdleState = evState.id === (this.spec.default_state ?? "idle");
62362
+ if (isIdleState && idleHoldMs > 0 && this.currentStateId !== evState.id) {
62363
+ if (!this.idleHoldTimer) {
62364
+ this.pendingIdleState = evState;
62365
+ this.idleHoldTimer = setTimeout(() => {
62366
+ this.idleHoldTimer = null;
62367
+ const committed = this.pendingIdleState;
62368
+ this.pendingIdleState = null;
62369
+ if (!committed) return;
62370
+ LOG2.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] idleHold committed after ${idleHoldMs}ms`);
62371
+ this.currentStateId = committed.id;
62372
+ this.currentEval = ev;
62373
+ this.pushHistory(committed.id, committed.label);
62374
+ this.emit({
62375
+ kind: "state_changed",
62376
+ state: committed,
62377
+ modal: null,
62378
+ controls: ev.controls.map((c) => ({ id: c.id, label: c.label, action_type: c.actionType }))
62379
+ });
62380
+ this.armOrCancelDelegateTimers(committed.id);
62381
+ if (this.opts.emitTrace) this.emit({ kind: "spec_trace", entries: ev.trace });
62382
+ }, idleHoldMs);
62383
+ }
62384
+ this.currentEval = ev;
62385
+ const graceMs2 = this.spec.debounce?.startup_grace_ms ?? STARTUP_GRACE_MS;
62386
+ if (!this.idleSeenOnce && Date.now() - this.startedAtMs >= graceMs2) {
62387
+ this.idleSeenOnce = true;
62388
+ const queued = this.pendingSends.splice(0);
62389
+ for (const text of queued) setTimeout(() => this.actuallySendMessage(text), 50);
62390
+ }
62391
+ if (this.pickerInProgress) this.tryAdvancePicker(screen);
62392
+ return;
61933
62393
  }
61934
62394
  const changed = forceEmit || evState.id !== this.currentStateId || !shallowSameModal(ev, this.currentEval) || !shallowSameControls(ev, this.currentEval);
61935
62395
  if (this.pickerInProgress) this.tryAdvancePicker(screen);
@@ -61945,6 +62405,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
61945
62405
  }
61946
62406
  if (changed) {
61947
62407
  this.currentStateId = evState.id;
62408
+ this.pushHistory(evState.id, evState.label);
61948
62409
  this.emit({
61949
62410
  kind: "state_changed",
61950
62411
  state: evState,
@@ -62376,7 +62837,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62376
62837
  activeInteractivePrompt: this.activeInteractivePrompt,
62377
62838
  exited: this.exited,
62378
62839
  screen,
62379
- sections
62840
+ sections,
62841
+ stateHistory: this.driver.getStateHistory(),
62842
+ idleHoldPending: this.driver.hasIdleHoldPending(),
62843
+ lastBusyAt: this.driver.getLastBusyAt(),
62844
+ specPath: this.driver.getSpecPath()
62380
62845
  };
62381
62846
  }
62382
62847
  getRuntimeMetadata() {
@@ -67885,17 +68350,17 @@ Run 'adhdev doctor' for detailed diagnostics.`
67885
68350
  }
67886
68351
  function readSession(sessionPath) {
67887
68352
  if (!sessionPath || !path25.isAbsolute(sessionPath)) return null;
67888
- const basename13 = path25.basename(sessionPath, ".jsonl");
67889
- if (!isSafeSessionId(basename13)) return null;
68353
+ const basename14 = path25.basename(sessionPath, ".jsonl");
68354
+ if (!isSafeSessionId(basename14)) return null;
67890
68355
  if (!fs14.existsSync(sessionPath)) return null;
67891
68356
  const sourceMtimeMs = statMtimeMs(sessionPath);
67892
- const messages = parseTranscriptFile(sessionPath, basename13);
68357
+ const messages = parseTranscriptFile(sessionPath, basename14);
67893
68358
  if (messages.length === 0) return null;
67894
68359
  const firstSystem = messages.find((m) => m.kind === "session_start");
67895
68360
  const workspace = firstSystem?.workspace || firstSystem?.content || void 0;
67896
68361
  return {
67897
68362
  messages,
67898
- providerSessionId: basename13,
68363
+ providerSessionId: basename14,
67899
68364
  source: "provider-native",
67900
68365
  sourcePath: sessionPath,
67901
68366
  sourceMtimeMs,
@@ -68095,8 +68560,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
68095
68560
  if (!fs15.existsSync(sessionPath)) return null;
68096
68561
  const meta3 = readSessionMeta(sessionPath);
68097
68562
  const metaId = String(meta3?.id ?? "").trim();
68098
- const basename13 = path26.basename(sessionPath, ".jsonl");
68099
- const uuidMatch = basename13.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
68563
+ const basename14 = path26.basename(sessionPath, ".jsonl");
68564
+ const uuidMatch = basename14.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
68100
68565
  const filenameUuid2 = uuidMatch ? uuidMatch[1] : "";
68101
68566
  if (metaId && filenameUuid2 && metaId !== filenameUuid2) return null;
68102
68567
  const sessionId = metaId || filenameUuid2;
@@ -75282,6 +75747,21 @@ ${e?.stderr || ""}`
75282
75747
  } : null
75283
75748
  };
75284
75749
  }
75750
+ case "get_spec_debug": {
75751
+ const sessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : typeof args?.sessionId === "string" ? args.sessionId.trim() : "";
75752
+ if (!sessionId) return { success: false, error: "targetSessionId required" };
75753
+ const target = this.deps.sessionRegistry.get(sessionId);
75754
+ if (!target) return { success: false, error: "Session not found", sessionId };
75755
+ const adapter = this.deps.cliManager.findAdapter(target.providerType, { instanceKey: sessionId })?.adapter;
75756
+ const snapshot = adapter && typeof adapter.getDebugSnapshot === "function" ? adapter.getDebugSnapshot() : null;
75757
+ return {
75758
+ success: true,
75759
+ sessionId,
75760
+ providerType: target.providerType,
75761
+ isSpecProvider: snapshot !== null,
75762
+ snapshot
75763
+ };
75764
+ }
75285
75765
  // ── User-level coordinator-prompt files (~/.adhdev/coordinator-prompts/).
75286
75766
  // These live on this daemon's filesystem and never sync to the
75287
75767
  // cloud / other daemons — they're per-machine config. The
@@ -76164,9 +76644,9 @@ ${e?.stderr || ""}`
76164
76644
  });
76165
76645
  let node;
76166
76646
  if (meshRecord.inline) {
76167
- const { randomUUID: randomUUID11 } = await import("crypto");
76647
+ const { randomUUID: randomUUID12 } = await import("crypto");
76168
76648
  node = {
76169
- id: `node_${randomUUID11().replace(/-/g, "")}`,
76649
+ id: `node_${randomUUID12().replace(/-/g, "")}`,
76170
76650
  workspace: result.worktreePath,
76171
76651
  repoRoot: result.worktreePath,
76172
76652
  daemonId: sourceNode.daemonId,
@@ -76609,7 +77089,7 @@ ${ptyResult.output.slice(-2e3)}`);
76609
77089
  };
76610
77090
  }
76611
77091
  const { existsSync: existsSync39, readFileSync: readFileSync33, writeFileSync: writeFileSync21, copyFileSync: copyFileSync4, mkdirSync: mkdirSync19 } = await import("fs");
76612
- const { dirname: dirname11 } = await import("path");
77092
+ const { dirname: dirname12 } = await import("path");
76613
77093
  const mcpConfigPath = coordinatorSetup.configPath;
76614
77094
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
76615
77095
  let hermesBaseConfig = null;
@@ -76644,7 +77124,7 @@ ${ptyResult.output.slice(-2e3)}`);
76644
77124
  };
76645
77125
  }
76646
77126
  try {
76647
- mkdirSync19(dirname11(mcpConfigPath), { recursive: true });
77127
+ mkdirSync19(dirname12(mcpConfigPath), { recursive: true });
76648
77128
  } catch (error48) {
76649
77129
  const message = `Could not prepare MCP config path for automatic setup: ${error48?.message || error48}`;
76650
77130
  LOG2.error("MeshCoordinator", message);
@@ -76654,7 +77134,7 @@ ${ptyResult.output.slice(-2e3)}`);
76654
77134
  const hadExistingMcpConfig = existsSync39(mcpConfigPath);
76655
77135
  let existingMcpConfig = hermesBaseConfig?.config || {};
76656
77136
  if (hermesBaseConfig) {
76657
- copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname11(mcpConfigPath));
77137
+ copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname12(mcpConfigPath));
76658
77138
  }
76659
77139
  if (hadExistingMcpConfig) {
76660
77140
  try {
@@ -76692,7 +77172,7 @@ ${ptyResult.output.slice(-2e3)}`);
76692
77172
  const cliArgs = [];
76693
77173
  const launchEnv = {};
76694
77174
  if (configFormat === "hermes_config_yaml") {
76695
- launchEnv.HERMES_HOME = dirname11(mcpConfigPath);
77175
+ launchEnv.HERMES_HOME = dirname12(mcpConfigPath);
76696
77176
  launchEnv.HERMES_IGNORE_USER_CONFIG = "";
76697
77177
  }
76698
77178
  let autoImportContextFilePath;
@@ -84572,7 +85052,7 @@ data: ${JSON.stringify(msg.data)}
84572
85052
  });
84573
85053
  }
84574
85054
  };
84575
- var import_crypto6 = require("crypto");
85055
+ var import_crypto7 = require("crypto");
84576
85056
  var import_session_host_core42 = require_dist2();
84577
85057
  var BASE_KEY_SEQUENCES = {
84578
85058
  enter: "\r",
@@ -84670,7 +85150,7 @@ data: ${JSON.stringify(msg.data)}
84670
85150
  const sessionId = String(options.sessionId || "").trim();
84671
85151
  if (!sessionId) throw new Error("sessionId is required");
84672
85152
  const mode = options.mode || "read";
84673
- const clientId = options.clientId || `raw-terminal-${process.pid}-${(0, import_crypto6.randomUUID)().slice(0, 8)}`;
85153
+ const clientId = options.clientId || `raw-terminal-${process.pid}-${(0, import_crypto7.randomUUID)().slice(0, 8)}`;
84674
85154
  const client = options.client || new import_session_host_core42.SessionHostClient({ endpoint: options.endpoint });
84675
85155
  await client.connect();
84676
85156
  const attachResponse = await client.request({