@adhdev/daemon-core 0.9.82-rc.263 → 0.9.82-rc.265

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.
@@ -74,6 +74,16 @@ export interface DaemonBuildBehind {
74
74
  head: string;
75
75
  /** Where the comparison matched: 'root' or the submodule path. */
76
76
  scope: string;
77
+ /**
78
+ * Whether any package changed between buildCommit..HEAD affects the daemon
79
+ * runtime (daemon-core, standalone, session-host, terminal-mux, ghostty,
80
+ * mcp-server). When false, only web/render packages changed — the daemon does
81
+ * NOT need a rebuild/restart; only the web deploy is pending. Conservative:
82
+ * when the changed-package set can't be determined it defaults to true.
83
+ */
84
+ isDaemonAffecting: boolean;
85
+ /** Distinct package names changed between buildCommit..HEAD (best-effort). */
86
+ affectedPackages?: string[];
77
87
  warning: string;
78
88
  }
79
89
  export type GitFileChangeStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'copied' | 'untracked' | 'conflict';
package/dist/index.js CHANGED
@@ -265,10 +265,10 @@ function readInjected(value) {
265
265
  }
266
266
  function getDaemonBuildInfo() {
267
267
  if (cached) return cached;
268
- const commit = readInjected(true ? "2cf602f99ce68b3d3f1af02b429f6fb7a7c8e686" : void 0) ?? "unknown";
269
- const commitShort = readInjected(true ? "2cf602f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
270
- const version = readInjected(true ? "0.9.82-rc.263" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
271
- const builtAt = readInjected(true ? "2026-06-14T13:48:10.699Z" : void 0);
268
+ const commit = readInjected(true ? "b062e0b564f44876b742641cc25ad182a3e088b3" : void 0) ?? "unknown";
269
+ const commitShort = readInjected(true ? "b062e0b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
270
+ const version = readInjected(true ? "0.9.82-rc.265" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
271
+ const builtAt = readInjected(true ? "2026-06-14T16:39:31.621Z" : void 0);
272
272
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
273
273
  return cached;
274
274
  }
@@ -339,6 +339,30 @@ async function getGitRepoStatus(workspace, options = {}) {
339
339
  );
340
340
  }
341
341
  }
342
+ async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
343
+ try {
344
+ const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
345
+ const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
346
+ if (files.length === 0) {
347
+ return { isDaemonAffecting: true, affectedPackages: [] };
348
+ }
349
+ const pkgs = /* @__PURE__ */ new Set();
350
+ let sawNonPackageOrUnknown = false;
351
+ for (const file of files) {
352
+ const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
353
+ if (!match) {
354
+ sawNonPackageOrUnknown = true;
355
+ continue;
356
+ }
357
+ pkgs.add(match[1]);
358
+ }
359
+ const affectedPackages = [...pkgs].sort();
360
+ const allWebOnly = !sawNonPackageOrUnknown && affectedPackages.length > 0 && affectedPackages.every((p) => WEB_ONLY_PACKAGES.has(p) && !DAEMON_RUNTIME_PACKAGES.has(p));
361
+ return { isDaemonAffecting: !allWebOnly, affectedPackages };
362
+ } catch {
363
+ return { isDaemonAffecting: true, affectedPackages: [] };
364
+ }
365
+ }
342
366
  async function detectDaemonBuildBehind(repo, submodules, options) {
343
367
  const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
344
368
  if (!build.commit || build.commit === "unknown") return void 0;
@@ -355,12 +379,21 @@ async function detectDaemonBuildBehind(repo, submodules, options) {
355
379
  const head = headResult.stdout.trim();
356
380
  if (!head || head === build.commit) continue;
357
381
  await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
382
+ const { isDaemonAffecting, affectedPackages } = await classifyDaemonBuildChange(
383
+ repoPath,
384
+ build.commit,
385
+ options
386
+ );
387
+ const scopeLabel = scope === "root" ? "workspace" : scope;
388
+ const warning = isDaemonAffecting ? `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}. Merged code is NOT live until the daemon is rebuilt/redeployed and restarted \u2014 a local dist rebuild alone does not update a cloud daemon.` : `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}, but only web packages changed (${(affectedPackages || []).join(", ") || "web"}). Daemon restart NOT required \u2014 redeploy the web app to reflect the change.`;
358
389
  return {
359
390
  buildCommit: build.commit,
360
391
  buildCommitShort: build.commitShort,
361
392
  head,
362
393
  scope,
363
- warning: `Live daemon was built from ${build.commitShort} which is behind ${scope === "root" ? "workspace" : scope} HEAD ${head.slice(0, 7)}. Merged code is NOT live until the daemon is rebuilt/redeployed and restarted \u2014 a local dist rebuild alone does not update a cloud daemon.`
394
+ isDaemonAffecting,
395
+ ...affectedPackages && affectedPackages.length > 0 ? { affectedPackages } : {},
396
+ warning
364
397
  };
365
398
  } catch {
366
399
  continue;
@@ -580,11 +613,29 @@ function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
580
613
  }
581
614
  return submodules;
582
615
  }
616
+ var DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
583
617
  var init_git_status = __esm({
584
618
  "src/git/git-status.ts"() {
585
619
  "use strict";
586
620
  init_git_executor();
587
621
  init_build_info();
622
+ DAEMON_RUNTIME_PACKAGES = /* @__PURE__ */ new Set([
623
+ "daemon-core",
624
+ "daemon-standalone",
625
+ "session-host-core",
626
+ "session-host-daemon",
627
+ "terminal-mux-core",
628
+ "terminal-mux-control",
629
+ "terminal-mux-cli",
630
+ "ghostty-vt-node",
631
+ "mcp-server"
632
+ ]);
633
+ WEB_ONLY_PACKAGES = /* @__PURE__ */ new Set([
634
+ "web-core",
635
+ "web-standalone",
636
+ "web-devconsole",
637
+ "terminal-render-web"
638
+ ]);
588
639
  }
589
640
  });
590
641
 
@@ -43509,10 +43560,31 @@ ${hintLines.join("\n")}` : "",
43509
43560
  };
43510
43561
  }
43511
43562
  const cleanupStarted = Date.now();
43563
+ const refineSessionCleanupMode = this.normalizeMeshSessionCleanupMode(
43564
+ mesh?.policy?.sessionCleanupOnNodeRemove
43565
+ );
43566
+ let refineSessionIds;
43567
+ if (refineSessionCleanupMode !== "preserve" && this.deps.sessionHostControl) {
43568
+ try {
43569
+ const liveSessions = await this.deps.sessionHostControl.listSessions();
43570
+ const workspace = typeof node.workspace === "string" ? node.workspace : "";
43571
+ refineSessionIds = liveSessions.filter((record) => {
43572
+ const sid = typeof record?.sessionId === "string" ? record.sessionId : "";
43573
+ if (!sid) return false;
43574
+ if (readStringValue(record?.meta?.meshCoordinatorFor) === meshId) return false;
43575
+ const boundToNode = readStringValue(record?.meta?.meshNodeId) === nodeId;
43576
+ const matchedByWorkspace = !!workspace && record?.workspace === workspace;
43577
+ return boundToNode || matchedByWorkspace;
43578
+ }).map((record) => String(record.sessionId));
43579
+ } catch {
43580
+ refineSessionIds = void 0;
43581
+ }
43582
+ }
43512
43583
  const removeResult = await this.execute("remove_mesh_node", {
43513
43584
  meshId,
43514
43585
  nodeId,
43515
- sessionCleanupMode: "preserve",
43586
+ sessionCleanupMode: refineSessionCleanupMode,
43587
+ ...refineSessionIds && refineSessionIds.length > 0 ? { sessionIds: refineSessionIds } : {},
43516
43588
  inlineMesh: args?.inlineMesh
43517
43589
  });
43518
43590
  recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
@@ -45582,6 +45654,23 @@ ${hintLines.join("\n")}` : "",
45582
45654
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
45583
45655
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
45584
45656
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
45657
+ const isDryRun = args?.dryRun !== false && args?.execute !== true;
45658
+ if (isDryRun) {
45659
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
45660
+ const mesh = meshRecord?.mesh;
45661
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
45662
+ if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
45663
+ return {
45664
+ success: true,
45665
+ dryRun: true,
45666
+ nodeId,
45667
+ workspace: node.workspace,
45668
+ validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
45669
+ mergeWillRun: false,
45670
+ cleanupWillRun: false,
45671
+ hint: "Dry-run only \u2014 no merge/push/cleanup performed. Re-invoke with execute:true to converge this node."
45672
+ };
45673
+ }
45585
45674
  return this.startMeshRefineJob(meshId, nodeId, args);
45586
45675
  }
45587
45676
  case "batch_refine_mesh_nodes": {
@@ -45603,9 +45692,17 @@ ${hintLines.join("\n")}` : "",
45603
45692
  const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
45604
45693
  args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
45605
45694
  );
45695
+ const explicitSessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
45606
45696
  let sessionCleanup;
45607
45697
  if (node && sessionCleanupMode !== "preserve") {
45608
- sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode, source: "mesh_remove_node" });
45698
+ sessionCleanup = await this.cleanupMeshSessions({
45699
+ meshId,
45700
+ nodeId,
45701
+ node,
45702
+ mode: sessionCleanupMode,
45703
+ ...explicitSessionIds && explicitSessionIds.length > 0 ? { sessionIds: explicitSessionIds } : {},
45704
+ source: "mesh_remove_node"
45705
+ });
45609
45706
  if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
45610
45707
  }
45611
45708
  let worktreeCleanup;