@adhdev/daemon-core 0.9.82-rc.95 → 0.9.82-rc.97

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.95",
3
+ "version": "0.9.82-rc.97",
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",
@@ -25,7 +25,7 @@ const RECENT_SEND_WINDOW_MS = 1200;
25
25
  export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
26
26
  const HERMES_CLI_STARTING_SEND_SETTLE_MS = 2_000;
27
27
  const CLI_NATIVE_HISTORY_FRESH_MS = 5 * 60_000;
28
- const CLI_NATIVE_TRANSCRIPT_PROVIDERS = new Set(['codex-cli', 'claude-cli', 'hermes-cli']);
28
+ const CLI_NATIVE_TRANSCRIPT_PROVIDERS = new Set(['codex-cli', 'claude-cli', 'hermes-cli', 'antigravity-cli']);
29
29
  const recentSendByTarget = new Map<string, number>();
30
30
 
31
31
  interface ApprovalSelectableInstance extends ProviderInstance {
@@ -55,7 +55,7 @@ import { getSessionCompletionMarker } from '../status/snapshot.js';
55
55
  import { execNpmCommandSync, resolveCurrentGlobalInstallSurface, spawnDetachedDaemonUpgradeHelper } from './upgrade-helper.js';
56
56
  import { getMeshQueueRevision } from '../mesh/mesh-work-queue.js';
57
57
  import type { RepoMeshSessionCleanupMode } from '../repo-mesh-types.js';
58
- import { homedir } from 'os';
58
+ import { homedir, hostname as osHostname } from 'os';
59
59
  import { basename as pathBasename, join as pathJoin, resolve as pathResolve } from 'path';
60
60
  import * as fs from 'fs';
61
61
 
@@ -235,13 +235,136 @@ function buildMeshNodeDisplayLabel(node: Record<string, unknown>, nodeId: string
235
235
  if (explicit) return explicit;
236
236
  const workspace = readStringValue(node.workspace, node.repoRoot, node.repo_root);
237
237
  const workspaceName = workspace ? pathBasename(workspace) : undefined;
238
- const host = readStringValue(node.hostname, node.host, node.daemonId, node.daemon_id, node.machineId, node.machine_id);
238
+ const host = readStringValue(node.machineName, node.machine_name, node.hostname, node.host, node.daemonId, node.daemon_id, node.machineId, node.machine_id);
239
239
  const provider = providerPriority[0] || (Array.isArray(node.providers) ? readStringValue(...node.providers) : undefined);
240
240
  const parts = [workspaceName, host, provider].filter(Boolean);
241
241
  if (parts.length > 0) return parts.join(' · ');
242
242
  return nodeId || 'unidentified mesh node';
243
243
  }
244
244
 
245
+ function normalizeMeshHostname(value: unknown): string | undefined {
246
+ const hostname = readStringValue(value);
247
+ if (!hostname) return undefined;
248
+ return hostname.toLowerCase().replace(/\.$/, '');
249
+ }
250
+
251
+ function readMeshNodeMachineId(node: Record<string, unknown>): string | undefined {
252
+ return readStringValue(
253
+ node.machineId,
254
+ node.machine_id,
255
+ readObjectRecord(node.machine)?.id,
256
+ readObjectRecord(node.machine)?.machineId,
257
+ readObjectRecord(node.lastProbe)?.machineId,
258
+ readObjectRecord(node.last_probe)?.machine_id,
259
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.id,
260
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.machineId,
261
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.id,
262
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.machine_id,
263
+ );
264
+ }
265
+
266
+ function readMeshNodeDaemonId(node: Record<string, unknown>): string | undefined {
267
+ return readStringValue(
268
+ node.daemonId,
269
+ node.daemon_id,
270
+ readObjectRecord(node.machine)?.daemonId,
271
+ readObjectRecord(node.machine)?.daemon_id,
272
+ readObjectRecord(node.lastProbe)?.daemonId,
273
+ readObjectRecord(node.last_probe)?.daemon_id,
274
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.daemonId,
275
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.daemon_id,
276
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.daemonId,
277
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.daemon_id,
278
+ );
279
+ }
280
+
281
+ function readMeshNodeHostname(node: Record<string, unknown>): string | undefined {
282
+ return readStringValue(
283
+ node.hostname,
284
+ node.host,
285
+ node.machineHostname,
286
+ node.machine_hostname,
287
+ readObjectRecord(node.machine)?.hostname,
288
+ readObjectRecord(node.machine)?.host,
289
+ readObjectRecord(node.lastProbe)?.hostname,
290
+ readObjectRecord(node.last_probe)?.hostname,
291
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.hostname,
292
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.hostname,
293
+ );
294
+ }
295
+
296
+ function readMeshNodeDisplayMachineName(node: Record<string, unknown>): string | undefined {
297
+ return readStringValue(
298
+ node.machineName,
299
+ node.machine_name,
300
+ node.machineLabel,
301
+ node.machine_label,
302
+ node.machineNickname,
303
+ node.machine_nickname,
304
+ node.alias,
305
+ readObjectRecord(node.machine)?.name,
306
+ readObjectRecord(node.machine)?.displayName,
307
+ readObjectRecord(node.machine)?.display_name,
308
+ readObjectRecord(node.lastProbe)?.machineName,
309
+ readObjectRecord(node.last_probe)?.machine_name,
310
+ readObjectRecord(readObjectRecord(node.lastProbe)?.machine)?.name,
311
+ readObjectRecord(readObjectRecord(node.last_probe)?.machine)?.name,
312
+ readMeshNodeHostname(node),
313
+ );
314
+ }
315
+
316
+ function compactMeshIdentityEvidence(value: string | undefined): string | undefined {
317
+ if (!value) return undefined;
318
+ return value.length > 24 ? `${value.slice(0, 12)}…${value.slice(-8)}` : value;
319
+ }
320
+
321
+ function buildMeshNodeMachineIdentity(node: Record<string, unknown>, opts: {
322
+ localMachineId?: string;
323
+ localDaemonId?: string;
324
+ coordinatorHostname?: string;
325
+ isSelfNode?: boolean;
326
+ }): Record<string, unknown> {
327
+ const machineId = readMeshNodeMachineId(node);
328
+ const daemonId = readMeshNodeDaemonId(node);
329
+ const hostname = readMeshNodeHostname(node);
330
+ const machineName = readMeshNodeDisplayMachineName(node);
331
+ const coordinatorHostname = readStringValue(opts.coordinatorHostname);
332
+ const machineIdMatches = Boolean(opts.localMachineId && machineId && opts.localMachineId === machineId);
333
+ const daemonIdMatches = Boolean(opts.localDaemonId && daemonId && opts.localDaemonId === daemonId);
334
+ const hostnameMatches = Boolean(
335
+ normalizeMeshHostname(hostname)
336
+ && normalizeMeshHostname(coordinatorHostname)
337
+ && normalizeMeshHostname(hostname) === normalizeMeshHostname(coordinatorHostname),
338
+ );
339
+ const sameMachine = opts.isSelfNode === true || machineIdMatches || daemonIdMatches || hostnameMatches;
340
+ const evidence: string[] = [];
341
+ for (const [label, value] of [['machineName', machineName], ['hostname', hostname], ['machineId', machineId], ['daemonId', daemonId]] as const) {
342
+ const compact = compactMeshIdentityEvidence(value);
343
+ if (compact) evidence.push(`${label}:${compact}`);
344
+ }
345
+ const locality = sameMachine ? 'same_machine' : (evidence.length > 0 ? 'remote_known' : 'remote_or_unknown');
346
+ const localityReason = sameMachine
347
+ ? (machineIdMatches ? 'matched coordinator machine id'
348
+ : daemonIdMatches ? 'matched coordinator daemon id'
349
+ : hostnameMatches ? 'matched coordinator hostname'
350
+ : 'selected coordinator node')
351
+ : evidence.length > 0
352
+ ? `known remote/other machine identity; no local coordinator match (${evidence.join(', ')})`
353
+ : 'no useful machine identity evidence available';
354
+ return {
355
+ daemonId,
356
+ machineId,
357
+ hostname,
358
+ machineName,
359
+ displayName: machineName || hostname || daemonId || machineId,
360
+ coordinatorHostname,
361
+ sameMachine,
362
+ locality,
363
+ localityReason,
364
+ identityEvidence: evidence,
365
+ };
366
+ }
367
+
245
368
  function normalizeInlineMeshGitStatus(
246
369
  status: Record<string, unknown>,
247
370
  node: any,
@@ -5115,6 +5238,7 @@ export class DaemonCommandRouter {
5115
5238
  return failureResult;
5116
5239
  }
5117
5240
  const directTruthUnavailableNodeIds = new Set(effectiveDirectTruth.unavailableNodeIds);
5241
+ const coordinatorHostname = osHostname();
5118
5242
  const selectedCoordinatorNodeId = readStringValue(
5119
5243
  mesh.coordinator?.preferredNodeId,
5120
5244
  (mesh.nodes?.[0] as any)?.id,
@@ -5134,6 +5258,12 @@ export class DaemonCommandRouter {
5134
5258
  ) || Boolean(
5135
5259
  daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId),
5136
5260
  ) || Boolean(meshRecord?.inline && nodeIndex === 0);
5261
+ const machineIdentity = buildMeshNodeMachineIdentity(node as Record<string, unknown>, {
5262
+ localMachineId,
5263
+ localDaemonId: this.deps.statusInstanceId,
5264
+ coordinatorHostname,
5265
+ isSelfNode,
5266
+ });
5137
5267
  const status: Record<string, unknown> = {
5138
5268
  nodeId,
5139
5269
  machineLabel: buildMeshNodeDisplayLabel(node as Record<string, unknown>, nodeId, providerPriority),
@@ -5146,7 +5276,8 @@ export class DaemonCommandRouter {
5146
5276
  worktreeBranch: node.worktreeBranch,
5147
5277
  role: normalizeMeshDaemonRole(node.role) || (meshHost.hostNodeId && nodeId === meshHost.hostNodeId ? 'host' : undefined),
5148
5278
  daemonId,
5149
- machineId: node.machineId,
5279
+ machineId: readMeshNodeMachineId(node as Record<string, unknown>) || node.machineId,
5280
+ machine: machineIdentity,
5150
5281
  machineStatus: node.machineStatus,
5151
5282
  health: 'unknown',
5152
5283
  providers: node.providers || [],
@@ -182,7 +182,7 @@ const WORKFLOW_SECTION = `## Orchestration Workflow
182
182
  c. **Targeted Tasks**: Use \`mesh_send_task\` only when you need to bypass the queue and force a specific node to execute a task immediately.
183
183
  d. For the first dispatch of a new task, provide a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
184
184
  e. For a continuation of the same issue in an existing session, send a concise **delta instruction**: current verified state, the exact failed/blocked step, the newly approved action, and final reporting requirements. Do not resend the full original task or open a new chat solely to continue the same work; that wastes coordinator and worker context.
185
- 4. **Monitor** — Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Use \`mesh_view_queue\` to see the status of all pending, assigned, completed, and failed tasks. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal. Handle approvals via \`mesh_approve\`.
185
+ 4. **Monitor** — Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Do **not** repeatedly call \`mesh_status\` or \`mesh_view_queue\` just to wait for assigned/generating work. After dispatching a direct or queued task, send one progress update with the task/session handle, then stop. Wait for \`pendingCoordinatorEvents\` or another completion/approval/status signal, an explicit user status request, or a real timeout/stall signal before reading status/chat/queue again. Use at most one compact \`mesh_read_chat\` check after a terminal signal. Handle approvals via \`mesh_approve\`.
186
186
  5. **Verify** — When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
187
187
  6. **Checkpoint** — Call \`mesh_checkpoint\` to save the work.
188
188
  7. **Converge branches** — Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe. Before/refine merging root commits that contain submodule gitlink changes, require each submodule commit to be reachable from the configured submodule remote main branch, not merely present on a feature ref or local checkout. If \`mesh_refine_node\` returns \`submodule_reachability_failed\` or publish-required evidence, keep the public convergence bucket as \`blocked_review\`; unless \`allowAutoPublishSubmoduleMainCommits\` is explicitly enabled and Refinery reports successful non-force publish plus post-publish verification, ask the user for explicit approval to push/publish the unreachable submodule commit(s) to submodule main, then rerun \`mesh_refine_node\`. Do not merge the root branch until the submodule commit(s) are reachable from submodule origin/main. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.