@adhdev/daemon-core 0.9.77-rc.51 → 0.9.77-rc.52

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.d.ts CHANGED
@@ -37,6 +37,8 @@ export { buildMeshLedgerReconciliationEvidence, buildMeshLedgerReplicaEvidence }
37
37
  export type { MeshLedgerReconciliationEvidence, MeshLedgerReplicaEvidence, MeshLedgerReplicaStatus } from './mesh/mesh-ledger-reconciliation.js';
38
38
  export { enqueueTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats } from './mesh/mesh-work-queue.js';
39
39
  export type { MeshWorkQueueEntry, MeshTaskStatus, MeshWorkQueueStats } from './mesh/mesh-work-queue.js';
40
+ export { buildMeshGraph } from './mesh/mesh-visualization.js';
41
+ export type { MeshGraph, MeshGraphNode, MeshGraphEdge, MeshGraphNodeType, MeshGraphEdgeType } from './mesh/mesh-visualization.js';
40
42
  export { triggerMeshQueue, drainPendingMeshCoordinatorEvents, getPendingMeshCoordinatorEvents, clearPendingMeshCoordinatorEvents } from './mesh/mesh-events.js';
41
43
  export type { PendingMeshCoordinatorEvent } from './mesh/mesh-events.js';
42
44
  export { P2pRelayFailureError, buildP2pRelayFailurePayload, classifyP2pRelayFailure, isP2pRelayTransportFailure, } from './mesh/p2p-relay-failure.js';
