@adhdev/daemon-core 0.9.82-rc.446 → 0.9.82-rc.447

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.
@@ -48,6 +48,7 @@ export declare function buildLivePeerGitConnection(connection: Record<string, un
48
48
  export declare function recordInlineMeshDirectGitTruth(node: any, git: Record<string, unknown>, source: 'selected_coordinator_local_git' | 'selected_coordinator_mesh_p2p_git'): {
49
49
  reporterPlatform: string | null;
50
50
  reporterArch: string | null;
51
+ reporterMachineNickname: string | null;
51
52
  };
52
53
  /**
53
54
  * Persist the live self-reported platform/arch onto the local meshes.json node
@@ -63,6 +64,7 @@ export declare function recordInlineMeshDirectGitTruth(node: any, git: Record<st
63
64
  export declare function persistNodeReporterPlatform(meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config', mesh: any, nodeId: string | undefined, reporter: {
64
65
  reporterPlatform: string | null;
65
66
  reporterArch: string | null;
67
+ reporterMachineNickname?: string | null;
66
68
  }): void;
67
69
  export declare function inlineMeshCarriesTransientNodeTruth(inlineMesh: any): boolean;
68
70
  export declare function readInlineMeshNodeId(node: any): string;
@@ -580,6 +580,16 @@ export interface LocalMeshNodeEntry {
580
580
  */
581
581
  reportedPlatform?: string;
582
582
  reportedArch?: string;
583
+ /**
584
+ * The operator-set machine nickname (config.machineNickname) of the daemon
585
+ * that owns this node's workspace. The local coordinator stamps its own
586
+ * config value onto its self/base node; a remote member self-reports its
587
+ * value on the git_status envelope (reporterMachineNickname), which the
588
+ * coordinator persists here on each direct git probe. Feeds
589
+ * buildMeshNodeDisplayLabel so the mesh UI renders the friendly nickname
590
+ * instead of a raw daemonId/nodeId. Absent until set/first-reported.
591
+ */
592
+ machineNickname?: string;
583
593
  policy: RepoMeshNodePolicy;
584
594
  /**
585
595
  * Per-node instruction surfaced in the coordinator prompt so the LLM
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.446",
3
+ "version": "0.9.82-rc.447",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "author": "vilmire",
47
47
  "license": "AGPL-3.0-or-later",
48
48
  "dependencies": {
49
- "@adhdev/mesh-shared": "0.9.82-rc.446",
49
+ "@adhdev/mesh-shared": "0.9.82-rc.447",
50
50
  "@adhdev/session-host-core": "*",
51
51
  "@agentclientprotocol/sdk": "^0.16.1",
52
52
  "ajv": "^8.20.0",
@@ -180,6 +180,13 @@ export const meshStatusHandlers: Record<string, HighFamilyHandler> = {
180
180
  const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
181
181
 
182
182
  const localMachineId = loadConfig().machineId || '';
183
+ // Local daemon's operator-set nickname — stamped onto the self/base
184
+ // node at render time so the friendly label resolves even before the
185
+ // persisted node record (addNode) has been rewritten with it.
186
+ const localMachineNickname = (() => {
187
+ const nick = loadConfig().machineNickname;
188
+ return typeof nick === 'string' && nick.trim() ? nick.trim() : '';
189
+ })();
183
190
  const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
184
191
  // Shared probe gate for this mesh_status call: the bootstrap
185
192
  // hydrate below and the per-node render loop further down both
@@ -302,6 +309,14 @@ export const meshStatusHandlers: Record<string, HighFamilyHandler> = {
302
309
  daemonId && (daemonIdsEquivalent(daemonId, localMachineId) || daemonIdsEquivalent(daemonId, ctx.deps.statusInstanceId)),
303
310
  ) || Boolean(meshRecord?.inline && nodeIndex === 0)
304
311
  || sparseConfiguredCoordinatorNode;
312
+ // The self/base node's friendly label comes from THIS daemon's
313
+ // local config.machineNickname. Stamp it onto the node record (if
314
+ // not already carried) so buildMeshNodeDisplayLabel below resolves
315
+ // to the nickname and labelSource reads 'explicit_metadata' even
316
+ // before addNode's persisted record has been rewritten.
317
+ if (isSelfNode && localMachineNickname && !readStringValue(node.machineNickname, node.machine_nickname)) {
318
+ node.machineNickname = localMachineNickname;
319
+ }
305
320
  const machineIdentity = buildMeshNodeMachineIdentity(node as Record<string, unknown>, {
306
321
  localMachineId,
307
322
  localDaemonId: ctx.deps.statusInstanceId,
@@ -10,7 +10,7 @@ import { existsSync, readFileSync, writeFileSync } from 'fs';
10
10
  import { join } from 'path';
11
11
  import { randomBytes, randomUUID } from 'crypto';
12
12
  import { shortHash } from '../system/hash.js';
13
- import { getConfigDir } from './config.js';
13
+ import { getConfigDir, loadConfig } from './config.js';
14
14
  import type {
15
15
  LocalMeshConfig,
16
16
  LocalMeshEntry,
@@ -492,6 +492,11 @@ export interface AddNodeOptions {
492
492
  clonedFromNodeId?: string;
493
493
  worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
494
494
  role?: RepoMeshDaemonRole;
495
+ /** Owning daemon's machine nickname. Defaults to this daemon's local
496
+ * config.machineNickname when omitted — a node is always added by (and on)
497
+ * the daemon that owns its workspace (self/base node or a local worktree
498
+ * clone), so the local config is the correct source. */
499
+ machineNickname?: string;
495
500
  }
