@yemi33/minions 0.1.1598 → 0.1.1600
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 +5 -1
- package/dashboard/js/command-center.js +17 -1
- package/dashboard/js/refresh.js +18 -0
- package/dashboard/layout.html +1 -1
- package/dashboard/pages/home.html +1 -1
- package/dashboard.js +2 -1
- package/engine/llm.js +20 -8
- package/engine/runtimes/copilot.js +16 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.1600 (2026-04-28)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
- match runtime tags to actual logos (pixel-crab Claude, mascot Copilot)
|
|
7
7
|
- replace runtime text tag with inline SVG logos
|
|
8
8
|
|
|
9
9
|
### Fixes
|
|
10
|
+
- keep cc stream final text complete
|
|
10
11
|
- switch Copilot icon to outline style for cleaner inline read
|
|
11
12
|
- un-invert Copilot — purple silhouette + white cutouts
|
|
12
13
|
- redraw Copilot icon to match actual mascot — vertical eye pills, not grill bars
|
|
13
14
|
- invert Copilot icon colors for better dark-theme visibility
|
|
14
15
|
|
|
16
|
+
### Other
|
|
17
|
+
- Stream CC chunks incrementally
|
|
18
|
+
|
|
15
19
|
## 0.1.1592 (2026-04-28)
|
|
16
20
|
|
|
17
21
|
### Features
|
|
@@ -54,6 +54,22 @@ function _ccActiveTab() {
|
|
|
54
54
|
return _ccTabs.find(function(t) { return t.id === _ccActiveTabId; }) || null;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function _ccMergeStreamText(prev, incoming) {
|
|
58
|
+
var current = prev || '';
|
|
59
|
+
var next = incoming || '';
|
|
60
|
+
if (!current) return next;
|
|
61
|
+
if (!next) return current;
|
|
62
|
+
if (next === current) return current;
|
|
63
|
+
if (next.startsWith(current)) return next;
|
|
64
|
+
if (current.startsWith(next)) return current;
|
|
65
|
+
for (var overlap = Math.min(current.length, next.length); overlap > 0; overlap--) {
|
|
66
|
+
if (current.slice(-overlap) === next.slice(0, overlap)) {
|
|
67
|
+
return current + next.slice(overlap);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return current + '\n\n' + next;
|
|
71
|
+
}
|
|
72
|
+
|
|
57
73
|
async function _ccDashboardHealth() {
|
|
58
74
|
var controller = new AbortController();
|
|
59
75
|
var timer = setTimeout(function() { controller.abort(); }, 3000);
|
|
@@ -580,7 +596,7 @@ async function _ccDoSend(message, skipUserMsg, forceTabId) {
|
|
|
580
596
|
|
|
581
597
|
async function _handleEvent(evt) {
|
|
582
598
|
if (evt.type === 'chunk') {
|
|
583
|
-
streamedText = evt.text;
|
|
599
|
+
streamedText = _ccMergeStreamText(streamedText, evt.text || '');
|
|
584
600
|
if (activeTab) activeTab._streamedText = streamedText;
|
|
585
601
|
updateStreamDiv();
|
|
586
602
|
} else if (evt.type === 'heartbeat') {
|
package/dashboard/js/refresh.js
CHANGED
|
@@ -35,6 +35,20 @@ function _changed(key, value) {
|
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function _formatCcPowerLabel(autoMode) {
|
|
39
|
+
var runtime = autoMode && autoMode.ccCli ? String(autoMode.ccCli) : 'claude';
|
|
40
|
+
var runtimeLabel = runtime.charAt(0).toUpperCase() + runtime.slice(1);
|
|
41
|
+
var model = autoMode && autoMode.ccModel ? String(autoMode.ccModel) : '';
|
|
42
|
+
return 'Ask anything, dispatch work, manage plans — powered by ' + runtimeLabel + (model ? ' (' + model + ')' : '');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function _formatCcDrawerLabel(autoMode) {
|
|
46
|
+
var runtime = autoMode && autoMode.ccCli ? String(autoMode.ccCli) : 'claude';
|
|
47
|
+
var runtimeLabel = runtime.charAt(0).toUpperCase() + runtime.slice(1);
|
|
48
|
+
var model = autoMode && autoMode.ccModel ? String(autoMode.ccModel) : '';
|
|
49
|
+
return runtimeLabel + (model ? ' (' + model + ')' : '') + '-powered. Full minions context. Enter to send, Shift+Enter for newline.';
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
function _processStatusUpdate(data) {
|
|
39
53
|
// Detect fresh install — clear stale browser state if install ID changed
|
|
40
54
|
if (data.installId) {
|
|
@@ -53,6 +67,10 @@ function _processStatusUpdate(data) {
|
|
|
53
67
|
if (autoEl) autoEl.innerHTML = data.autoMode?.approvePlans
|
|
54
68
|
? '<span style="font-size:9px;font-weight:600;padding:1px 6px;border-radius:3px;background:rgba(63,185,80,0.15);color:var(--green);border:1px solid rgba(63,185,80,0.3)">AUTO-APPROVE</span>'
|
|
55
69
|
: '';
|
|
70
|
+
const ccLabelEl = document.getElementById('cmd-powered-by');
|
|
71
|
+
if (ccLabelEl) ccLabelEl.textContent = _formatCcPowerLabel(data.autoMode);
|
|
72
|
+
const ccDrawerLabelEl = document.getElementById('cc-powered-by');
|
|
73
|
+
if (ccDrawerLabelEl) ccDrawerLabelEl.textContent = _formatCcDrawerLabel(data.autoMode);
|
|
56
74
|
const threshEl = document.getElementById('inbox-threshold');
|
|
57
75
|
if (threshEl && data.autoMode?.inboxThreshold) threshEl.textContent = data.autoMode.inboxThreshold;
|
|
58
76
|
|
package/dashboard/layout.html
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<textarea id="cc-input" rows="2" placeholder="Ask anything or give a command..." style="flex:1;padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:12px;resize:none;font-family:inherit" onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();ccSend()}"></textarea>
|
|
44
44
|
<button onclick="ccSend()" style="background:var(--blue);color:#fff;border:none;border-radius:6px;padding:8px 14px;font-size:12px;font-weight:600;cursor:pointer;align-self:flex-end">Send</button>
|
|
45
45
|
</div>
|
|
46
|
-
<div style="font-size:9px;color:var(--muted);margin-top:4px">
|
|
46
|
+
<div id="cc-powered-by" style="font-size:9px;color:var(--muted);margin-top:4px">Full minions context. Enter to send, Shift+Enter for newline.</div>
|
|
47
47
|
</div>
|
|
48
48
|
</div>
|
|
49
49
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<div class="cmd-meta" id="cmd-meta" style="display:none"></div>
|
|
11
11
|
<div class="cmd-hints">
|
|
12
12
|
<span style="color:var(--blue);font-weight:600">Command Center</span>
|
|
13
|
-
<span>Ask anything, dispatch work, manage plans
|
|
13
|
+
<span id="cmd-powered-by">Ask anything, dispatch work, manage plans</span>
|
|
14
14
|
<button class="cmd-history-btn" onclick="cmdShowHistory()">Past Commands</button>
|
|
15
15
|
<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green);border-color:var(--green)" onclick="openQuickNoteModal()">+ Note</button>
|
|
16
16
|
</div>
|
package/dashboard.js
CHANGED
|
@@ -474,7 +474,8 @@ function getStatus() {
|
|
|
474
474
|
decompose: CONFIG.engine?.autoDecompose !== false,
|
|
475
475
|
tempAgents: !!CONFIG.engine?.allowTempAgents,
|
|
476
476
|
inboxThreshold: CONFIG.engine?.inboxConsolidateThreshold || shared.ENGINE_DEFAULTS.inboxConsolidateThreshold,
|
|
477
|
-
|
|
477
|
+
ccCli: shared.resolveCcCli(CONFIG.engine),
|
|
478
|
+
ccModel: shared.resolveCcModel(CONFIG.engine),
|
|
478
479
|
ccEffort: CONFIG.engine?.ccEffort || shared.ENGINE_DEFAULTS.ccEffort,
|
|
479
480
|
},
|
|
480
481
|
initialized: !!(CONFIG.agents && Object.keys(CONFIG.agents).length > 0),
|
package/engine/llm.js
CHANGED
|
@@ -270,11 +270,20 @@ function _createStreamAccumulator({
|
|
|
270
270
|
const toolUses = [];
|
|
271
271
|
|
|
272
272
|
// Copilot streams `assistant.message_delta` with `data.deltaContent` chunks
|
|
273
|
-
// before emitting
|
|
274
|
-
//
|
|
275
|
-
//
|
|
273
|
+
// before emitting `assistant.message`. Tool-request messages can include
|
|
274
|
+
// narration ("I'll inspect...") that is only progress text, so terminal text
|
|
275
|
+
// comes from non-tool assistant messages or trailing deltas.
|
|
276
276
|
let copilotMessageBuffer = '';
|
|
277
277
|
|
|
278
|
+
function _streamText(value) {
|
|
279
|
+
return maxTextLength ? value.slice(-maxTextLength) : value;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function _copilotAssistantMessageHasTools(obj) {
|
|
283
|
+
const requests = obj?.data?.toolRequests;
|
|
284
|
+
return Array.isArray(requests) && requests.length > 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
278
287
|
function captureEvent(obj) {
|
|
279
288
|
if (!obj || typeof obj !== 'object') return;
|
|
280
289
|
|
|
@@ -322,12 +331,12 @@ function _createStreamAccumulator({
|
|
|
322
331
|
}
|
|
323
332
|
}
|
|
324
333
|
if (obj.type === 'assistant.message' && typeof obj.data?.content === 'string') {
|
|
325
|
-
//
|
|
334
|
+
// Tool-request narration ("I'll look into this...") is progress text, not
|
|
335
|
+
// the final answer. Keep streaming it live, but don't let it become the
|
|
336
|
+
// terminal result if the process exits before a final answer message.
|
|
326
337
|
const content = obj.data.content;
|
|
327
|
-
if (content)
|
|
328
|
-
|
|
329
|
-
copilotMessageBuffer = '';
|
|
330
|
-
}
|
|
338
|
+
if (content && !_copilotAssistantMessageHasTools(obj)) text = _streamText(content);
|
|
339
|
+
copilotMessageBuffer = '';
|
|
331
340
|
if (Array.isArray(obj.data.toolRequests)) {
|
|
332
341
|
for (const tr of obj.data.toolRequests) {
|
|
333
342
|
if (tr && tr.name) {
|
|
@@ -372,6 +381,9 @@ function _createStreamAccumulator({
|
|
|
372
381
|
const ev = runtime.parseStreamChunk(trimmed);
|
|
373
382
|
if (ev) captureEvent(ev);
|
|
374
383
|
}
|
|
384
|
+
if (copilotMessageBuffer) {
|
|
385
|
+
text = _streamText(copilotMessageBuffer);
|
|
386
|
+
}
|
|
375
387
|
// Reconciliation: if any field is still missing, ask the runtime adapter
|
|
376
388
|
// to re-parse the whole stdout. parseOutput() may catch a result event
|
|
377
389
|
// that was malformed when streamed in chunks.
|
|
@@ -300,8 +300,10 @@ const KNOWN_EVENT_TYPES = new Set([
|
|
|
300
300
|
* Returns { text, usage, sessionId, model } — same shape as the Claude adapter
|
|
301
301
|
* so engine/lifecycle.js can consume both transparently.
|
|
302
302
|
*
|
|
303
|
-
* - text: concatenation of
|
|
304
|
-
*
|
|
303
|
+
* - text: concatenation of answer `assistant.message.data.content`
|
|
304
|
+
* values, plus trailing deltas if the CLI exits before a final
|
|
305
|
+
* `assistant.message`. Narration attached to tool requests is
|
|
306
|
+
* progress text and is excluded from the final answer.
|
|
305
307
|
* - usage: mapped from the terminal `result` event. Copilot doesn't
|
|
306
308
|
* report cost/tokens — those fields are NULL, not 0, so the
|
|
307
309
|
* dashboard can distinguish "Copilot didn't tell us" from
|
|
@@ -322,6 +324,7 @@ function parseOutput(raw, { maxTextLength = 0 } = {}) {
|
|
|
322
324
|
let model = null;
|
|
323
325
|
let outputTokensTotal = 0;
|
|
324
326
|
let turnEndCount = 0;
|
|
327
|
+
let pendingDeltaContent = '';
|
|
325
328
|
|
|
326
329
|
for (const rawLine of safeRaw.split('\n')) {
|
|
327
330
|
const line = rawLine.trim();
|
|
@@ -331,9 +334,17 @@ function parseOutput(raw, { maxTextLength = 0 } = {}) {
|
|
|
331
334
|
if (!obj || typeof obj !== 'object') continue;
|
|
332
335
|
|
|
333
336
|
const type = obj.type;
|
|
334
|
-
if (type === 'assistant.
|
|
337
|
+
if (type === 'assistant.message_delta') {
|
|
338
|
+
const delta = obj.data?.deltaContent;
|
|
339
|
+
if (typeof delta === 'string') pendingDeltaContent += delta;
|
|
340
|
+
} else if (type === 'assistant.message') {
|
|
335
341
|
const content = obj.data?.content;
|
|
336
|
-
|
|
342
|
+
const toolRequests = obj.data?.toolRequests;
|
|
343
|
+
const hasToolRequests = Array.isArray(toolRequests) && toolRequests.length > 0;
|
|
344
|
+
if (typeof content === 'string') {
|
|
345
|
+
if (content && !hasToolRequests) messageContents.push(content);
|
|
346
|
+
pendingDeltaContent = '';
|
|
347
|
+
}
|
|
337
348
|
const ot = obj.data?.outputTokens;
|
|
338
349
|
if (typeof ot === 'number') outputTokensTotal += ot;
|
|
339
350
|
} else if (type === 'assistant.turn_end') {
|
|
@@ -366,7 +377,7 @@ function parseOutput(raw, { maxTextLength = 0 } = {}) {
|
|
|
366
377
|
}
|
|
367
378
|
}
|
|
368
379
|
|
|
369
|
-
let text = messageContents.join('');
|
|
380
|
+
let text = messageContents.join('') + pendingDeltaContent;
|
|
370
381
|
if (maxTextLength && text.length > maxTextLength) {
|
|
371
382
|
text = text.slice(-maxTextLength);
|
|
372
383
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1600",
|
|
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"
|