@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.mjs CHANGED
@@ -40,6 +40,7 @@ var init_repo_mesh_types = __esm({
40
40
  maxParallelTasks: 2,
41
41
  spawnedSessionVisibility: "visible",
42
42
  sessionCleanupOnNodeRemove: "preserve",
43
+ autoFastForward: { enabled: true },
43
44
  maxTaskRetries: 1
44
45
  };
45
46
  }
@@ -1357,7 +1358,17 @@ function normalizeRepoIdentity(remoteUrl) {
1357
1358
  return identity;
1358
1359
  }
1359
1360
  function mergeMeshPolicy(base, patch) {
1360
- const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
1361
+ const autoFastForward = normalizeAutoFastForwardPolicy({
1362
+ ...DEFAULT_MESH_POLICY.autoFastForward,
1363
+ ...base?.autoFastForward && typeof base.autoFastForward === "object" ? base.autoFastForward : {},
1364
+ ...patch?.autoFastForward && typeof patch.autoFastForward === "object" ? patch.autoFastForward : {}
1365
+ });
1366
+ const policy = {
1367
+ ...DEFAULT_MESH_POLICY,
1368
+ ...base || {},
1369
+ ...patch || {},
1370
+ autoFastForward
1371
+ };
1361
1372
  if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
1362
1373
  policy.dirtyWorkspaceBehavior = "warn";
1363
1374
  }
@@ -1372,6 +1383,15 @@ function mergeMeshPolicy(base, patch) {
1372
1383
  }
1373
1384
  return policy;
1374
1385
  }
1386
+ function normalizeAutoFastForwardPolicy(value) {
1387
+ const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1388
+ const maxBehind = Number(record.maxBehind);
1389
+ return {
1390
+ enabled: record.enabled !== false,
1391
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
1392
+ requireCleanSubmodules: record.requireCleanSubmodules !== false
1393
+ };
1394
+ }
1375
1395
  function listMeshes() {
1376
1396
  return loadMeshConfig().meshes;
1377
1397
  }
