@adhdev/daemon-core 0.9.82-rc.53 → 0.9.82-rc.55

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.d.ts CHANGED
@@ -36,6 +36,8 @@ export { syncMeshes } from './mesh/mesh-sync.js';
36
36
  export type { MeshSyncTransport, MeshSyncResult, RemoteMeshRecord } from './mesh/mesh-sync.js';
37
37
  export { appendLedgerEntry, appendRemoteLedgerEntries, readLedgerEntries, readLedgerSlice, getLedgerSummary, getLedgerDir, getSessionRecoveryContext, MAX_LEDGER_SLICE_LIMIT } from './mesh/mesh-ledger.js';
38
38
  export type { AppendRemoteLedgerResult, MeshLedgerEntry, MeshLedgerKind, MeshLedgerSlice, MeshLedgerSummary, ReadLedgerOptions, ReadLedgerSliceOptions, SessionRecoveryContext } from './mesh/mesh-ledger.js';
39
+ export { fastForwardMeshNode } from './mesh/mesh-fast-forward.js';
40
+ export type { MeshFastForwardNodeArgs, MeshFastForwardPlannedStep, MeshFastForwardResult } from './mesh/mesh-fast-forward.js';
39
41
  export { buildMeshLedgerReconciliationEvidence, buildMeshLedgerReplicaEvidence } from './mesh/mesh-ledger-reconciliation.js';
40
42
  export type { MeshLedgerReconciliationEvidence, MeshLedgerReplicaEvidence, MeshLedgerReplicaStatus } from './mesh/mesh-ledger-reconciliation.js';
41
43
  export { enqueueTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats } from './mesh/mesh-work-queue.js';
