@yemi33/minions 0.1.1612 → 0.1.1613
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 +2 -1
- package/dashboard/js/utils.js +2 -2
- package/engine/queries.js +9 -1
- package/engine/routing.js +18 -1
- package/engine.js +7 -4
- package/minions.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1613 (2026-04-28)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- fix npm test failures (#1846)
|
|
6
7
|
- hard-pin agent assignment when CC names a specific agent
|
|
7
8
|
- auto-detect available CLI runtimes and pin engine.defaultCli
|
|
8
9
|
- match runtime tags to actual logos (pixel-crab Claude, mascot Copilot)
|
package/dashboard/js/utils.js
CHANGED
|
@@ -183,8 +183,8 @@ function copyLlmText(btn) {
|
|
|
183
183
|
const clone = container.cloneNode(true);
|
|
184
184
|
clone.querySelectorAll('.llm-copy-btn').forEach(b => b.remove());
|
|
185
185
|
navigator.clipboard.writeText(clone.textContent.trim());
|
|
186
|
-
btn.
|
|
187
|
-
setTimeout(() => { btn.
|
|
186
|
+
btn.textContent = '\u2713';
|
|
187
|
+
setTimeout(() => { btn.textContent = '\u2398'; }, 1500);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
package/engine/queries.js
CHANGED
|
@@ -11,7 +11,7 @@ const shared = require('./shared');
|
|
|
11
11
|
|
|
12
12
|
const { safeRead, safeReadDir, safeJson, safeWrite, getProjects, mutateJsonFileLocked,
|
|
13
13
|
projectWorkItemsPath, projectPrPath, parseSkillFrontmatter, KB_CATEGORIES,
|
|
14
|
-
WI_STATUS, DONE_STATUSES, PRD_ITEM_STATUS, PR_STATUS, ENGINE_DEFAULTS } = shared;
|
|
14
|
+
WI_STATUS, DONE_STATUSES, PRD_ITEM_STATUS, PR_STATUS, ENGINE_DEFAULTS, DEFAULT_AGENT_METRICS } = shared;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Read the first `bytes` and last `bytes` of a file efficiently using byte offsets.
|
|
@@ -196,6 +196,14 @@ function getEngineLog() {
|
|
|
196
196
|
function getMetrics() {
|
|
197
197
|
const metrics = safeJson(path.join(ENGINE_DIR, 'metrics.json')) || {};
|
|
198
198
|
|
|
199
|
+
for (const [agentId, m] of Object.entries(metrics)) {
|
|
200
|
+
if (agentId.startsWith('_')) continue;
|
|
201
|
+
metrics[agentId] = {
|
|
202
|
+
...DEFAULT_AGENT_METRICS,
|
|
203
|
+
...(m && typeof m === 'object' && !Array.isArray(m) ? m : {}),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
199
207
|
// Enrich agent PR counts from pull-requests.json (source of truth)
|
|
200
208
|
const allPrs = getPullRequests();
|
|
201
209
|
const prCountByAgent = {};
|
package/engine/routing.js
CHANGED
|
@@ -116,7 +116,15 @@ function setTempBudget(n) {
|
|
|
116
116
|
}
|
|
117
117
|
function getTempBudget() { return _tempBudget; }
|
|
118
118
|
|
|
119
|
-
function
|
|
119
|
+
function normalizeAgentHints(agentHints, authorAgent = null) {
|
|
120
|
+
const raw = Array.isArray(agentHints) ? agentHints : (agentHints ? [agentHints] : []);
|
|
121
|
+
return raw
|
|
122
|
+
.map(id => id === '_author_' ? authorAgent : id)
|
|
123
|
+
.map(id => typeof id === 'string' ? id.trim().toLowerCase() : '')
|
|
124
|
+
.filter(Boolean);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function resolveAgent(workType, config, authorAgent = null, agentHints = null) {
|
|
120
128
|
const routes = getRoutingTableCached();
|
|
121
129
|
const route = routes[workType] || routes['implement'];
|
|
122
130
|
const agents = config.agents || {};
|
|
@@ -145,6 +153,14 @@ function resolveAgent(workType, config, authorAgent = null) {
|
|
|
145
153
|
return null;
|
|
146
154
|
};
|
|
147
155
|
|
|
156
|
+
const hintedAgents = normalizeAgentHints(agentHints, authorAgent);
|
|
157
|
+
if (hintedAgents.length > 0) {
|
|
158
|
+
for (const id of hintedAgents) {
|
|
159
|
+
if (isAvailable(id)) { _claimedAgents.add(id); return id; }
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
// Resolve _any_ token — pick any available agent (#480)
|
|
149
165
|
if (preferred === '_any_') { const pick = pickAnyIdle(); if (pick) return pick; }
|
|
150
166
|
else if (preferred && isAvailable(preferred)) { _claimedAgents.add(preferred); return preferred; }
|
|
@@ -192,4 +208,5 @@ module.exports = {
|
|
|
192
208
|
resolveAgent,
|
|
193
209
|
setTempBudget,
|
|
194
210
|
getTempBudget,
|
|
211
|
+
normalizeAgentHints,
|
|
195
212
|
};
|
package/engine.js
CHANGED
|
@@ -2441,7 +2441,8 @@ function discoverFromWorkItems(config, project) {
|
|
|
2441
2441
|
item._decomposing = true;
|
|
2442
2442
|
needsWrite = true;
|
|
2443
2443
|
}
|
|
2444
|
-
const
|
|
2444
|
+
const agentHints = item.preferred_agent || item.agents || null;
|
|
2445
|
+
const agentId = item.agent || resolveAgent(workType, config, null, agentHints);
|
|
2445
2446
|
if (!agentId) {
|
|
2446
2447
|
// Check if reason is budget
|
|
2447
2448
|
const cfgAgents = config.agents || {};
|
|
@@ -2960,7 +2961,8 @@ function discoverCentralWorkItems(config) {
|
|
|
2960
2961
|
|
|
2961
2962
|
} else {
|
|
2962
2963
|
// ─── Normal: single agent dispatch ──────────────────────────────
|
|
2963
|
-
const
|
|
2964
|
+
const agentHints = item.preferred_agent || item.agents || null;
|
|
2965
|
+
const agentId = item.agent || resolveAgent(workType, config, null, agentHints);
|
|
2964
2966
|
if (!agentId) continue;
|
|
2965
2967
|
|
|
2966
2968
|
const agentName = config.agents[agentId]?.name || agentId;
|
|
@@ -3602,7 +3604,8 @@ async function tickInner() {
|
|
|
3602
3604
|
// be of type string. Received undefined` and re-queues — every tick. Try to
|
|
3603
3605
|
// resolve a fallback via routing; if none is available, skip this tick.
|
|
3604
3606
|
if (!item.agent || typeof item.agent !== 'string') {
|
|
3605
|
-
const
|
|
3607
|
+
const agentHints = item.meta?.item?.preferred_agent || item.meta?.item?.agents || null;
|
|
3608
|
+
const fallback = resolveAgent(item.type || WORK_TYPE.FIX, config, null, agentHints);
|
|
3606
3609
|
if (!fallback) {
|
|
3607
3610
|
log('warn', `Pending dispatch ${item.id} has no agent and routing returned no fallback — skipping`);
|
|
3608
3611
|
continue;
|
|
@@ -3660,7 +3663,7 @@ async function tickInner() {
|
|
|
3660
3663
|
// Agent busy reassignment: if item has been waiting on a busy agent past the threshold,
|
|
3661
3664
|
// try to find an alternative agent via routing. Skip explicitly assigned items.
|
|
3662
3665
|
const reassignMs = config.engine?.agentBusyReassignMs ?? ENGINE_DEFAULTS.agentBusyReassignMs;
|
|
3663
|
-
const isExplicitReassign = !!item.meta?.item?.agent;
|
|
3666
|
+
const isExplicitReassign = !!(item.meta?.item?.agent || item.meta?.item?.preferred_agent || item.meta?.item?.agents?.length);
|
|
3664
3667
|
if (!isExplicitReassign && reassignMs > 0 && item._agentBusySince) {
|
|
3665
3668
|
const busySinceMs = new Date(item._agentBusySince).getTime();
|
|
3666
3669
|
if (Date.now() - busySinceMs > reassignMs) {
|
package/minions.js
CHANGED
|
@@ -465,6 +465,7 @@ async function initMinions({ skipScan = false, scanRoot, scanDepth } = {}) {
|
|
|
465
465
|
// Merge defaults — fills in new fields from upgrades while preserving user customizations
|
|
466
466
|
if (!config.engine) config.engine = {};
|
|
467
467
|
for (const [k, v] of Object.entries(ENGINE_DEFAULTS)) {
|
|
468
|
+
if (k === 'defaultCli') continue;
|
|
468
469
|
if (config.engine[k] === undefined) config.engine[k] = v;
|
|
469
470
|
}
|
|
470
471
|
if (!config.claude) config.claude = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1613",
|
|
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"
|