@adhdev/daemon-standalone 0.9.82-rc.185 → 0.9.82-rc.187

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/public/index.html CHANGED
@@ -7,9 +7,9 @@
7
7
  <meta name="description" content="ADHDev self-hosted dashboard for controlling AI agents" />
8
8
  <link rel="icon" href="/otter-logo.png" />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-B9KHrSa-.js"></script>
11
- <link rel="modulepreload" crossorigin href="/assets/vendor-DNk1FT1R.js">
12
- <link rel="stylesheet" crossorigin href="/assets/index-BSeeeP5M.css">
10
+ <script type="module" crossorigin src="/assets/index-BAFIjFAU.js"></script>
11
+ <link rel="modulepreload" crossorigin href="/assets/vendor-BwuWgaJI.js">
12
+ <link rel="stylesheet" crossorigin href="/assets/index-Du2W0r8n.css">
13
13
  </head>
14
14
  <body>
15
15
  <!-- Apply theme immediately to prevent FOIT (Flash of Incorrect Theme) -->
@@ -778,6 +778,172 @@ function unwrapCommandPayload(value) {
778
778
  }
779
779
  return current;
780
780
  }
781
+ function isDirectDispatchLedgerEntry(entry) {
782
+ if (entry?.kind !== "task_dispatched") return false;
783
+ const payload = entry.payload || {};
784
+ const via = readString(payload.via);
785
+ return payload.source === "direct" || via === "p2p_direct" || via === "local_direct" || via === "mesh_send_task";
786
+ }
787
+ function readMessageTimestampIso(message) {
788
+ for (const value of [message?.timestamp, message?.createdAt, message?.created_at, message?.updatedAt, message?.time]) {
789
+ if (typeof value === "number" && Number.isFinite(value)) {
790
+ const ms = value > 1e10 ? value : value * 1e3;
791
+ return new Date(ms).toISOString();
792
+ }
793
+ if (typeof value === "string" && value.trim()) {
794
+ const ms = new Date(value.trim()).getTime();
795
+ if (Number.isFinite(ms)) return new Date(ms).toISOString();
796
+ }
797
+ }
798
+ return void 0;
799
+ }
800
+ function readFinalAssistantTranscriptEvidence(payload) {
801
+ const rawMessages = Array.isArray(payload?.messages) ? payload.messages : [];
802
+ const finalAssistant = [...rawMessages].reverse().filter(isCoordinatorVisibleMessage).find((message) => {
803
+ const role = String(message?.role ?? "").toLowerCase();
804
+ return (role === "assistant" || role === "agent") && messageContent(message).trim();
805
+ });
806
+ const finalSummary = messageContent(finalAssistant).trim() || (typeof payload?.summary === "string" && payload.summary.trim() ? payload.summary.trim() : void 0);
807
+ return {
808
+ finalSummary,
809
+ transcriptMessageAt: finalAssistant ? readMessageTimestampIso(finalAssistant) : void 0
810
+ };
811
+ }
812
+ function findNodeSession(nodes, nodeId, sessionId) {
813
+ if (!nodeId || !sessionId) return {};
814
+ const node = nodes.find((candidate) => readString(candidate?.id) === nodeId || readString(candidate?.nodeId) === nodeId);
815
+ if (!node) return {};
816
+ const sessions = Array.isArray(node.sessions) ? node.sessions : [];
817
+ const session = sessions.find((candidate) => readSessionRecordId(candidate) === sessionId);
818
+ return { node, session };
819
+ }
820
+ function buildDirectDispatchReconciliationCandidates(directDispatches, ledgerEntries) {
821
+ const candidates = [];
822
+ const seenTaskIds = /* @__PURE__ */ new Set();
823
+ for (const dispatch of directDispatches || []) {
824
+ const taskId = readString(dispatch?.taskId);
825
+ if (!taskId || seenTaskIds.has(taskId)) continue;
826
+ seenTaskIds.add(taskId);
827
+ candidates.push(dispatch);
828
+ }
829
+ for (const entry of ledgerEntries || []) {
830
+ if (!isDirectDispatchLedgerEntry(entry)) continue;
831
+ const taskId = readString(entry.payload?.taskId);
832
+ if (!taskId || seenTaskIds.has(taskId)) continue;
833
+ seenTaskIds.add(taskId);
834
+ candidates.push({
835
+ taskId,
836
+ nodeId: entry.nodeId,
837
+ sessionId: entry.sessionId,
838
+ providerType: entry.providerType || readString(entry.payload?.providerType),
839
+ message: readString(entry.payload?.message),
840
+ dispatchedAt: entry.timestamp,
841
+ via: readString(entry.payload?.via)
842
+ });
843
+ }
844
+ return candidates;
845
+ }
846
+ async function reconcileDirectDispatchesFromTranscriptEvidence(ctx, liveNodes, directDispatches, ledgerEntries) {
847
+ let attempted = 0;
848
+ let reconciled = 0;
849
+ let skipped = 0;
850
+ const candidates = buildDirectDispatchReconciliationCandidates(directDispatches, ledgerEntries);
851
+ for (const dispatch of candidates) {
852
+ const taskId = readString(dispatch?.taskId);
853
+ const nodeId = readString(dispatch?.nodeId);
854
+ const sessionId = readString(dispatch?.sessionId);
855
+ if (!taskId || !nodeId || !sessionId) {
856
+ skipped += 1;
857
+ continue;
858
+ }
859
+ const { session } = findNodeSession(liveNodes, nodeId, sessionId);
860
+ if (!session || !isIdleSessionRecord(session)) {
861
+ skipped += 1;
862
+ continue;
863
+ }
864
+ const node = await findOptionalNodeWithRefresh(ctx, nodeId).catch(() => null);
865
+ if (!node) {
866
+ skipped += 1;
867
+ continue;
868
+ }
869
+ const providerType = readString(dispatch?.providerType) || resolveSessionProviderType(session);
870
+ const providerSessionId = readString(session?.providerSessionId) || readString(session?.activeChat?.providerSessionId) || readString(session?.settings?.providerSessionId) || resolveMeshSessionProviderMetadata(ctx, nodeId, sessionId)?.providerSessionId;
871
+ attempted += 1;
872
+ try {
873
+ const readResult = await commandForNode(ctx, node, "read_chat", {
874
+ sessionId,
875
+ targetSessionId: sessionId,
876
+ workspace: node.workspace,
877
+ ...providerType ? { agentType: providerType, providerType } : {},
878
+ ...providerSessionId ? { providerSessionId } : {},
879
+ tailLimit: 10
880
+ });
881
+ const payload = unwrapCommandPayload(readResult);
882
+ if (payload?.success === false) continue;
883
+ const evidence = readFinalAssistantTranscriptEvidence(payload);
884
+ if (!evidence.finalSummary) continue;
885
+ const result = (0, import_daemon_core.reconcileDirectDispatchCompletionFromTranscript)({
886
+ meshId: ctx.mesh.id,
887
+ nodeId,
888
+ sessionId,
889
+ providerType,
890
+ providerSessionId: readString(payload?.providerSessionId) || providerSessionId,
891
+ taskId,
892
+ finalSummary: evidence.finalSummary,
893
+ transcriptMessageAt: evidence.transcriptMessageAt,
894
+ targetCoordinatorDaemonId: ctx.localDaemonId,
895
+ source: "mcp_mesh_status_transcript_reconciliation"
896
+ });
897
+ if (result.reconciled) reconciled += 1;
898
+ } catch {
899
+ skipped += 1;
900
+ }
901
+ }
902
+ return { attempted, reconciled, skipped };
903
+ }
904
+ async function triggerMeshQueueAndReport(ctx, node, opts) {
905
+ if (!(isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport)) return void 0;
906
+ try {
907
+ let raw;
908
+ if (ctx.transport instanceof IpcTransport && node?.daemonId && opts?.localNode === false) {
909
+ raw = await ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id });
910
+ } else if (isLocalTransport(ctx.transport)) {
911
+ raw = await ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id });
912
+ } else {
913
+ return void 0;
914
+ }
915
+ const payload = unwrapCommandPayload(raw);
916
+ const trigger = payload?.trigger && typeof payload.trigger === "object" ? payload.trigger : payload;
917
+ return trigger && typeof trigger === "object" ? trigger : { success: true };
918
+ } catch (e) {
919
+ return {
920
+ success: false,
921
+ error: e?.message || String(e)
922
+ };
923
+ }
924
+ }
925
+ function buildQueueTriggerGuidance(queueTrigger) {
926
+ if (!queueTrigger || queueTrigger.claimed === true) return void 0;
927
+ if (queueTrigger.success === false) {
928
+ return {
929
+ queueClaimed: false,
930
+ queueDispatchState: "trigger_failed",
931
+ nextAction: "Do not assume the queued task is running. Check mesh_view_queue and daemon connectivity before redispatching."
932
+ };
933
+ }
934
+ if (queueTrigger.noIdleMeshSessionAvailable === true) {
935
+ return {
936
+ queueClaimed: false,
937
+ queueDispatchState: "pending_no_idle_mesh_session",
938
+ nextAction: "The task is queued but not running. Launch a managed worker with mesh_launch_session, or wait for a delegated session to become ready and trigger the queue again."
939
+ };
940
+ }
941
+ return {
942
+ queueClaimed: false,
943
+ queueDispatchState: "pending_or_waiting_for_ready",
944
+ nextAction: "The task is queued but this trigger did not claim it. Use mesh_view_queue for the current active-work source of truth before retrying."
945
+ };
946
+ }
781
947
  function isTerminalSessionRecord(session) {
782
948
  const status = typeof session?.status === "string" ? session.status.toLowerCase() : "";
783
949
  const lifecycle = typeof session?.lifecycle === "string" ? session.lifecycle.toLowerCase() : "";
@@ -797,11 +963,19 @@ function isMeshOwnedDelegateSession(session, meshId, nodeId) {
797
963
  if (sessionMeshId !== meshId) return false;
798
964
  return !sessionNodeId || sessionNodeId === nodeId;
799
965
  }
966
+ function hasRemoteRelayMetadata(session) {
967
+ return Boolean(
968
+ readString(session?.settings?.meshCoordinatorDaemonId) || readString(session?.meta?.meshCoordinatorDaemonId) || readString(session?.metadata?.meshCoordinatorDaemonId) || readString(session?.meshCoordinatorDaemonId)
969
+ );
970
+ }
971
+ function isRelaySafeRemoteDelegateSession(session, meshId, nodeId) {
972
+ return isMeshOwnedDelegateSession(session, meshId, nodeId) && hasRemoteRelayMetadata(session);
973
+ }
800
974
  function chooseDispatchableSession(sessions, providerType, meshId, nodeId) {
801
975
  const live = sessions.filter((session) => !isTerminalSessionRecord(session));
802
976
  const matchingProvider = (session) => !providerType || session?.providerType === providerType || session?.cliType === providerType;
803
977
  const meshSessions = live.filter(
804
- (session) => isMeshOwnedDelegateSession(session, meshId, nodeId)
978
+ (session) => isRelaySafeRemoteDelegateSession(session, meshId, nodeId)
805
979
  );
806
980
  return meshSessions.find((session) => isIdleSessionRecord(session) && matchingProvider(session)) || meshSessions.find(matchingProvider) || void 0;
807
981
  }
@@ -1006,7 +1180,7 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
1006
1180
  let resolvedProviderType = args.providerType?.trim() || providerPriorityList[0] || "";
1007
1181
  if (sessionId && args.verifiedSession) {
1008
1182
  const explicitSession = args.verifiedSession;
1009
- if (!isMeshOwnedDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
1183
+ if (!isRelaySafeRemoteDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
1010
1184
  return buildRelayUnsafeRemoteSessionFailure(
1011
1185
  ctx,
1012
1186
  node,
@@ -1041,7 +1215,7 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
1041
1215
  nextAction: `Launch a fresh session with mesh_launch_session(node_id: '${node.id}'${resolvedProviderType ? `, type: '${resolvedProviderType}'` : ""}) or retry without session_id so Repo Mesh can target a live delegate session.`
1042
1216
  };
1043
1217
  }
1044
- if (!isMeshOwnedDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
1218
+ if (!isRelaySafeRemoteDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
1045
1219
  return buildRelayUnsafeRemoteSessionFailure(
1046
1220
  ctx,
1047
1221
  node,
@@ -1198,8 +1372,6 @@ function buildNodeMachineIdentity(ctx, node) {
1198
1372
  function nodeHasLocalDaemonEvidence(ctx, node) {
1199
1373
  const isLocal = (session) => {
1200
1374
  if (!session || typeof session !== "object") return false;
1201
- if (ctx.localDaemonId && session.settings?.meshCoordinatorDaemonId === ctx.localDaemonId) return true;
1202
- if (session.launchedByCoordinator === true) return true;
1203
1375
  if (ctx.localDaemonId && session.runtime?.owner === ctx.localDaemonId) return true;
1204
1376
  if (ctx.localDaemonId && session.daemonClient?.daemonId === ctx.localDaemonId) return true;
1205
1377
  return false;
@@ -2033,7 +2205,7 @@ var ALL_MESH_TOOLS = [
2033
2205
  async function meshStatus(ctx, args = {}) {
2034
2206
  await refreshMeshFromDaemon(ctx);
2035
2207
  const { mesh, transport } = ctx;
2036
- const ledgerSummary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
2208
+ let ledgerSummary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
2037
2209
  const results = await Promise.all(mesh.nodes.map(async (node) => {
2038
2210
  const entry = {
2039
2211
  nodeId: node.id,
@@ -2164,11 +2336,19 @@ async function meshStatus(ctx, args = {}) {
2164
2336
  }
2165
2337
  return entry;
2166
2338
  }));
2167
- const ledgerEntries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 200 });
2339
+ let ledgerEntries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 200 });
2340
+ let directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(mesh.id);
2341
+ const directReconciliation = await reconcileDirectDispatchesFromTranscriptEvidence(ctx, results, directDispatches, ledgerEntries);
2342
+ if (directReconciliation.reconciled > 0) {
2343
+ ledgerEntries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 200 });
2344
+ directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(mesh.id);
2345
+ ledgerSummary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
2346
+ }
2168
2347
  const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
2169
2348
  meshId: mesh.id,
2170
2349
  queue: (0, import_daemon_core.getQueue)(mesh.id),
2171
2350
  ledgerEntries,
2351
+ directDispatches,
2172
2352
  nodes: results
2173
2353
  });
2174
2354
  const pollingGuidance = buildActiveWorkPollingGuidance(activeWorkEvidence.summary);
@@ -2364,13 +2544,20 @@ async function meshEnqueueTask(ctx, args) {
2364
2544
  try {
2365
2545
  const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode, requiredTags });
2366
2546
  if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
2367
- ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2547
+ const queueTrigger = await triggerMeshQueueAndReport(ctx);
2548
+ return JSON.stringify({
2549
+ success: true,
2550
+ source: "queue",
2551
+ taskId: task.id,
2552
+ status: task.status,
2553
+ taskMode: task.taskMode,
2554
+ requiredTags: task.requiredTags,
2555
+ queueTrigger,
2556
+ ...buildQueueTriggerGuidance(queueTrigger)
2368
2557
  });
2369
- return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode, requiredTags: task.requiredTags });
2370
2558
  }
2371
2559
  if (ctx.transport instanceof IpcTransport) {
2372
- ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2373
- });
2560
+ const queueTrigger = await triggerMeshQueueAndReport(ctx);
2374
2561
  const dispatchPromises = [];