496
501
 
497
502
  export function addNode(meshId: string, opts: AddNodeOptions): LocalMeshNodeEntry | undefined {
@@ -508,12 +513,27 @@ export function addNode(meshId: string, opts: AddNodeOptions): LocalMeshNodeEntr
508
513
  throw new Error('This workspace is already in the mesh');
509
514
  }
510
515
 
516
+ // A node is always added by the daemon that owns its workspace (the self/base
517
+ // node, or a local worktree clone spawned from this daemon), so this daemon's
518
+ // config.machineNickname is the correct owner nickname. Explicit opt wins.
519
+ const machineNickname = (() => {
520
+ const explicit = typeof opts.machineNickname === 'string' ? opts.machineNickname.trim() : '';
521
+ if (explicit) return explicit;
522
+ try {
523
+ const local = loadConfig().machineNickname;
524
+ return typeof local === 'string' && local.trim() ? local.trim() : undefined;
525
+ } catch {
526
+ return undefined;
527
+ }
528
+ })();
529
+
511
530
  const node: LocalMeshNodeEntry = {
512
531
  id: `node_${randomUUID().replace(/-/g, '')}`,
513
532
  workspace: opts.workspace.trim(),
514
533
  repoRoot: opts.repoRoot,
515
534
  daemonId: opts.daemonId,
516
535
  machineId: opts.machineId,
536
+ ...(machineNickname ? { machineNickname } : {}),
517
537
  capabilities: normalizeCapabilityTags(opts.capabilities),
518
538
  userOverrides: opts.userOverrides || {},
519
539
  policy: opts.policy || {},
@@ -559,6 +579,10 @@ export function updateNode(
559
579
  * operator intent) so capability-tag os=/arch= self-heals across loads. */
560
580
  reportedPlatform?: string;
561
581
  reportedArch?: string;
582
+ /** Owning daemon's self-reported machine nickname, carried on the
583
+ * git_status envelope. Persisted so the friendly label survives across
584
+ * coordinator restarts (mirrors reportedPlatform/reportedArch). */
585
+ reportedMachineNickname?: string;
562
586
  },
