@yemi33/minions 0.1.2350 → 0.1.2352
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/engine/live-checkout.js +80 -0
- package/engine/queries.js +117 -59
- package/package.json +1 -1
package/engine/live-checkout.js
CHANGED
|
@@ -389,6 +389,45 @@ function _defaultWriteInboxNote(slug, content) {
|
|
|
389
389
|
return require('./dispatch').writeInboxAlert(slug, content);
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
+
// Best-effort, side-effect-light resolution of `mainRef` as a restore target
|
|
393
|
+
// when a captured originalRef is found to be contaminated (see
|
|
394
|
+
// ENGINE_DISPATCH_BRANCH_PATTERN above). Mirrors the STALE-BASE GUARD's
|
|
395
|
+
// local-main / auto-base-repair fallback (Step 4d) but never switches HEAD
|
|
396
|
+
// itself — it only materializes a local `<mainRef>` branch (a plain ref op,
|
|
397
|
+
// no checkout, no fetch, issue #226 preserved) when auto-base-repair is
|
|
398
|
+
// enabled and no local ref already exists. Returns `{ ref, type }` on success
|
|
399
|
+
// or `{ ref: null, type: null }` when mainRef cannot be resolved without a
|
|
400
|
+
// fetch and auto-base-repair is disabled or unavailable.
|
|
401
|
+
async function _resolveMainRefForRestore({ git, baseOpts, mainRef, autoBaseRepair, _resolveAutoBaseRepair, localPath, logFn }) {
|
|
402
|
+
try {
|
|
403
|
+
await git(['rev-parse', '--verify', '--quiet', `refs/heads/${mainRef}`], baseOpts);
|
|
404
|
+
return { ref: mainRef, type: 'branch' };
|
|
405
|
+
} catch { /* fall through to auto-repair */ }
|
|
406
|
+
|
|
407
|
+
let wantBaseRepair = false;
|
|
408
|
+
if (typeof autoBaseRepair === 'boolean') {
|
|
409
|
+
wantBaseRepair = autoBaseRepair;
|
|
410
|
+
} else {
|
|
411
|
+
const resolver = (typeof _resolveAutoBaseRepair === 'function') ? _resolveAutoBaseRepair : _defaultResolveAutoBaseRepair;
|
|
412
|
+
try { wantBaseRepair = !!resolver(localPath); } catch { wantBaseRepair = false; }
|
|
413
|
+
}
|
|
414
|
+
if (!wantBaseRepair) return { ref: null, type: null };
|
|
415
|
+
|
|
416
|
+
try {
|
|
417
|
+
await git(['rev-parse', '--verify', '--quiet', `refs/remotes/origin/${mainRef}`], baseOpts);
|
|
418
|
+
} catch {
|
|
419
|
+
return { ref: null, type: null };
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
await git(['branch', '--no-track', mainRef, `refs/remotes/origin/${mainRef}`], baseOpts);
|
|
423
|
+
logFn('info',
|
|
424
|
+
`live-checkout: materialized local '${mainRef}' from 'origin/${mainRef}' (no fetch, issue #226 preserved) to correct a contaminated originalRef.`);
|
|
425
|
+
return { ref: mainRef, type: 'branch' };
|
|
426
|
+
} catch {
|
|
427
|
+
return { ref: null, type: null };
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
392
431
|
async function prepareLiveCheckout(opts = {}) {
|
|
393
432
|
const {
|
|
394
433
|
localPath,
|
|
@@ -842,6 +881,32 @@ async function prepareLiveCheckout(opts = {}) {
|
|
|
842
881
|
// Plain checkout — NO --force, NO -B, NO pull. Operator owns local commits.
|
|
843
882
|
const failed = await runCheckout(['checkout', branchName], { creating: false });
|
|
844
883
|
if (failed) return failed;
|
|
884
|
+
// ── originalRef contamination invariant (W-mrb6an8300058fd8). ──────────
|
|
885
|
+
// originalRef was captured at Step 3 BEFORE this checkout, from whatever
|
|
886
|
+
// HEAD happened to be. If it itself looks like a prior dispatch's own
|
|
887
|
+
// engine-managed branch (`_looksLikeAgentBranch` — the same `work/<id>`
|
|
888
|
+
// check issue #608's dirty-tree self-heal uses above) — and this isn't an
|
|
889
|
+
// explicit PR-continuation (allowNonMainBase) — it is never a sane restore
|
|
890
|
+
// target: prefer mainRef instead, while still surfacing the anomaly via
|
|
891
|
+
// logFn rather than silently swallowing it.
|
|
892
|
+
if (!allowNonMainBase && originalRefType === 'branch' && originalRef && originalRef !== mainRef &&
|
|
893
|
+
_looksLikeAgentBranch(originalRef)) {
|
|
894
|
+
logFn(
|
|
895
|
+
`[live-checkout] originalRef anomaly: HEAD was on engine-managed branch '${originalRef}' before checking out '${branchName}' — ` +
|
|
896
|
+
`this looks like leftover contamination from an earlier dispatch, not a sane restore target. Attempting to correct to '${mainRef}'.`,
|
|
897
|
+
'warn'
|
|
898
|
+
);
|
|
899
|
+
const corrected = await _resolveMainRefForRestore({ git, baseOpts, mainRef, autoBaseRepair, _resolveAutoBaseRepair, localPath, logFn });
|
|
900
|
+
if (corrected.ref) {
|
|
901
|
+
originalRef = corrected.ref;
|
|
902
|
+
originalRefType = corrected.type;
|
|
903
|
+
} else {
|
|
904
|
+
logFn(
|
|
905
|
+
`[live-checkout] originalRef anomaly: could not resolve '${mainRef}' as a corrected restore target (no local ref, auto-base-repair disabled, or 'origin/${mainRef}' missing) — leaving originalRef as the contaminated '${originalRef}'; a human should verify the operator checkout manually.`,
|
|
906
|
+
'warn'
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
845
910
|
return { ok: true, branch: branchName, created: false, originalRef, originalRefType };
|
|
846
911
|
}
|
|
847
912
|
|
|
@@ -983,6 +1048,21 @@ async function prepareLiveCheckout(opts = {}) {
|
|
|
983
1048
|
}
|
|
984
1049
|
logFn('info',
|
|
985
1050
|
`live-checkout: HEAD was on '${headBranch}' (not base '${mainRef}') — switched to local '${mainRef}' before forking '${branchName}' (no fetch, issue #226 preserved)`);
|
|
1051
|
+
// ── originalRef correction (W-mrb6an8300058fd8). ─────────────────────
|
|
1052
|
+
// originalRef/originalRefType were captured at Step 3 from the STALE
|
|
1053
|
+
// headBranch, BEFORE this self-heal ran. The tree has now been switched
|
|
1054
|
+
// to the CORRECTED mainRef, so the value returned to the caller (and
|
|
1055
|
+
// persisted on the dispatch record — engine.js spawnAgent ~line
|
|
1056
|
+
// 3106-3122) must reflect mainRef, not the stale branch. Otherwise
|
|
1057
|
+
// restoreLiveCheckoutAtDispatchEnd would put the operator checkout BACK
|
|
1058
|
+
// onto the stale branch at dispatch end, propagating the contamination
|
|
1059
|
+
// into every subsequent live-mode dispatch that captures HEAD (the
|
|
1060
|
+
// exact recurrence observed on minions-opg 2026-07-07: HEAD landed on
|
|
1061
|
+
// 'main' via this self-heal, but the persisted originalRef still said
|
|
1062
|
+
// 'work/sched-daily-remove-merged-prs-…', so the dispatch-end restore
|
|
1063
|
+
// switched the operator checkout back onto that stale branch).
|
|
1064
|
+
originalRef = mainRef;
|
|
1065
|
+
originalRefType = 'branch';
|
|
986
1066
|
}
|
|
987
1067
|
}
|
|
988
1068
|
|
package/engine/queries.js
CHANGED
|
@@ -2878,63 +2878,72 @@ function _resolveCommonGitDir(gitDir) {
|
|
|
2878
2878
|
return path.isAbsolute(raw) ? raw : path.resolve(gitDir, raw);
|
|
2879
2879
|
}
|
|
2880
2880
|
|
|
2881
|
-
// Enumerate the per-project git ref files we watch for cache-busting
|
|
2882
|
-
//
|
|
2883
|
-
//
|
|
2884
|
-
//
|
|
2881
|
+
// Enumerate the per-project git ref files we watch for cache-busting, split
|
|
2882
|
+
// into two groups (W-mrb6qnuc000785b2):
|
|
2883
|
+
// identityFiles — HEAD + logs/HEAD, resolved against the PER-WORKTREE
|
|
2884
|
+
// gitdir (`_resolveGitDir`). These are never shared across linked
|
|
2885
|
+
// worktrees of the same repo, so a change here means THIS worktree's
|
|
2886
|
+
// own branch/commit identity moved (opg-microsoft/minions#295, #381) —
|
|
2887
|
+
// the only signal allowed to gate `gitStale: true` / hide the branch
|
|
2888
|
+
// name in the dashboard.
|
|
2889
|
+
// sharedFiles — FETCH_HEAD + refs/remotes/origin/<comparator>, resolved
|
|
2890
|
+
// against the COMMON gitdir (`_resolveCommonGitDir`). These are written
|
|
2891
|
+
// by ANY linked worktree of the same repo doing a `git fetch` — a
|
|
2892
|
+
// legitimate signal that ahead/behind against origin may be stale and
|
|
2893
|
+
// worth recomputing, but NOT a signal that this worktree's own branch
|
|
2894
|
+
// identity changed. Lumping these into the same boolean as identityFiles
|
|
2895
|
+
// produced a permanent "(refreshing...)" chip on repos with several
|
|
2896
|
+
// active worktrees sharing one commondir, since some other worktree's
|
|
2897
|
+
// fetch touches these files constantly.
|
|
2898
|
+
// Same paths as the fast-state mtime tracker so callers see a coherent view
|
|
2899
|
+
// across surfaces.
|
|
2885
2900
|
function _projectGitRefFiles(localPath, configuredMainBranch) {
|
|
2886
2901
|
const gitDir = _resolveGitDir(localPath);
|
|
2887
2902
|
if (!gitDir) return null;
|
|
2888
2903
|
const commonGitDir = _resolveCommonGitDir(gitDir);
|
|
2889
|
-
const
|
|
2904
|
+
const identityFiles = [
|
|
2890
2905
|
// opg-microsoft/minions#381 — track HEAD directly so a bare `git checkout`
|
|
2891
2906
|
// (which rewrites .git/HEAD but may not advance logs/HEAD when reflog is
|
|
2892
2907
|
// disabled or when the snapshot already reflects the post-checkout mtime)
|
|
2893
|
-
// still triggers
|
|
2908
|
+
// still triggers identityAdvanced=true and the gitStale marker on the
|
|
2909
|
+
// next call.
|
|
2894
2910
|
path.join(gitDir, 'HEAD'),
|
|
2895
2911
|
path.join(gitDir, 'logs', 'HEAD'),
|
|
2912
|
+
];
|
|
2913
|
+
const sharedFiles = [
|
|
2896
2914
|
path.join(commonGitDir, 'FETCH_HEAD'),
|
|
2897
2915
|
];
|
|
2898
2916
|
const comparator = configuredMainBranch && String(configuredMainBranch).trim();
|
|
2899
2917
|
if (comparator) {
|
|
2900
|
-
|
|
2918
|
+
sharedFiles.push(path.join(commonGitDir, 'refs', 'remotes', 'origin', comparator));
|
|
2901
2919
|
}
|
|
2902
|
-
return
|
|
2920
|
+
return { identityFiles, sharedFiles };
|
|
2903
2921
|
}
|
|
2904
2922
|
|
|
2905
|
-
// Snapshot mtimeMs for each ref file
|
|
2906
|
-
//
|
|
2907
|
-
//
|
|
2908
|
-
//
|
|
2923
|
+
// Snapshot mtimeMs for each ref file, grouped by identity vs shared (see
|
|
2924
|
+
// `_projectGitRefFiles`). Missing files record `null`. Used as the baseline
|
|
2925
|
+
// that the next `getProjectGitStatus` call compares against — inequality,
|
|
2926
|
+
// not threshold-vs-timestamp, so the result is precision-independent
|
|
2927
|
+
// (Windows `Date.now()` can be 15ms coarse while NTFS mtime is
|
|
2909
2928
|
// sub-millisecond, which used to make threshold checks fire spuriously on
|
|
2910
2929
|
// freshly-written files).
|
|
2911
2930
|
function _snapshotProjectGitRefMtimes(localPath, configuredMainBranch) {
|
|
2912
|
-
const
|
|
2913
|
-
if (!
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2931
|
+
const groups = _projectGitRefFiles(localPath, configuredMainBranch);
|
|
2932
|
+
if (!groups) return null;
|
|
2933
|
+
const statMtime = f => {
|
|
2934
|
+
try { return fs.statSync(f).mtimeMs; }
|
|
2935
|
+
catch { return null; /* ENOENT recorded as null — flipping to present must bust */ }
|
|
2936
|
+
};
|
|
2937
|
+
const identity = Object.create(null);
|
|
2938
|
+
for (const f of groups.identityFiles) identity[f] = statMtime(f);
|
|
2939
|
+
const shared = Object.create(null);
|
|
2940
|
+
for (const f of groups.sharedFiles) shared[f] = statMtime(f);
|
|
2941
|
+
return { identity, shared };
|
|
2920
2942
|
}
|
|
2921
2943
|
|
|
2922
|
-
//
|
|
2923
|
-
//
|
|
2924
|
-
|
|
2925
|
-
// races on Windows. Lets `getProjectGitStatus` bypass its 15s TTL after
|
|
2926
|
-
// `git pull`, `git fetch`, `git checkout`, etc. so the next /api/status
|
|
2927
|
-
// reflects the new HEAD / ahead-behind within one SPA poll instead of
|
|
2928
|
-
// waiting out the TTL (W-mphdmr8c00030124). Cost: 2-3 statSync per call —
|
|
2929
|
-
// well under the 'cheap' budget.
|
|
2930
|
-
function _projectGitRefsAdvancedSince(localPath, configuredMainBranch, snapshot) {
|
|
2931
|
-
// No snapshot yet (legacy entry shape OR first call) — preserve the
|
|
2932
|
-
// current cached value so the TTL-only fast-path still works. A real
|
|
2933
|
-
// change still surfaces on the next /api/status because the fast-state
|
|
2934
|
-
// mtime tracker watches the same files and will bust the upstream cache.
|
|
2935
|
-
if (!snapshot) return false;
|
|
2936
|
-
const current = _snapshotProjectGitRefMtimes(localPath, configuredMainBranch);
|
|
2937
|
-
if (!current) return false;
|
|
2944
|
+
// Compare two flat {file: mtimeMs} maps and return true if ANY tracked
|
|
2945
|
+
// file's mtime (or existence) differs between them.
|
|
2946
|
+
function _refGroupChanged(current, snapshot) {
|
|
2938
2947
|
for (const file of Object.keys(snapshot)) {
|
|
2939
2948
|
if (current[file] !== snapshot[file]) return true;
|
|
2940
2949
|
}
|
|
@@ -2946,16 +2955,54 @@ function _projectGitRefsAdvancedSince(localPath, configuredMainBranch, snapshot)
|
|
|
2946
2955
|
return false;
|
|
2947
2956
|
}
|
|
2948
2957
|
|
|
2958
|
+
// Return `{ identityAdvanced, aheadBehindAdvanced }` describing which
|
|
2959
|
+
// tracked ref groups changed since `snapshot` (W-mrb6qnuc000785b2):
|
|
2960
|
+
// identityAdvanced — THIS worktree's own HEAD/logs/HEAD moved. The only
|
|
2961
|
+
// signal that should gate `gitStale: true`.
|
|
2962
|
+
// aheadBehindAdvanced — identityAdvanced OR the shared commondir files
|
|
2963
|
+
// (FETCH_HEAD / refs/remotes/origin/<comparator>)
|
|
2964
|
+
// changed — from a fetch in ANY linked worktree of
|
|
2965
|
+
// the same repo. Gates nulling ahead/behind and
|
|
2966
|
+
// bypassing the TTL to schedule a refresh, but never
|
|
2967
|
+
// gates gitStale on its own.
|
|
2968
|
+
// Replaces the older single-boolean threshold-vs-cachedTs check that
|
|
2969
|
+
// suffered from `Date.now()`/`mtimeMs` resolution races on Windows. Lets
|
|
2970
|
+
// `getProjectGitStatus` bypass its 15s TTL after `git pull`, `git fetch`,
|
|
2971
|
+
// `git checkout`, etc. so the next /api/status reflects the new HEAD /
|
|
2972
|
+
// ahead-behind within one SPA poll instead of waiting out the TTL
|
|
2973
|
+
// (W-mphdmr8c00030124). Cost: 2-4 statSync per call — well under the
|
|
2974
|
+
// 'cheap' budget.
|
|
2975
|
+
function _projectGitRefsAdvancedSince(localPath, configuredMainBranch, snapshot) {
|
|
2976
|
+
// No snapshot yet (legacy entry shape OR first call) — preserve the
|
|
2977
|
+
// current cached value so the TTL-only fast-path still works. A real
|
|
2978
|
+
// change still surfaces on the next /api/status because the fast-state
|
|
2979
|
+
// mtime tracker watches the same files and will bust the upstream cache.
|
|
2980
|
+
if (!snapshot) return { identityAdvanced: false, aheadBehindAdvanced: false };
|
|
2981
|
+
const current = _snapshotProjectGitRefMtimes(localPath, configuredMainBranch);
|
|
2982
|
+
if (!current) return { identityAdvanced: false, aheadBehindAdvanced: false };
|
|
2983
|
+
const identityAdvanced = _refGroupChanged(current.identity, snapshot.identity);
|
|
2984
|
+
const sharedAdvanced = _refGroupChanged(current.shared, snapshot.shared);
|
|
2985
|
+
return { identityAdvanced, aheadBehindAdvanced: identityAdvanced || sharedAdvanced };
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2949
2988
|
function getProjectGitStatus(localPath, configuredMainBranch = null) {
|
|
2950
2989
|
const norm = String(localPath || '').replace(/\\/g, '/');
|
|
2951
2990
|
if (!norm) return PROJECT_GIT_STATUS_MISSING;
|
|
2952
2991
|
const key = _projectGitStatusCacheKey(localPath, configuredMainBranch);
|
|
2953
2992
|
const now = Date.now();
|
|
2954
2993
|
const cached = _projectGitStatusCache.get(key);
|
|
2955
|
-
// Compute ref-mtime freshness once. Used
|
|
2956
|
-
//
|
|
2957
|
-
//
|
|
2958
|
-
|
|
2994
|
+
// Compute ref-mtime freshness once. Used below to gate the TTL fast-path
|
|
2995
|
+
// AND to decide whether the stale-while-revalidate return should null out
|
|
2996
|
+
// the known-stale ahead/behind counters (#2848) and/or flag gitStale
|
|
2997
|
+
// (opg-microsoft/minions#295, #381) — split so a fetch from an unrelated
|
|
2998
|
+
// worktree sharing this repo's commondir (FETCH_HEAD /
|
|
2999
|
+
// refs/remotes/origin/<comparator>) only refreshes ahead/behind quietly
|
|
3000
|
+
// and never flags THIS project's branch display as stale
|
|
3001
|
+
// (W-mrb6qnuc000785b2).
|
|
3002
|
+
const advancement = cached
|
|
3003
|
+
? _projectGitRefsAdvancedSince(localPath, configuredMainBranch, cached.refMtimes)
|
|
3004
|
+
: { identityAdvanced: false, aheadBehindAdvanced: false };
|
|
3005
|
+
const refsAdvanced = advancement.aheadBehindAdvanced;
|
|
2959
3006
|
// Within TTL: short-circuit ONLY when no tracked git ref has advanced
|
|
2960
3007
|
// past cached.ts. Without the mtime gate, a freshly-pulled repo serves
|
|
2961
3008
|
// the pre-pull ahead/behind counts for up to 15s + one SPA poll (~19s
|
|
@@ -2989,28 +3036,39 @@ function getProjectGitStatus(localPath, configuredMainBranch = null) {
|
|
|
2989
3036
|
if (!cached) return PROJECT_GIT_STATUS_PENDING;
|
|
2990
3037
|
// When tracked git refs have advanced past the cached snapshot, the
|
|
2991
3038
|
// cached ahead/behind counts are known to be stale (e.g. user just ran
|
|
2992
|
-
// `git pull` / `git fetch`
|
|
2993
|
-
//
|
|
2994
|
-
//
|
|
2995
|
-
//
|
|
3039
|
+
// `git pull` / `git fetch` — from THIS worktree or any other worktree
|
|
3040
|
+
// sharing the same repo commondir — and the local checkout is now
|
|
3041
|
+
// current). Returning the cached value as-is would briefly display a
|
|
3042
|
+
// misleading "behind: 8" after the user has already pulled to current —
|
|
3043
|
+
// see yemi33/minions#2848. Null those specific counters so the dashboard
|
|
2996
3044
|
// shows a pending state for ahead/behind until the background probe
|
|
2997
|
-
// settles. TTL-expiry fall-throughs (
|
|
2998
|
-
// prior counters because nothing
|
|
3045
|
+
// settles. TTL-expiry fall-throughs (aheadBehindAdvanced=false) still
|
|
3046
|
+
// return the prior counters because nothing has actually changed there.
|
|
2999
3047
|
//
|
|
3000
|
-
// opg-microsoft/minions#295: gitBranch/gitDirty on the cached
|
|
3001
|
-
// ALSO known-stale
|
|
3002
|
-
//
|
|
3003
|
-
//
|
|
3004
|
-
//
|
|
3005
|
-
//
|
|
3006
|
-
//
|
|
3007
|
-
//
|
|
3008
|
-
//
|
|
3009
|
-
//
|
|
3010
|
-
//
|
|
3011
|
-
//
|
|
3048
|
+
// opg-microsoft/minions#295 / #381: gitBranch/gitDirty on the cached
|
|
3049
|
+
// value are ALSO known-stale, but ONLY when THIS project's OWN
|
|
3050
|
+
// per-worktree HEAD/logs/HEAD moved (identityAdvanced) — e.g. the
|
|
3051
|
+
// operator ran `git switch` / `git pull` directly in a live checkout
|
|
3052
|
+
// outside the dashboard, or a bare `git checkout` rewrote HEAD. A shared
|
|
3053
|
+
// commondir file (FETCH_HEAD / refs/remotes/origin/<comparator>) changing
|
|
3054
|
+
// because some OTHER linked worktree of the same repo fetched is NOT
|
|
3055
|
+
// evidence this project's branch identity changed — gating gitStale on
|
|
3056
|
+
// that shared signal produced a permanently-stuck "(refreshing...)" chip
|
|
3057
|
+
// on repos with several active worktrees (W-mrb6qnuc000785b2). The cached
|
|
3058
|
+
// value still carries the OLD branch name, so a consumer rendering
|
|
3059
|
+
// `gitBranch` as authoritative briefly shows the pre-switch branch as if
|
|
3060
|
+
// current when identityAdvanced fires. We keep the cached
|
|
3061
|
+
// gitBranch/gitDirty on the object (so the next poll can self-correct
|
|
3062
|
+
// without a flash of "missing"), but add a `gitStale: true` marker so
|
|
3063
|
+
// render paths can avoid presenting the known-stale branch/dirty as
|
|
3064
|
+
// current and fall back to a neutral "refreshing" presentation. The async
|
|
3065
|
+
// refresh scheduled above self-corrects on the next poll. We do NOT add a
|
|
3066
|
+
// synchronous git probe here — status rebuild must never block the event
|
|
3067
|
+
// loop.
|
|
3012
3068
|
if (refsAdvanced) {
|
|
3013
|
-
|
|
3069
|
+
const next = { ...cached.value, ahead: null, behind: null };
|
|
3070
|
+
if (advancement.identityAdvanced) next.gitStale = true;
|
|
3071
|
+
return next;
|
|
3014
3072
|
}
|
|
3015
3073
|
return cached.value;
|
|
3016
3074
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2352",
|
|
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"
|