2375
2562
  for (const node of ctx.mesh.nodes) {
2376
2563
  const isLocalNode = isLocalControlPlaneNode(ctx, node);
@@ -2422,7 +2609,16 @@ async function meshEnqueueTask(ctx, args) {
2422
2609
  }
2423
2610
  Promise.all(dispatchPromises).catch(() => {
2424
2611
  });
2425
- return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode, requiredTags: task.requiredTags });
2612
+ return JSON.stringify({
2613
+ success: true,
2614
+ source: "queue",
2615
+ taskId: task.id,
2616
+ status: task.status,
2617
+ taskMode: task.taskMode,
2618
+ requiredTags: task.requiredTags,
2619
+ queueTrigger,
2620
+ ...buildQueueTriggerGuidance(queueTrigger)
2621
+ });
2426
2622
  }
2427
2623
  return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode, requiredTags: task.requiredTags });
2428
2624
  } catch (e) {
@@ -2444,9 +2640,15 @@ async function meshViewQueue(ctx, args) {
2444
2640
  const visibleSummary = buildQueueStatusSummary(queue);
2445
2641
  const maintenance = buildQueueMaintenanceReport(fullQueue);
2446
2642
  const liveNodes = await collectMeshViewQueueNodesWithLiveSessions(ctx);
2643
+ let ledgerEntries = (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 200 });
2644
+ let directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(ctx.mesh.id);
2645
+ const directReconciliation = await reconcileDirectDispatchesFromTranscriptEvidence(ctx, liveNodes, directDispatches, ledgerEntries);
2646
+ if (directReconciliation.reconciled > 0) {
2647
+ ledgerEntries = (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 200 });
2648
+ directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(ctx.mesh.id);
2649
+ }
2447
2650
  (0, import_daemon_core.markStaleDirectDispatches)(ctx.mesh.id);