@@ -6719,6 +6739,34 @@ function isIdleSessionState(state) {
6719
6739
  function isDirtyNode(node) {
6720
6740
  return node?.health === "dirty" || node?.git?.dirty === true;
6721
6741
  }
6742
+ function resolveAutoFastForwardPolicy(mesh) {
6743
+ const record = mesh?.policy?.autoFastForward && typeof mesh.policy.autoFastForward === "object" && !Array.isArray(mesh.policy.autoFastForward) ? mesh.policy.autoFastForward : {};
6744
+ const maxBehind = Number(record.maxBehind);
6745
+ return {
6746
+ enabled: record.enabled !== false,
6747
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
6748
+ requireCleanSubmodules: record.requireCleanSubmodules !== false
6749
+ };
6750
+ }
6751
+ function sessionStateLooksActive(state) {
6752
+ const status = readNonEmptyString2(state?.status).toLowerCase();
6753
+ const chatStatus = readNonEmptyString2(state?.activeChat?.status).toLowerCase();
6754
+ const active = /* @__PURE__ */ new Set(["generating", "streaming", "long_generating", "working", "starting", "waiting_approval"]);
6755
+ return active.has(status) || active.has(chatStatus);
6756
+ }
6757
+ function nodeHasActiveMeshWork(components, meshId, nodeId, currentSessionId) {
6758
+ if (nodeHasActiveAssignment(meshId, nodeId)) return true;
6759
+ return components.instanceManager.getByCategory("cli").some((inst) => {
6760
+ const state = inst.getState();
6761
+ const settings = state.settings || {};
6762
+ if (readNonEmptyString2(settings.meshNodeFor) !== meshId) return false;
6763
+ const instNodeId = readNonEmptyString2(settings.meshNodeId) || readNonEmptyString2(settings.nodeId);
6764
+ if (instNodeId !== nodeId) return false;
6765
+ const sessionId = readNonEmptyString2(state.instanceId);
6766
+ if (currentSessionId && sessionId === currentSessionId && isIdleSessionState(state)) return false;
6767
+ return sessionStateLooksActive(state);
6768
+ });
6769
+ }
6722
6770
  function isLaunchableNode(node) {
6723
6771
  if (!node || node.status === "disabled" || node.status === "removed") return false;
6724
6772
  const health = readNonEmptyString2(node.health).toLowerCase();
@@ -7047,6 +7095,9 @@ async function maybeAutoFastForwardIdleNode(components, args) {
7047
7095
  const workspace = readNonEmptyString2(node?.workspace);
7048
7096
  if (!workspace) return;
7049
7097
  if (!existsSync14(workspace)) return;
7098
+ const policy = resolveAutoFastForwardPolicy(mesh);
7099
+ if (!policy.enabled) return;
7100
+ if (nodeHasActiveMeshWork(components, args.meshId, args.nodeId, args.sessionId)) return;
7050
7101
  const throttleKey = `${args.meshId}:${args.nodeId}`;
7051
7102
  const now = Date.now();
7052
7103
  const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
@@ -7065,6 +7116,12 @@ async function maybeAutoFastForwardIdleNode(components, args) {
7065
7116
  trigger: "idle_auto"
7066
7117
  });
7067
7118
  if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return;
7119
+ const behind = Number(dryRun.current?.behind);
7120
+ if (policy.maxBehind !== void 0 && Number.isFinite(behind) && behind > policy.maxBehind) return;
7121
+ if (policy.requireCleanSubmodules) {
7122
+ const submodules = Array.isArray(dryRun.current?.submodules) ? dryRun.current.submodules : [];
7123
+ if (submodules.some((submodule) => submodule?.dirty || submodule?.outOfSync || submodule?.error)) return;
7124
+ }
7068
7125
  await fastForwardMeshNode({
7069
7126
  meshId: args.meshId,
7070
7127
  nodeId: args.nodeId,
@@ -10340,7 +10397,25 @@ var init_cli_state_engine = __esm({
10340
10397
  "CLI",
10341
10398
  `[${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}`
10342
10399
  );
10343
- const shouldHoldGenerating = status === "idle" && this.isWaitingForResponse && !!this.currentTurnScope && !modal && !(parsedStatus === "idle" && !!lastParsedAssistant);
10400
+ const hasFinalCurrentTurnAssistant = (() => {
10401
+ if (parsedStatus !== "idle") return false;
10402
+ const msgs = Array.isArray(parsedMessages) ? parsedMessages : [];
10403
+ let lastUserIdx = -1;
10404
+ for (let i = msgs.length - 1; i >= 0; i--) {
10405
+ if (msgs[i]?.role === "user") {
10406
+ lastUserIdx = i;
10407
+ break;
10408
+ }
10409
+ }
10410
+ const searchSlice = lastUserIdx >= 0 ? msgs.slice(lastUserIdx + 1) : msgs;
10411
+ return searchSlice.some((m) => {
10412
+ if (!m || m.role !== "assistant") return false;
10413
+ if (typeof m.content !== "string" || !m.content.trim()) return false;
10414
+ const kind = typeof m.kind === "string" && m.kind.trim() ? m.kind.trim() : "standard";
10415
+ return kind === "standard" && m.meta?.streaming !== true;
10416
+ });
10417
+ })();
10418
+ const shouldHoldGenerating = status === "idle" && this.isWaitingForResponse && !!this.currentTurnScope && !modal && !hasFinalCurrentTurnAssistant;
10344
10419
  if (shouldHoldGenerating) {
10345
10420
  this.applyHoldGenerating(ctx);
10346
10421
  return;
@@ -35407,6 +35482,35 @@ function extractToolOutputContent(payload) {
35407
35482
  }
35408
35483
  return "";
35409
35484
  }
35485
+ function hasAssistantStandardMessageSinceLastUser(records, content) {
35486
+ const normalized = content.trim();
35487
+ if (!normalized) return false;
35488
+ for (let i = records.length - 1; i >= 0; i--) {
35489
+ const record = records[i];
35490
+ if (record.kind === "session_start") continue;
35491
+ if (record.role === "user") return false;
35492
+ if (record.role === "assistant" && record.kind === "standard" && record.content.trim() === normalized) {
35493
+ return true;
35494
+ }
35495
+ }
35496
+ return false;
35497
+ }
35498
+ function pushAssistantStandardMessage(records, sessionId, receivedAt, content, workspace) {
35499
+ const text = content.trim();
35500
+ if (!text) return;
35501
+ if (hasAssistantStandardMessageSinceLastUser(records, text)) return;
35502
+ const msg = {
35503
+ ts: new Date(receivedAt).toISOString(),
35504
+ receivedAt,
35505
+ role: "assistant",
35506
+ content: text,
35507
+ kind: "standard",
35508
+ agent: "codex-cli",
35509
+ historySessionId: sessionId
35510
+ };
35511
+ if (workspace) msg.workspace = workspace;
35512
+ records.push(msg);
35513
+ }
35410
35514
  function readSessionMeta(filePath) {
35411
35515
  try {
35412
35516
  const firstLine = fs15.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
@@ -35462,13 +35566,34 @@ function parseSessionFile(filePath, sessionId, workspaceFallback) {
35462
35566
  }
35463
35567
  continue;
35464
35568
  }
35465
- if (type !== "response_item") continue;
35466
35569
  const payloadType = String(payload.type ?? "").trim();
35570
+ if (type === "event_msg") {
35571
+ if (payloadType === "task_complete") {
35572
+ pushAssistantStandardMessage(
35573
+ records,
35574
+ sessionId,
35575
+ receivedAt,
35576
+ flattenCodexContent(payload.last_agent_message),
35577
+ detectedWorkspace
35578
+ );
35579
+ } else if (payloadType === "agent_message" && String(payload.phase ?? "").trim() === "final_answer") {
35580
+ pushAssistantStandardMessage(
35581
+ records,
35582
+ sessionId,
35583
+ receivedAt,
35584
+ flattenCodexContent(payload.message),
35585
+ detectedWorkspace
35586
+ );
35587
+ }
35588
+ continue;
35589
+ }
35590
+ if (type !== "response_item") continue;
35467
35591
  if (payloadType === "message") {
35468
35592
  const role = String(payload.role ?? "").trim();
35469
35593
  if (role !== "user" && role !== "assistant") continue;
35470
35594
  const content = flattenCodexContent(payload.content);
35471
35595
  if (!content) continue;
35596
+ if (role === "assistant" && hasAssistantStandardMessageSinceLastUser(records, content)) continue;
35472
35597
  const msg = {
35473
35598
  ts: new Date(receivedAt).toISOString(),
35474
35599
  receivedAt,
@@ -39401,6 +39526,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
39401
39526
 
39402
39527
  // src/commands/router.ts
39403
39528
  init_mesh_work_queue();
39529
+ init_repo_mesh_types();
39404
39530
  import { homedir as homedir25, hostname as osHostname } from "os";
39405
39531
  import { basename as pathBasename, join as pathJoin, resolve as pathResolve2 } from "path";
39406
39532
  import * as fs22 from "fs";
@@ -39893,6 +40019,23 @@ function getGitSubmoduleDriftState(git) {
39893
40019
  }
39894
40020
  return { dirty, outOfSync };
39895
40021
  }
40022
+ function isInlineMeshAutoFastForwardEligible(git) {
40023
+ if (!git) return false;
40024
+ if (readBooleanValue(git.isGitRepo) !== true) return false;
40025
+ if (!readStringValue(git.branch)) return false;
40026
+ if (!readStringValue(git.upstream)) return false;
40027
+ const upstreamStatus = readStringValue(git.upstreamStatus, git.upstream_status);
40028
+ if (upstreamStatus !== "fresh") return false;
40029
+ if ((readNumberValue(git.ahead) ?? 0) !== 0) return false;
40030
+ if ((readNumberValue(git.behind) ?? 0) <= 0) return false;
40031
+ const hasConflicts = readBooleanValue(git.hasConflicts) ?? (Array.isArray(git.conflictFiles) && git.conflictFiles.length > 0);
40032
+ if (hasConflicts) return false;
40033
+ if ((readNumberValue(git.stashCount, git.stash_count) ?? 0) > 0) return false;
40034
+ const submoduleDrift = getGitSubmoduleDriftState(git);
40035
+ if (submoduleDrift.dirty || submoduleDrift.outOfSync) return false;
40036
+ const dirty = readBooleanValue(git.dirty) ?? countGitWorktreeChanges(git) > 0;
40037
+ return dirty !== true && countGitWorktreeChanges(git) === 0;
40038
+ }
39896
40039
  function deriveMeshNodeHealthFromGit(git) {
39897
40040
  if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
39898
40041
  const branch = readStringValue(git.branch);
@@ -40022,6 +40165,12 @@ function applyInlineMeshBranchConvergence(mesh, node, status) {
40022
40165
  status.isDirty = uncommittedChanges > 0;
40023
40166
  status.uncommittedChanges = uncommittedChanges;
40024
40167
  status.branchConvergence = buildInlineMeshBranchConvergence({ mesh, node, status });
40168
+ status.autoFastForwardEligible = isInlineMeshAutoFastForwardEligible(git);
40169
+ if (status.autoFastForwardEligible) {
40170
+ status.suggestedAction = "auto_fast_forward";
40171
+ } else {
40172
+ delete status.suggestedAction;
40173
+ }
40025
40174
  }
40026
40175
  function summarizeInlineMeshBranchConvergence(nodes) {
40027
40176
  const followUps = nodes.filter((node) => readObjectRecord(node.branchConvergence).needsConvergence === true).map((node) => {
@@ -41937,7 +42086,8 @@ var DaemonCommandRouter = class {
41937
42086
  ...result ? {
41938
42087
  success: result.success === true,
41939
42088
  result,
41940
- finalBranchConvergenceState: result.finalBranchConvergenceState
42089
+ finalBranchConvergenceState: result.finalBranchConvergenceState,
42090
+ ...result.blockerContext ? { blockerContext: result.blockerContext } : {}
41941
42091
  } : {}
41942
42092
  }
41943
42093
  });
@@ -42467,6 +42617,27 @@ var DaemonCommandRouter = class {
42467
42617
  finalBranchConvergenceState
42468
42618
  };
42469
42619
  }
42620
+ const requireApprovalForPush = mesh?.policy?.requireApprovalForPush ?? DEFAULT_MESH_POLICY.requireApprovalForPush;
42621
+ let pushResult;
42622
+ if (!requireApprovalForPush) {
42623
+ const pushStarted = Date.now();
42624
+ try {
42625
+ await execFileAsync3("git", ["push", "origin", baseBranch], { cwd: repoRoot, encoding: "utf8" });
42626
+ pushResult = { pushed: true, remote: "origin", branch: baseBranch, durationMs: Date.now() - pushStarted };
42627
+ recordMeshRefineStage(refineStages, "push", "passed", pushStarted, pushResult);
42628
+ finalBranchConvergenceState.status = "merged_pushed";
42629
+ } catch (e) {
42630
+ pushResult = {
42631
+ pushed: false,
42632
+ remote: "origin",
42633
+ branch: baseBranch,
42634
+ error: e?.message || String(e),
42635
+ stderr: e?.stderr,
42636
+ durationMs: Date.now() - pushStarted
42637
+ };
42638
+ recordMeshRefineStage(refineStages, "push", "failed", pushStarted, pushResult);
42639
+ }
42640
+ }
42470
42641
  return {
42471
42642
  success: true,
42472
42643
  merged: true,
@@ -42480,7 +42651,13 @@ var DaemonCommandRouter = class {
42480
42651
  mergeResult,
42481
42652
  refineStages,
42482
42653
  ...ledgerError ? { ledgerError } : {},
42483
- finalBranchConvergenceState
42654
+ finalBranchConvergenceState,
42655
+ // Push outcome or readiness info for coordinator.
42656
+ ...pushResult ? { pushResult } : {
42657
+ pushReady: true,
42658
+ pushCommand: `git push origin ${baseBranch}`,
42659
+ pushNote: "requireApprovalForPush is enabled \u2014 run the push command or obtain user approval before pushing."
42660
+ }
42484
42661
  };
42485
42662
  } catch (e) {
42486
42663
  return { success: false, error: e.message, refineStages };
@@ -42498,9 +42675,46 @@ var DaemonCommandRouter = class {
42498
42675
  const refineCode = typeof result.code === "string" ? result.code : "";
42499
42676
  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";
42500
42677
  const isTerminalSuccess = refineTerminalKind === "completed";
42678
+ const blockerContext = isTerminalSuccess ? void 0 : (() => {
42679
+ const code = typeof result.code === "string" ? result.code : refineTerminalKind;
42680
+ 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";
42681
+ const ctx = {
42682
+ stage,
42683
+ reason: code,
42684
+ terminalKind: refineTerminalKind
42685
+ };
42686
+ if (typeof result.error === "string") ctx.error = result.error;
42687
+ if (typeof result.blockedReason === "string") ctx.blockedReason = result.blockedReason;
42688
+ if (stage === "patch_equivalence" && result.patchEquivalence) {
42689
+ const pe = result.patchEquivalence;
42690
+ ctx.details = {
42691
+ expectedPatchId: pe.expectedPatchId,
42692
+ actualPatchId: pe.actualPatchId,
42693
+ status: pe.status,
42694
+ actionableHint: pe.actionableHint,
42695
+ error: pe.error
42696
+ };
42697
+ }
42698
+ if (stage === "submodule_reachability" && Array.isArray(result.unreachableSubmoduleCommits)) {
42699
+ ctx.details = {
42700
+ unreachableCount: result.unreachableSubmoduleCommits.length,
42701
+ paths: result.unreachableSubmoduleCommits.map((e) => e.path),
42702
+ autoPublishAllowed: result.unreachableSubmoduleCommits[0]?.autoPublishAllowed
42703
+ };
42704
+ }
42705
+ if (stage === "validation" && result.validationSummary) {
42706
+ const vs = result.validationSummary;
42707
+ ctx.details = {
42708
+ failureCode: vs.failureCode,
42709
+ commandsRun: Array.isArray(vs.commandsRun) ? vs.commandsRun.length : void 0
42710
+ };
42711
+ }
42712
+ return ctx;
42713
+ })();
42501
42714
  const normalizedResult = {
42502
42715
  ...result,
42503
42716
  terminalKind: refineTerminalKind,
42717
+ ...blockerContext ? { blockerContext } : {},
42504
42718
  ...result.nextStep === void 0 && !isTerminalSuccess ? {
42505
42719
  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."
42506
42720
  } : {}