@yemi33/minions 0.1.2084 → 0.1.2085
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/settings.js +2 -2
- package/dashboard.js +28 -21
- package/docs/deprecated.json +13 -0
- package/engine/cli.js +35 -0
- package/engine/shared.js +84 -19
- package/package.json +1 -1
package/dashboard/js/settings.js
CHANGED
|
@@ -393,8 +393,8 @@ async function openSettings() {
|
|
|
393
393
|
'<h4>Inbox & Status Retention</h4>' +
|
|
394
394
|
'<div class="settings-grid-2">' +
|
|
395
395
|
settingsField('Consolidation Threshold', 'set-inboxConsolidateThreshold', e.inboxConsolidateThreshold || 5, 'notes', 'Inbox notes before auto-consolidation') +
|
|
396
|
-
settingsField('Status WorkItems Retention', 'set-statusWorkItemsRetentionDays', e.statusWorkItemsRetentionDays ??
|
|
397
|
-
settingsField('Status Meetings Retention', 'set-statusMeetingsRetentionDays', e.statusMeetingsRetentionDays ??
|
|
396
|
+
settingsField('Status WorkItems Retention', 'set-statusWorkItemsRetentionDays', e.statusWorkItemsRetentionDays ?? 0, 'days', 'Optional age-based trim for done/failed/cancelled work items in the /api/status workItems slice (active items are always shipped). Default 0 = no trim — the slim projection that strips description/AC/references already cuts the payload by ~80%. Set to a positive integer to also drop terminal items older than N days.') +
|
|
397
|
+
settingsField('Status Meetings Retention', 'set-statusMeetingsRetentionDays', e.statusMeetingsRetentionDays ?? 0, 'days', 'Optional age-based trim for completed/archived meetings in the /api/status meetings slice (active meetings are always shipped). Default 0 = no trim — the slim projection that collapses findings/debate/transcript bodies to {agentId: true} sentinels already cuts the payload by ~80%. Set to a positive integer to also drop terminal meetings older than N days. Detail modal still fetches full bodies via /api/meetings/:id.') +
|
|
398
398
|
settingsField('Version Check Interval', 'set-versionCheckInterval', e.versionCheckInterval || 3600000, 'ms', 'How often to check npm for updates (default: 1 hour)') +
|
|
399
399
|
'</div>' +
|
|
400
400
|
'<h4>Operator & Comments</h4>' +
|
package/dashboard.js
CHANGED
|
@@ -73,6 +73,11 @@ const TITLE_SUFFIX = IS_DEV_MODE ? ' [DEV]' : '';
|
|
|
73
73
|
|
|
74
74
|
const PORT = parseInt(process.env.PORT || process.argv[2]) || 7331;
|
|
75
75
|
let CONFIG = queries.getConfig();
|
|
76
|
+
// Mirror cli.js: clear persisted statusWorkItemsRetentionDays=7 + the matching
|
|
77
|
+
// meetings field (prior default 7) so the new default (0, no trim) reaches the
|
|
78
|
+
// /api/status slimmers without needing an engine bounce first.
|
|
79
|
+
try { shared.applyStatusWorkItemsRetentionMigration(CONFIG); } catch { /* best-effort */ }
|
|
80
|
+
try { shared.applyStatusMeetingsRetentionMigration(CONFIG); } catch { /* best-effort */ }
|
|
76
81
|
let PROJECTS = _getProjects(CONFIG);
|
|
77
82
|
const CONFIG_PATH = path.join(MINIONS_DIR, 'config.json');
|
|
78
83
|
const PINNED_PATH = path.join(MINIONS_DIR, 'pinned.md');
|
|
@@ -95,6 +100,8 @@ function ensureConfiguredProjectStateFiles() {
|
|
|
95
100
|
|
|
96
101
|
function reloadConfig() {
|
|
97
102
|
CONFIG = queries.getConfig();
|
|
103
|
+
try { shared.applyStatusWorkItemsRetentionMigration(CONFIG); } catch { /* best-effort */ }
|
|
104
|
+
try { shared.applyStatusMeetingsRetentionMigration(CONFIG); } catch { /* best-effort */ }
|
|
98
105
|
PROJECTS = _getProjects(CONFIG);
|
|
99
106
|
ensureConfiguredProjectStateFiles();
|
|
100
107
|
}
|
|
@@ -1832,19 +1839,19 @@ function _safeStatusSlice(name, fn, fallback) {
|
|
|
1832
1839
|
}
|
|
1833
1840
|
|
|
1834
1841
|
// ── /api/status workItems slimming (W-mphejzmj000718bf) ─────────────────────
|
|
1835
|
-
//
|
|
1836
|
-
// (
|
|
1837
|
-
//
|
|
1838
|
-
//
|
|
1839
|
-
//
|
|
1840
|
-
//
|
|
1841
|
-
//
|
|
1842
|
-
// GET /api/work-items/<id>. Live measurement at task time: 796 items / ~3MB
|
|
1843
|
-
// → ~50–100 items / <500KB typical. Active items (pending/dispatched/queued)
|
|
1844
|
-
// are ALWAYS kept regardless of age.
|
|
1842
|
+
// Project each work item onto a narrow shape that omits the large free-text
|
|
1843
|
+
// fields (description, full acceptanceCriteria, full references) before
|
|
1844
|
+
// shipping on /api/status. The dashboard never renders description/AC/
|
|
1845
|
+
// references-detail off the cached slice — `wiRow` only needs counts +
|
|
1846
|
+
// status/badge fields, and `openWorkItemDetail` fetches the full record on
|
|
1847
|
+
// demand via GET /api/work-items/<id>. This slim projection is the bulk of
|
|
1848
|
+
// the payload savings (~3MB → <500KB typical) and runs unconditionally.
|
|
1845
1849
|
//
|
|
1846
|
-
//
|
|
1847
|
-
// (
|
|
1850
|
+
// engine.statusWorkItemsRetentionDays is an optional second-tier filter that
|
|
1851
|
+
// drops terminal (done/failed/cancelled) items older than N days. Default 0
|
|
1852
|
+
// = no trim (legacy behavior, full list shipped). Set to a positive integer
|
|
1853
|
+
// to opt into the date-based trim. Active items (pending/dispatched/queued)
|
|
1854
|
+
// are ALWAYS kept regardless of age.
|
|
1848
1855
|
const _ACTIVE_WI_STATUSES_FOR_STATUS = new Set(['pending', 'dispatched', 'queued', 'paused', 'decomposed']);
|
|
1849
1856
|
const _TERMINAL_WI_STATUSES_FOR_STATUS = new Set(['done', 'failed', 'cancelled']);
|
|
1850
1857
|
function _resolveStatusWorkItemsRetentionDays() {
|
|
@@ -1931,9 +1938,9 @@ function _slimWorkItemsForStatus(items) {
|
|
|
1931
1938
|
}
|
|
1932
1939
|
|
|
1933
1940
|
// ── /api/status meetings slimming (W-mphlrxx6000a8760) ──────────────────────
|
|
1934
|
-
// Mirrors the workItems
|
|
1935
|
-
// largest /api/status slice
|
|
1936
|
-
//
|
|
1941
|
+
// Mirrors the workItems slim above (PR #2816). Meetings were the second
|
|
1942
|
+
// largest /api/status slice — live measurement: 22 meetings / 4.3MB
|
|
1943
|
+
// (60% of the 7.2MB payload) before slimming. The list renderer in
|
|
1937
1944
|
// dashboard/js/render-meetings.js:renderMeetings only needs:
|
|
1938
1945
|
// - id, title, status, round, participants, agenda(short), createdAt,
|
|
1939
1946
|
// completedAt
|
|
@@ -1941,13 +1948,13 @@ function _slimWorkItemsForStatus(items) {
|
|
|
1941
1948
|
// ✓/⏳/○ icon — `m.findings?.[p]` truthy check, line 48-50)
|
|
1942
1949
|
// The detail modal calls `/api/meetings/:id` which serves the full record
|
|
1943
1950
|
// (findings.content + debate.content + conclusion + transcript bodies), so
|
|
1944
|
-
// dropping those from the slice is safe.
|
|
1951
|
+
// dropping those bodies from the slice is safe. The slim projection alone
|
|
1952
|
+
// delivers the bulk of the payload savings and always runs.
|
|
1945
1953
|
//
|
|
1946
|
-
//
|
|
1947
|
-
//
|
|
1948
|
-
//
|
|
1949
|
-
//
|
|
1950
|
-
// (returns the full list — but still slim-shaped — restoring legacy size).
|
|
1954
|
+
// engine.statusMeetingsRetentionDays is an optional second-tier filter that
|
|
1955
|
+
// drops terminal (completed/archived) meetings older than N days. Default 0
|
|
1956
|
+
// = no trim (legacy behavior, full list shipped — but still slim-shaped).
|
|
1957
|
+
// Active meetings (investigating/debating/concluding) are ALWAYS kept.
|
|
1951
1958
|
const _ACTIVE_MEETING_STATUSES_FOR_STATUS = new Set(['investigating', 'debating', 'concluding']);
|
|
1952
1959
|
const _TERMINAL_MEETING_STATUSES_FOR_STATUS = new Set(['completed', 'archived']);
|
|
1953
1960
|
function _resolveStatusMeetingsRetentionDays() {
|
package/docs/deprecated.json
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"id": "status-retention-stale-default-migration",
|
|
4
|
+
"description": "applyStatusWorkItemsRetentionMigration + applyStatusMeetingsRetentionMigration: one-time migrations that drop engine.statusWorkItemsRetentionDays=7 and engine.statusMeetingsRetentionDays=7 from loaded config so the new defaults (0, no trim) reach installs whose config.json was persisted while 7 was the baked-in default. The 7-day cutoffs were added alongside the slim projections (W-mphejzmj000718bf for workItems, W-mphlrxx6000a8760 for meetings) but surfaced as data loss to users (completed rows disappearing from /api/status after a week). The slim projections (which deliver the bulk of the payload savings) still run unconditionally; only the date filters were demoted to opt-in. shared.js mutates the in-memory config; engine/cli.js follows up with guarded shared.mutateJsonFileLocked calls on config.json so the fields are also removed on disk — affected installs are permanently corrected the first time the engine boots after this ships.",
|
|
5
|
+
"code": [
|
|
6
|
+
{ "file": "engine/shared.js", "note": "applyStatusWorkItemsRetentionMigration / applyStatusMeetingsRetentionMigration definitions + _resetStaleRetentionMigrationFlag / _resetStaleMeetingsRetentionMigrationFlag test helpers — pure, in-memory" },
|
|
7
|
+
{ "file": "engine/cli.js", "note": "Two boot blocks inside start() — each applies the in-memory pass THEN mutateJsonFileLocked on config.json to delete the field with skipWriteIfUnchanged so non-7 installs don't churn the file" },
|
|
8
|
+
{ "file": "dashboard.js", "note": "Initial CONFIG load + reloadConfig() both apply the in-memory migrations so the dashboard picks up the new defaults even if it boots before the engine writes config.json" }
|
|
9
|
+
],
|
|
10
|
+
"deprecated": "2026-05-29",
|
|
11
|
+
"targetRemovalDate": "2026-06-01",
|
|
12
|
+
"cleanup": "On or after 2026-06-01 (3 days), delete both migration functions + their reset helpers from engine/shared.js (including the shared.js export lines), the boot calls + mutateJsonFileLocked blocks in engine/cli.js, the call sites in dashboard.js, the tests in test/unit/status-workitems-retention.test.js and test/unit/status-meetings-retention.test.js gated on the function names, and this entry. Three days is enough because the on-disk rewrite happens on first engine boot — any install whose engine has rebooted at least once since this shipped has already had its config.json corrected and is no longer dependent on the in-memory shim.",
|
|
13
|
+
"notes": "Persistent custom values (any non-7 integer) are preserved untouched. The only at-risk users are those who explicitly want a 7-day window — they can re-set via the Settings page after removal. If a user never restarts the engine in the 3-day window, the shim still strips the persisted 7 on dashboard-only boot via the in-memory pass; the on-disk write is a hardening pass for the common case, not a strict requirement."
|
|
14
|
+
},
|
|
2
15
|
{
|
|
3
16
|
"id": "config-poll-key-migration",
|
|
4
17
|
"location": "engine/queries.js:126-163",
|
package/engine/cli.js
CHANGED
|
@@ -471,6 +471,41 @@ const commands = {
|
|
|
471
471
|
try { shared.applyLegacyCcModelMigration(config, { logger: e.log }); }
|
|
472
472
|
catch (err) { e.log('warn', `legacy ccModel migration failed: ${err.message}`); }
|
|
473
473
|
|
|
474
|
+
// Drop persisted statusWorkItemsRetentionDays=7 (the prior baked-in default)
|
|
475
|
+
// so the new default of 0 (no trim) reaches installs that opened Settings
|
|
476
|
+
// before the flip. Explicit non-7 values are preserved. We mutate in-memory
|
|
477
|
+
// AND rewrite config.json so the fix is permanent — the shim in shared.js
|
|
478
|
+
// can then retire on schedule without users regressing.
|
|
479
|
+
try {
|
|
480
|
+
const applied = shared.applyStatusWorkItemsRetentionMigration(config, { logger: e.log });
|
|
481
|
+
if (applied) {
|
|
482
|
+
const configPath = path.join(shared.MINIONS_DIR, 'config.json');
|
|
483
|
+
shared.mutateJsonFileLocked(configPath, (onDisk) => {
|
|
484
|
+
if (onDisk && onDisk.engine && onDisk.engine.statusWorkItemsRetentionDays === 7) {
|
|
485
|
+
delete onDisk.engine.statusWorkItemsRetentionDays;
|
|
486
|
+
}
|
|
487
|
+
return onDisk;
|
|
488
|
+
}, { defaultValue: {}, skipWriteIfUnchanged: true });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
catch (err) { e.log('warn', `statusWorkItemsRetentionDays migration failed: ${err.message}`); }
|
|
492
|
+
|
|
493
|
+
// Same treatment for statusMeetingsRetentionDays — the meetings slice had
|
|
494
|
+
// the same 7-day baked-in default and the same data-loss UX.
|
|
495
|
+
try {
|
|
496
|
+
const applied = shared.applyStatusMeetingsRetentionMigration(config, { logger: e.log });
|
|
497
|
+
if (applied) {
|
|
498
|
+
const configPath = path.join(shared.MINIONS_DIR, 'config.json');
|
|
499
|
+
shared.mutateJsonFileLocked(configPath, (onDisk) => {
|
|
500
|
+
if (onDisk && onDisk.engine && onDisk.engine.statusMeetingsRetentionDays === 7) {
|
|
501
|
+
delete onDisk.engine.statusMeetingsRetentionDays;
|
|
502
|
+
}
|
|
503
|
+
return onDisk;
|
|
504
|
+
}, { defaultValue: {}, skipWriteIfUnchanged: true });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
catch (err) { e.log('warn', `statusMeetingsRetentionDays migration failed: ${err.message}`); }
|
|
508
|
+
|
|
474
509
|
// Auto-heal projects missing workSources (cloned-repo / hand-rolled-config
|
|
475
510
|
// footgun): without this block, discoverFromWorkItems / discoverFromPrs
|
|
476
511
|
// bail silently and the engine looks healthy but never dispatches. The
|
package/engine/shared.js
CHANGED
|
@@ -2184,27 +2184,32 @@ const ENGINE_DEFAULTS = {
|
|
|
2184
2184
|
// the override and falls back to auto-resolution.
|
|
2185
2185
|
operatorLogin: null,
|
|
2186
2186
|
// ── /api/status workItems retention (W-mphejzmj000718bf) ────────────────────
|
|
2187
|
-
//
|
|
2188
|
-
// /api/status workItems slice
|
|
2189
|
-
//
|
|
2190
|
-
//
|
|
2191
|
-
//
|
|
2192
|
-
//
|
|
2193
|
-
//
|
|
2194
|
-
|
|
2187
|
+
// Optional age-based trim for done/failed/cancelled work items in the
|
|
2188
|
+
// /api/status workItems slice. Default 0 = no trim (full list shipped). The
|
|
2189
|
+
// bulk of the payload savings (~3MB → ~500KB) comes from _slimWorkItemForStatus
|
|
2190
|
+
// dropping description / full acceptanceCriteria / references — that slim
|
|
2191
|
+
// projection runs unconditionally. The date filter on top was a second-tier
|
|
2192
|
+
// optimization that surfaced as data loss to users (completed items vanishing
|
|
2193
|
+
// from /api/status after 7 days) so it now opts in via a positive integer.
|
|
2194
|
+
// Active items (pending/dispatched/queued) are ALWAYS shipped regardless of
|
|
2195
|
+
// age. The detail modal fetches the full record on demand via
|
|
2196
|
+
// GET /api/work-items/<id> when description/references/AC are needed.
|
|
2197
|
+
statusWorkItemsRetentionDays: 0,
|
|
2195
2198
|
|
|
2196
2199
|
// ── /api/status meetings retention (W-mphlrxx6000a8760) ─────────────────────
|
|
2197
|
-
// Same shape as statusWorkItemsRetentionDays —
|
|
2198
|
-
//
|
|
2199
|
-
//
|
|
2200
|
-
//
|
|
2201
|
-
//
|
|
2202
|
-
//
|
|
2203
|
-
//
|
|
2204
|
-
//
|
|
2205
|
-
//
|
|
2206
|
-
//
|
|
2207
|
-
|
|
2200
|
+
// Same shape as statusWorkItemsRetentionDays — optional age-based trim for
|
|
2201
|
+
// completed/archived meetings in the /api/status meetings slice. Default 0
|
|
2202
|
+
// = no trim (full list shipped). The slim projection (which collapses
|
|
2203
|
+
// ~95KB+ per-round findings/debate/transcript bodies down to {agentId: true}
|
|
2204
|
+
// sentinels) delivers the bulk of the payload savings and always runs.
|
|
2205
|
+
// The date filter on top was demoted to opt-in for the same reason as the
|
|
2206
|
+
// workItems trim: vanishing completed meetings read as data loss. Active
|
|
2207
|
+
// meetings (investigating/debating/concluding) are ALWAYS shipped regardless
|
|
2208
|
+
// of age. The detail modal fetches the full record (findings, debate,
|
|
2209
|
+
// conclusion, transcript bodies) on demand via GET /api/meetings/<id>.
|
|
2210
|
+
// A top-level meetingsTotal field is synthesized so the sidebar activity
|
|
2211
|
+
// dot still fires when ANY meeting gains a new round.
|
|
2212
|
+
statusMeetingsRetentionDays: 0,
|
|
2208
2213
|
};
|
|
2209
2214
|
|
|
2210
2215
|
// ─── Runtime Fleet Resolution (P-3b8e5f1d) ──────────────────────────────────
|
|
@@ -2401,6 +2406,64 @@ function _resetLegacyCcModelMigrationFlag() {
|
|
|
2401
2406
|
_legacyCcModelMigrationLogged = false;
|
|
2402
2407
|
}
|
|
2403
2408
|
|
|
2409
|
+
// ─── Stale statusWorkItemsRetentionDays Default Migration ────────────────────
|
|
2410
|
+
//
|
|
2411
|
+
// The retention default was 7 from W-mphejzmj000718bf until users reported the
|
|
2412
|
+
// trim hid completed work items from /api/status, which read as data loss.
|
|
2413
|
+
// We flipped the baked-in default to 0 (no trim). Installs that opened the
|
|
2414
|
+
// Settings page while the default was 7 have `engine.statusWorkItemsRetentionDays: 7`
|
|
2415
|
+
// persisted in their config.json — the resolver would return 7 and they'd
|
|
2416
|
+
// still see the trim. This shim drops a literal `7` at load time so the new
|
|
2417
|
+
// default of 0 applies. Operators who explicitly set a non-7 value (e.g. 14
|
|
2418
|
+
// or 30) are left untouched. No on-disk rewrite.
|
|
2419
|
+
|
|
2420
|
+
let _staleRetentionMigrationLogged = false;
|
|
2421
|
+
|
|
2422
|
+
function applyStatusWorkItemsRetentionMigration(config, { logger = log } = {}) {
|
|
2423
|
+
if (!config || !config.engine || typeof config.engine !== 'object') return false;
|
|
2424
|
+
const e = config.engine;
|
|
2425
|
+
if (e.statusWorkItemsRetentionDays !== 7) return false;
|
|
2426
|
+
delete e.statusWorkItemsRetentionDays;
|
|
2427
|
+
if (!_staleRetentionMigrationLogged) {
|
|
2428
|
+
_staleRetentionMigrationLogged = true;
|
|
2429
|
+
try {
|
|
2430
|
+
logger('warn', 'statusWorkItemsRetentionDays=7 was the previous default — clearing in-memory so the new default (0, no trim) applies. Re-save Settings to persist or set a positive value to opt back in.');
|
|
2431
|
+
} catch { /* logger may not be wired during tests — best-effort */ }
|
|
2432
|
+
}
|
|
2433
|
+
return true;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
/** Test helper: reset the dedup flag so repeated tests can re-trigger the log. */
|
|
2437
|
+
function _resetStaleRetentionMigrationFlag() {
|
|
2438
|
+
_staleRetentionMigrationLogged = false;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// Same shape as applyStatusWorkItemsRetentionMigration above, for the meetings
|
|
2442
|
+
// slice. The prior baked-in default of 7 caused completed/archived meetings to
|
|
2443
|
+
// vanish from /api/status after a week; we flipped the default to 0 and strip
|
|
2444
|
+
// the literal 7 from persisted configs so the new behavior applies.
|
|
2445
|
+
|
|
2446
|
+
let _staleMeetingsRetentionMigrationLogged = false;
|
|
2447
|
+
|
|
2448
|
+
function applyStatusMeetingsRetentionMigration(config, { logger = log } = {}) {
|
|
2449
|
+
if (!config || !config.engine || typeof config.engine !== 'object') return false;
|
|
2450
|
+
const e = config.engine;
|
|
2451
|
+
if (e.statusMeetingsRetentionDays !== 7) return false;
|
|
2452
|
+
delete e.statusMeetingsRetentionDays;
|
|
2453
|
+
if (!_staleMeetingsRetentionMigrationLogged) {
|
|
2454
|
+
_staleMeetingsRetentionMigrationLogged = true;
|
|
2455
|
+
try {
|
|
2456
|
+
logger('warn', 'statusMeetingsRetentionDays=7 was the previous default — clearing in-memory so the new default (0, no trim) applies. Re-save Settings to persist or set a positive value to opt back in.');
|
|
2457
|
+
} catch { /* logger may not be wired during tests — best-effort */ }
|
|
2458
|
+
}
|
|
2459
|
+
return true;
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
/** Test helper: reset the dedup flag so repeated tests can re-trigger the log. */
|
|
2463
|
+
function _resetStaleMeetingsRetentionMigrationFlag() {
|
|
2464
|
+
_staleMeetingsRetentionMigrationLogged = false;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2404
2467
|
// ─── Runtime Config Preflight Warnings ──────────────────────────────────────
|
|
2405
2468
|
//
|
|
2406
2469
|
// Emit non-fatal warnings about runtime/CLI configuration drift. Consumed by
|
|
@@ -5454,6 +5517,8 @@ module.exports = {
|
|
|
5454
5517
|
resolveAgentCli, resolveCcCli, resolveCcUseWorkerPool, resolveAgentModel, resolveCcModel,
|
|
5455
5518
|
resolveAgentMaxBudget, resolveAgentBareMode,
|
|
5456
5519
|
applyLegacyCcModelMigration, _resetLegacyCcModelMigrationFlag,
|
|
5520
|
+
applyStatusWorkItemsRetentionMigration, _resetStaleRetentionMigrationFlag,
|
|
5521
|
+
applyStatusMeetingsRetentionMigration, _resetStaleMeetingsRetentionMigrationFlag,
|
|
5457
5522
|
runtimeConfigWarnings,
|
|
5458
5523
|
projectWorkSourceWarnings,
|
|
5459
5524
|
backfillProjectWorkSourceDefaults,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2085",
|
|
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"
|