@yemi33/minions 0.1.912 → 0.1.913

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/CHANGELOG.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.912 (2026-04-13)
3
+ ## 0.1.913 (2026-04-13)
4
4
 
5
5
  ### Features
6
+ - fix dep re-merge failure on retry with existing commits (#977)
6
7
  - audit and harden log buffering implementation (#971)
7
8
  - replace magic string 'active' with PR_STATUS.ACTIVE in lifecycle.js (#969)
8
9
  - fix dashboard plan-pause nested lock violation (#968)
package/engine.js CHANGED
@@ -524,7 +524,37 @@ async function spawnAgent(dispatchItem, config) {
524
524
  }
525
525
  // Merge successfully-fetched + recovered (local-only pushed) branches sequentially
526
526
  const fetched = fetchable.filter((_, i) => fetchResults[i].status === 'fulfilled' || recoveredBranches.has(fetchable[i].branch));
527
- if (!depMergeFailed) {
527
+ // Skip dep re-merge if worktree HEAD already contains all dep commits (#973)
528
+ let skipDepMerge = false;
529
+ if (!depMergeFailed && fetched.length > 0) {
530
+ const ancestorChecks = await Promise.all(
531
+ fetched.map(async ({ branch: depBranch }) => {
532
+ try {
533
+ await execAsync(`git merge-base --is-ancestor "origin/${depBranch}" HEAD`, { ..._gitOpts, cwd: worktreePath });
534
+ return true;
535
+ } catch (_) { return false; }
536
+ })
537
+ );
538
+ if (ancestorChecks.every(Boolean)) {
539
+ log('info', `All ${fetched.length} dep branch(es) already merged into ${branchName} — skipping dep re-merge`);
540
+ skipDepMerge = true;
541
+ }
542
+ }
543
+ // Stash uncommitted changes before dep merge if worktree is dirty (#973)
544
+ let stashed = false;
545
+ if (!depMergeFailed && !skipDepMerge && fetched.length > 0) {
546
+ try {
547
+ const statusOut = (await execAsync('git status --porcelain', { ..._gitOpts, cwd: worktreePath })).stdout.toString().trim();
548
+ if (statusOut) {
549
+ await execAsync('git stash push --include-untracked -m "engine: stash before dep re-merge"', { ..._gitOpts, cwd: worktreePath });
550
+ stashed = true;
551
+ log('info', `Stashed uncommitted changes in ${branchName} before dep merge`);
552
+ }
553
+ } catch (stashErr) {
554
+ log('warn', `Failed to stash changes in ${branchName} before dep merge: ${stashErr.message}`);
555
+ }
556
+ }
557
+ if (!depMergeFailed && !skipDepMerge) {
528
558
  for (const { branch: depBranch, prId } of fetched) {
529
559
  try {
530
560
  await execAsync(`git merge "origin/${depBranch}" --no-edit`, { ..._gitOpts, cwd: worktreePath });
@@ -573,6 +603,15 @@ async function spawnAgent(dispatchItem, config) {
573
603
  }
574
604
  }
575
605
  }
606
+ // Restore stashed changes after dep merge (#973)
607
+ if (stashed) {
608
+ try {
609
+ await execAsync('git stash pop', { ..._gitOpts, cwd: worktreePath });
610
+ log('info', `Restored stashed changes in ${branchName} after dep merge`);
611
+ } catch (popErr) {
612
+ log('warn', `git stash pop failed in ${branchName}: ${popErr.message} — stash preserved for agent`);
613
+ }
614
+ }
576
615
  if (depMergeFailed) {
577
616
  _cleanupPromptFiles();
578
617
  // Build actionable failReason identifying the conflicting branch and files
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.912",
3
+ "version": "0.1.913",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"