package/dist/index.js CHANGED
@@ -5530,6 +5530,7 @@ __export(index_exports, {
5530
5530
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
5531
5531
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
5532
5532
  buildMachineInfo: () => buildMachineInfo,
5533
+ buildMeshGraph: () => buildMeshGraph,
5533
5534
  buildMeshLedgerReconciliationEvidence: () => buildMeshLedgerReconciliationEvidence,
5534
5535
  buildMeshLedgerReplicaEvidence: () => buildMeshLedgerReplicaEvidence,
5535
5536
  buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
@@ -7625,6 +7626,231 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
7625
7626
 
7626
7627
  // src/index.ts
7627
7628
  init_mesh_work_queue();
7629
+
7630
+ // src/mesh/mesh-visualization.ts
7631
+ function isDirty(git) {
7632
+ if (!git) return false;
7633
+ return git.staged + git.modified + git.untracked + git.deleted + git.renamed > 0;
7634
+ }
7635
+ function dirtyFileCount(git) {
7636
+ if (!git) return 0;
7637
+ return git.staged + git.modified + git.untracked + git.deleted + git.renamed;
7638
+ }
7639
+ function detectOrphanReasons(node, defaultBranch) {
7640
+ const reasons = [];
7641
+ const git = node.git;
7642
+ if (!git) {
7643
+ reasons.push("No git status available");
7644
+ return reasons;
7645
+ }
7646
+ if (!git.isGitRepo) {
7647
+ reasons.push("Not a git repository");
7648
+ return reasons;
7649
+ }
7650
+ if (git.branch === null && git.headCommit) {
7651
+ reasons.push("Detached HEAD");
7652
+ }
7653
+ if (git.branch && !git.upstream) {
7654
+ if (defaultBranch && git.branch !== defaultBranch) {
7655
+ reasons.push(`No upstream: ${git.branch}`);
7656
+ }
7657
+ }
7658
+ if (git.branch && git.upstream === null && defaultBranch && git.branch !== defaultBranch) {
7659
+ if (!reasons.includes(`No upstream: ${git.branch}`)) {
7660
+ reasons.push(`No upstream: ${git.branch}`);
7661
+ }
7662
+ }
7663
+ if (node.error) {
7664
+ reasons.push(`Error: ${node.error}`);
7665
+ }
7666
+ return reasons;
7667
+ }
7668
+ function nodeHealthPriority(health) {
7669
+ switch (health) {
7670
+ case "online":
7671
+ return 0;
7672
+ case "dirty":
7673
+ return 1;
7674
+ case "degraded":
7675
+ return 2;
7676
+ case "wrong_branch":
7677
+ return 3;
7678
+ case "offline":
7679
+ return 4;
7680
+ case "unknown":
7681
+ return 5;
7682
+ default:
7683
+ return 5;
7684
+ }
7685
+ }
7686
+ function pickDominantHealth(healths) {
7687
+ if (healths.length === 0) return "unknown";
7688
+ return healths.reduce(
7689
+ (best, h) => nodeHealthPriority(h) > nodeHealthPriority(best) ? h : best
7690
+ );
7691
+ }
7692
+ function buildMeshGraph(status) {
7693
+ const nodes = [];
7694
+ const edges = [];
7695
+ const warnings = [];
7696
+ const branchToNodeIds = /* @__PURE__ */ new Map();
7697
+ for (const nodeStatus of status.nodes) {
7698
+ const git = nodeStatus.git;
7699
+ const branch = git?.branch || null;
7700
+ const orphanReasons = detectOrphanReasons(nodeStatus, null);
7701
+ const dirty = isDirty(git);
7702
+ const dfc = dirtyFileCount(git);
7703
+ let type = "worktreeNode";
7704
+ if (orphanReasons.length > 0) {
7705
+ type = "orphanNode";
7706
+ }
7707
+ const graphNode = {
7708
+ id: nodeStatus.nodeId,
7709
+ type,
7710
+ label: nodeStatus.machineLabel || nodeStatus.nodeId.slice(0, 8),
7711
+ workspace: nodeStatus.workspace,
7712
+ branch,
7713
+ health: nodeStatus.health,
7714
+ ahead: git?.ahead ?? 0,
7715
+ behind: git?.behind ?? 0,
7716
+ dirty,
7717
+ dirtyFiles: dfc,
7718
+ hasConflicts: git?.hasConflicts ?? false,
7719
+ activeSessionCount: nodeStatus.activeSessions?.length ?? 0,
7720
+ activeSessions: nodeStatus.activeSessions ?? [],
7721
+ providers: nodeStatus.providers ?? [],
7722
+ isOrphan: orphanReasons.length > 0,
7723
+ orphanReasons,
7724
+ source: nodeStatus
7725
+ };
7726
+ nodes.push(graphNode);
7727
+ if (branch) {
7728
+ const list = branchToNodeIds.get(branch) ?? [];
7729
+ list.push(graphNode.id);
7730
+ branchToNodeIds.set(branch, list);
7731
+ }
7732
+ }
7733
+ const branchUpstreamCounts = /* @__PURE__ */ new Map();
7734
+ for (const n of status.nodes) {
7735
+ const b = n.git?.branch;
7736
+ const upstream = n.git?.upstream;
7737
+ if (b && upstream) {
7738
+ branchUpstreamCounts.set(b, (branchUpstreamCounts.get(b) ?? 0) + 1);
7739
+ }
7740
+ }
7741
+ let inferredDefaultBranch = null;
7742
+ let bestCount = 0;
7743
+ for (const [b, count] of branchUpstreamCounts) {
7744
+ if (count > bestCount) {
7745
+ bestCount = count;
7746
+ inferredDefaultBranch = b;
7747
+ }
7748
+ }
7749
+ const defaultBranchNodeId = inferredDefaultBranch ? `__branch_${inferredDefaultBranch}` : null;
7750
+ if (defaultBranchNodeId && inferredDefaultBranch) {
7751
+ const branchNodes = branchToNodeIds.get(inferredDefaultBranch) ?? [];
7752
+ const branchHealths = branchNodes.map(
7753
+ (id) => nodes.find((n) => n.id === id).health
7754
+ );
7755
+ const defaultNode = {
7756
+ id: defaultBranchNodeId,
7757
+ type: "defaultBranchNode",
7758
+ label: inferredDefaultBranch,
7759
+ workspace: "",
7760
+ branch: inferredDefaultBranch,
7761
+ health: pickDominantHealth(branchHealths),
7762
+ ahead: 0,
7763
+ behind: 0,
7764
+ dirty: false,
7765
+ dirtyFiles: 0,
7766
+ hasConflicts: false,
7767
+ activeSessionCount: 0,
7768
+ activeSessions: [],
7769
+ providers: [],
7770
+ isOrphan: false,
7771
+ orphanReasons: [],
7772
+ nextStepHint: branchNodes.length > 0 ? `${branchNodes.length} node(s) on default branch` : void 0,
7773
+ source: {
7774
+ nodeId: defaultBranchNodeId,
7775
+ machineLabel: inferredDefaultBranch,
7776
+ workspace: "",
7777
+ health: "online",
7778
+ providers: [],
7779
+ activeSessions: []
7780
+ }
7781
+ };
7782
+ nodes.push(defaultNode);
7783
+ const seenBranches = /* @__PURE__ */ new Set();
7784
+ for (const n of nodes) {
7785
+ if (n.type === "defaultBranchNode") continue;
7786
+ if (!n.branch) continue;
7787
+ if (n.branch === inferredDefaultBranch) {
7788
+ edges.push({
7789
+ id: `${defaultBranchNodeId}--${n.id}`,
7790
+ source: defaultBranchNodeId,
7791
+ target: n.id,
7792
+ type: "parentBranch",
7793
+ label: "default"
7794
+ });
7795
+ continue;
7796
+ }
7797
+ if (seenBranches.has(n.branch)) continue;
7798
+ seenBranches.add(n.branch);
7799
+ edges.push({
7800
+ id: `${defaultBranchNodeId}--branch_${n.branch}`,
7801
+ source: defaultBranchNodeId,
7802
+ target: n.branch,
7803
+ type: "parentBranch",
7804
+ label: n.branch
7805
+ });
7806
+ }
7807
+ }
7808
+ for (const [branch, ids] of branchToNodeIds) {
7809
+ if (ids.length < 2) continue;
7810
+ for (let i = 1; i < ids.length; i++) {
7811
+ edges.push({
7812
+ id: `wt_${ids[0]}--${ids[i]}`,
7813
+ source: ids[0],
7814
+ target: ids[i],
7815
+ type: "worktreeLink",
7816
+ label: branch
7817
+ });
7818
+ }
7819
+ }
7820
+ const orphanCount = nodes.filter((n) => n.isOrphan).length;
7821
+ if (orphanCount > 0) {
7822
+ warnings.push(`${orphanCount} orphan node(s) detected`);
7823
+ }
7824
+ const conflictCount = nodes.filter((n) => n.hasConflicts).length;
7825
+ if (conflictCount > 0) {
7826
+ warnings.push(`${conflictCount} node(s) with merge conflicts`);
7827
+ }
7828
+ const offlineCount = nodes.filter((n) => n.health === "offline").length;
7829
+ if (offlineCount > 0) {
7830
+ warnings.push(`${offlineCount} node(s) offline`);
7831
+ }
7832
+ const stats = {
7833
+ totalNodes: status.nodes.length,
7834
+ onlineNodes: status.nodes.filter((n) => n.health === "online").length,
7835
+ dirtyNodes: nodes.filter((n) => n.dirty).length,
7836
+ orphanNodes: orphanCount,
7837
+ errorNodes: status.nodes.filter((n) => !!n.error).length,
7838
+ offlineNodes: offlineCount,
7839
+ totalActiveSessions: status.nodes.reduce((sum, n) => sum + (n.activeSessions?.length ?? 0), 0)
7840
+ };
7841
+ return {
7842
+ meshId: status.meshId,
7843
+ meshName: status.meshName,
7844
+ repoIdentity: status.repoIdentity,
7845
+ refreshedAt: status.refreshedAt,
7846
+ nodes,
7847
+ edges,
7848
+ stats,
7849
+ warnings
7850
+ };
7851
+ }
7852
+
7853
+ // src/index.ts
7628
7854
  init_mesh_events();
7629
7855
 
7630
7856
  // src/mesh/p2p-relay-failure.ts
@@ -34035,6 +34261,7 @@ async function shutdownDaemonComponents(components) {
34035
34261
  buildChatTailDeliverySignature,
34036
34262
  buildCoordinatorSystemPrompt,
34037
34263
  buildMachineInfo,
34264
+ buildMeshGraph,
34038
34265
  buildMeshLedgerReconciliationEvidence,
34039
34266
  buildMeshLedgerReplicaEvidence,
34040
34267
  buildP2pRelayFailurePayload,