@yemi33/minions 0.1.757 → 0.1.759
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 +3 -1
- package/dashboard/js/command-center.js +21 -7
- package/dashboard.js +16 -31
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.759 (2026-04-09)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
- show branch strategy badge on PRD group header
|
|
7
7
|
|
|
8
8
|
### Fixes
|
|
9
|
+
- eliminate global ccSession corruption, clean up streaming state
|
|
10
|
+
- restore full streaming state (tools + partial text) on tab switch
|
|
9
11
|
- restored thinking UX matches original exactly (same bubble, layout)
|
|
10
12
|
- skip merged dependency branches instead of failing worktree setup
|
|
11
13
|
- restore same thinking UX when switching back to processing tab
|
|
@@ -135,28 +135,38 @@ function ccSwitchTab(id) {
|
|
|
135
135
|
for (var i = 0; i < tab.messages.length; i++) {
|
|
136
136
|
ccAddMessage(tab.messages[i].role, tab.messages[i].html, true);
|
|
137
137
|
}
|
|
138
|
-
// If this tab is still processing, restore the
|
|
138
|
+
// If this tab is still processing, restore the full streaming UX (tools, partial text, thinking)
|
|
139
139
|
if (tab._sending) {
|
|
140
140
|
var 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>';
|
|
141
141
|
var restoreStart = tab._sendStartedAt || Date.now();
|
|
142
142
|
var phases = [[0,'Thinking...'],[3000,'Reading minions context...'],[8000,'Analyzing...'],[15000,'Using tools to dig deeper...'],[30000,'Still working (multi-turn)...'],[60000,'Deep research in progress...']];
|
|
143
|
-
function
|
|
143
|
+
function _restoreStreamHtml() {
|
|
144
|
+
var html = '';
|
|
145
|
+
var tools = tab._toolsUsed || [];
|
|
146
|
+
if (tools.length > 0) {
|
|
147
|
+
html += '<div style="margin-bottom:6px">';
|
|
148
|
+
tools.forEach(function(t) { html += '<div style="color:var(--blue);font-size:11px">\uD83D\uDD27 ' + escHtml(t) + '</div>'; });
|
|
149
|
+
html += '</div>';
|
|
150
|
+
}
|
|
151
|
+
var text = tab._streamedText || '';
|
|
152
|
+
if (text) html += renderMd(text);
|
|
144
153
|
var ms = Date.now() - restoreStart;
|
|
145
154
|
var label = 'Thinking...';
|
|
146
155
|
for (var pi = phases.length - 1; pi >= 0; pi--) { if (ms >= phases[pi][0]) { label = phases[pi][1]; break; } }
|
|
147
156
|
var secs = Math.floor(ms / 1000);
|
|
148
|
-
|
|
157
|
+
html += '<div style="margin-top:' + (text ? '6px' : '0') + ';display:flex;align-items:center;gap:6px"><span style="color:var(--muted);font-size:11px">' + label + '</span>' + dotPulse + '<span style="margin-left:auto;font-size:10px;color:var(--muted)">' + secs + 's</span>' +
|
|
149
158
|
'<button onclick="ccAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer;margin-left:4px">Stop</button></div>';
|
|
159
|
+
return html;
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
ccAddMessage('assistant', _restoreThinkingHtml(), true);
|
|
161
|
+
ccAddMessage('assistant', _restoreStreamHtml(), true);
|
|
153
162
|
var restoreDiv = el.lastElementChild;
|
|
154
163
|
restoreDiv.id = 'cc-restore-thinking';
|
|
155
164
|
el.scrollTop = el.scrollHeight;
|
|
156
165
|
var restoreInterval = setInterval(function() {
|
|
157
166
|
var re = document.getElementById('cc-restore-thinking');
|
|
158
167
|
if (!re || !tab._sending) { clearInterval(restoreInterval); if (re) re.remove(); return; }
|
|
159
|
-
re.innerHTML = (
|
|
168
|
+
re.innerHTML = _restoreStreamHtml();
|
|
169
|
+
if (el.scrollHeight - el.scrollTop - el.clientHeight < 150) el.scrollTop = el.scrollHeight;
|
|
160
170
|
}, 1000);
|
|
161
171
|
}
|
|
162
172
|
ccRenderTabBar();
|
|
@@ -448,8 +458,10 @@ async function _ccDoSend(message, skipUserMsg) {
|
|
|
448
458
|
];
|
|
449
459
|
|
|
450
460
|
// Streaming state — declared before try so updateStreamDiv works during fetch
|
|
461
|
+
// Also saved on tab for restore when switching back
|
|
451
462
|
var streamedText = '';
|
|
452
463
|
var toolsUsed = [];
|
|
464
|
+
if (activeTab) { activeTab._streamedText = ''; activeTab._toolsUsed = []; }
|
|
453
465
|
|
|
454
466
|
// Get active tab's sessionId to send with request
|
|
455
467
|
var activeTab = _ccActiveTab();
|
|
@@ -526,9 +538,11 @@ async function _ccDoSend(message, skipUserMsg) {
|
|
|
526
538
|
var evt = JSON.parse(line.slice(6));
|
|
527
539
|
if (evt.type === 'chunk') {
|
|
528
540
|
streamedText = evt.text;
|
|
541
|
+
if (activeTab) activeTab._streamedText = streamedText;
|
|
529
542
|
updateStreamDiv();
|
|
530
543
|
} else if (evt.type === 'tool') {
|
|
531
544
|
toolsUsed.push(evt.name);
|
|
545
|
+
if (activeTab) activeTab._toolsUsed = toolsUsed.slice();
|
|
532
546
|
updateStreamDiv();
|
|
533
547
|
if (msgs.scrollHeight - msgs.scrollTop - msgs.clientHeight < 150) msgs.scrollTop = msgs.scrollHeight;
|
|
534
548
|
} else if (evt.type === 'done') {
|
|
@@ -611,7 +625,7 @@ async function _ccDoSend(message, skipUserMsg) {
|
|
|
611
625
|
' <button onclick="ccNewTab()" style="margin-top:6px;padding:4px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--muted);cursor:pointer;font-size:11px">New Session</button>');
|
|
612
626
|
}
|
|
613
627
|
} finally {
|
|
614
|
-
if (activeTab) { activeTab._sending = false; activeTab._abortController = null; }
|
|
628
|
+
if (activeTab) { activeTab._sending = false; activeTab._abortController = null; delete activeTab._streamedText; delete activeTab._toolsUsed; delete activeTab._sendStartedAt; }
|
|
615
629
|
_ccSending = (_ccTabs.some(function(t) { return t._sending; }));
|
|
616
630
|
try { clearInterval(phaseTimer); } catch { /* may not be defined if error before reader */ }
|
|
617
631
|
try { localStorage.removeItem('cc-sending'); } catch {}
|
package/dashboard.js
CHANGED
|
@@ -3329,16 +3329,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3329
3329
|
req.on('close', () => { ccInFlightTabs.delete(tabId); if (_ccStreamAbort) _ccStreamAbort(); });
|
|
3330
3330
|
|
|
3331
3331
|
try {
|
|
3332
|
-
// Session management — per-tab: use sessionId from request
|
|
3332
|
+
// Session management — per-tab: use sessionId from request, don't mutate global ccSession
|
|
3333
3333
|
const tabSessionId = body.sessionId || null;
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
ccSession = { sessionId: tabSessionId, createdAt: ccSession.createdAt, lastActiveAt: Date.now(), turnCount: ccSession.turnCount || 0, _promptHash: _ccPromptHash };
|
|
3337
|
-
} else if (!ccSessionValid()) {
|
|
3338
|
-
ccSession = { sessionId: null, createdAt: null, lastActiveAt: null, turnCount: 0 };
|
|
3339
|
-
}
|
|
3340
|
-
const wasResume = !!tabSessionId || !!(ccSessionValid() && ccSession.sessionId);
|
|
3341
|
-
const sessionId = tabSessionId || (wasResume ? ccSession.sessionId : null);
|
|
3334
|
+
const wasResume = !!tabSessionId;
|
|
3335
|
+
const sessionId = tabSessionId || null;
|
|
3342
3336
|
const preamble = wasResume ? '' : buildCCStatePreamble();
|
|
3343
3337
|
const prompt = (preamble ? preamble + '\n\n---\n\n' : '') + body.message;
|
|
3344
3338
|
|
|
@@ -3367,42 +3361,33 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3367
3361
|
const stderrTail = (result.stderr || '').trim().split('\n').filter(Boolean).slice(-3).join(' | ');
|
|
3368
3362
|
console.error(`[CC-stream] Failed: code=${result.code}, stderr=${(result.stderr || '').slice(0, 500)}, stdout_tail=${(result.raw || '').slice(-500)}`);
|
|
3369
3363
|
// If resuming a session failed, auto-reset so next attempt starts fresh
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
}
|
|
3376
|
-
retryHint = ccSession.sessionId
|
|
3377
|
-
? 'Your session is still active — just send your message again to retry.'
|
|
3378
|
-
: 'Try clicking **New Session** and sending your message again.';
|
|
3379
|
-
}
|
|
3380
|
-
res.write('data: ' + JSON.stringify({ type: 'done', text: `I had trouble processing that ${debugInfo}. ${stderrTail ? 'Detail: ' + stderrTail : ''}\n\n${retryHint}`, actions: [], sessionId: ccSession.sessionId }) + '\n\n');
|
|
3364
|
+
const retryHint = wasResume && result.code !== 0
|
|
3365
|
+
? 'Session was reset — send your message again to start fresh.'
|
|
3366
|
+
: 'Send your message again to retry.';
|
|
3367
|
+
// Return null sessionId on resume failure so client clears the stale session
|
|
3368
|
+
const errorSessionId = (wasResume && result.code !== 0) ? null : tabSessionId;
|
|
3369
|
+
res.write('data: ' + JSON.stringify({ type: 'done', text: `I had trouble processing that ${debugInfo}. ${stderrTail ? 'Detail: ' + stderrTail : ''}\n\n${retryHint}`, actions: [], sessionId: errorSessionId }) + '\n\n');
|
|
3381
3370
|
res.end();
|
|
3382
3371
|
return;
|
|
3383
3372
|
}
|
|
3384
3373
|
|
|
3385
3374
|
// Update session
|
|
3375
|
+
// Persist tab→session mapping (no global ccSession mutation)
|
|
3386
3376
|
const now = Date.now();
|
|
3387
|
-
|
|
3388
|
-
ccSession = { sessionId: result.sessionId, createdAt: ccSession.createdAt || now, lastActiveAt: now, turnCount: (ccSession.turnCount || 0) + 1, _promptHash: _ccPromptHash };
|
|
3389
|
-
safeWrite(path.join(ENGINE_DIR, 'cc-session.json'), ccSession);
|
|
3390
|
-
}
|
|
3391
|
-
|
|
3392
|
-
// Persist tab→session mapping if tabId provided
|
|
3377
|
+
const responseSessionId = result.sessionId || tabSessionId;
|
|
3393
3378
|
const tabId = body.tabId;
|
|
3394
|
-
if (tabId &&
|
|
3379
|
+
if (tabId && responseSessionId) {
|
|
3395
3380
|
try {
|
|
3396
3381
|
const sessions = shared.safeJsonArr(CC_SESSIONS_PATH);
|
|
3397
3382
|
const existing = sessions.find(s => s.id === tabId);
|
|
3398
3383
|
const preview = (body.message || '').slice(0, 80);
|
|
3399
3384
|
if (existing) {
|
|
3400
|
-
existing.sessionId =
|
|
3385
|
+
existing.sessionId = responseSessionId;
|
|
3401
3386
|
existing.lastActiveAt = new Date(now).toISOString();
|
|
3402
|
-
existing.turnCount =
|
|
3387
|
+
existing.turnCount = (existing.turnCount || 0) + 1;
|
|
3403
3388
|
existing.preview = preview;
|
|
3404
3389
|
} else {
|
|
3405
|
-
sessions.push({ id: tabId, title: (body.message || 'New chat').slice(0, 40), sessionId:
|
|
3390
|
+
sessions.push({ id: tabId, title: (body.message || 'New chat').slice(0, 40), sessionId: responseSessionId, createdAt: new Date(now).toISOString(), lastActiveAt: new Date(now).toISOString(), turnCount: 1, preview });
|
|
3406
3391
|
}
|
|
3407
3392
|
safeWrite(CC_SESSIONS_PATH, sessions);
|
|
3408
3393
|
} catch { /* non-critical */ }
|
|
@@ -3410,7 +3395,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
3410
3395
|
|
|
3411
3396
|
// Send final result with actions
|
|
3412
3397
|
const { text: displayText, actions } = parseCCActions(result.text);
|
|
3413
|
-
res.write('data: ' + JSON.stringify({ type: 'done', text: displayText, actions, sessionId:
|
|
3398
|
+
res.write('data: ' + JSON.stringify({ type: 'done', text: displayText, actions, sessionId: responseSessionId, newSession: !wasResume }) + '\n\n');
|
|
3414
3399
|
res.end();
|
|
3415
3400
|
} finally {
|
|
3416
3401
|
ccInFlightTabs.delete(tabId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.759",
|
|
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"
|