2448
- const ledgerEntries = (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 200 });
2449
- const directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(ctx.mesh.id);
2651
+ directDispatches = (0, import_daemon_core.getActiveDirectDispatches)(ctx.mesh.id);
2450
2652
  const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
2451
2653
  meshId: ctx.mesh.id,
2452
2654
  queue: fullQueue,
@@ -2485,6 +2687,15 @@ async function meshViewQueue(ctx, args) {
2485
2687
  activeWorkSummary: activeWorkEvidence.summary,
2486
2688
  ...pollingGuidance ? { pollingGuidance } : {},
2487
2689
  summary,
2690
+ visibleSummary,
2691
+ activeCounts: summary.activeCounts,
2692
+ historicalCounts: summary.historicalCounts,
2693
+ visibleActiveCounts: visibleSummary.activeCounts,
2694
+ visibleHistoricalCounts: visibleSummary.historicalCounts,
2695
+ activeCount: summary.activeCount,
2696
+ historicalCount: summary.historicalCount,
2697
+ visibleActiveCount: visibleSummary.activeCount,
2698
+ visibleHistoricalCount: visibleSummary.historicalCount,
2488
2699
  staleAssignedTasks,
2489
2700
  staleAssignedCount: maintenance.staleAssignedCount,
2490
2701
  queueMaintenance: maintenance,
@@ -2834,12 +3045,18 @@ async function meshSendTask(ctx, args) {
2834
3045
  targetSessionId: args.session_id,
2835
3046
  taskMode
2836
3047
  });
