@yemi33/minions 0.1.146 β†’ 0.1.147

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,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.147 (2026-04-01)
4
+
5
+ ### Engine
6
+ - engine/lifecycle.js
7
+ - engine/shared.js
8
+
9
+ ### Dashboard
10
+ - dashboard/js/render-work-items.js
11
+
12
+ ### Other
13
+ - .github/workflows/pr-tests.yml
14
+ - test/unit.test.js
15
+
3
16
  ## 0.1.146 (2026-04-01)
4
17
 
5
18
  ### Engine
@@ -388,6 +388,9 @@ function openWorkItemDetail(id) {
388
388
  if (item.references?.length) html += field('References', item.references.map(r => '<a href="' + escHtml(r.url) + '" target="_blank" style="color:var(--blue)">' + escHtml(r.title || r.url) + '</a>' + (r.type ? ' <span style="color:var(--muted);font-size:10px">(' + escHtml(r.type) + ')</span>' : '')).join('<br>'));
389
389
  if (item._humanFeedback) html += field('Human Feedback', (item._humanFeedback.rating === 'up' ? 'πŸ‘' : 'πŸ‘Ž') + (item._humanFeedback.comment ? ' β€” ' + escHtml(item._humanFeedback.comment) : ''));
390
390
  if (item._pr) html += field('Pull Request', '<a href="' + escHtml(item._prUrl || '#') + '" target="_blank" style="color:var(--blue)">' + escHtml(item._pr) + '</a>');
391
+ if (item._totalCostUsd != null) html += field('Cumulative Cost', '$' + Number(item._totalCostUsd).toFixed(4));
392
+ if (item._totalInputTokens) html += field('Total Input Tokens', Number(item._totalInputTokens).toLocaleString());
393
+ if (item._totalOutputTokens) html += field('Total Output Tokens', Number(item._totalOutputTokens).toLocaleString());
391
394
  html += '</div>';
392
395
 
393
396
  document.getElementById('modal-title').textContent = item.title || item.id;
@@ -1153,6 +1153,47 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
1153
1153
  } catch (err) { log('warn', `Session save: ${err.message}`); }
1154
1154
  }
1155
1155
 
1156
+ // ── Accumulate per-work-item cost tracking ──────────────────────────────────
1157
+ if (taskUsage && meta?.item?.id) {
1158
+ try {
1159
+ const wiPath = meta.source === 'central-work-item' || meta.source === 'central-work-item-fanout'
1160
+ ? path.join(MINIONS_DIR, 'work-items.json')
1161
+ : meta.project?.name ? path.join(MINIONS_DIR, 'projects', meta.project.name, 'work-items.json') : null;
1162
+ if (wiPath) {
1163
+ mutateJsonFileLocked(wiPath, (items) => {
1164
+ if (!Array.isArray(items)) return items;
1165
+ const wi = items.find(i => i.id === meta.item.id);
1166
+ if (wi) {
1167
+ wi._totalCostUsd = (wi._totalCostUsd || 0) + (taskUsage.costUsd || 0);
1168
+ wi._totalInputTokens = (wi._totalInputTokens || 0) + (taskUsage.inputTokens || 0);
1169
+ wi._totalOutputTokens = (wi._totalOutputTokens || 0) + (taskUsage.outputTokens || 0);
1170
+ }
1171
+ return items;
1172
+ }, { defaultValue: [] });
1173
+
1174
+ // Cost ceiling circuit breaker β€” treat like evalMaxIterations exceeded
1175
+ const engineCfg = config?.engine || {};
1176
+ const evalMaxCost = engineCfg.evalMaxCost != null ? engineCfg.evalMaxCost : shared.ENGINE_DEFAULTS.evalMaxCost;
1177
+ if (evalMaxCost != null && evalMaxCost > 0) {
1178
+ const freshItems = safeJson(wiPath) || [];
1179
+ const wi = freshItems.find(i => i.id === meta.item.id);
1180
+ if (wi && wi._totalCostUsd > evalMaxCost && wi.status !== 'needs-human-review') {
1181
+ mutateJsonFileLocked(wiPath, (items) => {
1182
+ if (!Array.isArray(items)) return items;
1183
+ const target = items.find(i => i.id === meta.item.id);
1184
+ if (target) {
1185
+ target.status = 'needs-human-review';
1186
+ target.failReason = `Cumulative cost $${wi._totalCostUsd.toFixed(2)} exceeds evalMaxCost ceiling $${evalMaxCost.toFixed(2)}`;
1187
+ log('warn', `Work item ${meta.item.id} exceeded cost ceiling ($${wi._totalCostUsd.toFixed(2)} > $${evalMaxCost.toFixed(2)}) β€” needs-human-review`);
1188
+ }
1189
+ return items;
1190
+ }, { defaultValue: [] });
1191
+ }
1192
+ }
1193
+ }
1194
+ } catch (err) { log('warn', `Cost accumulation: ${err.message}`); }
1195
+ }
1196
+
1156
1197
  // Handle decomposition results β€” create sub-items from decompose agent output
1157
1198
  let skipDoneStatus = false;
1158
1199
  if (type === 'decompose' && isSuccess && meta?.item?.id) {
package/engine/shared.js CHANGED
@@ -358,6 +358,7 @@ const ENGINE_DEFAULTS = {
358
358
  meetingRoundTimeout: 600000, // 10min per meeting round before auto-advance
359
359
  evalLoop: true, // enable evaluateβ†’fix loop after implementation completes
360
360
  evalMaxIterations: 3, // max evaluateβ†’fix cycles before escalating to human
361
+ evalMaxCost: null, // USD ceiling per work item across all eval iterations; null = no limit (gather baseline data first)
361
362
  };
362
363
 
363
364
  const DEFAULT_AGENTS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.146",
3
+ "version": "0.1.147",
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"