@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.mjs 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 ")) {
@@ -1185,7 +1185,8 @@ function buildRulesSection(coordinatorCliType) {
1185
1185
  - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
1186
1186
  - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
1187
1187
  - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
1188
- - **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.
1188
+ - **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.
1189
+ - **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.
1189
1190
  - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
1190
1191
  }
1191
1192
  var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
@@ -1209,6 +1210,7 @@ var init_coordinator_prompt = __esm({
1209
1210
  | \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
1210
1211
  | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
1211
1212
  | \`mesh_git_status\` | Check git status on a specific node |
1213
+ | \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
1212
1214
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
1213
1215
  | \`mesh_approve\` | Approve/reject a pending agent action |
1214
1216
  | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
@@ -1231,7 +1233,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
1231
1233
  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\`.
1232
1234
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
1233
1235
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
1234
- 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.
1236
+ 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.
1235
1237
  8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
1236
1238
  9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
1237
1239
 
@@ -8115,6 +8117,356 @@ async function syncMeshes(transport) {
8115
8117
  // src/index.ts
8116
8118
  init_mesh_ledger();
8117
8119
 
8120
+ // src/mesh/mesh-fast-forward.ts
8121
+ init_git_executor();
8122
+ var STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
8123
+ async function fastForwardMeshNode(args) {
8124
+ const workspace = typeof args.workspace === "string" ? args.workspace.trim() : "";
8125
+ const nodeId = normalizeOptionalString(args.nodeId);
8126
+ const meshId = normalizeOptionalString(args.meshId);
8127
+ const requestedBranch = normalizeOptionalString(args.branch);
8128
+ const updateSubmodules = args.updateSubmodules === true;
8129
+ const dryRun = args.dryRun === true || args.execute !== true;
8130
+ const plannedSteps = buildPlannedSteps(updateSubmodules);
8131
+ const base = {
8132
+ ...nodeId ? { nodeId } : {},
8133
+ ...meshId ? { meshId } : {},
8134
+ workspace,
8135
+ dryRun,
8136
+ updateSubmodules,
8137
+ plannedSteps
8138
+ };
8139
+ if (!workspace) {
8140
+ return block(base, "invalid_workspace", ["workspace_required"]);
8141
+ }
8142
+ const current = await getGitRepoStatus(workspace, {
8143
+ ...STATUS_OPTIONS,
8144
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8145
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8146
+ });
8147
+ const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
8148
+ if (earlyBlockers.length > 0) {
8149
+ return {
8150
+ ...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
8151
+ current,
8152
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers)))
8153
+ };
8154
+ }
8155
+ if (current.behind === 0) {
8156
+ const result2 = {
8157
+ ...base,
8158
+ success: true,
8159
+ code: "already_up_to_date",
8160
+ allowed: true,
8161
+ willRun: false,
8162
+ executed: false,
8163
+ blockingReasons: [],
8164
+ current,
8165
+ preStatus: current,
8166
+ postStatus: current,
8167
+ finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
8168
+ };
8169
+ await appendFastForwardLedger(result2, "noop");
8170
+ return result2;
8171
+ }
8172
+ const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || "", args.timeoutMs);
8173
+ if (!ancestorCheck.ok) {
8174
+ const result2 = {
8175
+ ...block(base, "non_fast_forward", ["head_is_not_ancestor_of_upstream"]),
8176
+ current,
8177
+ preStatus: current,
8178
+ operationError: ancestorCheck.error,
8179
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
8180
+ };
8181
+ await appendFastForwardLedger(result2, "blocked");
8182
+ return result2;
8183
+ }
8184
+ if (dryRun) {
8185
+ const result2 = {
8186
+ ...base,
8187
+ success: true,
8188
+ code: "fast_forward_available",
8189
+ allowed: true,
8190
+ willRun: false,
8191
+ executed: false,
8192
+ blockingReasons: [],
8193
+ current,
8194
+ preStatus: current,
8195
+ finalBranchConvergenceState: buildConvergenceState(current, "fast_forward_available")
8196
+ };
8197
+ return result2;
8198
+ }
8199
+ try {
8200
+ await runGit(workspace, ["merge", "--ff-only", current.upstream || ""], { timeoutMs: args.timeoutMs ?? 3e4 });
8201
+ } catch (error) {
8202
+ const result2 = {
8203
+ ...block(base, "merge_ff_only_failed", ["merge_ff_only_failed"]),
8204
+ current,
8205
+ preStatus: current,
8206
+ operationError: formatGitError2(error),
8207
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
8208
+ };
8209
+ await appendFastForwardLedger(result2, "failed");
8210
+ return result2;
8211
+ }
8212
+ let postStatus = await getGitRepoStatus(workspace, {
8213
+ ...STATUS_OPTIONS,
8214
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8215
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8216
+ });
8217
+ const submoduleIssues = collectSubmoduleBlockers(postStatus, "post");
8218
+ let submoduleFollowUpRequired = false;
8219
+ let operationError;
8220
+ if (submoduleIssues.length > 0) {
8221
+ if (updateSubmodules) {
8222
+ try {
8223
+ await runGit(workspace, ["submodule", "update", "--init", "--recursive"], { timeoutMs: args.timeoutMs ?? 6e4 });
8224
+ postStatus = await getGitRepoStatus(workspace, {
8225
+ ...STATUS_OPTIONS,
8226
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
8227
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
8228
+ });
8229
+ } catch (error) {
8230
+ operationError = formatGitError2(error);
8231
+ }
8232
+ } else {
8233
+ submoduleFollowUpRequired = true;
8234
+ }
8235
+ }
8236
+ const postBlockers = collectPostExecutionBlockers(postStatus);
8237
+ if (operationError) postBlockers.push("submodule_update_failed");
8238
+ if (submoduleFollowUpRequired) postBlockers.push("submodule_update_required");
8239
+ const success = postBlockers.length === 0 || submoduleFollowUpRequired;
8240
+ const code = postBlockers.length === 0 ? "fast_forward_applied" : submoduleFollowUpRequired ? "fast_forward_applied_submodule_update_required" : "post_verify_failed";
8241
+ const result = {
8242
+ ...base,
8243
+ success,
8244
+ code,
8245
+ allowed: true,
8246
+ willRun: true,
8247
+ executed: true,
8248
+ blockingReasons: postBlockers,
8249
+ current,
8250
+ preStatus: current,
8251
+ postStatus,
8252
+ ...operationError ? { operationError } : {},
8253
+ finalBranchConvergenceState: buildConvergenceState(
8254
+ postStatus,
8255
+ postBlockers.length === 0 ? "fast_forwarded" : submoduleFollowUpRequired ? "follow_up_required" : "post_verify_failed"
8256
+ )
8257
+ };
8258
+ await appendFastForwardLedger(result, success ? "executed" : "failed");
8259
+ return result;
8260
+ }
8261
+ function buildPlannedSteps(updateSubmodules) {
8262
+ const steps = [
8263
+ {
8264
+ operation: "refresh_upstream",
8265
+ description: "Refresh the tracked upstream remote ref before trusting ahead/behind state.",
8266
+ safe: true,
8267
+ willMutateWorktree: false
8268
+ },
8269
+ {
8270
+ operation: "verify_clean_worktree",
8271
+ description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
8272
+ safe: true,
8273
+ willMutateWorktree: false
8274
+ },
8275
+ {
8276
+ operation: "verify_fast_forward",
8277
+ description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
8278
+ safe: true,
8279
+ willMutateWorktree: false
8280
+ },
8281
+ {
8282
+ operation: "merge_ff_only",
8283
+ description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
8284
+ safe: true,
8285
+ willMutateWorktree: true
8286
+ }
8287
+ ];
8288
+ if (updateSubmodules) {
8289
+ steps.push({
8290
+ operation: "submodule_update",
8291
+ description: "If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.",
8292
+ safe: true,
8293
+ willMutateWorktree: true
8294
+ });
8295
+ }
8296
+ steps.push({
8297
+ operation: "verify_post_status",
8298
+ description: "Re-read daemon-owned git status and report final branch convergence state.",
8299
+ safe: true,
8300
+ willMutateWorktree: false
8301
+ });
8302
+ return steps;
8303
+ }
8304
+ function collectPreflightBlockers(status, requestedBranch) {
8305
+ const blockers = [];
8306
+ if (!status.isGitRepo) blockers.push("not_git_repo");
8307
+ if (!status.branch) blockers.push("detached_head_or_unknown_branch");
8308
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
8309
+ if (!status.upstream) blockers.push("upstream_missing");
8310
+ if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
8311
+ if (status.hasConflicts) blockers.push("conflicts_present");
8312
+ if (status.staged > 0) blockers.push("staged_changes_present");
8313
+ if (status.modified > 0) blockers.push("modified_changes_present");
8314
+ if (status.untracked > 0) blockers.push("untracked_changes_present");
8315
+ if (status.deleted > 0) blockers.push("deleted_changes_present");
8316
+ if (status.renamed > 0) blockers.push("renamed_changes_present");
8317
+ if (status.stashCount > 0) blockers.push("stash_entries_present");
8318
+ blockers.push(...collectSubmoduleBlockers(status, "pre"));
8319
+ if (status.ahead > 0 && status.behind > 0) {
8320
+ blockers.push("branch_diverged_from_upstream");
8321
+ blockers.push("branch_has_local_commits");
8322
+ } else if (status.ahead > 0) blockers.push("branch_has_local_commits");
8323
+ return blockers;
8324
+ }
8325
+ function collectPostExecutionBlockers(status) {
8326
+ const blockers = [];
8327
+ if (!status.isGitRepo) blockers.push("post_not_git_repo");
8328
+ if (status.hasConflicts) blockers.push("post_conflicts_present");
8329
+ if (status.ahead !== 0) blockers.push("post_branch_ahead");
8330
+ if (status.behind !== 0) blockers.push("post_branch_still_behind");
8331
+ if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
8332
+ blockers.push("post_working_tree_not_clean");
8333
+ }
8334
+ if (status.stashCount > 0) blockers.push("post_stash_entries_present");
8335
+ blockers.push(...collectSubmoduleBlockers(status, "post"));
8336
+ return blockers;
8337
+ }
8338
+ function collectSubmoduleBlockers(status, phase) {
8339
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
8340
+ const blockers = [];
8341
+ for (const submodule of submodules) {
8342
+ if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
8343
+ if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
8344
+ if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
8345
+ }
8346
+ return blockers;
8347
+ }
8348
+ function chooseBlockCode(status, blockers) {
8349
+ if (blockers.includes("not_git_repo")) return "not_git_repo";
8350
+ if (blockers.includes("branch_mismatch")) return "branch_mismatch";
8351
+ if (blockers.includes("upstream_missing")) return "upstream_missing";
8352
+ if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
8353
+ if (blockers.some((reason) => reason.includes("submodule"))) return "submodule_not_clean";
8354
+ if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
8355
+ if (blockers.includes("branch_has_local_commits") || status.ahead > 0) return "branch_ahead";
8356
+ if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
8357
+ return "preflight_blocked";
8358
+ }
8359
+ function codeToConvergenceStatus(code) {
8360
+ if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
8361
+ if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
8362
+ return "blocked";
8363
+ }
8364
+ async function verifyHeadIsAncestorOfUpstream(workspace, upstream, timeoutMs) {
8365
+ if (!upstream) return { ok: false, error: "missing upstream" };
8366
+ try {
8367
+ await runGit(workspace, ["merge-base", "--is-ancestor", "HEAD", upstream], { timeoutMs: timeoutMs ?? 15e3 });
8368
+ return { ok: true };
8369
+ } catch (error) {
8370
+ return { ok: false, error: formatGitError2(error) };
8371
+ }
8372
+ }
8373
+ function block(base, code, blockingReasons) {
8374
+ const normalizedReasons = normalizeBlockingReasons(blockingReasons);
8375
+ return {
8376
+ ...base,
8377
+ success: false,
8378
+ code,
8379
+ allowed: false,
8380
+ willRun: false,
8381
+ executed: false,
8382
+ blockingReasons: normalizedReasons
8383
+ };
8384
+ }
8385
+ function normalizeBlockingReasons(reasons) {
8386
+ const normalized = /* @__PURE__ */ new Set();
8387
+ for (const reason of reasons) {
8388
+ normalized.add(reason);
8389
+ }
8390
+ if ([
8391
+ "conflicts_present",
8392
+ "staged_changes_present",
8393
+ "modified_changes_present",
8394
+ "untracked_changes_present",
8395
+ "deleted_changes_present",
8396
+ "renamed_changes_present"
8397
+ ].some((reason) => normalized.has(reason))) {
8398
+ normalized.add("working_tree_not_clean");
8399
+ }
8400
+ return Array.from(normalized);
8401
+ }
8402
+ function buildConvergenceState(status, convergenceStatus) {
8403
+ return {
8404
+ status: convergenceStatus,
8405
+ branch: status.branch,
8406
+ headCommit: status.headCommit,
8407
+ upstream: status.upstream,
8408
+ ahead: status.ahead,
8409
+ behind: status.behind,
8410
+ dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
8411
+ stashCount: status.stashCount,
8412
+ submodules: summarizeSubmodules(status.submodules)
8413
+ };
8414
+ }
8415
+ function summarizeSubmodules(submodules) {
8416
+ return (submodules || []).map((submodule) => ({
8417
+ path: submodule.path,
8418
+ commit: submodule.commit,
8419
+ dirty: submodule.dirty,
8420
+ outOfSync: submodule.outOfSync,
8421
+ ...submodule.error ? { error: submodule.error } : {}
8422
+ }));
8423
+ }
8424
+ function normalizeOptionalString(value) {
8425
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
8426
+ }
8427
+ function formatGitError2(error) {
8428
+ if (error instanceof GitCommandError) {
8429
+ return error.stderr || error.stdout || error.message;
8430
+ }
8431
+ if (error instanceof Error) return error.message;
8432
+ return String(error);
8433
+ }
8434
+ async function appendFastForwardLedger(result, outcome) {
8435
+ if (!result.meshId) return;
8436
+ try {
8437
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
8438
+ appendLedgerEntry2(result.meshId, {
8439
+ kind: "direct_fast_forward",
8440
+ ...result.nodeId ? { nodeId: result.nodeId } : {},
8441
+ payload: {
8442
+ operation: "mesh_fast_forward_node",
8443
+ outcome,
8444
+ code: result.code,
8445
+ workspace: result.workspace,
8446
+ allowed: result.allowed,
8447
+ dryRun: result.dryRun,
8448
+ willRun: result.willRun,
8449
+ executed: result.executed,
8450
+ branch: result.postStatus?.branch ?? result.current?.branch,
8451
+ upstream: result.postStatus?.upstream ?? result.current?.upstream,
8452
+ before: result.current ? {
8453
+ headCommit: result.current.headCommit,
8454
+ ahead: result.current.ahead,
8455
+ behind: result.current.behind
8456
+ } : void 0,
8457
+ after: result.postStatus ? {
8458
+ headCommit: result.postStatus.headCommit,
8459
+ ahead: result.postStatus.ahead,
8460
+ behind: result.postStatus.behind
8461
+ } : void 0,
8462
+ blockingReasons: result.blockingReasons
8463
+ }
8464
+ });
8465
+ } catch (error) {
8466
+ result.ledgerError = error instanceof Error ? error.message : String(error);
8467
+ }
8468
+ }
8469
+
8118
8470
  // src/mesh/mesh-ledger-reconciliation.ts
8119
8471
  function lastTimestamp(slice) {
8120
8472
  const entries = Array.isArray(slice?.entries) ? slice.entries : [];
@@ -23734,10 +24086,10 @@ function getMessageEventTime(message) {
23734
24086
  function stringifyPreviewContent(content) {
23735
24087
  if (typeof content === "string") return content;
23736
24088
  if (Array.isArray(content)) {
23737
- return content.map((block) => {
23738
- if (typeof block === "string") return block;
23739
- if (block && typeof block === "object" && "text" in block) {
23740
- return String(block.text || "");
24089
+ return content.map((block2) => {
24090
+ if (typeof block2 === "string") return block2;
24091
+ if (block2 && typeof block2 === "object" && "text" in block2) {
24092
+ return String(block2.text || "");
23741
24093
  }
23742
24094
  return "";
23743
24095
  }).join(" ");
@@ -26982,6 +27334,32 @@ var DaemonCommandRouter = class {
26982
27334
  cleanupWillRun: false
26983
27335
  };
26984
27336
  }
27337
+ case "fast_forward_mesh_node": {
27338
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
27339
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
27340
+ let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
27341
+ let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
27342
+ if (!workspace && meshId && nodeId) {
27343
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
27344
+ const mesh = meshRecord?.mesh;
27345
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
27346
+ workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
27347
+ if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
27348
+ submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
27349
+ }
27350
+ }
27351
+ const result = await fastForwardMeshNode({
27352
+ meshId: meshId || void 0,
27353
+ nodeId: nodeId || void 0,
27354
+ workspace,
27355
+ branch: typeof args?.branch === "string" ? args.branch : void 0,
27356
+ execute: args?.execute === true,
27357
+ dryRun: args?.dryRun === true,
27358
+ updateSubmodules: args?.updateSubmodules === true,
27359
+ submoduleIgnorePaths
27360
+ });
27361
+ return result;
27362
+ }
26985
27363
  case "refine_mesh_node": {
26986
27364
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26987
27365
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
@@ -27492,20 +27870,20 @@ var DaemonCommandRouter = class {
27492
27870
  const geminiMdPath = `${workspace}/GEMINI.md`;
27493
27871
  const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
27494
27872
  const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
27495
- const block = `${marker}
27873
+ const block2 = `${marker}
27496
27874
  ${cliCmdSystemPrompt}
27497
27875
  ${markerEnd}`;
27498
27876
  if (efs(geminiMdPath)) {
27499
27877
  const existing = rfs(geminiMdPath, "utf-8");
27500
27878
  const replaced = existing.replace(
27501
27879
  new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
27502
- block
27880
+ block2
27503
27881
  );
27504
27882
  wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
27505
27883
 
27506
- ${block}`);
27884
+ ${block2}`);
27507
27885
  } else {
27508
- wfs(geminiMdPath, block);
27886
+ wfs(geminiMdPath, block2);
27509
27887
  }
27510
27888
  LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
27511
27889
  } catch (e) {
@@ -36148,6 +36526,7 @@ export {
36148
36526
  enqueueTask,
36149
36527
  ensureSessionHostReady,
36150
36528
  execNpmCommandSync,
36529
+ fastForwardMeshNode,
36151
36530
  filterActivityChatMessages,
36152
36531
  filterChatMessagesByVisibility,
36153
36532
  filterInternalChatMessages,