@yemi33/minions 0.1.2318 → 0.1.2320

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.
@@ -2051,15 +2051,6 @@ async function ccExecuteAction(action, targetTabId, opts) {
2051
2051
  wakeEngine();
2052
2052
  break;
2053
2053
  }
2054
- case 'link-pr': {
2055
- var prLinkRes = await _ccFetch('/api/pull-requests/link', { url: action.url, title: action.title || '', project: action.project || '', contextOnly: action.autoObserve === false });
2056
- var prLinkData = await prLinkRes.json().catch(function() { return {}; });
2057
- // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; PR URL and server message wrapped in escHtml() (fields: action.url, prLinkData.message)
2058
- status.innerHTML = '&#10003; PR linked: <strong>' + escHtml(action.url) + '</strong>' +
2059
- (prLinkData.message ? '<div style="font-size:var(--text-base);color:var(--muted);margin-top:4px">' + escHtml(prLinkData.message) + '</div>' : '');
2060
- status.style.color = 'var(--green)';
2061
- break;
2062
- }
2063
2054
  case 'archive-meeting': {
2064
2055
  await _ccFetch('/api/meetings/archive', { id: action.id });
2065
2056
  // eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; meeting id wrapped in escHtml() (fields: action.id)
@@ -1098,6 +1098,28 @@ function createStreamConsumer(ctx) {
1098
1098
  // form `...prev.next...`. First push is NEVER prefixed (would leave every
1099
1099
  // reply with a leading blank line). Reset by reset() on stream restart.
1100
1100
  let _hadPriorAssistantMessage = false;
1101
+ // `terminalText` accumulates EVERY non-tool assistant.message across the
1102
+ // whole turn, including ones separated by intervening tool calls. That
1103
+ // whole-turn scope is wrong for `ctx.setText(...)` on the `result` event:
1104
+ // the dashboard's `ccSegmentsFinalize`/`_ccSegMergeText` (render-utils.js)
1105
+ // expect the authoritative final text to describe ONLY the *trailing* text
1106
+ // segment (correct for Claude's single last-message `result.result`), and
1107
+ // merge it into just the last segment. Sending the whole-turn text there
1108
+ // duplicated earlier paragraphs (W-mr3rdn9j000u6d5d) because the trailing
1109
+ // segment only ever received the post-tool delta via ctx.pushText, not the
1110
+ // full accumulated turn.
1111
+ //
1112
+ // `trailingText`/`_hadPriorTrailingMessage` mirror `terminalText`/
1113
+ // `_hadPriorAssistantMessage` but are reset to '' / false on every tool
1114
+ // boundary (a real tool call — not `task_complete`), so their scope always
1115
+ // matches the trailing segment the dashboard will merge into.
1116
+ let trailingText = '';
1117
+ let _hadPriorTrailingMessage = false;
1118
+
1119
+ function _resetTrailingSegment() {
1120
+ trailingText = '';
1121
+ _hadPriorTrailingMessage = false;
1122
+ }
1101
1123
 
1102
1124
  function _captureTaskComplete(summary, success = true, { clearBuffer = false } = {}) {
1103
1125
  if (typeof summary !== 'string' || !summary) return;
@@ -1117,7 +1139,7 @@ function createStreamConsumer(ctx) {
1117
1139
  // The result event is the first Copilot event that contains the resumable
1118
1140
  // sessionId. Do not mark the earlier assistant.message as terminal or
1119
1141
  // Minions can resolve before session persistence data is available.
1120
- const finalText = terminalText || copilotMessageBuffer || taskCompleteSummary;
1142
+ const finalText = trailingText || copilotMessageBuffer || taskCompleteSummary;
1121
1143
  if (finalText) ctx.setText(finalText);
1122
1144
  }
1123
1145
 
@@ -1149,21 +1171,30 @@ function createStreamConsumer(ctx) {
1149
1171
  // the terminal answer. A non-tool assistant.message overrides any
1150
1172
  // streamed deltas (Copilot's authoritative final text for the turn).
1151
1173
  if (content && !hasTools) {
1152
- // Second-and-later terminating message in a single turn: prefix the
1153
- // pushed text with `\n\n` so the dashboard merge sees a clean
1154
- // paragraph boundary instead of welding `<prev>.<next>` together
1155
- // (W-mq1jwwqo000f20d9 CC chunk welding fix). The first push must
1156
- // NOT be prefixed or every reply starts with a blank line. Tool-use
1157
- // boundaries are skipped those get rendered as visible chips
1158
- // client-side and already act as natural separators.
1159
- const pushed = _hadPriorAssistantMessage ? '\n\n' + content : content;
1174
+ // Second-and-later terminating message within the SAME trailing
1175
+ // segment (no tool boundary since): prefix the pushed text with
1176
+ // `\n\n` so the dashboard merge sees a clean paragraph boundary
1177
+ // instead of welding `<prev>.<next>` together (W-mq1jwwqo000f20d9
1178
+ // CC chunk welding fix). The first push in a segment must NOT be
1179
+ // prefixed (would leave every reply/segment with a leading blank
1180
+ // line). This is now gated on `_hadPriorTrailingMessage` (reset on
1181
+ // every real tool boundary below), not the whole-turn flag — a
1182
+ // tool boundary already opens a brand-new segment on the dashboard
1183
+ // side (ccSegmentsApplyChunk), so the first post-tool push needs no
1184
+ // extra separator, and `trailingText` must track exactly what was
1185
+ // pushed so ctx.setText(...) on `result` reconciles cleanly
1186
+ // (W-mr3rdn9j000u6d5d).
1187
+ const pushed = _hadPriorTrailingMessage ? '\n\n' + content : content;
1160
1188
  terminalText = _hadPriorAssistantMessage ? terminalText + '\n\n' + content : content;
1189
+ trailingText = _hadPriorTrailingMessage ? trailingText + '\n\n' + content : content;
1161
1190
  ctx.pushText(pushed);
1162
1191
  _hadPriorAssistantMessage = true;
1192
+ _hadPriorTrailingMessage = true;
1163
1193
  }
1164
1194
  copilotMessageBuffer = '';
1165
1195
  }
1166
1196
  if (Array.isArray(data.toolRequests)) {
1197
+ let sawRealTool = false;
1167
1198
  for (const tr of data.toolRequests) {
1168
1199
  if (!tr || !tr.name) continue;
1169
1200
  if (tr.name === 'task_complete') {
@@ -1171,7 +1202,12 @@ function createStreamConsumer(ctx) {
1171
1202
  continue;
1172
1203
  }
1173
1204
  ctx.pushToolUse(tr.name, tr.arguments || {});
1205
+ sawRealTool = true;
1174
1206
  }
1207
+ // A real (non-task_complete) tool call closes the trailing segment —
1208
+ // the NEXT non-tool assistant.message starts a fresh segment on the
1209
+ // dashboard side, so its finalize-time scope must reset here too.
1210
+ if (sawRealTool) _resetTrailingSegment();
1175
1211
  }
1176
1212
  return;
1177
1213
  }
@@ -1188,6 +1224,11 @@ function createStreamConsumer(ctx) {
1188
1224
  if (!ctx.toolUseAlreadySeen(name, input)) {
1189
1225
  ctx.pushToolUse(name, input);
1190
1226
  }
1227
+ // Same trailing-segment boundary reset as the toolRequests branch above
1228
+ // — `tool.execution_start` is the standalone event shape observed in
1229
+ // the primary repro (assistant.message → tool.execution_start →
1230
+ // assistant.message → result).
1231
+ _resetTrailingSegment();
1191
1232
  }
1192
1233
  }
1193
1234
 
@@ -1196,6 +1237,7 @@ function createStreamConsumer(ctx) {
1196
1237
  terminalText = '';
1197
1238
  taskCompleteSummary = '';
1198
1239
  _hadPriorAssistantMessage = false;
1240
+ _resetTrailingSegment();
1199
1241
  }
1200
1242
 
1201
1243
  return { consume, reset };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2318",
3
+ "version": "0.1.2320",
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"