@adhdev/daemon-core 0.9.82-rc.366 → 0.9.82-rc.367

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.
@@ -6,6 +6,33 @@ import type { CommandResult, CommandHelpers } from './handler.js';
6
6
  import { type InputEnvelope } from '../providers/contracts.js';
7
7
  export declare const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25000;
8
8
  export declare function buildSendInputSignature(input: InputEnvelope): string;
9
+ /**
10
+ * read_chat node scope verdict. One physical daemon hosts a base node plus several
11
+ * worktree nodes; mesh_read_chat always dispatches read_chat with the requested
12
+ * node's workspace (`args.workspace`). When the resolved target session actually
13
+ * lives in a DIFFERENT worktree, returning its transcript — or worse, letting the
14
+ * native-history-by-workspace fallback splice sibling worktree turns into the
15
+ * reply — makes the coordinator believe one session received every worktree's
16
+ * work. This guard refuses a CONFIRMED cross-workspace read instead of mixing.
17
+ *
18
+ * Conservative by design (mirrors the WTCLAIM fix-B "unknown → allow" rule): only
19
+ * a session id that resolves to a known workspace which is unequal to a known
20
+ * intended workspace blocks. When either side is unknown — no targetSessionId, no
21
+ * args.workspace, an unregistered session, the coordinator self-session, or a
22
+ * plain dashboard read that never passes a node workspace — the read proceeds
23
+ * untouched, so base-node and same-daemon coordinator reads never regress.
24
+ */
25
+ export declare function evaluateReadChatNodeWorkspaceScope(args: {
26
+ targetSessionId?: string;
27
+ intendedWorkspace?: string;
28
+ sessionWorkspace?: string;
29
+ }): {
30
+ scoped: false;
31
+ } | {
32
+ scoped: true;
33
+ intended: string;
34
+ actual: string;
35
+ };
9
36
  interface DebugSanitizeOptions {
10
37
  maxDepth?: number;
11
38
  maxArrayLength?: number;
@@ -86,6 +86,7 @@ export declare function finalizeMeshNodeStatus(args: {
86
86
  }): void;
87
87
  export declare const MESH_DIRECT_PROBE_TIMEOUT_MS: number;
88
88
  export declare const MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS: number;
89
+ export declare const MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS: number;
89
90
  /**
90
91
  * De-duplicates and rate-limits per-peer git_status probes so a single mesh
91
92
  * refresh — or a burst of refreshes from the dashboard auto-retry loop — cannot
@@ -116,6 +117,37 @@ export declare class MeshGitProbeCache {
116
117
  */
117
118
  probe(daemonId: string, workspace: string, probe: () => Promise<Record<string, unknown> | null>): Promise<Record<string, unknown> | null>;
118
119
  }
120
+ /**
121
+ * Await `work` under a warmup-aware deadline so a cold-open DataChannel handshake
122
+ * is NOT charged against the command response budget — the root cause of the
123
+ * "first mesh probe to a cold peer false-times-out, the warm retry succeeds"
124
+ * signature. Two budgets, switched by the live peer connection state:
125
+ *
126
+ * - While `isConnected()` returns false the peer's channel is still opening; the
127
+ * cold-open `connectTimeoutMs` budget applies. This phase is deliberately
128
+ * generous because a TURN-relayed cross-machine handshake legitimately needs
129
+ * many seconds — but a genuine connect *failure* is surfaced by `work`
130
+ * rejecting on its own (the mesh manager fails the peer the instant its
131
+ * PeerConnection state goes terminal), so a real failure is never masked for
132
+ * the whole window.
133
+ * - The first time `isConnected()` returns true the channel is warm; from that
134
+ * instant the tight `responseTimeoutMs` governs how long the handler may take.
135
+ * Warm-channel callers therefore see behavior identical to the old single
136
+ * `Promise.race(work, responseTimeoutMs)`.
137
+ *
138
+ * Rejects with `Error('timeout')` when either budget is exhausted, mirroring the
139
+ * previous single-race contract. Pure except for timers + the injected
140
+ * `isConnected` probe, so it is unit-testable under fake timers without any real
141
+ * WebRTC. When no connection getter is wired `isConnected` should be `() => true`
142
+ * (the caller's choice) so the response deadline governs from t0 — the legacy
143
+ * single-budget behavior, never a combined connect+response window.
144
+ */
145
+ export declare function awaitWithWarmupDeadline<T>(work: Promise<T>, opts: {
146
+ isConnected: () => boolean;
147
+ connectTimeoutMs: number;
148
+ responseTimeoutMs: number;
149
+ pollIntervalMs?: number;
150
+ }): Promise<T>;
119
151
  /**
120
152
  * Probe a remote peer's git_status with a bounded retry budget, but only while
121
153
  * the peer is reported `connected`. A single slow (often TURN-relayed) peer can
@@ -136,6 +168,8 @@ export declare function probeRemoteMeshGitStatusWithRetry(args: {
136
168
  timeoutMs: number;
137
169
  /** Per-attempt timeout for retries (attempts > 0); defaults to timeoutMs. */
