@yemi33/minions 0.1.90 → 0.1.92

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,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.92 (2026-04-01)
4
+
5
+ ### Engine
6
+ - engine/lifecycle.js
7
+ - engine/shared.js
8
+
9
+ ### Dashboard
10
+ - dashboard/js/render-other.js
11
+
12
+ ## 0.1.91 (2026-04-01)
13
+
14
+ ### Dashboard
15
+ - dashboard/styles.css
16
+
3
17
  ## 0.1.90 (2026-04-01)
4
18
 
5
19
  ### Dashboard
@@ -142,12 +142,14 @@ function renderTokenUsage(metrics) {
142
142
  const agentsWithUsage = agents.filter(([, m]) => (m.totalCostUsd || 0) > 0);
143
143
  if (agentsWithUsage.length > 0) {
144
144
  html += '<div style="font-size:10px;color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Agent Usage</div>';
145
- html += '<table class="token-agent-table"><thead><tr><th>Agent</th><th>Cost</th><th>Input</th><th>Output</th><th>Cache</th><th>$/task</th></tr></thead><tbody>';
145
+ html += '<table class="token-agent-table"><thead><tr><th>Agent</th><th>Model</th><th>Cost</th><th>Input</th><th>Output</th><th>Cache</th><th>$/task</th></tr></thead><tbody>';
146
146
  for (const [id, m] of agentsWithUsage.sort((a, b) => (b[1].totalCostUsd || 0) - (a[1].totalCostUsd || 0))) {
147
147
  const tasks = (m.tasksCompleted || 0) + (m.tasksErrored || 0);
148
148
  const perTask = tasks > 0 ? fmtCost((m.totalCostUsd || 0) / tasks) : '-';
149
+ const modelLabel = (m.model || '').replace(/^claude-/, '').replace(/\[.*\]$/, '') || '-';
149
150
  html += '<tr>' +
150
151
  '<td style="font-weight:600">' + escHtml(id) + '</td>' +
152
+ '<td style="color:var(--muted);font-size:10px">' + escHtml(modelLabel) + '</td>' +
151
153
  '<td>' + fmtCost(m.totalCostUsd || 0) + '</td>' +
152
154
  '<td>' + fmtTokens(m.totalInputTokens || 0) + '</td>' +
153
155
  '<td>' + fmtTokens(m.totalOutputTokens || 0) + '</td>' +
@@ -161,8 +163,8 @@ function renderTokenUsage(metrics) {
161
163
  // Engine (Haiku) usage table
162
164
  const engineEntries = Object.entries(engine).filter(([, e]) => (e.costUsd || 0) > 0 || (e.calls || 0) > 0);
163
165
  if (engineEntries.length > 0) {
164
- const labels = { 'consolidation': 'Consolidation', 'command-center': 'Command Center', 'doc-chat': 'Doc Chat' };
165
- html += '<div style="font-size:10px;color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Engine Usage (Haiku)</div>';
166
+ const labels = { 'consolidation': 'Consolidation', 'command-center': 'Command Center', 'doc-chat': 'Doc Chat', 'kb-sweep': 'KB Sweep', 'schedule-parse': 'Schedule Parse' };
167
+ html += '<div style="font-size:10px;color:var(--muted);margin:12px 0 4px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Engine Usage</div>';
166
168
  html += '<table class="token-agent-table"><thead><tr><th>Operation</th><th>Cost</th><th>Calls</th><th>Input</th><th>Output</th><th>$/call</th></tr></thead><tbody>';
167
169
  for (const [cat, e] of engineEntries.sort((a, b) => (b[1].costUsd || 0) - (a[1].costUsd || 0))) {
168
170
  const perCall = (e.calls || 0) > 0 ? fmtCost((e.costUsd || 0) / e.calls) : '-';
@@ -131,9 +131,12 @@
131
131
  .token-bar:hover .token-bar-tip { display: block; }
132
132
  .token-chart-labels { display: flex; gap: 3px; }
133
133
  .token-chart-labels span { flex: 1; min-width: 8px; max-width: 24px; font-size: 8px; color: var(--muted); text-align: center; overflow: hidden; }
134
- .token-agent-table { width: 100%; margin-top: var(--space-5); }
134
+ .token-agent-table { width: 100%; margin-top: var(--space-5); table-layout: fixed; }
135
135
  .token-agent-table th { text-align: left; font-size: var(--text-sm); color: var(--muted); font-weight: 500; padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--border); }
136
- .token-agent-table td { font-size: var(--text-base); padding: var(--space-2) var(--space-4); }
136
+ .token-agent-table th:first-child { width: 28%; }
137
+ .token-agent-table th:not(:first-child) { text-align: right; }
138
+ .token-agent-table td { font-size: var(--text-base); padding: var(--space-2) var(--space-4); font-variant-numeric: tabular-nums; }
139
+ .token-agent-table td:not(:first-child) { text-align: right; }
137
140
  .kb-tabs { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-4); }
138
141
  .kb-tab { background: var(--surface2); border: 1px solid var(--border); color: var(--muted); font-size: var(--text-base); cursor: pointer; padding: var(--space-1) var(--space-5); border-radius: var(--radius-sm); transition: all var(--transition-base); }
139
142
  .kb-tab:hover { color: var(--text); border-color: var(--text); }
@@ -880,7 +880,7 @@ function createReviewFeedbackForAuthor(reviewerAgentId, pr, config) {
880
880
  log('info', `Created review feedback for ${authorAgentId} from ${reviewerAgentId} on ${pr.id}`);
881
881
  }
882
882
 
883
- function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount) {
883
+ function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount, model) {
884
884
 
885
885
  const metricsPath = path.join(ENGINE_DIR, 'metrics.json');
886
886
  const metrics = safeJson(metricsPath) || {};
@@ -891,6 +891,7 @@ function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount
891
891
  const m = metrics[agentId];
892
892
  m.lastTask = dispatchItem.task;
893
893
  m.lastCompleted = ts();
894
+ if (model) m.model = model;
894
895
  if (result === 'success') {
895
896
  m.tasksCompleted++;
896
897
  if (prsCreatedCount > 0) m.prsCreated = (m.prsCreated || 0) + prsCreatedCount;
@@ -930,8 +931,8 @@ function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount
930
931
  // ─── Agent Output Parsing ────────────────────────────────────────────────────
931
932
 
932
933
  function parseAgentOutput(stdout) {
933
- const { text, usage, sessionId } = shared.parseStreamJsonOutput(stdout, { maxTextLength: 2000 });
934
- return { resultSummary: text, taskUsage: usage, sessionId };
934
+ const { text, usage, sessionId, model } = shared.parseStreamJsonOutput(stdout, { maxTextLength: 2000 });
935
+ return { resultSummary: text, taskUsage: usage, sessionId, model };
935
936
  }
936
937
 
937
938
  /**
@@ -1016,7 +1017,7 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
1016
1017
  const meta = dispatchItem.meta;
1017
1018
  const isSuccess = code === 0;
1018
1019
  const result = isSuccess ? 'success' : 'error';
1019
- const { resultSummary, taskUsage, sessionId } = parseAgentOutput(stdout);
1020
+ const { resultSummary, taskUsage, sessionId, model } = parseAgentOutput(stdout);
1020
1021
 
1021
1022
  // Save session for potential resume on next dispatch
1022
1023
  if (isSuccess && sessionId && agentId && !agentId.startsWith('temp-')) {
@@ -1179,7 +1180,7 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
1179
1180
  // Don't count auto-retries as errors in metrics — only count final outcomes
1180
1181
  const isAutoRetry = !isSuccess && meta?.item?.id && (meta.item._retryCount || 0) < 3;
1181
1182
  const metricsResult = isAutoRetry ? 'retry' : result;
1182
- updateMetrics(agentId, dispatchItem, metricsResult, taskUsage, prsCreatedCount);
1183
+ updateMetrics(agentId, dispatchItem, metricsResult, taskUsage, prsCreatedCount, model);
1183
1184
 
1184
1185
  return { resultSummary, taskUsage };
1185
1186
  }
package/engine/shared.js CHANGED
@@ -205,6 +205,7 @@ function parseStreamJsonOutput(raw, { maxTextLength = 0 } = {}) {
205
205
  let text = '';
206
206
  let usage = null;
207
207
  let sessionId = null;
208
+ let model = null;
208
209
 
209
210
  function extractResult(obj) {
210
211
  if (obj.type !== 'result') return false;
@@ -225,6 +226,16 @@ function parseStreamJsonOutput(raw, { maxTextLength = 0 } = {}) {
225
226
  }
226
227
 
227
228
  const lines = raw.split('\n');
229
+ // Scan forward for model from init message (appears early in output)
230
+ for (let i = 0; i < Math.min(lines.length, 10); i++) {
231
+ const line = lines[i].trim();
232
+ if (!line || !line.startsWith('{')) continue;
233
+ try {
234
+ const obj = JSON.parse(line);
235
+ if (obj.type === 'system' && obj.subtype === 'init' && obj.model) { model = obj.model; break; }
236
+ } catch {}
237
+ }
238
+ // Scan backward for result (appears at end of output)
228
239
  for (let i = lines.length - 1; i >= 0; i--) {
229
240
  const line = lines[i].trim();
230
241
  if (!line) continue;
@@ -245,7 +256,7 @@ function parseStreamJsonOutput(raw, { maxTextLength = 0 } = {}) {
245
256
  } catch {}
246
257
  }
247
258
  }
248
- return { text, usage, sessionId };
259
+ return { text, usage, sessionId, model };
249
260
  }
250
261
 
251
262
  // ── Knowledge Base ──────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.90",
3
+ "version": "0.1.92",
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"