@yemi33/minions 0.1.1820 → 0.1.1821

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,9 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1820 (2026-05-09)
3
+ ## 0.1.1821 (2026-05-09)
4
4
 
5
5
  ### Features
6
- - add --open flag (and MINIONS_FORCE_OPEN env) to bypass the recent-browser-tab heuristic (#2274)
6
+ - correlate CC action failures (#2264)
7
+
8
+ ## 0.1.1819 (2026-05-09)
7
9
 
8
10
  ### Fixes
9
11
  - stop visibility=hidden beacons from racing pagehide and resurrecting closed-tab entries in dashboard-browser.json (#2275)
@@ -10,6 +10,7 @@ var _ccTabs = []; // [{id, title, sessionId, messages: [{role, html}]}]
10
10
  var _ccActiveTabId = null;
11
11
  var _ccOpen = false;
12
12
  var _ccRetrySeq = 0;
13
+ var _ccMessageSeq = 0;
13
14
  // Per-tab sending state stored on tab objects: tab._sending, tab._queue, tab._abortController
14
15
  // Legacy globals for backward compat (badge, drawer close check)
15
16
  var _ccSending = false; // true if active tab is sending (UI indicator only)
@@ -341,7 +342,7 @@ function ccSwitchTab(id) {
341
342
  el.innerHTML = '';
342
343
  // Re-render messages from the tab's data
343
344
  for (var i = 0; i < tab.messages.length; i++) {
344
- ccAddMessage(tab.messages[i].role, tab.messages[i].html, true);
345
+ ccAddMessage(tab.messages[i].role, tab.messages[i].html, true, null, tab.messages[i]);
345
346
  }
346
347
  // If this tab is still processing, restore the full streaming UX (tools, partial text, thinking)
347
348
  if (tab._sending) {
@@ -454,7 +455,7 @@ function ccRestoreMessages() {
454
455
  if (!tab) return;
455
456
  if (el.children.length > 0 || tab.messages.length === 0) return; // Already rendered or nothing to restore
456
457
  for (var i = 0; i < tab.messages.length; i++) {
457
- ccAddMessage(tab.messages[i].role, tab.messages[i].html, true);
458
+ ccAddMessage(tab.messages[i].role, tab.messages[i].html, true, null, tab.messages[i]);
458
459
  }
459
460
  // Restore "thinking" indicator if CC was mid-request when page refreshed
460
461
  try {
@@ -502,7 +503,7 @@ function ccSaveState() {
502
503
  if (!m || typeof m.html !== 'string') return m;
503
504
  var stripped = _ccStripActionBlockFromText(m.html);
504
505
  if (stripped === m.html) return m;
505
- return { role: m.role, html: stripped };
506
+ return Object.assign({}, m, { html: stripped });
506
507
  });
507
508
  return { id: t.id, title: t.title, sessionId: t.sessionId, messages: msgs };
508
509
  });
@@ -526,11 +527,21 @@ function ccUpdateSessionIndicator() {
526
527
  }
527
528
  }
528
529
 
530
+ function _ccNewMessageId(prefix) {
531
+ _ccMessageSeq++;
532
+ return (prefix || 'cc-msg') + '-' + Date.now().toString(36) + '-' + _ccMessageSeq;
533
+ }
534
+
535
+ function _ccMessageDomId(messageId) {
536
+ return 'cc-msg-' + String(messageId || '').replace(/[^a-zA-Z0-9_-]/g, '-');
537
+ }
538
+
529
539
  function ccAddMessage(role, html, skipSave, targetTabId, meta) {
530
540
  var isUser = role === 'user';
531
541
  var isSystem = role === 'system';
532
542
  var isAction = role === 'action';
533
543
  var isAssistant = !isUser && !isSystem && !isAction;
544
+ var messageId = meta && (meta.messageId || meta._messageId) ? String(meta.messageId || meta._messageId) : '';
534
545
  var targetTab = targetTabId ? _ccTabs.find(function(t) { return t.id === targetTabId; }) : _ccActiveTab();
535
546
  // Only render to DOM if this message is for the currently visible tab
536
547
  var isVisible = !targetTabId || targetTabId === _ccActiveTabId;
@@ -538,6 +549,10 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
538
549
  var el = document.getElementById('cc-messages');
539
550
  var div = document.createElement('div');
540
551
  div.className = isAssistant ? 'cc-msg-assistant' : '';
552
+ if (messageId) {
553
+ div.id = _ccMessageDomId(messageId);
554
+ div.setAttribute('data-cc-message-id', messageId);
555
+ }
541
556
  if (meta && meta.retryId) div.setAttribute('data-cc-retry-id', meta.retryId);
542
557
  div.style.cssText = 'padding:8px 12px;border-radius:8px;font-size:12px;line-height:1.6;max-width:95%;' +
543
558
  (isUser ? 'background:var(--blue);color:#fff;align-self:flex-end' : isSystem ? 'align-self:center;max-width:100%' : isAction ? 'align-self:flex-start;padding:2px 0' : 'background:var(--surface2);color:var(--text);align-self:flex-start;border:1px solid var(--border);position:relative');
@@ -550,6 +565,7 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
550
565
  var tab = targetTab;
551
566
  if (tab) {
552
567
  var msg = { role: role, html: html };
568
+ if (messageId) msg._messageId = messageId;
553
569
  if (meta && meta.retryId) msg._retryId = meta.retryId;
554
570
  tab.messages.push(msg);
555
571
  // Auto-title from first user message
@@ -565,6 +581,7 @@ function ccAddMessage(role, html, skipSave, targetTabId, meta) {
565
581
  }
566
582
  ccSaveState();
567
583
  }
584
+ return messageId;
568
585
  }
569
586
 
570
587
  async function ccSend(options) {
@@ -809,34 +826,26 @@ async function _ccDoSend(message, skipUserMsg, forceTabId, intentMetadata) {
809
826
  addMsg('system', '<div style="text-align:center;padding:6px 12px;font-size:11px;color:var(--muted);background:var(--surface2);border-radius:6px;margin:4px 0">' + resetText + '</div>', false, activeTabId);
810
827
  }
811
828
  var finalText = _ccMergeStreamText(streamedText, evt.text || '');
829
+ if (evt.actions && evt.actions.length > 0) _tagServerExecuted(evt.actions, evt.actionResults);
812
830
  var rendered = renderMd(finalText || streamedText || '');
813
- addMsg('assistant', rendered + _ccElapsedFooter('{seconds}s'));
831
+ var assistantMessageId = _ccNewMessageId('cc-turn');
832
+ var actionFeedbackHtml = _ccBuildActionResultFeedbackHtml(evt.actions || [], evt.actionResults || [], {
833
+ delayed: !!isReconnect,
834
+ emittedAt: evt.actionResultsAt || evt.emittedAt || ''
835
+ });
836
+ addMsg('assistant', rendered + _ccElapsedFooter('{seconds}s') + actionFeedbackHtml, false, { messageId: assistantMessageId });
814
837
  if (evt.sessionId !== undefined) {
815
838
  var originTab = _ccTabs.find(function(t) { return t.id === activeTabId; });
816
839
  if (originTab) { originTab.sessionId = evt.sessionId || null; }
817
840
  ccSaveState(); ccUpdateSessionIndicator();
818
841
  }
819
842
  if (evt.actions && evt.actions.length > 0) {
820
- _tagServerExecuted(evt.actions, evt.actionResults);
821
- for (var ai = 0; ai < evt.actions.length; ai++) { await ccExecuteAction(evt.actions[ai], activeTabId); }
822
- // Surface per-action errors/warnings inline alongside the prose so the user can see
823
- // exactly which actions failed or completed with caveats. Previously these only
824
- // appeared as a small "executed" pill which gave no detail.
825
- if (evt.actionResults && Array.isArray(evt.actionResults)) {
826
- var failures = evt.actionResults.filter(function(r) { return r && r.error; });
827
- var warnings = evt.actionResults.filter(function(r) { return r && r.warning; });
828
- if (failures.length > 0) {
829
- var failHtml = failures.map(function(r) {
830
- return '<li>' + escHtml(r.type || (r.actionContext && r.actionContext.type) || 'action') + ': ' + escHtml(r.error) + _ccActionContextSuffix(r.actionContext) + '</li>';
831
- }).join('');
832
- addMsg('system', '<div style="padding:6px 12px;font-size:11px;color:var(--red);background:var(--surface2);border-radius:6px;margin:4px 0">⚠️ ' + failures.length + ' action' + (failures.length > 1 ? 's' : '') + ' failed:<ul style="margin:4px 0 0 16px;padding:0">' + failHtml + '</ul></div>', false, activeTabId);
833
- }
834
- if (warnings.length > 0) {
835
- var warnHtml = warnings.map(function(r) {
836
- return '<li>' + escHtml(r.type || (r.actionContext && r.actionContext.type) || 'action') + ': ' + escHtml(r.warning) + _ccActionContextSuffix(r.actionContext) + '</li>';
837
- }).join('');
838
- addMsg('system', '<div style="padding:6px 12px;font-size:11px;color:var(--orange);background:var(--surface2);border-radius:6px;margin:4px 0">ℹ️ ' + warnings.length + ' action' + (warnings.length > 1 ? '' : '') + ' completed with warnings:<ul style="margin:4px 0 0 16px;padding:0">' + warnHtml + '</ul></div>', false, activeTabId);
843
+ for (var ai = 0; ai < evt.actions.length; ai++) {
844
+ if (evt.actions[ai] && evt.actions[ai]._serverExecuted) {
845
+ _ccRunServerActionSideEffects(evt.actions[ai]);
846
+ continue;
839
847
  }
848
+ await ccExecuteAction(evt.actions[ai], activeTabId, { originMessageId: assistantMessageId });
840
849
  }
841
850
  } else if (evt.actionParseError) {
842
851
  // Issue #1834: server saw ===ACTIONS=== but couldn't parse the JSON.
@@ -1016,6 +1025,79 @@ async function _ccFetch(url, body, method) {
1016
1025
  return res;
1017
1026
  }
1018
1027
 
1028
+ function _ccActionResultSubject(action, result) {
1029
+ var value = (result && (result.title || result.id || result.duplicateOf || result.file || result.target || result.endpoint)) ||
1030
+ (action && (action.title || action.id || action.file || action.target || action.endpoint)) || '';
1031
+ return String(value || '').replace(/\s+/g, ' ').trim().slice(0, 120);
1032
+ }
1033
+
1034
+ function _ccActionResultType(action, result) {
1035
+ return String((result && result.type) || (action && action.type) || 'action').trim() || 'action';
1036
+ }
1037
+
1038
+ function _ccActionResultLine(action, result) {
1039
+ var type = _ccActionResultType(action, result);
1040
+ var subject = _ccActionResultSubject(action, result);
1041
+ var label = escHtml(type) + (subject ? ' <strong>' + escHtml(subject) + '</strong>' : '');
1042
+ var contextSuffix = result && result.actionContext ? _ccActionContextSuffix(result.actionContext) : '';
1043
+ if (result && result.error) {
1044
+ return '<li class="cc-action-feedback-row cc-action-feedback-error">&#10007; ' + label + ': ' + escHtml(result.error) + contextSuffix + '</li>';
1045
+ }
1046
+ if (result && result.warning) {
1047
+ return '<li class="cc-action-feedback-row cc-action-feedback-warning">&#9888; ' + label + ': ' + escHtml(result.warning) + contextSuffix + '</li>';
1048
+ }
1049
+ if (result && result.ok) {
1050
+ var duplicate = result.duplicate ? ' <span style="color:var(--orange)">already exists</span>' : '';
1051
+ return '<li class="cc-action-feedback-row cc-action-feedback-ok">&#10003; ' + label + duplicate + contextSuffix + '</li>';
1052
+ }
1053
+ return '';
1054
+ }
1055
+
1056
+ function _ccBuildActionResultFeedbackHtml(actions, actionResults, opts) {
1057
+ if (!Array.isArray(actions) || !Array.isArray(actionResults)) return '';
1058
+ var rows = [];
1059
+ for (var i = 0; i < actions.length && i < actionResults.length; i++) {
1060
+ var r = actionResults[i];
1061
+ if (!r || (!r.ok && !r.error && !r.warning)) continue;
1062
+ var row = _ccActionResultLine(actions[i] || {}, r);
1063
+ if (row) rows.push(row);
1064
+ }
1065
+ if (rows.length === 0) return '';
1066
+ var failures = actionResults.filter(function(r) { return r && r.error; }).length;
1067
+ var warnings = actionResults.filter(function(r) { return r && r.warning; }).length;
1068
+ var delayed = !!(opts && opts.delayed);
1069
+ var emittedAt = opts && opts.emittedAt ? String(opts.emittedAt) : '';
1070
+ var label = delayed ? 'Action results from previous turn' : 'Action results';
1071
+ var timing = emittedAt ? ' <span style="color:var(--muted);font-weight:400">(' + escHtml(emittedAt) + ')</span>' : '';
1072
+ var color = failures > 0 ? 'var(--red)' : warnings > 0 ? 'var(--orange)' : 'var(--green)';
1073
+ return '<div class="cc-action-feedback" data-cc-action-feedback="true" style="margin-top:8px;padding:6px 10px;border:1px dashed var(--border);border-radius:6px;background:var(--surface);font-size:11px;color:' + color + '">' +
1074
+ '<div style="font-weight:700">' + label + timing + '</div>' +
1075
+ '<ul style="margin:4px 0 0 16px;padding:0">' + rows.join('') + '</ul>' +
1076
+ '</div>';
1077
+ }
1078
+
1079
+ function _ccAppendHtmlToMessage(tabOrId, messageId, html) {
1080
+ if (!messageId || !html) return false;
1081
+ var tab = typeof tabOrId === 'object' && tabOrId ? tabOrId : _ccTabs.find(function(t) { return t.id === tabOrId; });
1082
+ if (!tab || !Array.isArray(tab.messages)) return false;
1083
+ var msg = tab.messages.find(function(m) { return m && m._messageId === messageId; });
1084
+ if (!msg) return false;
1085
+ msg.html = (msg.html || '') + html;
1086
+ if (typeof _ccActiveTabId !== 'undefined' && tab.id === _ccActiveTabId && typeof document !== 'undefined') {
1087
+ var el = document.getElementById(_ccMessageDomId(messageId));
1088
+ if (el && typeof el.insertAdjacentHTML === 'function') el.insertAdjacentHTML('beforeend', html);
1089
+ }
1090
+ return true;
1091
+ }
1092
+
1093
+ function _ccRunServerActionSideEffects(action) {
1094
+ var type = String(action && action.type || '');
1095
+ if (['dispatch','fix','explore','review','test','create-meeting','plan','execute-plan','approve-plan','resume-plan','trigger-pipeline','advance-meeting','trigger-verify','regenerate-plan','continue-pipeline'].indexOf(type) >= 0) {
1096
+ wakeEngine();
1097
+ }
1098
+ refresh();
1099
+ }
1100
+
1019
1101
  var CC_ACTION_CONTEXT_STALE_MS = 2 * 60 * 1000;
1020
1102
  function _ccActionContextIsStale(ctx, nowMs) {
1021
1103
  if (!ctx || !ctx.requestedAt) return false;
@@ -1059,7 +1141,7 @@ function _tagServerExecuted(actions, actionResults) {
1059
1141
  }
1060
1142
  }
1061
1143
 
1062
- async function ccExecuteAction(action, targetTabId) {
1144
+ async function ccExecuteAction(action, targetTabId, opts) {
1063
1145
  action = _ccNormalizeDispatchAction(action);
1064
1146
  var status = document.createElement('div');
1065
1147
  status.style.cssText = 'padding:4px 10px;border-radius:4px;font-size:10px;align-self:flex-start;border:1px dashed var(--border);color:var(--muted)';
@@ -1081,6 +1163,11 @@ async function ccExecuteAction(action, targetTabId) {
1081
1163
  _ccActionContextSuffix(action._serverContext);
1082
1164
  status.style.color = 'var(--green)';
1083
1165
  }
1166
+ if (opts && opts.originMessageId && _ccAppendHtmlToMessage(targetTabId || _ccActiveTabId, opts.originMessageId, status.outerHTML)) {
1167
+ ccSaveState();
1168
+ refresh();
1169
+ return;
1170
+ }
1084
1171
  ccAddMessage('action', status.outerHTML, false, targetTabId);
1085
1172
  if (['dispatch','fix','explore','review','test','create-meeting'].includes(action.type)) wakeEngine();
1086
1173
  refresh();
@@ -1584,6 +1671,11 @@ async function ccExecuteAction(action, targetTabId) {
1584
1671
  status.style.color = 'var(--red)';
1585
1672
  }
1586
1673
 
1674
+ if (opts && opts.originMessageId && _ccAppendHtmlToMessage(targetTabId || _ccActiveTabId, opts.originMessageId, status.outerHTML)) {
1675
+ ccSaveState();
1676
+ refresh();
1677
+ return;
1678
+ }
1587
1679
  ccAddMessage('action', status.outerHTML, false, targetTabId);
1588
1680
  refresh();
1589
1681
  }
package/dashboard.js CHANGED
@@ -3325,6 +3325,16 @@ async function _ccExecuteLocalApiAction(action) {
3325
3325
  };
3326
3326
  }
3327
3327
 
3328
+ function _ccActionFailureLabel(action) {
3329
+ const type = String(action?.type || 'action').trim() || 'action';
3330
+ const title = String(action?.title || action?.id || action?.file || action?.target || '').replace(/\s+/g, ' ').trim();
3331
+ return title ? `${type} failed for '${title.slice(0, 120)}'` : `${type} failed`;
3332
+ }
3333
+
3334
+ function _ccMultiProjectRequiredError(action) {
3335
+ return `${_ccActionFailureLabel(action)}: project field is required when ${PROJECTS.length} projects are configured: ${PROJECTS.map(p => p.name).join(', ')}`;
3336
+ }
3337
+
3328
3338
  async function executeCCActions(actions, { source = 'command-center', inferredProject = null } = {}) {
3329
3339
  const results = [];
3330
3340
  const dispatchIdsCreatedInThisCall = new Map();
@@ -3379,7 +3389,7 @@ async function executeCCActions(actions, { source = 'command-center', inferredPr
3379
3389
  }
3380
3390
  if (!targetProject) {
3381
3391
  if (PROJECTS.length > 1) {
3382
- results.push({ type: action.type, error: `project field is required when ${PROJECTS.length} projects are configured: ${PROJECTS.map(p => p.name).join(', ')}` });
3392
+ results.push({ type: action.type, error: _ccMultiProjectRequiredError(action) });
3383
3393
  break;
3384
3394
  }
3385
3395
  if (PROJECTS.length === 1) targetProject = PROJECTS[0];
@@ -3541,7 +3551,7 @@ async function executeCCActions(actions, { source = 'command-center', inferredPr
3541
3551
  }
3542
3552
  if (!targetProject) {
3543
3553
  if (PROJECTS.length > 1) {
3544
- results.push({ type: 'reopen-work-item', id: action.id, error: `project field is required when ${PROJECTS.length} projects are configured: ${PROJECTS.map(p => p.name).join(', ')}` });
3554
+ results.push({ type: 'reopen-work-item', id: action.id, error: _ccMultiProjectRequiredError({ ...action, type: 'reopen-work-item' }) });
3545
3555
  break;
3546
3556
  }
3547
3557
  if (PROJECTS.length === 1) targetProject = PROJECTS[0];
@@ -7263,6 +7273,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
7263
7273
  await executeCCActions(parsed.actions),
7264
7274
  { message: body.message, requestedAt: actionRequestedAt }
7265
7275
  );
7276
+ parsed.actionResultsAt = new Date().toISOString();
7266
7277
  }
7267
7278
  // Mirror only user-facing text to Teams; never send the internal action block.
7268
7279
  if (!tabId.startsWith('teams-')) {
@@ -7594,14 +7605,16 @@ What would you like to discuss or change? When you're happy, say "approve" and I
7594
7605
  { message: body.message, intentMetadata: body.intentMetadata, source: 'command-center', answerText: displayText, toolUses }
7595
7606
  );
7596
7607
  let actionResults;
7608
+ let actionResultsAt;
7597
7609
  if (actions.length > 0) {
7598
7610
  actionResults = _annotateCCActionResults(
7599
7611
  actions,
7600
7612
  await executeCCActions(actions),
7601
7613
  { message: body.message, requestedAt: actionRequestedAt }
7602
7614
  );
7615
+ actionResultsAt = new Date().toISOString();
7603
7616
  }
7604
- const donePayload = { type: 'done', text: displayText, actions, actionResults, sessionId: responseSessionId, newSession: !wasResume };
7617
+ const donePayload = { type: 'done', text: displayText, actions, actionResults, actionResultsAt, sessionId: responseSessionId, newSession: !wasResume };
7605
7618
  // Issue #1834: surface action JSON parse failures so the UI can warn
7606
7619
  // instead of silently dropping. Client renders this as a small notice.
7607
7620
  if (_actionParseError) donePayload.actionParseError = _actionParseError;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-09T17:43:03.560Z"
4
+ "cachedAt": "2026-05-09T18:10:43.397Z"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1820",
3
+ "version": "0.1.1821",
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"