@adhdev/daemon-core 0.9.82-rc.212 → 0.9.82-rc.214

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
@@ -45,6 +45,7 @@ var init_repo_mesh_types = __esm({
45
45
  maxParallelTasks: 2,
46
46
  spawnedSessionVisibility: "visible",
47
47
  sessionCleanupOnNodeRemove: "preserve",
48
+ autoFastForward: { enabled: true },
48
49
  maxTaskRetries: 1
49
50
  };
50
51
  }
@@ -1359,7 +1360,17 @@ function normalizeRepoIdentity(remoteUrl) {
1359
1360
  return identity;
1360
1361
  }
1361
1362
  function mergeMeshPolicy(base, patch) {
1362
- const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
1363
+ const autoFastForward = normalizeAutoFastForwardPolicy({
1364
+ ...DEFAULT_MESH_POLICY.autoFastForward,
1365
+ ...base?.autoFastForward && typeof base.autoFastForward === "object" ? base.autoFastForward : {},
1366
+ ...patch?.autoFastForward && typeof patch.autoFastForward === "object" ? patch.autoFastForward : {}
1367
+ });
1368
+ const policy = {
1369
+ ...DEFAULT_MESH_POLICY,
1370
+ ...base || {},
1371
+ ...patch || {},
1372
+ autoFastForward
1373
+ };
1363
1374
  if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
1364
1375
  policy.dirtyWorkspaceBehavior = "warn";
1365
1376
  }
@@ -1374,6 +1385,15 @@ function mergeMeshPolicy(base, patch) {
1374
1385
  }
1375
1386
  return policy;
1376
1387
  }
1388
+ function normalizeAutoFastForwardPolicy(value) {
1389
+ const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1390
+ const maxBehind = Number(record.maxBehind);
1391
+ return {
1392
+ enabled: record.enabled !== false,
1393
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
1394
+ requireCleanSubmodules: record.requireCleanSubmodules !== false
1395
+ };
1396
+ }
1377
1397
  function listMeshes() {
1378
1398
  return loadMeshConfig().meshes;
1379
1399
  }