138
170
  retryTimeoutMs?: number;
171
+ /** Cold-open warmup budget per attempt; defaults to MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS. */
172
+ connectTimeoutMs?: number;
139
173
  getConnection?: (daemonId: string) => Record<string, unknown> | null;
140
174
  onConnection?: (connection: Record<string, unknown>) => void;
141
175
  }): Promise<Record<string, unknown> | null>;
package/dist/index.js CHANGED
@@ -316,10 +316,10 @@ function readInjected(value) {
316
316
  }
317
317
  function getDaemonBuildInfo() {
318
318
  if (cached) return cached;
319
- const commit = readInjected(true ? "c2224ab0c9d05e85b4cbf88e4fc696f3733ec397" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "c2224ab0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.366" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-24T02:22:36.214Z" : void 0);
319
+ const commit = readInjected(true ? "bb7e66dbc483232a27d1de42cf8ecba3eb0a818c" : void 0) ?? "unknown";
320
+ const commitShort = readInjected(true ? "bb7e66db" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
+ const version = readInjected(true ? "0.9.82-rc.367" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
+ const builtAt = readInjected(true ? "2026-06-24T04:45:13.384Z" : void 0);
323
323
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
324
  return cached;
325
325
  }
@@ -2903,6 +2903,16 @@ function meshNodeIdMatches(node, candidateId) {
2903
2903
  if (!trimmed) return false;
2904
2904
  return normalizeMeshNodeId(node) === trimmed;
2905
2905
  }
2906
+ function normalizeMeshWorkspaceForCompare(dir) {
2907
+ if (typeof dir !== "string") return "";
2908
+ return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
2909
+ }
2910
+ function meshWorkspacesEquivalent(a, b) {
2911
+ const left = normalizeMeshWorkspaceForCompare(a);
2912
+ const right = normalizeMeshWorkspaceForCompare(b);
2913
+ if (!left || !right) return false;
2914
+ return left === right;
2915
+ }
2906
2916
  function machineCoreFromDaemonId(id) {
2907
2917
  const trimmed = readString3(id);
2908
2918
  if (!trimmed) return void 0;
@@ -12856,10 +12866,6 @@ function deliverTaskToSession(dispatchThunk, ctx) {
12856
12866
  }
12857
12867
  });
12858
12868
  }
12859
- function normalizeMeshWorkspaceForCompare(dir) {
12860
- if (typeof dir !== "string") return "";
12861
- return dir.trim().replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
12862
- }
12863
12869
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
12864
12870
  const mesh = getMeshWithCache(components, meshId);
12865
12871
  const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
@@ -13711,7 +13717,10 @@ function injectMeshSystemMessage(components, args) {
13711
13717
  if (terminal?.kind === "task_completed" && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
13712
13718
  const newDispatchAfterTerminal = hasDispatchAfterTerminal(args.meshId, eventSessionId, terminal.id);
13713
13719
  const supersedesWeakTerminal = isWeakTerminalLedgerPayload(terminal.payload) && isGenuineCompletionEvidence(args.metadataEvent);
13714
- if (!newDispatchAfterTerminal && !supersedesWeakTerminal) {
13720
+ const terminalTaskId = readNonEmptyString2(terminal.payload.taskId);
13721
+ const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId);
13722
+ const distinctTaskCompletion = !!eventTaskId && !!terminalTaskId && eventTaskId !== terminalTaskId;
13723
+ if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion) {
13715
13724
  const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
13716
13725
  const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
13717
13726
  const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
@@ -14157,6 +14166,16 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
14157
14166
  nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId) || void 0,
14158
14167
  workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
14159
14168
  };
14169
+ const selfDaemonIds = resolveCoordinatorDrainDaemonIds(components);
14170
+ if (selfDaemonIds.some((self) => daemonIdsEquivalent(self, coordinatorDaemonId))) {
14171
+ try {
14172
+ handleMeshForwardEvent(components, payload);
14173
+ LOG.info("MeshEvents", `Self-addressed unresolved-delegate ${eventName} routed via local router (coordinator ${coordinatorDaemonId} is self) \u2014 outbox skipped`);
14174
+ } catch (e) {
14175
+ LOG.warn("MeshEvents", `Local route of self-addressed unresolved-delegate ${eventName} failed: ${e?.message || e}`);
14176
+ }
14177
+ return true;
14178
+ }
14160
14179
  const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
14161
14180
  const fwdTraceCtx = {
14162
14181
  taskId: payload.taskId,
@@ -14665,6 +14684,8 @@ async function retryUnresolvedDelegateForwards(components) {
14665
14684
  expireStaleUnresolvedDelegateForwards();
14666
14685
  const entries = peekUnresolvedDelegateForwards();
14667
14686
  if (entries.length === 0) return;
14687
+ const selfIds = resolveCoordinatorDaemonIds(components);
14688
+ const isSelfCoordinatorId = (id) => selfIds.some((self) => daemonIdsEquivalent(self, id));
14668
14689
  for (const entry of entries) {
14669
14690
  const entryTraceCtx = {
14670
14691
  taskId: entry.payload.taskId,
@@ -14672,6 +14693,23 @@ async function retryUnresolvedDelegateForwards(components) {
14672
14693
  nodeId: readNonEmptyString2(entry.payload.nodeId),
14673
14694
  event: readNonEmptyString2(entry.payload.event)
14674
14695
  };
14696
+ if (isSelfCoordinatorId(entry.coordinatorDaemonId)) {
14697
+ let localResult;
14698
+ try {
14699
+ traceMeshEventStage("forward_send", entryTraceCtx, `self \u2192 local router (${entry.coordinatorDaemonId})`);
14700
+ localResult = handleMeshForwardEvent(components, entry.payload);
14701
+ } catch (e) {
14702
+ LOG.warn("MeshReconcile", `Local route of self-addressed forward to ${entry.coordinatorDaemonId} threw: ${e?.message || e} \u2014 draining anyway to break the retry loop`);
14703
+ }
14704
+ ackUnresolvedDelegateForward(entry.id);
14705
+ if (localResult && localResult.success === false) {
14706
+ LOG.warn("MeshReconcile", `Self-addressed unresolved-delegate ${readNonEmptyString2(entry.payload.event)} rejected by local router (${readNonEmptyString2(localResult.error) || "no reason"}) \u2014 drained to break the self-forward retry loop`);
14707
+ traceMeshEventDrop("self_forward_local_rejected", entryTraceCtx, readNonEmptyString2(localResult.error) || "no reason");
14708
+ } else {
14709
+ LOG.info("MeshReconcile", `Self-addressed unresolved-delegate ${readNonEmptyString2(entry.payload.event)} routed via local router (coordinator ${entry.coordinatorDaemonId} is self) \u2014 drained`);
14710
+ }
14711
+ continue;
14712
+ }
14675
14713
  let result;
14676
14714
  try {
14677
14715
  traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
@@ -28227,6 +28265,7 @@ var CHAT_SOURCE_REGISTRY = new ChatSourceRegistry();
28227
28265
 
28228
28266
  // src/commands/chat-commands.ts
28229
28267
  init_chat_message_normalization();
28268
+ init_dist();
28230
28269
  var RECENT_SEND_WINDOW_MS = 1200;
28231
28270
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
28232
28271
  var HOT_TAIL_MIN_LIMIT = 60;
@@ -28788,6 +28827,24 @@ function normalizeComparableWorkspace(value) {
28788
28827
  if (!text) return "";
28789
28828
  return path16.resolve(text);
28790
28829
  }
28830
+ function evaluateReadChatNodeWorkspaceScope(args) {
28831
+ const targetSessionId = typeof args.targetSessionId === "string" ? args.targetSessionId.trim() : "";
28832
+ if (!targetSessionId) return { scoped: false };
28833
+ const intended = normalizeMeshWorkspaceForCompare(args.intendedWorkspace);
28834
+ const actual = normalizeMeshWorkspaceForCompare(args.sessionWorkspace);
28835
+ if (!intended || !actual) return { scoped: false };
28836
+ if (intended === actual) return { scoped: false };
28837
+ return { scoped: true, intended, actual };
28838
+ }
28839
+ function resolveTargetSessionActualWorkspace(h, targetSessionId) {
28840
+ const registryWorkspace = h.ctx?.sessionRegistry?.get?.(targetSessionId)?.workspace;
28841
+ if (typeof registryWorkspace === "string" && registryWorkspace.trim()) return registryWorkspace;
28842
+ const adapter = h.getCliAdapter?.(targetSessionId);
28843
+ if (adapter && typeof adapter.workingDir === "string" && adapter.workingDir.trim()) return adapter.workingDir;
28844
+ const instanceWorkspace = getTargetInstance(h, { targetSessionId })?.getState?.()?.workspace;
28845
+ if (typeof instanceWorkspace === "string" && instanceWorkspace.trim()) return instanceWorkspace;
28846
+ return "";
28847
+ }
28791
28848
  function isCurrentRuntimePtySafelyAttributed(args) {
28792
28849
  if (args.adapter.cliType !== "codex-cli") return false;
28793
28850
  if (!Array.isArray(args.ptyMessages) || args.ptyMessages.length === 0) return false;
@@ -29602,6 +29659,24 @@ async function handleChatHistory(h, args) {
29602
29659
  }
29603
29660
  }
29604
29661
  async function handleReadChat(h, args) {
29662
+ {
29663
+ const guardSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
29664
+ if (guardSessionId && typeof args?.workspace === "string" && args.workspace.trim()) {
29665
+ const verdict = evaluateReadChatNodeWorkspaceScope({
29666
+ targetSessionId: guardSessionId,
29667
+ intendedWorkspace: args.workspace,
29668
+ sessionWorkspace: resolveTargetSessionActualWorkspace(h, guardSessionId)
29669
+ });
29670
+ if (verdict.scoped) {
29671
+ LOG.info("Command", `[read_chat] node scope mismatch: session ${guardSessionId} workspace "${verdict.actual}" \u2260 requested node workspace "${verdict.intended}" \u2014 refusing cross-worktree transcript`);
29672
+ return {
29673
+ success: false,
29674
+ code: "read_chat_session_node_scope_mismatch",
29675
+ error: `Session ${guardSessionId} belongs to a different worktree (workspace "${verdict.actual}") than the requested node (workspace "${verdict.intended}"). Refusing to return a cross-worktree transcript \u2014 target the node that owns this session.`
29676
+ };
29677
+ }
29678
+ }
29679
+ }
29605
29680
  let providerHint = args?.agentType || args?.providerType;
29606
29681
  if (!providerHint) {
29607
29682
  const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
@@ -29990,10 +30065,19 @@ async function handleReadChat(h, args) {
29990
30065
  ptyStatusApprovalOnly: false
29991
30066
  });
29992
30067
  if (supportsNative && !decision.nativeSelected) {
30068
+ LOG.debug("Command", `[read_chat] soft pending: no live adapter and native history not safely mappable target=${String(args?.targetSessionId || "")} provider=${agentStr} reason=native_history_not_safely_available`);
29993
30069
  return {
29994
- success: false,
30070
+ success: true,
30071
+ pending: true,
30072
+ // Both signals are true here: we reached the history-only path
30073
+ // because no live adapter was found (`live_adapter_not_found`),
30074
+ // and native history is not safely mappable
30075
+ // (`native_history_not_safely_available`).
30076
+ reason: "native_history_not_safely_available",
30077
+ reasons: ["live_adapter_not_found", "native_history_not_safely_available"],
29995
30078
  code: "native_history_not_safely_available",
29996
- error: "Provider-native history was not safely available for the requested CLI session.",
30079
+ messages: [],
30080
+ status: "idle",
29997
30081
  providerSessionId: historyProviderSessionId,
29998
30082
  messageSource: decision.messageSource,
29999
30083
  transcriptProvenance: decision.messageSource
@@ -49493,6 +49577,7 @@ function readMeshTimeoutEnvMs(name, defaultMs) {
49493
49577
  }
49494
49578
  var MESH_DIRECT_PROBE_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_TIMEOUT_MS", 25e3);
49495
49579
  var MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS", 25e3);
49580
+ var MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS", 45e3);
49496
49581
  var MESH_DIRECT_PROBE_REUSE_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_REUSE_MS", 12e3);
49497
49582
  var MeshGitProbeCache = class {
49498
49583
  constructor(reuseMs, now = Date.now) {
@@ -49530,12 +49615,73 @@ var MeshGitProbeCache = class {
49530
49615
  }
49531
49616
  }
49532
49617
  };
49618
+ function awaitWithWarmupDeadline(work, opts) {
49619
+ const pollMs = Math.max(1, Math.min(opts.pollIntervalMs ?? 200, opts.connectTimeoutMs));
49620
+ return new Promise((resolve24, reject) => {
49621
+ let done = false;
49622
+ let poll;
49623
+ let responseTimer;
49624
+ const startedAt = Date.now();
49625
+ const cleanup = () => {
49626
+ if (poll) {
49627
+ clearInterval(poll);
49628
+ poll = void 0;
49629
+ }
49630
+ if (responseTimer) {
49631
+ clearTimeout(responseTimer);
49632
+ responseTimer = void 0;
49633
+ }
49634
+ };
49635
+ const settle = (fn) => {
49636
+ if (done) return;
49637
+ done = true;
49638
+ cleanup();
49639
+ fn();
49640
+ };
49641
+ const armResponse = () => {
49642
+ if (responseTimer || done) return;
49643
+ responseTimer = setTimeout(
49644
+ () => settle(() => reject(new Error("timeout"))),
49645
+ opts.responseTimeoutMs
49646
+ );
49647
+ if (typeof responseTimer.unref === "function") responseTimer.unref();
49648
+ };
49649
+ const onPoll = () => {
49650
+ if (done) return;
49651
+ if (opts.isConnected()) {
49652
+ if (poll) {
49653
+ clearInterval(poll);
49654
+ poll = void 0;
49655
+ }
49656
+ armResponse();
49657
+ return;
49658
+ }
49659
+ if (Date.now() - startedAt >= opts.connectTimeoutMs) {
49660
+ settle(() => reject(new Error("timeout")));
49661
+ }
49662
+ };
49663
+ if (opts.isConnected()) {
49664
+ armResponse();
49665
+ } else {
49666
+ poll = setInterval(onPoll, pollMs);
49667
+ if (typeof poll.unref === "function") poll.unref();
49668
+ }
49669
+ work.then(
49670
+ (val) => settle(() => resolve24(val)),
49671
+ (err) => settle(() => reject(err))
49672
+ );
49673
+ });
49674
+ }
49533
49675
  async function probeRemoteMeshGitStatus(args) {
49534
49676
  if (!args.dispatchMeshCommand) return null;
49535
- const remoteResult = await Promise.race([
49536
- args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace, refreshUpstream: true }),
49537
- new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), args.timeoutMs))
49538
- ]);
49677
+ const dispatch = args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace, refreshUpstream: true });
49678
+ const getConnection = args.getConnection;
49679
+ const isConnected = getConnection ? () => readMeshConnectionState(getConnection(args.daemonId)) === "connected" : () => true;
49680
+ const remoteResult = await awaitWithWarmupDeadline(dispatch, {
49681
+ isConnected,
49682
+ connectTimeoutMs: args.connectTimeoutMs,
49683
+ responseTimeoutMs: args.responseTimeoutMs
49684
+ });
49539
49685
  const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
49540
49686
  if (!remoteGit || typeof remoteGit !== "object" || typeof remoteGit.isGitRepo !== "boolean") return null;
49541
49687
  const reporterPlatform = readStringValue(remoteResult?.reporterPlatform);
@@ -49570,7 +49716,9 @@ async function probeRemoteMeshGitStatusWithRetry(args) {
49570
49716
  dispatchMeshCommand: args.dispatchMeshCommand,
49571
49717
  daemonId: args.daemonId,
49572
49718
  workspace: args.workspace,
49573
- timeoutMs: attempt === 0 ? args.timeoutMs : args.retryTimeoutMs ?? args.timeoutMs
49719
+ responseTimeoutMs: attempt === 0 ? args.timeoutMs : args.retryTimeoutMs ?? args.timeoutMs,
49720
+ connectTimeoutMs: args.connectTimeoutMs ?? MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS,
49721
+ getConnection: args.getConnection
49574
49722
  });
49575
49723
  if (remoteGit) return remoteGit;
49576
49724
  } catch {
@@ -49653,6 +49801,7 @@ async function hydrateInlineMeshDirectTruth(args) {
49653
49801
  workspace,
49654
49802
  timeoutMs: MESH_DIRECT_PROBE_TIMEOUT_MS,
49655
49803
  retryTimeoutMs: MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS,
49804
+ connectTimeoutMs: MESH_DIRECT_PROBE_CONNECT_TIMEOUT_MS,
49656
49805
  getConnection: args.getMeshPeerConnectionStatus
49657
49806
  });
49658
49807
  const remoteGit = args.probeCache ? await args.probeCache.probe(daemonId, workspace, runProbe) : await runProbe();
@@ -49704,13 +49853,13 @@ function liveSessionRecordMatchesMeshNode(record, meshId, nodeId, nodeWorkspace
49704
49853
  if (!recordNodeId || recordNodeId !== nodeId) return false;
49705
49854
  if (nodeIsMissingLocalWorktree) return false;
49706
49855
  const recordWorkspace = readStringValue(record?.workspace);
49707
- if (nodeWorkspace && recordWorkspace && recordWorkspace !== nodeWorkspace) return false;
49856
+ if (nodeWorkspace && recordWorkspace && !meshWorkspacesEquivalent(recordWorkspace, nodeWorkspace)) return false;
49708
49857
  const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
49709
49858
  return !recordMeshId || recordMeshId === meshId;
49710
49859
  }
49711
49860
  function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
49712
49861
  const recordWorkspace = readStringValue(record?.workspace);
49713
- if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
49862
+ if (!recordWorkspace || !workspace || !meshWorkspacesEquivalent(recordWorkspace, workspace)) return false;
49714
49863
  const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
49715
49864
  if (recordMeshId) return recordMeshId === meshId;
49716
49865
  return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);