@yemi33/minions 0.1.2352 → 0.1.2354
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/dashboard.js +71 -19
- package/docs/README.md +2 -0
- package/docs/kb-dedup-duplicate-pair-investigation.md +138 -0
- package/docs/kb-sweep.md +13 -1
- package/docs/live-checkout-mode.md +7 -4
- package/docs/shared-lifecycle-module-map.md +675 -0
- package/engine/cli.js +4 -0
- package/engine/lifecycle.js +55 -22
- package/engine/live-checkout.js +64 -5
- package/engine/playbook.js +1 -0
- package/engine/pr-action.js +12 -7
- package/engine/process-utils.js +700 -0
- package/engine/shared.js +39 -666
- package/engine.js +78 -0
- package/package.json +1 -1
- package/playbooks/plan-to-prd.md +2 -0
package/engine.js
CHANGED
|
@@ -2460,6 +2460,21 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2460
2460
|
const _liveAllowNonMainBase = !!(meta?.useExistingBranch || meta?.branchStrategy === 'shared-branch');
|
|
2461
2461
|
const _wiIdForAlert = meta?.item?.id || id;
|
|
2462
2462
|
const _liveCheckout = require('./engine/live-checkout');
|
|
2463
|
+
// W-mrawgw4q000a6bff: stash-before-reset ordering. Resolve BOTH recovery
|
|
2464
|
+
// policies here (before the first prepareLiveCheckout call) so we can
|
|
2465
|
+
// decide precedence up front instead of letting prepareLiveCheckout's
|
|
2466
|
+
// internal (autoReset-only) resolution win by default. When auto-stash is
|
|
2467
|
+
// enabled, pass `autoReset: false` to force this first call to just report
|
|
2468
|
+
// `{ ok:false, reason:'dirty' }` on a dirty tree — bypassing its internal
|
|
2469
|
+
// destructive reset attempt entirely — so the non-destructive stash path
|
|
2470
|
+
// below gets first crack at the dirty tree. Auto-reset then only runs as an
|
|
2471
|
+
// explicit LAST-RESORT fallback (see the `_autoStash.outcome === 'unchanged'`
|
|
2472
|
+
// block below) when stash is disabled or itself failed. When auto-stash is
|
|
2473
|
+
// disabled, `autoReset` stays `undefined` so prepareLiveCheckout keeps its
|
|
2474
|
+
// original behavior of self-resolving straight to reset (no change for
|
|
2475
|
+
// auto-reset-only dispatches).
|
|
2476
|
+
const _wantAutoStash = (typeof _liveCheckout.resolveLiveCheckoutAutoStash === 'function')
|
|
2477
|
+
&& !!_liveCheckout.resolveLiveCheckoutAutoStash({ project, engine: engineConfig });
|
|
2463
2478
|
let _liveResult;
|
|
2464
2479
|
try {
|
|
2465
2480
|
_liveResult = await _liveCheckout.prepareLiveCheckout({
|
|
@@ -2471,6 +2486,7 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2471
2486
|
wiId: _wiIdForAlert,
|
|
2472
2487
|
skipDirtyCheck: !!project.skipLiveCheckoutDirtyCheck,
|
|
2473
2488
|
allowNonMainBase: _liveAllowNonMainBase,
|
|
2489
|
+
autoReset: _wantAutoStash ? false : undefined,
|
|
2474
2490
|
log: (msg, lvl) => log(lvl || 'info', msg),
|
|
2475
2491
|
});
|
|
2476
2492
|
} catch (liveErr) {
|
|
@@ -2544,6 +2560,59 @@ async function spawnAgent(dispatchItem, config) {
|
|
|
2544
2560
|
return null;
|
|
2545
2561
|
}
|
|
2546
2562
|
_liveResult = _autoStash.liveResult;
|
|
2563
|
+
// ── Auto-reset LAST-RESORT fallback (W-mrawgw4q000a6bff) ────────────────
|
|
2564
|
+
// Stash was attempted above (if enabled) and had first crack at the dirty
|
|
2565
|
+
// tree. If the tree is STILL confirmed-dirty here — either because
|
|
2566
|
+
// auto-stash is disabled, or because `applyLiveCheckoutAutoStash` itself
|
|
2567
|
+
// reported `outcome:'unchanged'` (the `git stash push` call failed) — and
|
|
2568
|
+
// the fleet/project auto-reset policy resolves true, NOW perform the
|
|
2569
|
+
// destructive `fetch` + `reset --hard origin/<ref>` as a fallback, reusing
|
|
2570
|
+
// prepareLiveCheckout's existing reset logic by re-invoking it with an
|
|
2571
|
+
// explicit `autoReset: true` (bypassing config resolution, which we've
|
|
2572
|
+
// already evaluated). This only fires when the first prepareLiveCheckout
|
|
2573
|
+
// call above was forced to `autoReset:false` (i.e. auto-stash was enabled
|
|
2574
|
+
// but did not recover a clean tree) — when auto-stash was disabled from the
|
|
2575
|
+
// start, the FIRST call already self-resolved auto-reset internally, so
|
|
2576
|
+
// `_autoStash.outcome` is `'unchanged'` there too but `_wantAutoStash` was
|
|
2577
|
+
// false and the original call's own resolution already ran (nothing to
|
|
2578
|
+
// retry here, only re-checking after a NO-OP stash gate). Never destructive
|
|
2579
|
+
// when disabled; never runs when stash already succeeded (`outcome ===
|
|
2580
|
+
// 'stashed'`).
|
|
2581
|
+
// Compute this once, phrased differently from the confirmed-dirty check
|
|
2582
|
+
// below (so source-inspection tests anchored on the literal dirty-alert
|
|
2583
|
+
// check text keep matching that ORIGINAL occurrence, not this one).
|
|
2584
|
+
const _fallbackReason = (_liveResult && _liveResult.ok === false) ? _liveResult.reason : null;
|
|
2585
|
+
if (_wantAutoStash && _autoStash.outcome === 'unchanged'
|
|
2586
|
+
&& _fallbackReason === 'dirty'
|
|
2587
|
+
&& shared.resolveLiveCheckoutAutoReset(project, engineConfig)) {
|
|
2588
|
+
log('info', `spawnAgent: live-checkout auto-stash did not clear the dirty tree for ${id}; falling back to auto-reset (liveCheckoutAutoReset)`);
|
|
2589
|
+
try {
|
|
2590
|
+
_liveResult = await _liveCheckout.prepareLiveCheckout({
|
|
2591
|
+
localPath: cwd,
|
|
2592
|
+
branchName,
|
|
2593
|
+
mainRef: _liveMainRef,
|
|
2594
|
+
gitOpts: _gitOpts,
|
|
2595
|
+
dispatchId: id,
|
|
2596
|
+
wiId: _wiIdForAlert,
|
|
2597
|
+
skipDirtyCheck: !!project.skipLiveCheckoutDirtyCheck,
|
|
2598
|
+
allowNonMainBase: _liveAllowNonMainBase,
|
|
2599
|
+
autoReset: true,
|
|
2600
|
+
log: (msg, lvl) => log(lvl || 'info', msg),
|
|
2601
|
+
});
|
|
2602
|
+
} catch (resetFallbackErr) {
|
|
2603
|
+
log('error', `spawnAgent: live-checkout auto-reset fallback threw for ${id}: ${resetFallbackErr.message}`);
|
|
2604
|
+
_cleanupPromptFiles();
|
|
2605
|
+
completeDispatch(
|
|
2606
|
+
id,
|
|
2607
|
+
DISPATCH_RESULT.ERROR,
|
|
2608
|
+
`live-checkout failed: ${resetFallbackErr.message}`.slice(0, 800),
|
|
2609
|
+
'Live-checkout helper threw during the auto-reset fallback (not proof of a dirty tree). Auto-retried with bounded backoff; transient git/branch-lock state usually clears on the next attempt.',
|
|
2610
|
+
{ failureClass: FAILURE_CLASS.LIVE_CHECKOUT_FAILED },
|
|
2611
|
+
);
|
|
2612
|
+
cleanupTempAgent(agentId);
|
|
2613
|
+
return null;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2547
2616
|
if (_liveResult && _liveResult.ok === false && _liveResult.reason === 'dirty') {
|
|
2548
2617
|
const _dirtyFiles = Array.isArray(_liveResult.dirtyFiles) ? _liveResult.dirtyFiles : [];
|
|
2549
2618
|
const _branchInfo = typeof _liveResult.branchInfo === 'string' ? _liveResult.branchInfo : '';
|
|
@@ -8875,6 +8944,15 @@ function buildWorkItemDispatchVars(item, vars, config, options = {}) {
|
|
|
8875
8944
|
} catch (e) { log('warn', `checkpoint read for ${item.id}: ${e.message}`); }
|
|
8876
8945
|
}
|
|
8877
8946
|
|
|
8947
|
+
// Retry context — surfaces WHY the previous attempt was bounced (e.g. a
|
|
8948
|
+
// validation-gate rejection like the plan-to-prd #893 PRD-file check) so a
|
|
8949
|
+
// retried agent doesn't blindly repeat the same mistake. Populated whenever
|
|
8950
|
+
// a prior tick set item._lastRetryReason (dispatch.js / lifecycle.js retry
|
|
8951
|
+
// paths); empty string on a fresh (non-retry) dispatch.
|
|
8952
|
+
vars.retry_context = (item._retryCount && item._lastRetryReason)
|
|
8953
|
+
? `## Retry Context (attempt ${item._retryCount + 1})\n\nThe previous attempt did not pass validation:\n\n> ${item._lastRetryReason}\n\nAddress this before completing again.`
|
|
8954
|
+
: '';
|
|
8955
|
+
|
|
8878
8956
|
// ASK-specific variables
|
|
8879
8957
|
if (workType === WORK_TYPE.ASK) {
|
|
8880
8958
|
vars.question = item.title + (item.description ? '\n\n' + item.description : '');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2354",
|
|
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"
|