@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 +2 -0
- package/dist/index.js +393 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +392 -13
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-fast-forward.d.ts +39 -0
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/package.json +1 -1
- package/src/commands/router.ts +30 -0
- package/src/index.ts +2 -0
- package/src/mesh/coordinator-prompt.ts +4 -2
- package/src/mesh/mesh-fast-forward.ts +430 -0
- package/src/mesh/mesh-ledger.ts +1 -0
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
|
|
375
|
-
if (!
|
|
376
|
-
const lines =
|
|
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((
|
|
23983
|
-
if (typeof
|
|
23984
|
-
if (
|
|
23985
|
-
return String(
|
|
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
|
|
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
|
-
|
|
28126
|
+
block2
|
|
27748
28127
|
);
|
|
27749
28128
|
wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
|
|
27750
28129
|
|
|
27751
|
-
${
|
|
28130
|
+
${block2}`);
|
|
27752
28131
|
} else {
|
|
27753
|
-
wfs(geminiMdPath,
|
|
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,
|