@adhdev/daemon-core 0.9.82-rc.222 → 0.9.82-rc.224

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
@@ -24784,7 +24784,9 @@ async function handleReadChat(h, args) {
24784
24784
  const historyLimit = normalizeReadChatTailLimit(args);
24785
24785
  try {
24786
24786
  const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h);
24787
- const workspace = typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
24787
+ const targetSid = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
24788
+ const registrySessionWorkspace = targetSid ? h.ctx?.sessionRegistry?.get?.(targetSid)?.workspace : void 0;
24789
+ const workspace = typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : typeof registrySessionWorkspace === "string" ? registrySessionWorkspace : void 0;
24788
24790
  const intendedWorkspace = typeof args?.workspace === "string" ? args.workspace : void 0;
24789
24791
  const supportsNative = supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.nativeHistory);
24790
24792
  const history = supportsNative ? readCliProviderNativeHistory(agentStr, {
@@ -39344,7 +39346,12 @@ function applyInlineMeshBranchConvergence(mesh, node, status) {
39344
39346
  }
39345
39347
  }
39346
39348
  function summarizeInlineMeshBranchConvergence(nodes) {
39347
- const followUps = nodes.filter((node) => readObjectRecord(node.branchConvergence).needsConvergence === true).map((node) => {
39349
+ const followUps = nodes.filter((node) => {
39350
+ if (readObjectRecord(node.branchConvergence).needsConvergence !== true) return false;
39351
+ const workspace = typeof node.workspace === "string" ? node.workspace : "";
39352
+ if (workspace && !fs23.existsSync(workspace)) return false;
39353
+ return true;
39354
+ }).map((node) => {
39348
39355
  const convergence = readObjectRecord(node.branchConvergence);
39349
39356
  return {
39350
39357
  nodeId: node.nodeId,
@@ -40855,7 +40862,66 @@ var DaemonCommandRouter = class {
40855
40862
  } catch (e) {
40856
40863
  const message = String(e?.message || e || "worktree cleanup failed");
40857
40864
  const dirty = message.includes("dirty worktree") || message.includes("local changes");
40858
- const submoduleForceBlocked = /working trees containing submodules cannot be moved or removed/i.test(message) && !forceFallbackConvergence.allow;
40865
+ const isSubmoduleGuard = /working trees containing submodules cannot be moved or removed/i.test(message);
40866
+ const submoduleForceBlocked = isSubmoduleGuard && !forceFallbackConvergence.allow;
40867
+ if (isSubmoduleGuard && forceFallbackConvergence.allow) {
40868
+ const { execFile: execFile4 } = await import("child_process");
40869
+ const { promisify: promisify7 } = await import("util");
40870
+ const execFileAsync3 = promisify7(execFile4);
40871
+ const GIT_TIMEOUT_CLEANUP = 3e4;
40872
+ const GIT_MAX_BUFFER_CLEANUP = 4 * 1024 * 1024;
40873
+ try {
40874
+ await execFileAsync3("git", ["-C", workspace, "submodule", "deinit", "--all", "-f"], {
40875
+ encoding: "utf8",
40876
+ timeout: GIT_TIMEOUT_CLEANUP,
40877
+ maxBuffer: GIT_MAX_BUFFER_CLEANUP,
40878
+ windowsHide: true
40879
+ });
40880
+ await execFileAsync3("git", ["worktree", "remove", "--force", workspace], {
40881
+ cwd: repoRoot,
40882
+ encoding: "utf8",
40883
+ timeout: GIT_TIMEOUT_CLEANUP,
40884
+ maxBuffer: GIT_MAX_BUFFER_CLEANUP,
40885
+ windowsHide: true
40886
+ });
40887
+ return {
40888
+ success: true,
40889
+ removedPath: workspace,
40890
+ repoRoot,
40891
+ fallback: "git_worktree_remove_submodule_deinit",
40892
+ forced: true,
40893
+ reason: "working_trees_containing_submodules",
40894
+ convergence: forceFallbackConvergence
40895
+ };
40896
+ } catch (deinitError) {
40897
+ try {
40898
+ fs23.rmSync(workspace, { recursive: true, force: true });
40899
+ await execFileAsync3("git", ["worktree", "prune"], {
40900
+ cwd: repoRoot,
40901
+ encoding: "utf8",
40902
+ timeout: GIT_TIMEOUT_CLEANUP,
40903
+ maxBuffer: GIT_MAX_BUFFER_CLEANUP,
40904
+ windowsHide: true
40905
+ });
40906
+ return {
40907
+ success: true,
40908
+ removedPath: workspace,
40909
+ repoRoot,
40910
+ fallback: "fs_rm_worktree_prune",
40911
+ forced: true,
40912
+ reason: "working_trees_containing_submodules",
40913
+ convergence: forceFallbackConvergence
40914
+ };
40915
+ } catch (rmError) {
40916
+ return {
40917
+ success: false,
40918
+ code: "mesh_worktree_cleanup_failed",
40919
+ error: `All removal fallbacks exhausted. deinit+remove: ${deinitError?.message || deinitError}; rmSync+prune: ${rmError?.message || rmError}`,
40920
+ recoveryHint: "Manually remove the worktree directory and run git worktree prune from the source repo."
40921
+ };
40922
+ }
40923
+ }
40924
+ }
40859
40925
  return {
40860
40926
  success: false,
40861
40927
  code: dirty ? "mesh_worktree_cleanup_dirty" : submoduleForceBlocked ? "mesh_worktree_cleanup_force_fallback_blocked" : "mesh_worktree_cleanup_failed",
@@ -40867,9 +40933,13 @@ var DaemonCommandRouter = class {
40867
40933
  }
40868
40934
  async getWorktreeForceCleanupConvergence(args) {
40869
40935
  const metadataStatus = typeof args.node?.branchConvergence?.status === "string" ? args.node.branchConvergence.status : "";
40870
- if (metadataStatus === "merged_to_main" || metadataStatus === "cleanup_candidate") {
40936
+ if (metadataStatus === "merged_to_main" || metadataStatus === "cleanup_candidate" || metadataStatus === "merged_pushed") {
40871
40937
  return { allow: true, status: metadataStatus, source: "node_branch_convergence" };
40872
40938
  }
40939
+ const refinedConvergence = typeof args.node?.refineState?.finalBranchConvergenceState?.status === "string" ? args.node.refineState.finalBranchConvergenceState.status : typeof args.node?.lastRefineResult?.finalBranchConvergenceState?.status === "string" ? args.node.lastRefineResult.finalBranchConvergenceState.status : "";
40940
+ if (refinedConvergence === "merged_pushed" || refinedConvergence === "merged_to_main") {
40941
+ return { allow: true, status: refinedConvergence, source: "node_refine_state" };
40942
+ }
40873
40943
  const { execFile: execFile4 } = await import("child_process");
40874
40944
  const { promisify: promisify7 } = await import("util");
40875
40945
  const execFileAsync3 = promisify7(execFile4);
@@ -41355,11 +41425,24 @@ var DaemonCommandRouter = class {
41355
41425
  if (!branch) return { success: false, error: "Could not determine branch of the worktree node", refineStages };
41356
41426
  const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
41357
41427
  const baseBranch = baseBranchStdout.trim();
41358
- const { stdout: baseHeadStdout } = await execFileAsync3("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
41428
+ let fetchWarning;
41429
+ try {
41430
+ await execFileAsync3("git", ["fetch", "origin", baseBranch], { cwd: repoRoot, encoding: "utf8" });
41431
+ } catch (e) {
41432
+ fetchWarning = `git fetch origin ${baseBranch} failed (proceeding with local HEAD): ${e?.message}`;
41433
+ }
41434
+ let baseHeadRaw;
41435
+ try {
41436
+ const { stdout } = await execFileAsync3("git", ["rev-parse", `origin/${baseBranch}`], { cwd: repoRoot, encoding: "utf8" });
41437
+ baseHeadRaw = stdout.trim();
41438
+ } catch {
41439
+ const { stdout: localHead } = await execFileAsync3("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
41440
+ baseHeadRaw = localHead.trim();
41441
+ }
41359
41442
  const { stdout: branchHeadStdout } = await execFileAsync3("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
41360
- const baseHead = baseHeadStdout.trim();
41443
+ const baseHead = baseHeadRaw;
41361
41444
  let branchHead = branchHeadStdout.trim();
41362
- recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, { branch, baseBranch, baseHead, branchHead });
41445
+ recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, { branch, baseBranch, baseHead, branchHead, ...fetchWarning ? { fetchWarning } : {} });
41363
41446
  const validationStarted = Date.now();
41364
41447
  const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace, {
41365
41448
  // M2-2: consume the node's persisted bootstrap state; persist re-runs.
@@ -41378,11 +41461,25 @@ var DaemonCommandRouter = class {
41378
41461
  { validationStatus: validationSummary.status, commandsRun: validationSummary.commandsRun.length }
41379
41462
  );
41380
41463
  if (validationSummary.status === "failed") {
41464
+ const firstFailedCmd = Array.isArray(validationSummary.commandsRun) ? validationSummary.commandsRun.find((c) => c.success === false) : void 0;
41465
+ const buildValidationFailedError = () => {
41466
+ const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted. Configure validation.bootstrapCommands if Refinery should bootstrap dependencies before validation." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.";
41467
+ if (!firstFailedCmd) return base;
41468
+ const cmdName = typeof firstFailedCmd.displayCommand === "string" ? firstFailedCmd.displayCommand : typeof firstFailedCmd.command === "string" ? [firstFailedCmd.command, ...Array.isArray(firstFailedCmd.args) ? firstFailedCmd.args : []].join(" ").trim() : typeof firstFailedCmd.cmd === "string" ? firstFailedCmd.cmd : "";
41469
+ const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s) => typeof s === "string" && s.length > 0).join("\n");
41470
+ const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
41471
+ return [
41472
+ base,
41473
+ cmdName ? `First failing command: ${cmdName}` : "",
41474
+ tail ? `Output (tail):
41475
+ ${tail}` : ""
41476
+ ].filter(Boolean).join("\n");
41477
+ };
41381
41478
  return {
41382
41479
  success: false,
41383
41480
  code: validationSummary.failureCode || "validation_failed",
41384
41481
  convergenceStatus: "blocked_review",
41385
- error: validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted. Configure validation.bootstrapCommands if Refinery should bootstrap dependencies before validation." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.",
41482
+ error: buildValidationFailedError(),
41386
41483
  branch,
41387
41484
  into: baseBranch,
41388
41485
  validationSummary,
@@ -41984,13 +42081,54 @@ var DaemonCommandRouter = class {
41984
42081
  this.deps.instanceManager.sendEvent(sessionId, "interactive_prompt_response", response);
41985
42082
  return { success: true };
41986
42083
  }
41987
- case "launch_cli":
42084
+ case "launch_cli": {
42085
+ const launchResult = await this.deps.cliManager.handleCliCommand(cmd, args);
42086
+ const meshNodeId = readStringValue(args?.settings?.meshNodeId);
42087
+ const meshId = readStringValue(args?.settings?.meshNodeFor);
42088
+ if (meshNodeId && meshId && launchResult?.success !== false) {
42089
+ try {
42090
+ const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
42091
+ const meshObj = getMesh2(meshId) ?? this.getCachedInlineMesh(meshId);
42092
+ const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => n.id === meshNodeId || n.nodeId === meshNodeId) : void 0;
42093
+ const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
42094
+ if (bootstrapStatus === "running") {
42095
+ return { success: true, ...launchResult, bootstrapPending: true };
42096
+ }
42097
+ } catch {
42098
+ }
42099
+ }
42100
+ return launchResult;
42101
+ }
41988
42102
  case "stop_cli":
41989
42103
  case "set_cli_view_mode":
41990
- case "record_provider_pty":
41991
- case "agent_command": {
42104
+ case "record_provider_pty": {
41992
42105
  return this.deps.cliManager.handleCliCommand(cmd, args);
41993
42106
  }
42107
+ case "agent_command": {
42108
+ const agentResult = await this.deps.cliManager.handleCliCommand(cmd, args);
42109
+ const meshCtx = args?.meshContext;
42110
+ const dispatchNodeId = readStringValue(meshCtx?.nodeId);
42111
+ const dispatchMeshId = readStringValue(meshCtx?.meshId);
42112
+ if (dispatchNodeId && dispatchMeshId && agentResult?.success !== false) {
42113
+ try {
42114
+ const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
42115
+ const meshObj = getMesh2(dispatchMeshId) ?? this.getCachedInlineMesh(dispatchMeshId);
42116
+ const nodeObj = Array.isArray(meshObj?.nodes) ? meshObj.nodes.find((n) => n.id === dispatchNodeId || n.nodeId === dispatchNodeId) : void 0;
42117
+ const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
42118
+ if (bootstrapStatus === "running") {
42119
+ return {
42120
+ success: true,
42121
+ ...agentResult,
42122
+ dispatchAcknowledgementRisk: true,
42123
+ dispatchAcknowledgementRiskReason: "bootstrap_still_running",
42124
+ nextAction: "Wait for worktree_bootstrap_complete event before dispatching work to this node."
42125
+ };
42126
+ }
42127
+ } catch {
42128
+ }
42129
+ }
42130
+ return agentResult;
42131
+ }
41994
42132
  // ─── Logs ───
41995
42133
  case "get_logs": {
41996
42134
  const count = parseInt(args?.count) || parseInt(args?.lines) || 100;
@@ -43375,9 +43513,11 @@ var DaemonCommandRouter = class {
43375
43513
  if (meshRecord?.inline) {
43376
43514
  removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
43377
43515
  if (removed) this.invalidateAggregateMeshStatus(meshId);
43516
+ if (!removed && !node) removed = true;
43378
43517
  } else {
43379
43518
  const { removeNode: removeNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
43380
43519
  removed = removeNode2(meshId, nodeId);
43520
+ if (!removed && !node) removed = true;
43381
43521
  if (removed) this.invalidateAggregateMeshStatus(meshId);
43382
43522
  }
43383
43523
  if (removed) {
@@ -43561,8 +43701,37 @@ var DaemonCommandRouter = class {
43561
43701
  setupPromise.then((value) => ({ completed: true, value })),
43562
43702
  new Promise((resolve23) => setTimeout(() => resolve23({ completed: false }), setupWaitMs))
43563
43703
  ]);
43704
+ const emitBootstrapEvent = (eventStatus2, bootstrapState2, startedAtMs, extraPayload) => {
43705
+ try {
43706
+ const durationMs = Date.now() - startedAtMs;
43707
+ const eventPayload = {
43708
+ event: `worktree_${eventStatus2}`,
43709
+ meshId,
43710
+ nodeLabel: node.id,
43711
+ nodeId: node.id,
43712
+ workspace: result.worktreePath,
43713
+ metadataEvent: {
43714
+ source: "clone_mesh_node_bootstrap",
43715
+ nodeId: node.id,
43716
+ status: eventStatus2,
43717
+ worktreePath: result.worktreePath,
43718
+ durationMs,
43719
+ bootstrapStatus: bootstrapState2.status,
43720
+ ...bootstrapState2.error ? { error: bootstrapState2.error } : {},
43721
+ ...bootstrapState2.exitCode !== void 0 ? { exitCode: bootstrapState2.exitCode } : {},
43722
+ ...extraPayload || {}
43723
+ },
43724
+ queuedAt: Date.now()
43725
+ };
43726
+ queuePendingMeshCoordinatorEvent(eventPayload);
43727
+ } catch {
43728
+ }
43729
+ };
43730
+ const bootstrapStartedMs = Date.now();
43564
43731
  if (!setupResult.completed) {
43565
- setupPromise.catch((error) => {
43732
+ setupPromise.then(({ bootstrapState: bootstrapState2 }) => {
43733
+ emitBootstrapEvent("bootstrap_complete", bootstrapState2, bootstrapStartedMs);
43734
+ }).catch((error) => {
43566
43735
  const failedState = {
43567
43736
  ...runningBootstrapState,
43568
43737
  status: "failed",
@@ -43571,6 +43740,7 @@ var DaemonCommandRouter = class {
43571
43740
  };
43572
43741
  void persistWorktreeSetupState(failedState);
43573
43742
  void appendCloneLedger(false, failedState);
43743
+ emitBootstrapEvent("bootstrap_failed", failedState, bootstrapStartedMs, { error: error?.message || String(error) });
43574
43744
  });
43575
43745
  return {
43576
43746
  success: true,
@@ -43588,6 +43758,7 @@ var DaemonCommandRouter = class {
43588
43758
  };
43589
43759
  }
43590
43760
  const { submodulesInitialized, bootstrapState } = setupResult.value;
43761
+ emitBootstrapEvent("bootstrap_complete", bootstrapState, bootstrapStartedMs);
43591
43762
  return {
43592
43763
  success: true,
43593
43764
  node,
@@ -43655,7 +43826,34 @@ var DaemonCommandRouter = class {
43655
43826
  const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue trigger");
43656
43827
  if (ownerFailure) return ownerFailure;
43657
43828
  try {
43658
- const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
43829
+ const { triggerMeshQueue: triggerMeshQueue2, tryAssignQueueTask: tryAssignQueueTask2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
43830
+ const preferredNodeId = typeof args?.preferredNodeId === "string" ? args.preferredNodeId.trim() : "";
43831
+ if (preferredNodeId) {
43832
+ const cliInstances = this.deps.instanceManager.getByCategory("cli");
43833
+ const sorted = [...cliInstances].sort((a, b) => {
43834
+ const aSettings = a.getState().settings || {};
43835
+ const bSettings = b.getState().settings || {};
43836
+ const aNode = readStringValue(aSettings.meshNodeId, aSettings.nodeId);
43837
+ const bNode = readStringValue(bSettings.meshNodeId, bSettings.nodeId);
43838
+ return (aNode === preferredNodeId ? -1 : 0) - (bNode === preferredNodeId ? -1 : 0);
43839
+ });
43840
+ for (const inst of sorted) {
43841
+ const state = inst.getState();
43842
+ const settings = state.settings || {};
43843
+ const nodeId = readStringValue(settings.meshNodeId, settings.nodeId);
43844
+ if (!nodeId || nodeId !== preferredNodeId) continue;
43845
+ const meshNodeFor = readStringValue(settings.meshNodeFor);
43846
+ if (meshNodeFor !== meshId) continue;
43847
+ const status = (readStringValue(state.status) || "").toLowerCase();
43848
+ if (status !== "idle") continue;
43849
+ const sessionId = typeof state.instanceId === "string" ? state.instanceId : "";
43850
+ const providerType = readStringValue(state.type, settings.providerType) || "";
43851
+ if (sessionId && providerType) {
43852
+ tryAssignQueueTask2(this.deps, meshId, nodeId, sessionId, providerType);
43853
+ break;
43854
+ }
43855
+ }
43856
+ }
43659
43857
  const trigger = await triggerMeshQueue2(this.deps, meshId);
43660
43858
  return { success: true, trigger };
43661
43859
  } catch (e) {