2837
- if (isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport) {
2838
- ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2839
- });
2840
- }
3048
+ const queueTrigger = isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport ? await triggerMeshQueueAndReport(ctx) : void 0;
2841
3049
  const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id, ctx.localDaemonId) : [];
2842
- const result = { success: true, source: "queue", nodeId: args.node_id, taskId: task.id, status: task.status, taskMode: task.taskMode };
3050
+ const result = {
3051
+ success: true,
3052
+ source: "queue",
3053
+ nodeId: args.node_id,
3054
+ taskId: task.id,
3055
+ status: task.status,
3056
+ taskMode: task.taskMode,
3057
+ queueTrigger,
3058
+ ...buildQueueTriggerGuidance(queueTrigger)
3059
+ };
2843
3060
  if (pendingEvents.length > 0) {
2844
3061
  result.pendingCoordinatorEvents = pendingEvents;
2845
3062
  }
@@ -3012,17 +3229,13 @@ async function meshLaunchSession(ctx, args) {
3012
3229
  });
3013
3230
  } catch {
3014
3231
  }
3015
- if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
3016
- ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
3017
- });
3018
- } else if (isLocalTransport(ctx.transport)) {
3019
- ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
3020
- });
3021
- }
3232
+ const queueTrigger = await triggerMeshQueueAndReport(ctx, node, { localNode: isLocalNode });
3022
3233
  return JSON.stringify({
3023
3234
  ...launchPayload,
3024
3235
  resolvedProviderType,
3025
- ...providerSessionId ? { providerSessionId } : {}
3236
+ ...providerSessionId ? { providerSessionId } : {},
3237
+ queueTrigger,
3238
+ ...buildQueueTriggerGuidance(queueTrigger)
3026
3239
  }, null, 2);
3027
3240
  } else if (!isLocalTransport(ctx.transport) && node.daemonId) {
3028
3241
  let resolvedProviderType = typeof args.type === "string" && args.type.trim() ? args.type : "";