@adhdev/daemon-standalone 0.9.82-rc.212 → 0.9.82-rc.213

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.js CHANGED
@@ -29749,6 +29749,7 @@ var require_dist3 = __commonJS({
29749
29749
  maxParallelTasks: 2,
29750
29750
  spawnedSessionVisibility: "visible",
29751
29751
  sessionCleanupOnNodeRemove: "preserve",
29752
+ autoFastForward: { enabled: true },
29752
29753
  maxTaskRetries: 1
29753
29754
  };
29754
29755
  }
@@ -31074,7 +31075,17 @@ ${error48.message || ""}`;
31074
31075
  return identity;
31075
31076
  }
31076
31077
  function mergeMeshPolicy(base, patch) {
31077
- const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
31078
+ const autoFastForward = normalizeAutoFastForwardPolicy({
31079
+ ...DEFAULT_MESH_POLICY.autoFastForward,
31080
+ ...base?.autoFastForward && typeof base.autoFastForward === "object" ? base.autoFastForward : {},
31081
+ ...patch?.autoFastForward && typeof patch.autoFastForward === "object" ? patch.autoFastForward : {}
31082
+ });
31083
+ const policy = {
31084
+ ...DEFAULT_MESH_POLICY,
31085
+ ...base || {},
31086
+ ...patch || {},
31087
+ autoFastForward
31088
+ };
31078
31089
  if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
31079
31090
  policy.dirtyWorkspaceBehavior = "warn";
31080
31091
  }
@@ -31089,6 +31100,15 @@ ${error48.message || ""}`;
31089
31100
  }
31090
31101
  return policy;
31091
31102
  }
31103
+ function normalizeAutoFastForwardPolicy(value) {
31104
+ const record2 = value && typeof value === "object" && !Array.isArray(value) ? value : {};
31105
+ const maxBehind = Number(record2.maxBehind);
31106
+ return {
31107
+ enabled: record2.enabled !== false,
31108
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
31109
+ requireCleanSubmodules: record2.requireCleanSubmodules !== false
31110
+ };
31111
+ }
31092
31112
  function listMeshes() {
31093
31113
  return loadMeshConfig().meshes;
31094
31114
  }
@@ -36482,6 +36502,34 @@ Next step: ${nextStep}`;
36482
36502
  function isDirtyNode(node) {
36483
36503
  return node?.health === "dirty" || node?.git?.dirty === true;
36484
36504
  }
36505
+ function resolveAutoFastForwardPolicy(mesh) {
36506
+ const record2 = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
36507
+ const maxBehind = Number(record2.maxBehind);
36508
+ return {
36509
+ enabled: record2.enabled !== false,
36510
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
36511
+ requireCleanSubmodules: record2.requireCleanSubmodules !== false
36512
+ };
36513
+ }
36514
+ function sessionStateLooksActive(state) {
36515
+ const status = readNonEmptyString2(state?.status).toLowerCase();
36516
+ const chatStatus = readNonEmptyString2(state?.activeChat?.status).toLowerCase();
36517
+ const active = /* @__PURE__ */ new Set(["generating", "streaming", "long_generating", "working", "starting", "waiting_approval"]);
36518
+ return active.has(status) || active.has(chatStatus);
36519
+ }
36520
+ function nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId) {
36521
+ if (nodeHasActiveAssignment(meshId, nodeId)) return true;
36522
+ return components.instanceManager.getByCategory("cli").some((inst) => {
36523
+ const state = inst.getState();
36524
+ const settings = state.settings || {};
36525
+ if (readNonEmptyString2(settings.meshNodeFor) !== meshId) return false;
36526
+ const instNodeId = readNonEmptyString2(settings.meshNodeId) || readNonEmptyString2(settings.nodeId);
36527
+ if (instNodeId !== nodeId) return false;
36528
+ const sessionId = readNonEmptyString2(state.instanceId);
36529
+ if (currentSessionId && sessionId === currentSessionId && isIdleSessionState(state)) return false;
36530
+ return sessionStateLooksActive(state);
36531
+ });
36532
+ }
36485
36533
  function isLaunchableNode(node) {
36486
36534
  if (!node || node.status === "disabled" || node.status === "removed") return false;
36487
36535
  const health = readNonEmptyString2(node.health).toLowerCase();
@@ -36810,6 +36858,9 @@ Next step: ${nextStep}`;
36810
36858
  const workspace = readNonEmptyString2(node?.workspace);