563
587
  ): LocalMeshNodeEntry | undefined {
564
588
  const config = loadMeshConfig();
@@ -571,6 +595,7 @@ export function updateNode(
571
595
  if (opts.userOverrides) node.userOverrides = { ...node.userOverrides, ...opts.userOverrides };
572
596
  if (opts.reportedPlatform && opts.reportedPlatform.trim()) node.reportedPlatform = opts.reportedPlatform.trim();
573
597
  if (opts.reportedArch && opts.reportedArch.trim()) node.reportedArch = opts.reportedArch.trim();
598
+ if (opts.reportedMachineNickname && opts.reportedMachineNickname.trim()) node.machineNickname = opts.reportedMachineNickname.trim();
574
599
  if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
575
600
  if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
576
601
  if (Object.prototype.hasOwnProperty.call(opts, 'systemPrompt')) {
@@ -4,6 +4,7 @@ import { getGitDiffSummary, getGitFileDiff } from './git-diff.js';
4
4
  import { GitCommandError, isPathInside, resolveGitRepository, runGit } from './git-executor.js';
5
5
  import { createGitSnapshotStore } from './git-snapshot-store.js';
6
6
  import { getGitRepoStatus } from './git-status.js';
7
+ import { loadConfig } from '../config/config.js';
7
8
  import type {
8
9
  GitCommandName,
9
10
  GitDiffSummary,
@@ -113,7 +114,9 @@ type GitCommandSuccess =
113
114
  // reporterPlatform/reporterArch carry the responding daemon's process.platform/
114
115
  // process.arch so a mesh coordinator probing this node over P2P can self-heal the
115
116
  // node's userOverrides.platform/arch (the fields capability-tag routing reads).
116
- | { success: true; status: GitRepoStatus; reporterPlatform?: string; reporterArch?: string }
117
+ // reporterMachineNickname carries the responding daemon's config.machineNickname
118
+ // so the coordinator can populate node.machineNickname → the friendly display label.
119
+ | { success: true; status: GitRepoStatus; reporterPlatform?: string; reporterArch?: string; reporterMachineNickname?: string }
117
120
  | { success: true; diffSummary: GitDiffSummary }
118
121
  | { success: true; diff: GitFileDiff }
119
122
  | { success: true; snapshot: GitSnapshot }
@@ -315,7 +318,23 @@ export async function handleGitCommand(
315
318
  // stamps it onto the node's userOverrides.platform/arch (the fields
316
319
  // buildMeshNodeCapabilityTags reads). These are siblings of `status`, not
317
320
  // part of GitRepoStatus, so the git payload shape is untouched.
318
- return { success: true, status, reporterPlatform: process.platform, reporterArch: process.arch };
321
+ // The machine nickname rides the same channel so the coordinator can render
322
+ // this node's friendly label instead of a raw daemonId/nodeId.
323
+ const reporterMachineNickname = (() => {
324
+ try {
325
+ const nick = loadConfig().machineNickname;
326
+ return typeof nick === 'string' && nick.trim() ? nick.trim() : undefined;
327
+ } catch {
328
+ return undefined;
329
+ }
330
+ })();
331
+ return {
332
+ success: true,
333
+ status,
334
+ reporterPlatform: process.platform,
335
+ reporterArch: process.arch,
336
+ ...(reporterMachineNickname ? { reporterMachineNickname } : {}),
337
+ };
319
338
  }
320
339
 
321
340
  case 'git_diff_summary': {
@@ -319,9 +319,9 @@ export function recordInlineMeshDirectGitTruth(
319
319
  node: any,
320
320
  git: Record<string, unknown>,
321
321
  source: 'selected_coordinator_local_git' | 'selected_coordinator_mesh_p2p_git',
322
- ): { reporterPlatform: string | null; reporterArch: string | null } {
322
+ ): { reporterPlatform: string | null; reporterArch: string | null; reporterMachineNickname: string | null } {
323
323
  if (!node || typeof node !== 'object' || Array.isArray(node)) {
324
- return { reporterPlatform: null, reporterArch: null };
324
+ return { reporterPlatform: null, reporterArch: null, reporterMachineNickname: null };
325
325
  }
326
326
  const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
327
327
  const updatedAt = new Date(checkedAt).toISOString();
@@ -359,7 +359,14 @@ export function recordInlineMeshDirectGitTruth(
359
359
  // for an inline/cache mesh this keeps the runtime object self-consistent.
360
360
  if (reporterPlatform) node.reportedPlatform = reporterPlatform;
361
361
  if (reporterArch) node.reportedArch = reporterArch;
362
- return { reporterPlatform, reporterArch };
362
+ // Machine nickname: only a remote member self-reports it (reporterMachineNickname
363
+ // rides the git_status envelope). For a local_source probe the workspace lives on
364
+ // THIS machine, but the self/base node already carries the local config nickname
365
+ // (addNode stamps it), so we only stamp from an explicit report here — never
366
+ // overwrite an existing nickname with an empty value.
367
+ const reporterMachineNickname = readStringValue(git.reporterMachineNickname) ?? null;
368
+ if (reporterMachineNickname) node.machineNickname = reporterMachineNickname;
369
+ return { reporterPlatform, reporterArch, reporterMachineNickname };
363
370
  }
364
371
 
365
372
  /**
@@ -396,16 +403,17 @@ export function persistNodeReporterPlatform(
396
403
  meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config',
397
404
  mesh: any,
398
405
  nodeId: string | undefined,
399
- reporter: { reporterPlatform: string | null; reporterArch: string | null },
406
+ reporter: { reporterPlatform: string | null; reporterArch: string | null; reporterMachineNickname?: string | null },
400
407
  ): void {
401
408
  if (meshSource !== 'local_config') return;
402
409
  const meshId = readStringValue(mesh?.id);
403
410
  if (!meshId || !nodeId) return;
404
411
  const reportedPlatform = reporter.reporterPlatform ?? undefined;
405
412
  const reportedArch = reporter.reporterArch ?? undefined;
406
- if (!reportedPlatform && !reportedArch) return;
413
+ const reportedMachineNickname = reporter.reporterMachineNickname ?? undefined;
414
+ if (!reportedPlatform && !reportedArch && !reportedMachineNickname) return;
407
415
  void import('../config/mesh-config.js')
408
- .then(({ updateNode }) => updateNode(meshId, nodeId, { reportedPlatform, reportedArch }))
416
+ .then(({ updateNode }) => updateNode(meshId, nodeId, { reportedPlatform, reportedArch, reportedMachineNickname }))
409
417
  .catch(() => { /* best-effort self-heal; never block status assembly */ });
410
418
  }
411
419
 
@@ -1409,9 +1417,11 @@ async function probeRemoteMeshGitStatus(args: {
1409
1417
  // persist them to node.userOverrides without touching the git status shape.
1410
1418
  const reporterPlatform = readStringValue(remoteResult?.reporterPlatform);
1411
1419
  const reporterArch = readStringValue(remoteResult?.reporterArch);
1420
+ const reporterMachineNickname = readStringValue(remoteResult?.reporterMachineNickname);
1412
1421
  const git = remoteGit as Record<string, unknown>;
1413
1422
  if (reporterPlatform) git.reporterPlatform = reporterPlatform;
1414
1423
  if (reporterArch) git.reporterArch = reporterArch;
1424
+ if (reporterMachineNickname) git.reporterMachineNickname = reporterMachineNickname;
1415
1425
  return git;
1416
1426
  }
1417
1427
 
@@ -849,6 +849,16 @@ export interface LocalMeshNodeEntry {
849
849
  */
850
850
  reportedPlatform?: string;
851
851
  reportedArch?: string;
852
+ /**
853
+ * The operator-set machine nickname (config.machineNickname) of the daemon
854
+ * that owns this node's workspace. The local coordinator stamps its own
855
+ * config value onto its self/base node; a remote member self-reports its
856
+ * value on the git_status envelope (reporterMachineNickname), which the
857
+ * coordinator persists here on each direct git probe. Feeds
858
+ * buildMeshNodeDisplayLabel so the mesh UI renders the friendly nickname
859
+ * instead of a raw daemonId/nodeId. Absent until set/first-reported.
860
+ */
861
+ machineNickname?: string;
852
862
  policy: RepoMeshNodePolicy;
853
863
  /**
854
864
  * Per-node instruction surfaced in the coordinator prompt so the LLM