@@ -6725,6 +6745,34 @@ function isIdleSessionState(state) {
6725
6745
  function isDirtyNode(node) {
6726
6746
  return node?.health === "dirty" || node?.git?.dirty === true;
6727
6747
  }
6748
+ function resolveAutoFastForwardPolicy(mesh) {
6749
+ const record = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
6750
+ const maxBehind = Number(record.maxBehind);
6751
+ return {
6752
+ enabled: record.enabled !== false,
6753
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
6754
+ requireCleanSubmodules: record.requireCleanSubmodules !== false
6755
+ };
6756
+ }
6757
+ function sessionStateLooksActive(state) {
6758
+ const status = readNonEmptyString2(state?.status).toLowerCase();
6759
+ const chatStatus = readNonEmptyString2(state?.activeChat?.status).toLowerCase();
6760
+ const active = /* @__PURE__ */ new Set(["generating", "streaming", "long_generating", "working", "starting", "waiting_approval"]);
6761
+ return active.has(status) || active.has(chatStatus);
6762
+ }
6763
+ function nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId) {
6764
+ if (nodeHasActiveAssignment(meshId, nodeId)) return true;
6765
+ return components.instanceManager.getByCategory("cli").some((inst) => {
6766
+ const state = inst.getState();
6767
+ const settings = state.settings || {};
6768
+ if (readNonEmptyString2(settings.meshNodeFor) !== meshId) return false;
6769
+ const instNodeId = readNonEmptyString2(settings.meshNodeId) || readNonEmptyString2(settings.nodeId);
6770
+ if (instNodeId !== nodeId) return false;
6771
+ const sessionId = readNonEmptyString2(state.instanceId);
6772
+ if (currentSessionId && sessionId === currentSessionId && isIdleSessionState(state)) return false;
6773
+ return sessionStateLooksActive(state);
6774
+ });
6775
+ }
6728
6776
  function isLaunchableNode(node) {
6729
6777
  if (!node || node.status === "disabled" || node.status === "removed") return false;
6730
6778
  const health = readNonEmptyString2(node.health).toLowerCase();
@@ -7053,6 +7101,9 @@ async function maybeAutoFastForwardIdleNode(components, args) {
7053
7101
  const workspace = readNonEmptyString2(node?.workspace);
7054
7102
  if (!workspace) return;
7055
7103
  if (!(0, import_fs10.existsSync)(workspace)) return;
7104
+ const policy = resolveAutoFastForwardPolicy(mesh);
7105
+ if (!policy.enabled) return;
7106
+ if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
7056
7107
  const throttleKey = `${args.meshId}:${args.nodeId}`;
7057
7108
  const now = Date.now();
7058
7109
  const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
@@ -7071,6 +7122,12 @@ async function maybeAutoFastForwardIdleNode(components, args) {
7071
7122
  trigger: "idle_auto"
7072
7123
  });
7073
7124
  if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return;
7125
+ const behind = Number(dryRun.current?.behind);
7126
+ if (policy.maxBehind !== void 0 && Number.isFinite(behind) && behind > policy.maxBehind) return;
7127
+ if (policy.requireCleanSubmodules) {
7128
+ const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
7129
+ if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return;
7130
+ }
7074
7131
  await fastForwardMeshNode({
7075
7132
  meshId: args.meshId,
7076
7133
  nodeId: args.nodeId,
@@ -10344,7 +10401,25 @@ var init_cli_state_engine = __esm({
10344
10401
  "CLI",
10345
10402
  `[${this.provider.type}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 140)} status=${String(status || "")} parsedStatus=${String(parsedStatus || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify((lastParsedAssistant?.content || "").slice(0, 120)).slice(0, 160)} responseBuffer=${JSON.stringify((snap.responseBuffer || "").slice(0, 160)).slice(0, 220)} recentActivity=${recentInteractiveActivity}`
10346
10403
  );
10347
- const shouldHoldGenerating = status === "idle" && this.isWaitingForResponse && !!this.currentTurnScope && !modal && !(parsedStatus === "idle" && !!lastParsedAssistant);
10404
+ const hasFinalCurrentTurnAssistant = (() => {
10405
+ if (parsedStatus !== "idle") return false;
10406
+ const msgs = Array.isArray(parsedMessages) ? parsedMessages : [];
10407
+ let lastUserIdx = -1;
10408
+ for (let i = msgs.length - 1; i >= 0; i--) {
10409
+ if (msgs[i]?.role === "user") {
10410
+ lastUserIdx = i;
10411
+ break;
10412
+ }
10413
+ }
10414
+ const searchSlice = lastUserIdx >= 0 ? msgs.slice(lastUserIdx + 1) : msgs;
10415
+ return searchSlice.some((m) => {
10416
+ if (!m || m.role !== "assistant") return false;
10417
+ if (typeof m.content !== "string" || !m.content.trim()) return false;
10418
+ const kind = typeof m.kind === "string" && m.kind.trim() ? m.kind.trim() : "standard";
10419
+ return kind === "standard" && m.meta?.streaming !== true;
10420
+ });
10421
+ })();
10422
+ const shouldHoldGenerating = status === "idle" && this.isWaitingForResponse && !!this.currentTurnScope && !modal && !hasFinalCurrentTurnAssistant;
10348
10423
  if (shouldHoldGenerating) {
10349
10424
  this.applyHoldGenerating(ctx);
10350
10425
  return;
@@ -35735,6 +35810,35 @@ function extractToolOutputContent(payload) {
35735
35810
  }
35736
35811
  return "";
35737
35812
  }
35813
+ function hasAssistantStandardMessageSinceLastUser(records, content) {
35814
+ const normalized = content.trim();
35815
+ if (!normalized) return false;
35816
+ for (let i = records.length - 1; i >= 0; i--) {
35817
+ const record = records[i];
35818
+ if (record.kind === "session_start") continue;
35819
+ if (record.role === "user") return false;
35820
+ if (record.role === "assistant" && record.kind === "standard" && record.content.trim() === normalized) {
35821
+ return true;
35822
+ }
35823
+ }
35824
+ return false;
35825
+ }
35826
+ function pushAssistantStandardMessage(records, sessionId, receivedAt, content, workspace) {
35827
+ const text = content.trim();
35828
+ if (!text) return;
35829
+ if (hasAssistantStandardMessageSinceLastUser(records, text)) return;
35830
+ const msg = {
35831
+ ts: new Date(receivedAt).toISOString(),
35832
+ receivedAt,
35833
+ role: "assistant",
35834
+ content: text,
35835
+ kind: "standard",
35836
+ agent: "codex-cli",
35837
+ historySessionId: sessionId
35838
+ };
35839
+ if (workspace) msg.workspace = workspace;
35840
+ records.push(msg);
35841
+ }
35738
35842
  function readSessionMeta(filePath) {
35739
35843
  try {
35740
35844
  const firstLine = fs15.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
@@ -35790,13 +35894,34 @@ function parseSessionFile(filePath, sessionId, workspaceFallback) {
35790
35894
  }
35791
35895
  continue;
35792
35896
  }
35793
- if (type !== "response_item") continue;
35794
35897
  const payloadType = String(payload.type ?? "").trim();
35898
+ if (type === "event_msg") {
35899
+ if (payloadType === "task_complete") {
35900
+ pushAssistantStandardMessage(
35901
+ records,
35902
+ sessionId,
35903
+ receivedAt,
35904
+ flattenCodexContent(payload.last_agent_message),
35905
+ detectedWorkspace
35906
+ );
35907
+ } else if (payloadType === "agent_message" && String(payload.phase ?? "").trim() === "final_answer") {
35908
+ pushAssistantStandardMessage(
35909
+ records,
35910
+ sessionId,
35911
+ receivedAt,
35912
+ flattenCodexContent(payload.message),
35913
+ detectedWorkspace
35914
+ );
35915
+ }
35916
+ continue;
35917
+ }
35918
+ if (type !== "response_item") continue;
35795
35919
  if (payloadType === "message") {
35796
35920
  const role = String(payload.role ?? "").trim();
35797
35921
  if (role !== "user" && role !== "assistant") continue;
35798
35922
  const content = flattenCodexContent(payload.content);
35799
35923
  if (!content) continue;
35924
+ if (role === "assistant" && hasAssistantStandardMessageSinceLastUser(records, content)) continue;
35800
35925
  const msg = {
35801
35926
  ts: new Date(receivedAt).toISOString(),
35802
35927
  receivedAt,
@@ -39729,6 +39854,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
39729
39854
 
39730
39855
  // src/commands/router.ts
39731
39856
  init_mesh_work_queue();
39857
+ init_repo_mesh_types();
39732
39858
  var import_os3 = require("os");
39733
39859
  var import_path10 = require("path");
39734
39860
  var fs22 = __toESM(require("fs"));
@@ -40221,6 +40347,23 @@ function getGitSubmoduleDriftState(git) {
40221
40347
  }
40222
40348
  return { dirty, outOfSync };
40223
40349
  }
40350
+ function isInlineMeshAutoFastForwardEligible(git) {
40351
+ if (!git) return false;
40352
+ if (readBooleanValue(git.isGitRepo) !== true) return false;
40353
+ if (!readStringValue(git.branch)) return false;
40354
+ if (!readStringValue(git.upstream)) return false;
40355
+ const upstreamStatus = readStringValue(git.upstreamStatus, git.upstream_status);
40356
+ if (upstreamStatus !== "fresh") return false;
40357
+ if ((readNumberValue(git.ahead) ?? 0) !== 0) return false;
40358
+ if ((readNumberValue(git.behind) ?? 0) <= 0) return false;
40359
+ const hasConflicts = readBooleanValue(git.hasConflicts) ?? (Array.isArray(git.conflictFiles) && git.conflictFiles.length > 0);
40360
+ if (hasConflicts) return false;
40361
+ if ((readNumberValue(git.stashCount, git.stash_count) ?? 0) > 0) return false;
40362
+ const submoduleDrift = getGitSubmoduleDriftState(git);
40363
+ if (submoduleDrift.dirty || submoduleDrift.outOfSync) return false;
40364
+ const dirty = readBooleanValue(git.dirty) ?? countGitWorktreeChanges(git) > 0;
40365
+ return dirty !== true && countGitWorktreeChanges(git) === 0;
40366
+ }
40224
40367
  function deriveMeshNodeHealthFromGit(git) {
40225
40368
  if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
40226
40369
  const branch = readStringValue(git.branch);
@@ -40350,6 +40493,12 @@ function applyInlineMeshBranchConvergence(mesh, node, status) {
40350
40493
  status.isDirty = uncommittedChanges > 0;
40351
40494
  status.uncommittedChanges = uncommittedChanges;
40352
40495
  status.branchConvergence = buildInlineMeshBranchConvergence({ mesh, node, status });
40496
+ status.autoFastForwardEligible = isInlineMeshAutoFastForwardEligible(git);
40497
+ if (status.autoFastForwardEligible) {
40498
+ status.suggestedAction = "auto_fast_forward";
40499
+ } else {
40500
+ delete status.suggestedAction;
40501
+ }
40353
40502
  }
40354
40503
  function summarizeInlineMeshBranchConvergence(nodes) {
40355
40504
  const followUps = nodes.filter((node) => readObjectRecord(node.branchConvergence).needsConvergence === true).map((node) => {
@@ -42265,7 +42414,8 @@ var DaemonCommandRouter = class {
42265
42414
  ...result ? {
42266
42415
  success: result.success === true,
42267
42416
  result,
42268
- finalBranchConvergenceState: result.finalBranchConvergenceState
42417
+ finalBranchConvergenceState: result.finalBranchConvergenceState,
42418
+ ...result.blockerContext ? { blockerContext: result.blockerContext } : {}
42269
42419
  } : {}
42270
42420
  }
42271
42421
  });
@@ -42795,6 +42945,27 @@ var DaemonCommandRouter = class {
42795
42945
  finalBranchConvergenceState
42796
42946
  };
42797
42947
  }
42948
+ const requireApprovalForPush = mesh?.policy?.requireApprovalForPush ?? DEFAULT_MESH_POLICY.requireApprovalForPush;
42949
+ let pushResult;
42950
+ if (!requireApprovalForPush) {
42951
+ const pushStarted = Date.now();
42952
+ try {
42953
+ await execFileAsync3("git", ["push", "origin", baseBranch], { cwd: repoRoot, encoding: "utf8" });
42954
+ pushResult = { pushed: true, remote: "origin", branch: baseBranch, durationMs: Date.now() - pushStarted };
42955
+ recordMeshRefineStage(refineStages, "push", "passed", pushStarted, pushResult);
42956
+ finalBranchConvergenceState.status = "merged_pushed";
42957
+ } catch (e) {
42958
+ pushResult = {
42959
+ pushed: false,
42960
+ remote: "origin",
42961
+ branch: baseBranch,
42962
+ error: e?.message || String(e),
42963
+ stderr: e?.stderr,
42964
+ durationMs: Date.now() - pushStarted
42965
+ };
42966
+ recordMeshRefineStage(refineStages, "push", "failed", pushStarted, pushResult);
42967
+ }
42968
+ }
42798
42969
  return {
42799
42970
  success: true,
42800
42971
  merged: true,
@@ -42808,7 +42979,13 @@ var DaemonCommandRouter = class {
42808
42979
  mergeResult,
42809
42980
  refineStages,
42810
42981
  ...ledgerError ? { ledgerError } : {},
42811
- finalBranchConvergenceState
42982
+ finalBranchConvergenceState,
42983
+ // Push outcome or readiness info for coordinator.
42984
+ ...pushResult ? { pushResult } : {
42985
+ pushReady: true,
42986
+ pushCommand: `git push origin ${baseBranch}`,
42987
+ pushNote: "requireApprovalForPush is enabled \u2014 run the push command or obtain user approval before pushing."
42988
+ }
42812
42989
  };
42813
42990
  } catch (e) {
42814
42991
  return { success: false, error: e.message, refineStages };
@@ -42826,9 +43003,46 @@ var DaemonCommandRouter = class {
42826
43003
  const refineCode = typeof result.code === "string" ? result.code : "";
42827
43004
  const refineTerminalKind = result.success === true ? "completed" : refineCode === "blocked_review" ? "blocked_review" : refineCode === "validation_failed" || refineCode === "validation_dependencies_missing" ? "validation_failed" : refineCode === "submodule_reachability_failed" ? "submodule_reachability_failed" : refineCode === "merge_failed" || refineCode === "patch_equivalence_failed" || refineCode === "needs_rebase" || refineCode === "needs_rebase_with_conflicts" ? "merge_failed" : refineCode === "cleanup_failed" ? "cleanup_failed" : "merge_failed";
42828
43005
  const isTerminalSuccess = refineTerminalKind === "completed";
43006
+ const blockerContext = isTerminalSuccess ? void 0 : (() => {
43007
+ const code = typeof result.code === "string" ? result.code : refineTerminalKind;
43008
+ const stage = refineTerminalKind === "validation_failed" ? "validation" : refineTerminalKind === "submodule_reachability_failed" ? "submodule_reachability" : refineCode === "patch_equivalence_failed" ? "patch_equivalence" : refineCode === "needs_rebase" || refineCode === "needs_rebase_with_conflicts" ? "patch_equivalence" : refineTerminalKind === "merge_failed" ? "merge" : refineTerminalKind === "cleanup_failed" ? "cleanup" : "unknown";
43009
+ const ctx = {
43010
+ stage,
43011
+ reason: code,
43012
+ terminalKind: refineTerminalKind
43013
+ };
43014
+ if (typeof result.error === "string") ctx.error = result.error;
43015
+ if (typeof result.blockedReason === "string") ctx.blockedReason = result.blockedReason;
43016
+ if (stage === "patch_equivalence" && result.patchEquivalence) {
43017
+ const pe = result.patchEquivalence;
43018
+ ctx.details = {
43019
+ expectedPatchId: pe.expectedPatchId,
43020
+ actualPatchId: pe.actualPatchId,
43021
+ status: pe.status,
43022
+ actionableHint: pe.actionableHint,
43023
+ error: pe.error
43024
+ };
43025
+ }
43026
+ if (stage === "submodule_reachability" && Array.isArray(result.unreachableSubmoduleCommits)) {
43027
+ ctx.details = {
43028
+ unreachableCount: result.unreachableSubmoduleCommits.length,
43029
+ paths: result.unreachableSubmoduleCommits.map((e) => e.path),
43030
+ autoPublishAllowed: result.unreachableSubmoduleCommits[0]?.autoPublishAllowed
43031
+ };
43032
+ }
43033
+ if (stage === "validation" && result.validationSummary) {
43034
+ const vs = result.validationSummary;
43035
+ ctx.details = {
43036
+ failureCode: vs.failureCode,
43037
+ commandsRun: Array.isArray(vs.commandsRun) ? vs.commandsRun.length : void 0
43038
+ };
43039
+ }
43040
+ return ctx;
43041
+ })();
42829
43042
  const normalizedResult = {
42830
43043
  ...result,
42831
43044
  terminalKind: refineTerminalKind,
43045
+ ...blockerContext ? { blockerContext } : {},
42832
43046
  ...result.nextStep === void 0 && !isTerminalSuccess ? {
42833
43047
  nextStep: refineTerminalKind === "blocked_review" ? "Request user review/approval before attempting to merge again." : refineTerminalKind === "validation_failed" ? "Fix failing tests or configure validation.bootstrapCommands and retry mesh_refine_node." : refineTerminalKind === "submodule_reachability_failed" ? "Push unreachable submodule commits to origin/main, then retry mesh_refine_node." : refineTerminalKind === "merge_failed" ? "Resolve merge conflicts or patch equivalence issues, then retry mesh_refine_node." : refineTerminalKind === "cleanup_failed" ? "Manually remove the worktree and retry or use mesh_remove_node." : "Inspect refineStages for the failing stage and retry."
42834
43048
  } : {}