@yemi33/minions 0.1.279 → 0.1.280

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,6 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.279 (2026-04-03)
3
+ ## 0.1.280 (2026-04-03)
4
+
5
+ ### Features
6
+ - thinking indicator shows progressive phases with elapsed timer
4
7
 
5
8
  ### Fixes
6
9
  - doc chat elapsed time no longer overlaps copy button
@@ -215,6 +215,15 @@ async function _ccDoSend(message, skipUserMsg) {
215
215
  let streamedText = '';
216
216
  let toolsUsed = [];
217
217
  const dotPulse = '<span style="display:inline-flex;gap:3px;margin-left:6px;vertical-align:middle"><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.2s"></span><span style="width:4px;height:4px;background:var(--blue);border-radius:50%;animation:dotPulse 1.2s infinite;animation-delay:0.4s"></span></span>';
218
+ function _getThinkingPhase() {
219
+ var elapsed = Date.now() - ccStartTime;
220
+ var label = 'Thinking...';
221
+ for (var pi = phases.length - 1; pi >= 0; pi--) {
222
+ if (elapsed >= phases[pi][0]) { label = phases[pi][1]; break; }
223
+ }
224
+ var secs = Math.floor(elapsed / 1000);
225
+ return label + ' <span style="font-size:9px;color:var(--border)">' + secs + 's</span>';
226
+ }
218
227
  function updateStreamDiv() {
219
228
  var html = '';
220
229
  if (toolsUsed.length > 0) {
@@ -227,13 +236,16 @@ async function _ccDoSend(message, skipUserMsg) {
227
236
  if (streamedText) {
228
237
  html += renderMd(streamedText);
229
238
  }
230
- html += '<div style="margin-top:' + (streamedText ? '6px' : '0') + '"><span style="color:var(--muted);font-size:11px">Thinking...' + dotPulse + '</span></div>';
239
+ html += '<div style="margin-top:' + (streamedText ? '6px' : '0') + '"><span style="color:var(--muted);font-size:11px">' + _getThinkingPhase() + dotPulse + '</span></div>';
231
240
  streamDiv.innerHTML = html;
232
241
  // Re-append queue indicators so they stay below the streaming content
233
242
  if (_ccQueue.length > 0) _renderQueueIndicator();
234
243
  if (msgs.scrollHeight - msgs.scrollTop - msgs.clientHeight < 150) msgs.scrollTop = msgs.scrollHeight;
235
244
  }
236
245
 
246
+ // Periodically update thinking phase text + timer
247
+ const phaseTimer = setInterval(updateStreamDiv, 1000);
248
+
237
249
  const reader = res.body.getReader();
238
250
  const decoder = new TextDecoder();
239
251
  let buf = '';
@@ -257,7 +269,7 @@ async function _ccDoSend(message, skipUserMsg) {
257
269
  if (msgs.scrollHeight - msgs.scrollTop - msgs.clientHeight < 150) msgs.scrollTop = msgs.scrollHeight;
258
270
  } else if (evt.type === 'done') {
259
271
  // Replace streaming div with a proper ccAddMessage
260
- streamDiv.remove();
272
+ clearInterval(phaseTimer); streamDiv.remove();
261
273
  // placeholder was added with skipSave=true — nothing to pop
262
274
  const ccElapsed = Math.round((Date.now() - ccStartTime) / 1000);
263
275
  const rendered = renderMd(evt.text || streamedText || '');
@@ -267,7 +279,7 @@ async function _ccDoSend(message, skipUserMsg) {
267
279
  for (const action of evt.actions) { await ccExecuteAction(action); }
268
280
  }
269
281
  } else if (evt.type === 'error') {
270
- streamDiv.remove();
282
+ clearInterval(phaseTimer); streamDiv.remove();
271
283
  // placeholder was skipSave — no pop needed
272
284
  ccAddMessage('assistant', '<span style="color:var(--red)">' + escHtml(evt.error) + '</span>');
273
285
  }
@@ -281,7 +293,7 @@ async function _ccDoSend(message, skipUserMsg) {
281
293
  try {
282
294
  const evt = JSON.parse(line.slice(6));
283
295
  if (evt.type === 'done') {
284
- streamDiv.remove();
296
+ clearInterval(phaseTimer); streamDiv.remove();
285
297
  // placeholder was skipSave — no pop needed
286
298
  const ccElapsed = Math.round((Date.now() - ccStartTime) / 1000);
287
299
  const rendered = renderMd(evt.text || streamedText || '');
@@ -299,7 +311,7 @@ async function _ccDoSend(message, skipUserMsg) {
299
311
  }
300
312
  // If stream ended without a 'done' event, finalize with whatever we have
301
313
  if (streamDiv.parentNode) {
302
- streamDiv.remove();
314
+ clearInterval(phaseTimer); streamDiv.remove();
303
315
  if (streamedText) {
304
316
  const ccElapsed = Math.round((Date.now() - ccStartTime) / 1000);
305
317
  ccAddMessage('assistant', renderMd(streamedText) + '<div style="font-size:9px;color:var(--muted);margin-top:6px;display:flex;justify-content:flex-end;padding-right:30px">' + ccElapsed + 's</div>');
@@ -314,6 +326,7 @@ async function _ccDoSend(message, skipUserMsg) {
314
326
  } finally {
315
327
  _ccSending = false;
316
328
  _ccAbortController = null;
329
+ try { clearInterval(phaseTimer); } catch { /* may not be defined if error before reader */ }
317
330
  try { localStorage.removeItem('cc-sending'); } catch {}
318
331
  // Show notification badge on CC button if drawer is closed
319
332
  if (!_ccOpen) showNotifBadge(document.getElementById('cc-toggle-btn'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.279",
3
+ "version": "0.1.280",
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"