36811
36859
  if (!workspace) return;
36812
36860
  if (!(0, import_fs10.existsSync)(workspace)) return;
36861
+ const policy = resolveAutoFastForwardPolicy(mesh);
36862
+ if (!policy.enabled) return;
36863
+ if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
36813
36864
  const throttleKey = `${args.meshId}:${args.nodeId}`;
36814
36865
  const now = Date.now();
36815
36866
  const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
@@ -36828,6 +36879,12 @@ Next step: ${nextStep}`;
36828
36879
  trigger: "idle_auto"
36829
36880
  });
36830
36881
  if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return;
36882
+ const behind = Number(dryRun.current?.behind);
36883
+ if (policy.maxBehind !== void 0 && Number.isFinite(behind) && behind > policy.maxBehind) return;
36884
+ if (policy.requireCleanSubmodules) {
36885
+ const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
36886
+ if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return;
36887
+ }
36831
36888
  await fastForwardMeshNode({
36832
36889
  meshId: args.meshId,
36833
36890
  nodeId: args.nodeId,
@@ -69763,6 +69820,23 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
69763
69820
  }
69764
69821
  return { dirty, outOfSync };
69765
69822
  }
69823
+ function isInlineMeshAutoFastForwardEligible(git) {
69824
+ if (!git) return false;
69825
+ if (readBooleanValue(git.isGitRepo) !== true) return false;
69826
+ if (!readStringValue(git.branch)) return false;
69827
+ if (!readStringValue(git.upstream)) return false;
69828
+ const upstreamStatus = readStringValue(git.upstreamStatus, git.upstream_status);
69829
+ if (upstreamStatus !== "fresh") return false;
69830
+ if ((readNumberValue(git.ahead) ?? 0) !== 0) return false;
69831
+ if ((readNumberValue(git.behind) ?? 0) <= 0) return false;
69832
+ const hasConflicts = readBooleanValue(git.hasConflicts) ?? (Array.isArray(git.conflictFiles) && git.conflictFiles.length > 0);
69833
+ if (hasConflicts) return false;
69834
+ if ((readNumberValue(git.stashCount, git.stash_count) ?? 0) > 0) return false;
69835
+ const submoduleDrift = getGitSubmoduleDriftState(git);
69836
+ if (submoduleDrift.dirty || submoduleDrift.outOfSync) return false;
69837
+ const dirty = readBooleanValue(git.dirty) ?? countGitWorktreeChanges(git) > 0;
69838
+ return dirty !== true && countGitWorktreeChanges(git) === 0;
69839
+ }
69766
69840
  function deriveMeshNodeHealthFromGit(git) {
69767
69841
  if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
69768
69842
  const branch = readStringValue(git.branch);
@@ -69892,6 +69966,12 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
69892
69966
  status.isDirty = uncommittedChanges > 0;
69893
69967
  status.uncommittedChanges = uncommittedChanges;
69894
69968
  status.branchConvergence = buildInlineMeshBranchConvergence({ mesh, node, status });
69969
+ status.autoFastForwardEligible = isInlineMeshAutoFastForwardEligible(git);
69970
+ if (status.autoFastForwardEligible) {
69971
+ status.suggestedAction = "auto_fast_forward";
69972
+ } else {
69973
+ delete status.suggestedAction;
69974
+ }
69895
69975
  }
69896
69976
  function summarizeInlineMeshBranchConvergence(nodes) {
69897
69977
  const followUps = nodes.filter((node) => readObjectRecord(node.branchConvergence).needsConvergence === true).map((node) => {