@adhdev/daemon-core 0.9.82-rc.116 → 0.9.82-rc.118

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.mjs CHANGED
@@ -14577,6 +14577,10 @@ var DEFAULT_APPROVAL_POSITIVE_HINTS = [
14577
14577
  function normalizeApprovalLabel(value) {
14578
14578
  return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
14579
14579
  }
14580
+ function isNegativeApprovalLabel(value) {
14581
+ const label = normalizeApprovalLabel(value);
14582
+ return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
14583
+ }
14580
14584
  function getApprovalPositiveHints(provider) {
14581
14585
  const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
14582
14586
  return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
@@ -14584,19 +14588,19 @@ function getApprovalPositiveHints(provider) {
14584
14588
  function pickApprovalButton(buttons, provider) {
14585
14589
  const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
14586
14590
  if (labels.length === 0) {
14587
- return { index: 0, label: "Approve" };
14591
+ return { index: -1, label: "" };
14588
14592
  }
14589
14593
  const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
14590
14594
  const hints = getApprovalPositiveHints(provider);
14591
14595
  for (const hint of hints) {
14592
- const exactIndex = normalizedButtons.findIndex((label) => label === hint);
14596
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
14593
14597
  if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
14594
- const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
14598
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
14595
14599
  if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
14596
- const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
14600
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
14597
14601
  if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
14598
14602
  }
14599
- return { index: 0, label: labels[0] };
14603
+ return { index: -1, label: "" };
14600
14604
  }
14601
14605
  function formatAutoApprovalMessage(modalMessage, buttonLabel) {
14602
14606
  const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
@@ -16650,6 +16654,7 @@ function buildCliMessageSourceProvenance(args) {
16650
16654
  }
16651
16655
  function buildNativeHistoryFallbackReason(args) {
16652
16656
  if (!supportsCliNativeTranscript(args.providerType, args.provider)) return "provider_native_transcript_not_supported";
16657
+ if (args.unavailableReason) return `native_history_unavailable:${args.unavailableReason}`;
16653
16658
  if (args.nativeSource === "native-unavailable") return "native_history_unavailable";
16654
16659
  if (args.nativeHistoryCoverage === "partial") return "native_history_partial";
16655
16660
  if (args.nativeHistoryCoverage === "unavailable") return "native_history_unavailable";
@@ -16724,6 +16729,15 @@ function hasSafeNativeHistoryMapping(args) {
16724
16729
  return hasOverlappingVisibleConversationText(args.nativeMessages, args.ptyMessages || []);
16725
16730
  }
16726
16731
  function readCliProviderNativeHistory(agentStr, args) {
16732
+ if (!args.historySessionId) {
16733
+ return {
16734
+ messages: [],
16735
+ hasMore: false,
16736
+ source: "native-unavailable",
16737
+ unavailableReason: "native_history_workspace_only_lookup_unsafe",
16738
+ lookup: "session"
16739
+ };
16740
+ }
16727
16741
  const sessionHistory = readProviderChatHistory(agentStr, {
16728
16742
  canonicalHistory: args.canonicalHistory,
16729
16743
  historySessionId: args.historySessionId,
@@ -16734,20 +16748,7 @@ function readCliProviderNativeHistory(agentStr, args) {
16734
16748
  historyBehavior: args.historyBehavior,
16735
16749
  scripts: args.scripts
16736
16750
  });
16737
- if (sessionHistory.source !== "native-unavailable" || args.exactSessionScoped || !args.historySessionId || !args.workspace) {
16738
- return { ...sessionHistory, lookup: args.historySessionId ? "session" : "workspace" };
16739
- }
16740
- const workspaceHistory = readProviderChatHistory(agentStr, {
16741
- canonicalHistory: args.canonicalHistory,
16742
- historySessionId: void 0,
16743
- workspace: args.workspace,
16744
- offset: args.offset,
16745
- limit: args.limit,
16746
- excludeRecentCount: args.excludeRecentCount,
16747
- historyBehavior: args.historyBehavior,
16748
- scripts: args.scripts
16749
- });
16750
- return { ...workspaceHistory, lookup: "workspace" };
16751
+ return { ...sessionHistory, lookup: "session" };
16751
16752
  }
16752
16753
  function isNativeHistoryFreshEnough(args) {
16753
16754
  const nativeNewest = getMessageNewestReceivedAt(args.nativeMessages);
@@ -17490,6 +17491,7 @@ async function handleReadChat(h, args) {
17490
17491
  provider,
17491
17492
  nativeSource: nativeHistory.source,
17492
17493
  nativeHistoryCoverage,
17494
+ unavailableReason,
17493
17495
  nativeMessageCount: nativeMessages.length,
17494
17496
  safeMapping,
17495
17497
  freshEnough
@@ -17589,6 +17591,7 @@ async function handleReadChat(h, args) {
17589
17591
  provider,
17590
17592
  nativeSource: history.source,
17591
17593
  nativeHistoryCoverage,
17594
+ unavailableReason,
17592
17595
  nativeMessageCount: historyMessages.length,
17593
17596
  safeMapping,
17594
17597
  freshEnough: true
@@ -27604,6 +27607,12 @@ function finalizeMeshNodeStatus(args) {
27604
27607
  status.launchBlockedMessage = readStringValue(bootstrap.error) || "Required worktree bootstrap failed; resolve it before launching an agent into this node.";
27605
27608
  return;
27606
27609
  }
27610
+ if (bootstrap.status === "running" && bootstrap.required !== false) {
27611
+ status.launchReady = false;
27612
+ status.launchBlockedReason = "worktree_bootstrap_running";
27613
+ status.launchBlockedMessage = "Required worktree bootstrap is still running; wait for it to finish before launching an agent into this node.";
27614
+ return;
27615
+ }
27607
27616
  }
27608
27617
  const connectionState = readStringValue(readObjectRecord(status.connection).state);
27609
27618
  status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
@@ -27704,9 +27713,12 @@ function summarizeMeshSessionRecord(record) {
27704
27713
  isCached: false
27705
27714
  };
27706
27715
  }
27707
- function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
27716
+ function liveSessionRecordMatchesMeshNode(record, meshId, nodeId, nodeWorkspace = "", nodeIsMissingLocalWorktree = false) {
27708
27717
  const recordNodeId = readStringValue(record?.meta?.meshNodeId);
27709
27718
  if (!recordNodeId || recordNodeId !== nodeId) return false;
27719
+ if (nodeIsMissingLocalWorktree) return false;
27720
+ const recordWorkspace = readStringValue(record?.workspace);
27721
+ if (nodeWorkspace && recordWorkspace && recordWorkspace !== nodeWorkspace) return false;
27710
27722
  const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
27711
27723
  return !recordMeshId || recordMeshId === meshId;
27712
27724
  }
@@ -27731,9 +27743,13 @@ function readLiveMeshNodeWorkspace(args) {
27731
27743
  return "";
27732
27744
  }
27733
27745
  function collectLiveMeshSessionRecords(args) {
27746
+ const nodeWorkspace = readStringValue(args.node?.workspace);
27747
+ const nodeIsMissingLocalWorktree = args.node?.isLocalWorktree === true && !!nodeWorkspace && !fs11.existsSync(nodeWorkspace);
27734
27748
  const matches = args.liveSessionRecords.filter((record) => {
27735
- const nodeWorkspace = readStringValue(args.node?.workspace);
27736
- if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
27749
+ const recordNodeId = readStringValue(record?.meta?.meshNodeId);
27750
+ if (recordNodeId && recordNodeId !== args.nodeId) return false;
27751
+ if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId, nodeWorkspace || "", nodeIsMissingLocalWorktree)) return true;
27752
+ if (nodeIsMissingLocalWorktree) return false;
27737
27753
  return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
27738
27754
  });
27739
27755
  if (args.allowCoordinatorSession) {
@@ -27749,11 +27765,15 @@ function collectLiveMeshSessionRecords(args) {
27749
27765
  function buildHistoricalMeshSessions(args) {
27750
27766
  const liveNodeIds = /* @__PURE__ */ new Set();
27751
27767
  const liveWorkspaces = /* @__PURE__ */ new Set();
27768
+ const missingLocalWorktreeNodeIds = /* @__PURE__ */ new Set();
27752
27769
  for (const node of args.nodes || []) {
27753
27770
  const nodeId = readStringValue(node?.id, node?.nodeId);
27754
27771
  const workspace = readStringValue(node?.workspace);
27755
27772
  if (nodeId) liveNodeIds.add(nodeId);
27756
27773
  if (workspace) liveWorkspaces.add(workspace);
27774
+ if (nodeId && node?.isLocalWorktree === true && workspace && !fs11.existsSync(workspace)) {
27775
+ missingLocalWorktreeNodeIds.add(nodeId);
27776
+ }
27757
27777
  }
27758
27778
  const sessions = [];
27759
27779
  for (const record of args.liveSessionRecords || []) {
@@ -27762,7 +27782,7 @@ function buildHistoricalMeshSessions(args) {
27762
27782
  if (recordMeshId !== args.meshId) continue;
27763
27783
  const recordNodeId = readStringValue(meta.meshNodeId);
27764
27784
  const workspace = readStringValue(record?.workspace);
27765
- const removedNode = !!recordNodeId && !liveNodeIds.has(recordNodeId);
27785
+ const removedNode = !!recordNodeId && (!liveNodeIds.has(recordNodeId) || missingLocalWorktreeNodeIds.has(recordNodeId));
27766
27786
  const orphanedWorkspace = !!workspace && !liveWorkspaces.has(workspace) && meta.meshCoordinatorFor !== args.meshId;
27767
27787
  if (!removedNode && !orphanedWorkspace) continue;
27768
27788
  sessions.push({
@@ -30953,56 +30973,113 @@ var DaemonCommandRouter = class {
30953
30973
  if (!node) return { success: false, error: "Failed to register worktree node" };
30954
30974
  this.invalidateAggregateMeshStatus(meshId);
30955
30975
  }
30956
- const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
30957
- if (initSubmodules) {
30958
- try {
30959
- const { runGit: runGit3 } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
30960
- await runGit3(
30961
- { workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true },
30962
- ["submodule", "update", "--init", "--recursive"],
30963
- { timeoutMs: 12e4 }
30964
- );
30965
- } catch (subErr) {
30966
- console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
30976
+ const persistWorktreeSetupState = async (bootstrapState2) => {
30977
+ node.worktreeBootstrap = bootstrapState2;
30978
+ if (meshRecord.inline) {
30979
+ this.updateInlineMeshNode(meshId, mesh, node);
30980
+ return;
30967
30981
  }
30968
- }
30969
- const bootstrapState = await runMeshWorktreeBootstrap(mesh, result.worktreePath);
30970
- node.worktreeBootstrap = bootstrapState;
30971
- if (!meshRecord.inline) {
30972
30982
  try {
30973
30983
  const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
30974
- updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState });
30984
+ updateNode2(meshId, node.id, { worktreeBootstrap: bootstrapState2 });
30975
30985
  this.invalidateAggregateMeshStatus(meshId);
30976
30986
  } catch {
30977
30987
  }
30978
- }
30979
- try {
30980
- const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
30981
- appendLedgerEntry2(meshId, {
30982
- kind: "node_cloned",
30983
- nodeId: node.id,
30984
- payload: {
30985
- sourceNodeId,
30986
- branch: result.branch,
30987
- worktreePath: result.worktreePath,
30988
- submodulesInitialized: initSubmodules,
30989
- worktreeBootstrap: {
30990
- status: bootstrapState.status,
30991
- required: bootstrapState.required,
30992
- configSource: bootstrapState.configSource,
30993
- configSourceType: bootstrapState.configSourceType,
30994
- lastCommand: bootstrapState.lastCommand,
30995
- exitCode: bootstrapState.exitCode
30988
+ };
30989
+ const appendCloneLedger = async (initSubmodules2, bootstrapState2) => {
30990
+ try {
30991
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
30992
+ appendLedgerEntry2(meshId, {
30993
+ kind: "node_cloned",
30994
+ nodeId: node.id,
30995
+ payload: {
30996
+ sourceNodeId,
30997
+ branch: result.branch,
30998
+ worktreePath: result.worktreePath,
30999
+ submodulesInitialized: initSubmodules2,
31000
+ worktreeBootstrap: {
31001
+ status: bootstrapState2.status,
31002
+ required: bootstrapState2.required,
31003
+ configSource: bootstrapState2.configSource,
31004
+ configSourceType: bootstrapState2.configSourceType,
31005
+ lastCommand: bootstrapState2.lastCommand,
31006
+ exitCode: bootstrapState2.exitCode
31007
+ }
30996
31008
  }
31009
+ });
31010
+ } catch {
31011
+ }
31012
+ };
31013
+ const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
31014
+ const loadedBootstrap = loadMeshWorktreeBootstrapConfig(mesh, result.worktreePath);
31015
+ const runningBootstrapState = {
31016
+ status: "running",
31017
+ required: loadedBootstrap.config?.required !== false,
31018
+ configSource: loadedBootstrap.path || loadedBootstrap.source,
31019
+ configSourceType: loadedBootstrap.sourceType,
31020
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
31021
+ };
31022
+ await persistWorktreeSetupState(runningBootstrapState);
31023
+ const finishWorktreeSetup = async () => {
31024
+ let submodulesInitialized2 = false;
31025
+ if (initSubmodules) {
31026
+ try {
31027
+ const { runGit: runGit3 } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
31028
+ await runGit3(
31029
+ { workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true },
31030
+ ["submodule", "update", "--init", "--recursive"],
31031
+ { timeoutMs: 12e4 }
31032
+ );
31033
+ submodulesInitialized2 = true;
31034
+ } catch (subErr) {
31035
+ console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
30997
31036
  }
31037
+ }
31038
+ const bootstrapState2 = await runMeshWorktreeBootstrap(mesh, result.worktreePath);
31039
+ await persistWorktreeSetupState(bootstrapState2);
31040
+ await appendCloneLedger(submodulesInitialized2, bootstrapState2);
31041
+ return { submodulesInitialized: submodulesInitialized2, bootstrapState: bootstrapState2 };
31042
+ };
31043
+ const requestedSetupWaitMs = Number(args?.setupWaitMs ?? args?.bootstrapWaitMs ?? 8e3);
31044
+ const setupWaitMs = Number.isFinite(requestedSetupWaitMs) ? Math.min(Math.max(requestedSetupWaitMs, 0), 14e3) : 8e3;
31045
+ const setupPromise = finishWorktreeSetup();
31046
+ const setupResult = await Promise.race([
31047
+ setupPromise.then((value) => ({ completed: true, value })),
31048
+ new Promise((resolve17) => setTimeout(() => resolve17({ completed: false }), setupWaitMs))
31049
+ ]);
31050
+ if (!setupResult.completed) {
31051
+ setupPromise.catch((error) => {
31052
+ const failedState = {
31053
+ ...runningBootstrapState,
31054
+ status: "failed",
31055
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
31056
+ error: error?.message || String(error)
31057
+ };
31058
+ void persistWorktreeSetupState(failedState);
31059
+ void appendCloneLedger(false, failedState);
30998
31060
  });
30999
- } catch {
31061
+ return {
31062
+ success: true,
31063
+ async: true,
31064
+ status: "accepted",
31065
+ node,
31066
+ worktreePath: result.worktreePath,
31067
+ branch: result.branch,
31068
+ worktreeBootstrap: runningBootstrapState,
31069
+ worktreeSetup: {
31070
+ status: "running",
31071
+ setupWaitMs,
31072
+ message: "Worktree node is registered; submodule/bootstrap setup is continuing in the background."
31073
+ }
31074
+ };
31000
31075
  }
31076
+ const { submodulesInitialized, bootstrapState } = setupResult.value;
31001
31077
  return {
31002
31078
  success: true,
31003
31079
  node,
31004
31080
  worktreePath: result.worktreePath,
31005
31081
  branch: result.branch,
31082
+ submodulesInitialized,
31006
31083
  worktreeBootstrap: bootstrapState
31007
31084
  };
31008
31085
  } catch (e) {
@@ -31459,12 +31536,18 @@ ${block2}`);
31459
31536
  for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
31460
31537
  const nodeId = String(node.id || node.nodeId || "");
31461
31538
  const daemonId = readStringValue(node.daemonId);
31539
+ const nodeMachineId = readMeshNodeMachineId(node);
31540
+ const nodeHostname = readMeshNodeHostname(node);
31462
31541
  const providerPriority = readProviderPriorityFromPolicy(node.policy);
31542
+ const configuredCoordinatorNode = Boolean(
31543
+ nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId
31544
+ );
31545
+ const sparseConfiguredCoordinatorNode = configuredCoordinatorNode && !daemonId && !nodeMachineId && !nodeHostname;
31463
31546
  const isSelfNode = Boolean(
31464
31547
  nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
31465
31548
  ) || Boolean(
31466
31549
  daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
31467
- ) || Boolean(meshRecord?.inline && nodeIndex === 0);
31550
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0) || sparseConfiguredCoordinatorNode;
31468
31551
  const machineIdentity = buildMeshNodeMachineIdentity(node, {
31469
31552
  localMachineId,
31470
31553
  localDaemonId: this.deps.statusInstanceId,
@@ -31481,7 +31564,7 @@ ${block2}`);
31481
31564
  worktreeBranch: node.worktreeBranch,
31482
31565
  role: normalizeMeshDaemonRole(node.role) || (meshHost.hostNodeId && nodeId === meshHost.hostNodeId ? "host" : void 0),
31483
31566
  daemonId,
31484
- machineId: readMeshNodeMachineId(node) || node.machineId,
31567
+ machineId: nodeMachineId || node.machineId,
31485
31568
  machine: machineIdentity,
31486
31569
  machineStatus: node.machineStatus,
31487
31570
  health: "unknown",