@yemi33/minions 0.1.75 → 0.1.76
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 +13 -0
- package/dashboard/js/live-stream.js +38 -34
- package/dashboard/js/render-plans.js +7 -2
- package/dashboard/js/render-prd.js +6 -1
- package/engine/lifecycle.js +1 -1
- package/engine/meeting.js +26 -1
- package/engine/shared.js +36 -20
- package/engine/timeout.js +2 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.76 (2026-03-31)
|
|
4
|
+
|
|
5
|
+
### Engine
|
|
6
|
+
- engine/lifecycle.js
|
|
7
|
+
- engine/meeting.js
|
|
8
|
+
- engine/shared.js
|
|
9
|
+
- engine/timeout.js
|
|
10
|
+
|
|
11
|
+
### Dashboard
|
|
12
|
+
- dashboard/js/live-stream.js
|
|
13
|
+
- dashboard/js/render-plans.js
|
|
14
|
+
- dashboard/js/render-prd.js
|
|
15
|
+
|
|
3
16
|
## 0.1.75 (2026-03-31)
|
|
4
17
|
|
|
5
18
|
### Dashboard
|
|
@@ -7,10 +7,38 @@ function renderLiveChatMessage(raw) {
|
|
|
7
7
|
const el = document.getElementById('live-messages');
|
|
8
8
|
if (!el) return;
|
|
9
9
|
|
|
10
|
+
function renderJsonObj(obj) {
|
|
11
|
+
if (obj.type === 'assistant' && obj.message?.content) {
|
|
12
|
+
for (const block of obj.message.content) {
|
|
13
|
+
if (block.type === 'thinking') {
|
|
14
|
+
el.innerHTML += '<div style="font-size:10px;color:var(--muted);padding:2px 8px;font-style:italic">\u{1F4AD} Thinking...</div>';
|
|
15
|
+
}
|
|
16
|
+
if (block.type === 'text' && block.text) {
|
|
17
|
+
el.innerHTML += '<div style="background:var(--surface2);padding:8px 12px;border-radius:12px 12px 12px 2px;max-width:90%;margin:4px 0;font-size:12px;white-space:pre-wrap;word-break:break-word">' + escHtml(block.text) + '</div>';
|
|
18
|
+
}
|
|
19
|
+
if (block.type === 'tool_use') {
|
|
20
|
+
el.innerHTML += '<div style="background:var(--surface);border:1px solid var(--border);padding:4px 8px;border-radius:4px;margin:2px 0;font-size:10px;color:var(--muted);cursor:pointer" onclick="this.nextElementSibling.style.display=this.nextElementSibling.style.display===\'none\'?\'block\':\'none\'">' +
|
|
21
|
+
'\u{1F527} ' + escHtml(block.name || 'tool') + '</div>' +
|
|
22
|
+
'<div style="display:none;background:var(--bg);padding:4px 8px;border-radius:4px;margin:0 0 4px;font-size:10px;font-family:monospace;white-space:pre-wrap;max-height:200px;overflow-y:auto;color:var(--muted)">' + escHtml(JSON.stringify(block.input, null, 2).slice(0, 500)) + '</div>';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (obj.type === 'tool_result' || (obj.type === 'user' && obj.message?.content?.[0]?.type === 'tool_result')) {
|
|
27
|
+
const content = obj.message?.content?.[0]?.content || obj.content || '';
|
|
28
|
+
const text = typeof content === 'string' ? content : JSON.stringify(content);
|
|
29
|
+
if (text.length > 10) {
|
|
30
|
+
el.innerHTML += '<div style="background:var(--bg);border-left:2px solid var(--border);padding:2px 8px;margin:0 0 2px 16px;font-size:9px;font-family:monospace;color:var(--muted);max-height:100px;overflow-y:auto;white-space:pre-wrap;cursor:pointer" onclick="this.style.maxHeight=this.style.maxHeight===\'100px\'?\'none\':\'100px\'">' + escHtml(text.slice(0, 1000)) + (text.length > 1000 ? '...' : '') + '</div>';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (obj.type === 'result') {
|
|
34
|
+
el.innerHTML += '<div style="background:rgba(63,185,80,0.1);border:1px solid var(--green);padding:8px 12px;border-radius:8px;margin:8px 0;font-size:12px;color:var(--green)">\u2713 Task complete</div>';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
10
38
|
const lines = raw.split('\n');
|
|
11
39
|
for (const line of lines) {
|
|
12
40
|
const trimmed = line.trim();
|
|
13
|
-
if (!trimmed) continue;
|
|
41
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
14
42
|
|
|
15
43
|
// Human steering messages
|
|
16
44
|
if (trimmed.startsWith('[human-steering]')) {
|
|
@@ -24,41 +52,17 @@ function renderLiveChatMessage(raw) {
|
|
|
24
52
|
continue;
|
|
25
53
|
}
|
|
26
54
|
|
|
27
|
-
//
|
|
28
|
-
if (trimmed.startsWith('
|
|
55
|
+
// JSON array format (--output-format json)
|
|
56
|
+
if (trimmed.startsWith('[')) {
|
|
29
57
|
try {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
for (const block of obj.message.content) {
|
|
35
|
-
if (block.type === 'text' && block.text) {
|
|
36
|
-
el.innerHTML += '<div style="background:var(--surface2);padding:8px 12px;border-radius:12px 12px 12px 2px;max-width:90%;margin:4px 0;font-size:12px;white-space:pre-wrap;word-break:break-word">' + escHtml(block.text) + '</div>';
|
|
37
|
-
}
|
|
38
|
-
if (block.type === 'tool_use') {
|
|
39
|
-
el.innerHTML += '<div style="background:var(--surface);border:1px solid var(--border);padding:4px 8px;border-radius:4px;margin:2px 0;font-size:10px;color:var(--muted);cursor:pointer" onclick="this.nextElementSibling.style.display=this.nextElementSibling.style.display===\'none\'?\'block\':\'none\'">' +
|
|
40
|
-
'🔧 ' + escHtml(block.name || 'tool') + '</div>' +
|
|
41
|
-
'<div style="display:none;background:var(--bg);padding:4px 8px;border-radius:4px;margin:0 0 4px;font-size:10px;font-family:monospace;white-space:pre-wrap;max-height:200px;overflow-y:auto;color:var(--muted)">' + escHtml(JSON.stringify(block.input, null, 2).slice(0, 500)) + '</div>';
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Tool result
|
|
47
|
-
if (obj.type === 'tool_result' || (obj.type === 'user' && obj.message?.content?.[0]?.type === 'tool_result')) {
|
|
48
|
-
const content = obj.message?.content?.[0]?.content || obj.content || '';
|
|
49
|
-
const text = typeof content === 'string' ? content : JSON.stringify(content);
|
|
50
|
-
if (text.length > 10) {
|
|
51
|
-
el.innerHTML += '<div style="background:var(--bg);border-left:2px solid var(--border);padding:2px 8px;margin:0 0 2px 16px;font-size:9px;font-family:monospace;color:var(--muted);max-height:100px;overflow-y:auto;white-space:pre-wrap;cursor:pointer" onclick="this.style.maxHeight=this.style.maxHeight===\'100px\'?\'none\':\'100px\'">' + escHtml(text.slice(0, 1000)) + (text.length > 1000 ? '...' : '') + '</div>';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Result (final)
|
|
56
|
-
if (obj.type === 'result') {
|
|
57
|
-
el.innerHTML += '<div style="background:rgba(63,185,80,0.1);border:1px solid var(--green);padding:8px 12px;border-radius:8px;margin:8px 0;font-size:12px;color:var(--green)">✓ Task complete</div>';
|
|
58
|
-
}
|
|
58
|
+
const arr = JSON.parse(trimmed);
|
|
59
|
+
if (Array.isArray(arr)) { for (const obj of arr) renderJsonObj(obj); continue; }
|
|
60
|
+
} catch { /* fall through to raw text */ }
|
|
61
|
+
}
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
// Single JSON object (--output-format stream-json)
|
|
64
|
+
if (trimmed.startsWith('{')) {
|
|
65
|
+
try { renderJsonObj(JSON.parse(trimmed)); continue; } catch { /* fall through */ }
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
// Fallback: raw text (stderr, non-JSON lines)
|
|
@@ -213,12 +213,15 @@ function renderPlans(plans) {
|
|
|
213
213
|
'onclick="event.stopPropagation();planExecute(\'' + escHtml(p.file) + '\',\'' + escHtml(p.project) + '\',this)">Execute</button>' : '';
|
|
214
214
|
const showPause = effectiveStatus === 'in-progress' && prdFile && !isArchived;
|
|
215
215
|
const showResume = (effectiveStatus === 'paused' || effectiveStatus === 'awaiting-approval') && prdFile && !isArchived;
|
|
216
|
+
const showVerify = effectiveStatus === 'completed' && prdFile && !isArchived;
|
|
216
217
|
const pauseBtn = showPause ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--yellow)" ' +
|
|
217
218
|
'onclick="event.stopPropagation();planPause(\'' + escHtml(prdFile) + '\')">Pause</button>' : '';
|
|
218
219
|
const resumeBtn = showResume
|
|
219
220
|
? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green)" ' +
|
|
220
221
|
'onclick="event.stopPropagation();planApprove(\'' + escHtml(prdFile) + '\')">' + (effectiveStatus === 'awaiting-approval' ? 'Approve' : 'Resume') + '</button>'
|
|
221
222
|
: '';
|
|
223
|
+
const verifyBtn = showVerify ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--green)" ' +
|
|
224
|
+
'onclick="event.stopPropagation();triggerVerify(\'' + escHtml(prdFile) + '\')">Verify</button>' : '';
|
|
222
225
|
const deleteBtn = !isArchived ? '<button class="pr-pager-btn" style="font-size:9px;padding:2px 8px;color:var(--red)" ' +
|
|
223
226
|
'onclick="event.stopPropagation();planDelete(\'' + escHtml(p.file) + '\')">Delete</button>' : '';
|
|
224
227
|
|
|
@@ -235,7 +238,7 @@ function renderPlans(plans) {
|
|
|
235
238
|
(p.updatedAt ? '<span title="Last updated: ' + p.updatedAt + '">Updated ' + timeAgo(p.updatedAt) + '</span>' : '') +
|
|
236
239
|
(p.completedAt ? '<span>' + p.completedAt.slice(0, 10) + '</span>' : '') +
|
|
237
240
|
(p.generatedBy ? '<span>by ' + escHtml(p.generatedBy) + '</span>' : '') +
|
|
238
|
-
executeBtn + pauseBtn + resumeBtn + deleteBtn +
|
|
241
|
+
executeBtn + pauseBtn + resumeBtn + verifyBtn + deleteBtn +
|
|
239
242
|
'</div>' +
|
|
240
243
|
'</div>' +
|
|
241
244
|
'</div>' +
|
|
@@ -448,10 +451,12 @@ async function planView(file) {
|
|
|
448
451
|
'onclick="planPause(\'' + escHtml(normalizedFile) + '\');closeModal()">Pause</button>' : '';
|
|
449
452
|
const modalResumeBtn = isPaused ? '<button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--green)" ' +
|
|
450
453
|
'onclick="planApprove(\'' + escHtml(normalizedFile) + '\');closeModal()">Resume</button>' : '';
|
|
454
|
+
const modalVerifyBtn = isModalCompleted ? '<button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--green)" ' +
|
|
455
|
+
'onclick="triggerVerify(\'' + escHtml(normalizedFile) + '\')">Verify</button>' : '';
|
|
451
456
|
|
|
452
457
|
const lastModLabel = lastMod ? '<div style="font-size:10px;color:var(--muted);font-weight:400;margin-top:2px">Last updated: ' + new Date(lastMod).toLocaleString() + '</div>' : '';
|
|
453
458
|
const actionBtns = '<div style="display:flex;gap:4px;flex-wrap:wrap;margin-top:4px">' +
|
|
454
|
-
(modalCompletedLabel || '') + (modalInProgressLabel || '') + (modalExecuteBtn || '') + (modalPauseBtn || '') + (modalResumeBtn || '') +
|
|
459
|
+
(modalCompletedLabel || '') + (modalInProgressLabel || '') + (modalExecuteBtn || '') + (modalPauseBtn || '') + (modalResumeBtn || '') + (modalVerifyBtn || '') +
|
|
455
460
|
' <button class="pr-pager-btn" style="font-size:10px;padding:2px 10px;color:var(--red)" ' +
|
|
456
461
|
'onclick="planDelete(\'' + escHtml(normalizedFile) + '\')">Delete</button>' +
|
|
457
462
|
'</div>';
|
|
@@ -32,6 +32,8 @@ function renderPrd(prd, prog) {
|
|
|
32
32
|
if (prdFile) {
|
|
33
33
|
if (effectiveStatus === 'awaiting-approval') {
|
|
34
34
|
actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="planApprove(\'' + escHtml(prdFile) + '\')">Approve</button>';
|
|
35
|
+
} else if (effectiveStatus === 'completed') {
|
|
36
|
+
actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--green);border-color:var(--green);margin-left:4px" onclick="triggerVerify(\'' + escHtml(prdFile) + '\')">Verify</button>';
|
|
35
37
|
} else if (effectiveStatus === 'in-progress') {
|
|
36
38
|
actions = ' <button class="pr-pager-btn" style="font-size:9px;padding:1px 6px;color:var(--yellow);border-color:var(--yellow);margin-left:4px" onclick="planPause(\'' + escHtml(prdFile) + '\')">Pause</button>';
|
|
37
39
|
} else if (effectiveStatus === 'paused') {
|
|
@@ -209,11 +211,14 @@ function renderPrdProgress(prog) {
|
|
|
209
211
|
'<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan || g.file) + '\')" style="color:var(--blue);cursor:pointer;font-size:10px;padding:2px 8px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:4px" title="Review latest plan changes">Review plan</span>' +
|
|
210
212
|
'</div>'
|
|
211
213
|
: '';
|
|
214
|
+
const isCompleted = t && t.allDone;
|
|
212
215
|
const pauseResumeBtn = isAwaitingApproval
|
|
213
216
|
? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Approve</span>'
|
|
214
217
|
: isPaused
|
|
215
218
|
? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Resume</span>'
|
|
216
|
-
:
|
|
219
|
+
: isCompleted
|
|
220
|
+
? '<span onclick="event.stopPropagation();triggerVerify(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Verify</span>'
|
|
221
|
+
: '<span onclick="event.stopPropagation();planPause(\'' + escHtml(g.file) + '\')" style="color:var(--yellow);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.3);border-radius:3px">Pause</span>';
|
|
217
222
|
const deleteBtn = '<span onclick="event.stopPropagation();planDelete(\'' + escHtml(g.file) + '\')" style="color:var(--red);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.3);border-radius:3px">Delete</span>';
|
|
218
223
|
const sourcePlanLink = g.sourcePlan
|
|
219
224
|
? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:9px;padding:1px 6px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="View source plan">📄 Plan</span>'
|
package/engine/lifecycle.js
CHANGED
|
@@ -72,7 +72,7 @@ function checkPlanCompletion(meta, config) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
const doneItems = planItems.filter(w => w.status === 'done' || w.status === 'in-pr');
|
|
75
|
-
const failedItems =
|
|
75
|
+
const failedItems = planItems.filter(w => w.status === 'failed');
|
|
76
76
|
|
|
77
77
|
// 1. Mark plan as completed
|
|
78
78
|
plan.status = 'completed';
|
package/engine/meeting.js
CHANGED
|
@@ -259,8 +259,33 @@ function endMeeting(meetingId) {
|
|
|
259
259
|
return meeting;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
function archiveMeeting(id) {
|
|
263
|
+
const meeting = getMeeting(id);
|
|
264
|
+
if (!meeting) return null;
|
|
265
|
+
meeting.status = 'archived';
|
|
266
|
+
meeting.archivedAt = new Date().toISOString();
|
|
267
|
+
saveMeeting(meeting);
|
|
268
|
+
return meeting;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function unarchiveMeeting(id) {
|
|
272
|
+
const meeting = getMeeting(id);
|
|
273
|
+
if (!meeting || meeting.status !== 'archived') return null;
|
|
274
|
+
meeting.status = 'completed';
|
|
275
|
+
delete meeting.archivedAt;
|
|
276
|
+
saveMeeting(meeting);
|
|
277
|
+
return meeting;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function deleteMeeting(id) {
|
|
281
|
+
const filePath = path.join(MEETINGS_DIR, id + '.json');
|
|
282
|
+
if (!fs.existsSync(filePath)) return false;
|
|
283
|
+
fs.unlinkSync(filePath);
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
|
|
262
287
|
module.exports = {
|
|
263
288
|
MEETINGS_DIR, getMeetings, getMeeting, saveMeeting, createMeeting,
|
|
264
289
|
discoverMeetingWork, collectMeetingFindings,
|
|
265
|
-
addMeetingNote, advanceMeetingRound, endMeeting,
|
|
290
|
+
addMeetingNote, advanceMeetingRound, endMeeting, archiveMeeting, unarchiveMeeting, deleteMeeting,
|
|
266
291
|
};
|
package/engine/shared.js
CHANGED
|
@@ -177,32 +177,48 @@ function gitEnv() {
|
|
|
177
177
|
* Single source of truth — used by llm.js, consolidation.js, and lifecycle.js.
|
|
178
178
|
*/
|
|
179
179
|
function parseStreamJsonOutput(raw, { maxTextLength = 0 } = {}) {
|
|
180
|
-
const lines = raw.split('\n');
|
|
181
180
|
let text = '';
|
|
182
181
|
let usage = null;
|
|
183
182
|
let sessionId = null;
|
|
183
|
+
|
|
184
|
+
function extractResult(obj) {
|
|
185
|
+
if (obj.type !== 'result') return false;
|
|
186
|
+
if (obj.result) text = maxTextLength ? obj.result.slice(0, maxTextLength) : obj.result;
|
|
187
|
+
if (obj.session_id) sessionId = obj.session_id;
|
|
188
|
+
if (obj.total_cost_usd || obj.usage) {
|
|
189
|
+
usage = {
|
|
190
|
+
costUsd: obj.total_cost_usd || 0,
|
|
191
|
+
inputTokens: obj.usage?.input_tokens || 0,
|
|
192
|
+
outputTokens: obj.usage?.output_tokens || 0,
|
|
193
|
+
cacheRead: obj.usage?.cache_read_input_tokens || obj.usage?.cacheReadInputTokens || 0,
|
|
194
|
+
cacheCreation: obj.usage?.cache_creation_input_tokens || obj.usage?.cacheCreationInputTokens || 0,
|
|
195
|
+
durationMs: obj.duration_ms || 0,
|
|
196
|
+
numTurns: obj.num_turns || 0,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const lines = raw.split('\n');
|
|
184
203
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
185
204
|
const line = lines[i].trim();
|
|
186
|
-
if (!line
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
usage = {
|
|
194
|
-
costUsd: obj.total_cost_usd || 0,
|
|
195
|
-
inputTokens: obj.usage?.input_tokens || 0,
|
|
196
|
-
outputTokens: obj.usage?.output_tokens || 0,
|
|
197
|
-
cacheRead: obj.usage?.cache_read_input_tokens || obj.usage?.cacheReadInputTokens || 0,
|
|
198
|
-
cacheCreation: obj.usage?.cache_creation_input_tokens || obj.usage?.cacheCreationInputTokens || 0,
|
|
199
|
-
durationMs: obj.duration_ms || 0,
|
|
200
|
-
numTurns: obj.num_turns || 0,
|
|
201
|
-
};
|
|
205
|
+
if (!line) continue;
|
|
206
|
+
// Handle JSON array format (--output-format json)
|
|
207
|
+
if (line.startsWith('[')) {
|
|
208
|
+
try {
|
|
209
|
+
const arr = JSON.parse(line);
|
|
210
|
+
for (let j = arr.length - 1; j >= 0; j--) {
|
|
211
|
+
if (extractResult(arr[j])) break;
|
|
202
212
|
}
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
213
|
+
if (text || usage) break;
|
|
214
|
+
} catch {}
|
|
215
|
+
}
|
|
216
|
+
// Handle newline-delimited format (--output-format stream-json)
|
|
217
|
+
if (line.startsWith('{')) {
|
|
218
|
+
try {
|
|
219
|
+
if (extractResult(JSON.parse(line))) break;
|
|
220
|
+
} catch {}
|
|
221
|
+
}
|
|
206
222
|
}
|
|
207
223
|
return { text, usage, sessionId };
|
|
208
224
|
}
|
package/engine/timeout.js
CHANGED
|
@@ -140,11 +140,8 @@ function checkTimeouts(config) {
|
|
|
140
140
|
// Extract output text for the output.log
|
|
141
141
|
const outputLogPath = path.join(AGENTS_DIR, item.agent, 'output.log');
|
|
142
142
|
try {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
const result = JSON.parse(resultLine);
|
|
146
|
-
safeWrite(outputLogPath, `# Output for dispatch ${item.id}\n# Exit code: ${isSuccess ? 0 : 1}\n# Completed: ${ts()}\n# Detected via output scan\n\n## Result\n${result.result || '(no text)'}\n`);
|
|
147
|
-
}
|
|
143
|
+
const { text } = shared.parseStreamJsonOutput(liveLog);
|
|
144
|
+
safeWrite(outputLogPath, `# Output for dispatch ${item.id}\n# Exit code: ${isSuccess ? 0 : 1}\n# Completed: ${ts()}\n# Detected via output scan\n\n## Result\n${text || '(no text)'}\n`);
|
|
148
145
|
} catch (e) { log('warn', 'parse output result: ' + e.message); }
|
|
149
146
|
|
|
150
147
|
completeDispatch(item.id, isSuccess ? 'success' : 'error', 'Completed (detected from output)');
|
package/package.json
CHANGED