package/dist/index.js CHANGED
@@ -371,9 +371,9 @@ async function listWorktrees(repoRoot) {
371
371
  function parseWorktreeListOutput(output) {
372
372
  const entries = [];
373
373
  const blocks = output.trim().split(/\n\n+/);
374
- for (const block of blocks) {
375
- if (!block.trim()) continue;
376
- const lines = block.trim().split("\n");
374
+ for (const block2 of blocks) {
375
+ if (!block2.trim()) continue;
376
+ const lines = block2.trim().split("\n");
377
377
  const entry = { path: "", head: "", branch: null, bare: false };
378
378
  for (const line of lines) {
379
379
  if (line.startsWith("worktree ")) {
@@ -1190,7 +1190,8 @@ function buildRulesSection(coordinatorCliType) {
1190
1190
  - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
1191
1191
  - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
1192
1192
  - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
1193
- - **Do not strand completed branches.** A checkpointed or clean feature/worktree branch is not done by itself. Merge/refine it to the mesh default branch, or explicitly report one of \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\` with the next action.
1193
+ - **Do not strand completed branches.** A checkpointed or clean feature/worktree branch is not done by itself. Merge/refine it to the mesh default branch, fast-forward obvious clean behind-only branches with \`mesh_fast_forward_node\`, or explicitly report one of \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\` with the next action.
1194
+ - **Keep Refinery validation project-configurable.** \`mesh_refine_node\` must execute validation from repo mesh/refine config (for example \`.adhdev/refine.{json,yaml,yml}\`, \`.adhdev/repo-mesh-refine.*\`, or \`repo-mesh.refine.*\`). Heuristics are suggestions/scaffolding only, not the execution path.
1194
1195
  - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
1195
1196
  }
1196
1197
  var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
@@ -1214,6 +1215,7 @@ var init_coordinator_prompt = __esm({
1214
1215
  | \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
1215
1216
  | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
1216
1217
  | \`mesh_git_status\` | Check git status on a specific node |
1218
+ | \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
1217
1219
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
1218
1220
  | \`mesh_approve\` | Approve/reject a pending agent action |
1219
1221
  | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
@@ -1236,7 +1238,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
1236
1238
  4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Use \`mesh_view_queue\` to see the status of all pending, assigned, completed, and failed tasks. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal. Handle approvals via \`mesh_approve\`.
1237
1239
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
1238
1240
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
1239
- 7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary and \`mesh_refine_node\` for clean worktree branches when safe. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
1241
+ 7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
1240
1242
  8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
1241
1243
  9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
1242
1244
 
@@ -6209,6 +6211,7 @@ __export(index_exports, {
6209
6211
  enqueueTask: () => enqueueTask,
6210
6212
  ensureSessionHostReady: () => ensureSessionHostReady,
6211
6213
  execNpmCommandSync: () => execNpmCommandSync,
6214
+ fastForwardMeshNode: () => fastForwardMeshNode,
6212
6215
  filterActivityChatMessages: () => filterActivityChatMessages,
6213
6216
  filterChatMessagesByVisibility: () => filterChatMessagesByVisibility,
6214
6217
  filterInternalChatMessages: () => filterInternalChatMessages,
@@ -8365,6 +8368,356 @@ async function syncMeshes(transport) {
8365
8368
  // src/index.ts
8366
8369
  init_mesh_ledger();
8367
8370
 
8371
+ // src/mesh/mesh-fast-forward.ts
8372
+ init_git_executor();
8373
+ var STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
8374
+ async function fastForwardMeshNode(args) {
8375
+ const workspace = typeof args.workspace === "string" ? args.workspace.trim() : "";
8376
+ const nodeId = normalizeOptionalString(args.nodeId);
8377
+ const meshId = normalizeOptionalString(args.meshId);
8378
+ const requestedBranch = normalizeOptionalString(args.branch);
8379
+ const updateSubmodules = args.updateSubmodules === true;
8380
+ const dryRun = args.dryRun === true || args.execute !== true;
8381
+ const plannedSteps = buildPlannedSteps(updateSubmodules);
8382
+ const base = {
8383
+ ...nodeId ? { nodeId } : {},
8384
+ ...meshId ? { meshId } : {},
8385
+ workspace,
8386
+ dryRun,
8387
+ updateSubmodules,
8388
+ plannedSteps
8389
+ };
8390
+ if (!workspace) {
8391
+ return block(base, "invalid_workspace", ["workspace_required"]);
8392
+ }
8393
+ const current = await getGitRepoStatus(workspace, {
8394
+ ...STATUS_OPTIONS,
8395
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8396
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8397
+ });
8398
+ const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
8399
+ if (earlyBlockers.length > 0) {
8400
+ return {
8401
+ ...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
8402
+ current,
8403
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers)))
8404
+ };
8405
+ }
8406
+ if (current.behind === 0) {
8407
+ const result2 = {
8408
+ ...base,
8409
+ success: true,
8410
+ code: "already_up_to_date",
8411
+ allowed: true,
8412
+ willRun: false,
8413
+ executed: false,
8414
+ blockingReasons: [],
8415
+ current,
8416
+ preStatus: current,
8417
+ postStatus: current,
8418
+ finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
8419
+ };
8420
+ await appendFastForwardLedger(result2, "noop");
8421
+ return result2;
8422
+ }
8423
+ const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || "", args.timeoutMs);
8424
+ if (!ancestorCheck.ok) {
8425
+ const result2 = {
8426
+ ...block(base, "non_fast_forward", ["head_is_not_ancestor_of_upstream"]),
8427
+ current,
8428
+ preStatus: current,
8429
+ operationError: ancestorCheck.error,
8430
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
8431
+ };
8432
+ await appendFastForwardLedger(result2, "blocked");
8433
+ return result2;
8434
+ }
8435
+ if (dryRun) {
8436
+ const result2 = {
8437
+ ...base,
8438
+ success: true,
8439
+ code: "fast_forward_available",
8440
+ allowed: true,
8441
+ willRun: false,
8442
+ executed: false,
8443
+ blockingReasons: [],
8444
+ current,
8445
+ preStatus: current,
8446
+ finalBranchConvergenceState: buildConvergenceState(current, "fast_forward_available")
8447
+ };
8448
+ return result2;
8449
+ }
8450
+ try {
8451
+ await runGit(workspace, ["merge", "--ff-only", current.upstream || ""], { timeoutMs: args.timeoutMs ?? 3e4 });
8452
+ } catch (error) {
8453
+ const result2 = {
8454
+ ...block(base, "merge_ff_only_failed", ["merge_ff_only_failed"]),
8455
+ current,
8456
+ preStatus: current,
8457
+ operationError: formatGitError2(error),
8458
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
8459
+ };
8460
+ await appendFastForwardLedger(result2, "failed");
8461
+ return result2;
8462
+ }
8463
+ let postStatus = await getGitRepoStatus(workspace, {
8464
+ ...STATUS_OPTIONS,
8465
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8466
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8467
+ });
8468
+ const submoduleIssues = collectSubmoduleBlockers(postStatus, "post");
8469
+ let submoduleFollowUpRequired = false;
8470
+ let operationError;
8471
+ if (submoduleIssues.length > 0) {
8472
+ if (updateSubmodules) {
8473
+ try {
8474
+ await runGit(workspace, ["submodule", "update", "--init", "--recursive"], { timeoutMs: args.timeoutMs ?? 6e4 });
8475
+ postStatus = await getGitRepoStatus(workspace, {
8476
+ ...STATUS_OPTIONS,
8477
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8478
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8479
+ });
8480
+ } catch (error) {
8481
+ operationError = formatGitError2(error);
8482
+ }
8483
+ } else {
8484
+ submoduleFollowUpRequired = true;
8485
+ }
8486
+ }
8487
+ const postBlockers = collectPostExecutionBlockers(postStatus);
8488
+ if (operationError) postBlockers.push("submodule_update_failed");
8489
+ if (submoduleFollowUpRequired) postBlockers.push("submodule_update_required");
8490
+ const success = postBlockers.length === 0 || submoduleFollowUpRequired;
8491
+ const code = postBlockers.length === 0 ? "fast_forward_applied" : submoduleFollowUpRequired ? "fast_forward_applied_submodule_update_required" : "post_verify_failed";
8492
+ const result = {
8493
+ ...base,
8494
+ success,
8495
+ code,
8496
+ allowed: true,
8497
+ willRun: true,
8498
+ executed: true,
8499
+ blockingReasons: postBlockers,
8500
+ current,
8501
+ preStatus: current,
8502
+ postStatus,
8503
+ ...operationError ? { operationError } : {},
8504
+ finalBranchConvergenceState: buildConvergenceState(
8505
+ postStatus,
8506
+ postBlockers.length === 0 ? "fast_forwarded" : submoduleFollowUpRequired ? "follow_up_required" : "post_verify_failed"
8507
+ )
8508
+ };
8509
+ await appendFastForwardLedger(result, success ? "executed" : "failed");
8510
+ return result;
8511
+ }
8512
+ function buildPlannedSteps(updateSubmodules) {
8513
+ const steps = [
8514
+ {
8515
+ operation: "refresh_upstream",
8516
+ description: "Refresh the tracked upstream remote ref before trusting ahead/behind state.",
8517
+ safe: true,
8518
+ willMutateWorktree: false
8519
+ },
8520
+ {
8521
+ operation: "verify_clean_worktree",
8522
+ description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
8523
+ safe: true,
8524
+ willMutateWorktree: false
8525
+ },
8526
+ {
8527
+ operation: "verify_fast_forward",
8528
+ description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
8529
+ safe: true,
8530
+ willMutateWorktree: false
8531
+ },
8532
+ {
8533
+ operation: "merge_ff_only",
8534
+ description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
8535
+ safe: true,
8536
+ willMutateWorktree: true
8537
+ }
8538
+ ];
8539
+ if (updateSubmodules) {
8540
+ steps.push({
8541
+ operation: "submodule_update",
8542
+ description: "If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.",
8543
+ safe: true,
8544
+ willMutateWorktree: true
8545
+ });
8546
+ }
8547
+ steps.push({
8548
+ operation: "verify_post_status",
8549
+ description: "Re-read daemon-owned git status and report final branch convergence state.",
8550
+ safe: true,
8551
+ willMutateWorktree: false
8552
+ });
8553
+ return steps;
8554
+ }
8555
+ function collectPreflightBlockers(status, requestedBranch) {
8556
+ const blockers = [];
8557
+ if (!status.isGitRepo) blockers.push("not_git_repo");
8558
+ if (!status.branch) blockers.push("detached_head_or_unknown_branch");
8559
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
8560
+ if (!status.upstream) blockers.push("upstream_missing");
8561
+ if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
8562
+ if (status.hasConflicts) blockers.push("conflicts_present");
8563
+ if (status.staged > 0) blockers.push("staged_changes_present");
8564
+ if (status.modified > 0) blockers.push("modified_changes_present");
8565
+ if (status.untracked > 0) blockers.push("untracked_changes_present");
8566
+ if (status.deleted > 0) blockers.push("deleted_changes_present");
8567
+ if (status.renamed > 0) blockers.push("renamed_changes_present");
8568
+ if (status.stashCount > 0) blockers.push("stash_entries_present");
8569
+ blockers.push(...collectSubmoduleBlockers(status, "pre"));
8570
+ if (status.ahead > 0 && status.behind > 0) {
8571
+ blockers.push("branch_diverged_from_upstream");
8572
+ blockers.push("branch_has_local_commits");
8573
+ } else if (status.ahead > 0) blockers.push("branch_has_local_commits");
8574
+ return blockers;
8575
+ }
8576
+ function collectPostExecutionBlockers(status) {
8577
+ const blockers = [];
8578
+ if (!status.isGitRepo) blockers.push("post_not_git_repo");
8579
+ if (status.hasConflicts) blockers.push("post_conflicts_present");
8580
+ if (status.ahead !== 0) blockers.push("post_branch_ahead");
8581
+ if (status.behind !== 0) blockers.push("post_branch_still_behind");
8582
+ if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
8583
+ blockers.push("post_working_tree_not_clean");
8584
+ }
8585
+ if (status.stashCount > 0) blockers.push("post_stash_entries_present");
8586
+ blockers.push(...collectSubmoduleBlockers(status, "post"));
8587
+ return blockers;
8588
+ }
8589
+ function collectSubmoduleBlockers(status, phase) {
8590
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
8591
+ const blockers = [];
8592
+ for (const submodule of submodules) {
8593
+ if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
8594
+ if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
8595
+ if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
8596
+ }
8597
+ return blockers;
8598
+ }
8599
+ function chooseBlockCode(status, blockers) {
8600
+ if (blockers.includes("not_git_repo")) return "not_git_repo";
8601
+ if (blockers.includes("branch_mismatch")) return "branch_mismatch";
8602
+ if (blockers.includes("upstream_missing")) return "upstream_missing";
8603
+ if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
8604
+ if (blockers.some((reason) => reason.includes("submodule"))) return "submodule_not_clean";
8605
+ if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
8606
+ if (blockers.includes("branch_has_local_commits") || status.ahead > 0) return "branch_ahead";
8607
+ if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
8608
+ return "preflight_blocked";
8609
+ }
8610
+ function codeToConvergenceStatus(code) {
8611
+ if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
8612
+ if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
8613
+ return "blocked";
8614
+ }
8615
+ async function verifyHeadIsAncestorOfUpstream(workspace, upstream, timeoutMs) {
8616
+ if (!upstream) return { ok: false, error: "missing upstream" };
8617
+ try {
8618
+ await runGit(workspace, ["merge-base", "--is-ancestor", "HEAD", upstream], { timeoutMs: timeoutMs ?? 15e3 });
8619
+ return { ok: true };
8620
+ } catch (error) {
8621
+ return { ok: false, error: formatGitError2(error) };
8622
+ }
8623
+ }
8624
+ function block(base, code, blockingReasons) {
8625
+ const normalizedReasons = normalizeBlockingReasons(blockingReasons);
8626
+ return {
8627
+ ...base,
8628
+ success: false,
8629
+ code,
8630
+ allowed: false,
8631
+ willRun: false,
8632
+ executed: false,
8633
+ blockingReasons: normalizedReasons
8634
+ };
8635
+ }
8636
+ function normalizeBlockingReasons(reasons) {
8637
+ const normalized = /* @__PURE__ */ new Set();
8638
+ for (const reason of reasons) {
8639
+ normalized.add(reason);
8640
+ }
8641
+ if ([
8642
+ "conflicts_present",
8643
+ "staged_changes_present",
8644
+ "modified_changes_present",
8645
+ "untracked_changes_present",
8646
+ "deleted_changes_present",
8647
+ "renamed_changes_present"
8648
+ ].some((reason) => normalized.has(reason))) {
8649
+ normalized.add("working_tree_not_clean");
8650
+ }
8651
+ return Array.from(normalized);
8652
+ }
8653
+ function buildConvergenceState(status, convergenceStatus) {
8654
+ return {
8655
+ status: convergenceStatus,
8656
+ branch: status.branch,
8657
+ headCommit: status.headCommit,
8658
+ upstream: status.upstream,
8659
+ ahead: status.ahead,
8660
+ behind: status.behind,
8661
+ dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
8662
+ stashCount: status.stashCount,
8663
+ submodules: summarizeSubmodules(status.submodules)
8664
+ };
8665
+ }
8666
+ function summarizeSubmodules(submodules) {
8667
+ return (submodules || []).map((submodule) => ({
8668
+ path: submodule.path,
8669
+ commit: submodule.commit,
8670
+ dirty: submodule.dirty,
8671
+ outOfSync: submodule.outOfSync,
8672
+ ...submodule.error ? { error: submodule.error } : {}
8673
+ }));
8674
+ }
8675
+ function normalizeOptionalString(value) {
8676
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
8677
+ }
8678
+ function formatGitError2(error) {
8679
+ if (error instanceof GitCommandError) {
8680
+ return error.stderr || error.stdout || error.message;
8681
+ }
8682
+ if (error instanceof Error) return error.message;
8683
+ return String(error);
8684
+ }
8685
+ async function appendFastForwardLedger(result, outcome) {
8686
+ if (!result.meshId) return;
8687
+ try {
8688
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
8689
+ appendLedgerEntry2(result.meshId, {
8690
+ kind: "direct_fast_forward",
8691
+ ...result.nodeId ? { nodeId: result.nodeId } : {},
8692
+ payload: {
8693
+ operation: "mesh_fast_forward_node",
8694
+ outcome,
8695
+ code: result.code,
8696
+ workspace: result.workspace,
8697
+ allowed: result.allowed,
8698
+ dryRun: result.dryRun,
8699
+ willRun: result.willRun,
8700
+ executed: result.executed,
8701
+ branch: result.postStatus?.branch ?? result.current?.branch,
8702
+ upstream: result.postStatus?.upstream ?? result.current?.upstream,
8703
+ before: result.current ? {
8704
+ headCommit: result.current.headCommit,
8705
+ ahead: result.current.ahead,
8706
+ behind: result.current.behind
8707
+ } : void 0,
8708
+ after: result.postStatus ? {
8709
+ headCommit: result.postStatus.headCommit,
8710
+ ahead: result.postStatus.ahead,
8711
+ behind: result.postStatus.behind
8712
+ } : void 0,
8713
+ blockingReasons: result.blockingReasons
8714
+ }
8715
+ });
8716
+ } catch (error) {
8717
+ result.ledgerError = error instanceof Error ? error.message : String(error);
8718
+ }
8719
+ }
8720
+
8368
8721
  // src/mesh/mesh-ledger-reconciliation.ts
8369
8722
  function lastTimestamp(slice) {
8370
8723
  const entries = Array.isArray(slice?.entries) ? slice.entries : [];
@@ -23979,10 +24332,10 @@ function getMessageEventTime(message) {
23979
24332
  function stringifyPreviewContent(content) {
23980
24333
  if (typeof content === "string") return content;
23981
24334
  if (Array.isArray(content)) {
23982
- return content.map((block) => {
23983
- if (typeof block === "string") return block;
23984
- if (block && typeof block === "object" && "text" in block) {
23985
- return String(block.text || "");
24335
+ return content.map((block2) => {
24336
+ if (typeof block2 === "string") return block2;
24337
+ if (block2 && typeof block2 === "object" && "text" in block2) {
24338
+ return String(block2.text || "");
23986
24339
  }
23987
24340
  return "";
23988
24341
  }).join(" ");
@@ -27227,6 +27580,32 @@ var DaemonCommandRouter = class {
27227
27580
  cleanupWillRun: false
27228
27581
  };
27229
27582
  }
27583
+ case "fast_forward_mesh_node": {
27584
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
27585
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
27586
+ let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
27587
+ let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
27588
+ if (!workspace && meshId && nodeId) {
27589
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
27590
+ const mesh = meshRecord?.mesh;
27591
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
27592
+ workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
27593
+ if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
27594
+ submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
27595
+ }
27596
+ }
27597
+ const result = await fastForwardMeshNode({
27598
+ meshId: meshId || void 0,
27599
+ nodeId: nodeId || void 0,
27600
+ workspace,
27601
+ branch: typeof args?.branch === "string" ? args.branch : void 0,
27602
+ execute: args?.execute === true,
27603
+ dryRun: args?.dryRun === true,
27604
+ updateSubmodules: args?.updateSubmodules === true,
27605
+ submoduleIgnorePaths
27606
+ });
27607
+ return result;
27608
+ }
27230
27609
  case "refine_mesh_node": {
27231
27610
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
27232
27611
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
@@ -27737,20 +28116,20 @@ var DaemonCommandRouter = class {
27737
28116
  const geminiMdPath = `${workspace}/GEMINI.md`;
27738
28117
  const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
27739
28118
  const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
27740
- const block = `${marker}
28119
+ const block2 = `${marker}
27741
28120
  ${cliCmdSystemPrompt}
27742
28121
  ${markerEnd}`;
27743
28122
  if (efs(geminiMdPath)) {
27744
28123
  const existing = rfs(geminiMdPath, "utf-8");
27745
28124
  const replaced = existing.replace(
27746
28125
  new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
27747
- block
28126
+ block2
27748
28127
  );
27749
28128
  wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
27750
28129
 
27751
- ${block}`);
28130
+ ${block2}`);
27752
28131
  } else {
27753
- wfs(geminiMdPath, block);
28132
+ wfs(geminiMdPath, block2);
27754
28133
  }
27755
28134
  LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
27756
28135
  } catch (e) {
@@ -36389,6 +36768,7 @@ async function shutdownDaemonComponents(components) {
36389
36768
  enqueueTask,
36390
36769
  ensureSessionHostReady,
36391
36770
  execNpmCommandSync,
36771
+ fastForwardMeshNode,
36392
36772
  filterActivityChatMessages,
36393
36773
  filterChatMessagesByVisibility,
36394
36774
  filterInternalChatMessages,