cli-jaw 1.7.32 → 1.7.33
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/dist/bin/cli-jaw.js +11 -0
- package/dist/bin/cli-jaw.js.map +1 -1
- package/dist/bin/star-prompt.js +96 -0
- package/dist/bin/star-prompt.js.map +1 -0
- package/dist/src/agent/args.js +0 -4
- package/dist/src/agent/args.js.map +1 -1
- package/dist/src/agent/events.js +328 -54
- package/dist/src/agent/events.js.map +1 -1
- package/dist/src/agent/spawn.js +9 -6
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/cli/command-context.js +1 -0
- package/dist/src/cli/command-context.js.map +1 -1
- package/dist/src/cli/commands.js +2 -1
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/handlers.js +20 -0
- package/dist/src/cli/handlers.js.map +1 -1
- package/dist/src/cli/registry.js +6 -19
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/core/config.js +1 -0
- package/dist/src/core/config.js.map +1 -1
- package/package.json +1 -1
- package/public/css/tool-ui.css +20 -1
- package/public/dist/assets/constants-IeOVgtYz.js +1 -0
- package/public/dist/assets/{employees-CpgcoYx1.js → employees-Do9d6Xi5.js} +1 -1
- package/public/dist/assets/{index-DVAk6-ox.css → index-qALA03H1.css} +1 -1
- package/public/dist/assets/{index-DlhVtNGh.js → index-yGExjgR_.js} +4 -4
- package/public/dist/assets/{memory-jVeY3J9Z.js → memory-DeZSzBAb.js} +1 -1
- package/public/dist/assets/memory-Dpe-qPbZ.js +1 -0
- package/public/dist/assets/render-CQnnZ-_i.js +30 -0
- package/public/dist/assets/{settings-DN37FmEm.js → settings-C8bSXG3q.js} +1 -1
- package/public/dist/assets/settings-COrhSfDh.js +1 -0
- package/public/dist/assets/skills-BO0V4aHG.js +1 -0
- package/public/dist/assets/{skills-C-Hd0Khs.js → skills-Ci5t_dsV.js} +1 -1
- package/public/dist/assets/{slash-commands-DKD_PVHP.js → slash-commands-0RvnZU9z.js} +1 -1
- package/public/dist/assets/slash-commands-DbUvFtCk.js +1 -0
- package/public/dist/assets/ui-Cxk1_e0b.js +1 -0
- package/public/dist/assets/ui-IWxpAzJ7.js +131 -0
- package/public/dist/assets/vendor-icons-Bs4t7RP2.js +1 -0
- package/public/dist/assets/ws-FsYmCE65.js +14 -0
- package/public/dist/index.html +2 -2
- package/public/js/constants.ts +5 -18
- package/public/js/features/process-block.ts +10 -1
- package/public/js/features/settings-types.ts +1 -1
- package/public/js/features/tool-ui.ts +2 -0
- package/public/js/icons.ts +15 -0
- package/public/js/ui.ts +80 -18
- package/public/js/virtual-scroll.ts +38 -8
- package/public/js/ws.ts +7 -3
- package/public/dist/assets/constants-2eOyiA6N.js +0 -1
- package/public/dist/assets/memory-CnXTT6wp.js +0 -1
- package/public/dist/assets/render-CtsdCdtV.js +0 -30
- package/public/dist/assets/settings-DidDB9Rr.js +0 -1
- package/public/dist/assets/skills-BsXI_IT2.js +0 -1
- package/public/dist/assets/slash-commands-DTi0pAMr.js +0 -1
- package/public/dist/assets/ui-BUkXAGyS.js +0 -1
- package/public/dist/assets/ui-N2Up5Bik.js +0 -130
- package/public/dist/assets/vendor-icons-C6LXvgi0.js +0 -1
- package/public/dist/assets/ws-Dgn9Mqgb.js +0 -14
package/dist/src/agent/events.js
CHANGED
|
@@ -67,6 +67,68 @@ function clipText(text, max) {
|
|
|
67
67
|
function buildPreview(text, max = 80) {
|
|
68
68
|
return clipText(toSingleLine(text), max);
|
|
69
69
|
}
|
|
70
|
+
function appendDetail(...parts) {
|
|
71
|
+
return parts.map(p => String(p || '').trim()).filter(Boolean).join('\n');
|
|
72
|
+
}
|
|
73
|
+
function formatJsonDetail(label, value) {
|
|
74
|
+
if (value == null)
|
|
75
|
+
return '';
|
|
76
|
+
try {
|
|
77
|
+
return `${label}: ${typeof value === 'string' ? value : JSON.stringify(value, null, 2)}`;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return `${label}: ${String(value)}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function formatAssistantTextSegment(ctx, text) {
|
|
84
|
+
const raw = String(text || '');
|
|
85
|
+
if (!raw)
|
|
86
|
+
return '';
|
|
87
|
+
if (!ctx.outputTextStarted) {
|
|
88
|
+
ctx.outputTextStarted = true;
|
|
89
|
+
return raw;
|
|
90
|
+
}
|
|
91
|
+
if (/\s$/.test(ctx.fullText) || /^\s/.test(raw) || /^[,.;:!?)]/.test(raw) || /^-\S/.test(raw))
|
|
92
|
+
return raw;
|
|
93
|
+
return raw.startsWith('- ') || raw.startsWith('* ')
|
|
94
|
+
? `\n${raw}`
|
|
95
|
+
: `\n- ${raw}`;
|
|
96
|
+
}
|
|
97
|
+
function appendAssistantTextSegment(ctx, text) {
|
|
98
|
+
const segment = formatAssistantTextSegment(ctx, text);
|
|
99
|
+
if (!segment)
|
|
100
|
+
return '';
|
|
101
|
+
ctx.fullText += segment;
|
|
102
|
+
return segment;
|
|
103
|
+
}
|
|
104
|
+
function emitGeminiThought(ctx, agentLabel, empTag, text) {
|
|
105
|
+
const detail = String(text || '').trim();
|
|
106
|
+
if (!detail)
|
|
107
|
+
return;
|
|
108
|
+
const tool = {
|
|
109
|
+
icon: '💭',
|
|
110
|
+
label: buildPreview(detail, 80) || 'thinking...',
|
|
111
|
+
toolType: 'thinking',
|
|
112
|
+
detail,
|
|
113
|
+
};
|
|
114
|
+
ctx.toolLog.push(tool);
|
|
115
|
+
syncLiveTools(ctx);
|
|
116
|
+
broadcast('agent_tool', { agentId: agentLabel, ...tool, ...empTag });
|
|
117
|
+
}
|
|
118
|
+
function extractGeminiThoughtText(content) {
|
|
119
|
+
if (typeof content === 'string')
|
|
120
|
+
return content;
|
|
121
|
+
if (Array.isArray(content)) {
|
|
122
|
+
return content
|
|
123
|
+
.filter((p) => p?.type === 'thought' || p?.type === 'thinking')
|
|
124
|
+
.map((p) => String(p.thought || p.text || p.content || ''))
|
|
125
|
+
.join('');
|
|
126
|
+
}
|
|
127
|
+
if (content && typeof content === 'object') {
|
|
128
|
+
return String(content.thought || content.text || content.content || '');
|
|
129
|
+
}
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
70
132
|
function toIndentedPreview(text, max = 200) {
|
|
71
133
|
const raw = String(text || '').trim();
|
|
72
134
|
if (!raw)
|
|
@@ -84,6 +146,22 @@ function isOpencodeToolFailure(part) {
|
|
|
84
146
|
|| status === 'denied'
|
|
85
147
|
|| status === 'cancelled';
|
|
86
148
|
}
|
|
149
|
+
function cleanOpencodeTaskResult(output) {
|
|
150
|
+
const raw = String(output || '').trim();
|
|
151
|
+
if (!raw)
|
|
152
|
+
return '';
|
|
153
|
+
const match = raw.match(/<task_result>([\s\S]*?)<\/task_result>/);
|
|
154
|
+
return (match?.[1] || raw).trim();
|
|
155
|
+
}
|
|
156
|
+
function formatOpenCodeTaskDetail(part) {
|
|
157
|
+
const state = part?.state || {};
|
|
158
|
+
const input = state.input || {};
|
|
159
|
+
const meta = state.metadata || {};
|
|
160
|
+
const model = meta.model
|
|
161
|
+
? [meta.model.providerID, meta.model.modelID].filter(Boolean).join('/')
|
|
162
|
+
: '';
|
|
163
|
+
return appendDetail(input.prompt ? `prompt: ${clipText(String(input.prompt), 300)}` : '', model ? `model: ${model}` : '', meta.sessionId ? `child_session: ${meta.sessionId}` : '', cleanOpencodeTaskResult(state.output) ? `result: ${cleanOpencodeTaskResult(state.output)}` : '');
|
|
164
|
+
}
|
|
87
165
|
function finalizeOpencodePendingTools(ctx, agentLabel, empTag) {
|
|
88
166
|
const pendingRefs = ctx.opencodePendingToolRefs || [];
|
|
89
167
|
if (!pendingRefs.length)
|
|
@@ -110,6 +188,11 @@ export function extractSessionId(cli, event) {
|
|
|
110
188
|
}
|
|
111
189
|
export function extractOutputChunk(cli, event, ctx) {
|
|
112
190
|
if (cli === 'gemini') {
|
|
191
|
+
if (ctx?.pendingOutputChunk) {
|
|
192
|
+
const chunk = ctx.pendingOutputChunk;
|
|
193
|
+
ctx.pendingOutputChunk = '';
|
|
194
|
+
return chunk;
|
|
195
|
+
}
|
|
113
196
|
// [#107] Skip thought/thinking events (future-proofing for when Gemini CLI adds them)
|
|
114
197
|
if (event.type === 'thought' || event.thought === true)
|
|
115
198
|
return '';
|
|
@@ -133,6 +216,11 @@ export function extractOutputChunk(cli, event, ctx) {
|
|
|
133
216
|
}
|
|
134
217
|
// [P0-1.5] Codex: emit agent_message text as live chunk
|
|
135
218
|
if (cli === 'codex') {
|
|
219
|
+
if (ctx?.pendingOutputChunk) {
|
|
220
|
+
const chunk = ctx.pendingOutputChunk;
|
|
221
|
+
ctx.pendingOutputChunk = '';
|
|
222
|
+
return chunk;
|
|
223
|
+
}
|
|
136
224
|
if (event.type === 'item.completed' && event.item?.type === 'agent_message') {
|
|
137
225
|
return String(event.item.text || '');
|
|
138
226
|
}
|
|
@@ -326,10 +414,10 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
326
414
|
if (event.type === 'assistant' && event.message?.content) {
|
|
327
415
|
for (const block of event.message.content) {
|
|
328
416
|
if (block.type === 'text') {
|
|
329
|
-
ctx
|
|
417
|
+
const segment = appendAssistantTextSegment(ctx, block.text);
|
|
330
418
|
const scope = liveScopeOf(ctx);
|
|
331
419
|
if (scope)
|
|
332
|
-
appendLiveRunText(scope,
|
|
420
|
+
appendLiveRunText(scope, segment);
|
|
333
421
|
}
|
|
334
422
|
}
|
|
335
423
|
}
|
|
@@ -383,23 +471,24 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
383
471
|
if (event.type === 'item.completed') {
|
|
384
472
|
if (event.item?.type === 'agent_message') {
|
|
385
473
|
const text = String(event.item.text || '');
|
|
386
|
-
ctx
|
|
474
|
+
const segment = appendAssistantTextSegment(ctx, text);
|
|
475
|
+
ctx.pendingOutputChunk = (ctx.pendingOutputChunk || '') + segment;
|
|
387
476
|
// [spark-visibility] Spark and other lightweight codex models often
|
|
388
477
|
// emit only an agent_message (no reasoning/command_execution), so the
|
|
389
478
|
// toolLog would be empty and the run would be invisible in the UI.
|
|
390
479
|
// Surface the final message as a 💬 entry so every codex run shows at
|
|
391
480
|
// least one toolLog step. Dedup is handled by seenToolKeys via stepRef.
|
|
392
|
-
if (
|
|
481
|
+
if (segment.trim()) {
|
|
393
482
|
const itemId = event.item.id || '';
|
|
394
483
|
const tool = {
|
|
395
484
|
icon: '💬',
|
|
396
|
-
label: buildPreview(
|
|
485
|
+
label: buildPreview(segment, 80) || 'message',
|
|
397
486
|
toolType: 'tool',
|
|
398
|
-
detail:
|
|
487
|
+
detail: segment,
|
|
399
488
|
stepRef: itemId ? `codex:item:${itemId}` : undefined,
|
|
400
489
|
status: 'done',
|
|
401
490
|
};
|
|
402
|
-
const key = tool.stepRef || `codex:msg:${ctx.toolLog.length}:${
|
|
491
|
+
const key = tool.stepRef || `codex:msg:${ctx.toolLog.length}:${segment.slice(0, 30)}`;
|
|
403
492
|
if (!ctx.seenToolKeys || !ctx.seenToolKeys.has(key)) {
|
|
404
493
|
if (ctx.seenToolKeys)
|
|
405
494
|
ctx.seenToolKeys.add(key);
|
|
@@ -409,8 +498,15 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
409
498
|
}
|
|
410
499
|
}
|
|
411
500
|
}
|
|
412
|
-
if (event.item?.type === 'collab_tool_call'
|
|
413
|
-
|
|
501
|
+
if (event.item?.type === 'collab_tool_call'
|
|
502
|
+
&& ['spawn_agent', 'wait'].includes(String(event.item.tool || event.item.name || ''))) {
|
|
503
|
+
ctx.hasActiveSubAgent = false;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
else if (event.type === 'item.started') {
|
|
507
|
+
if (event.item?.type === 'collab_tool_call'
|
|
508
|
+
&& ['spawn_agent', 'wait'].includes(String(event.item.tool || event.item.name || ''))) {
|
|
509
|
+
ctx.hasActiveSubAgent = true;
|
|
414
510
|
}
|
|
415
511
|
}
|
|
416
512
|
else if (event.type === 'turn.completed' && event.usage) {
|
|
@@ -449,20 +545,30 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
449
545
|
if (event.type === 'init' && event.model) {
|
|
450
546
|
ctx.model = event.model;
|
|
451
547
|
}
|
|
452
|
-
// [#107]
|
|
548
|
+
// [#107/#121] Thought content never enters fullText; optional visibility uses process steps.
|
|
453
549
|
if (event.type === 'thought' || event.thought === true) {
|
|
454
|
-
|
|
550
|
+
if (ctx.showReasoning) {
|
|
551
|
+
emitGeminiThought(ctx, agentLabel, empTag, event.content || event.thought || event.text);
|
|
552
|
+
pushTrace(ctx, `[${agentLabel}] gemini thought (visible)`);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
pushTrace(ctx, `[${agentLabel}] gemini thought (hidden)`);
|
|
556
|
+
}
|
|
455
557
|
break;
|
|
456
558
|
}
|
|
457
559
|
if (event.type === 'message' && event.role === 'assistant') {
|
|
458
560
|
// [#107] If content is an array (ACP-style), extract only text parts
|
|
459
561
|
if (Array.isArray(event.content)) {
|
|
562
|
+
if (ctx.showReasoning) {
|
|
563
|
+
emitGeminiThought(ctx, agentLabel, empTag, extractGeminiThoughtText(event.content));
|
|
564
|
+
}
|
|
460
565
|
const textOnly = event.content
|
|
461
566
|
.filter((p) => p?.type === 'text')
|
|
462
567
|
.map((p) => String(p?.text || ''))
|
|
463
568
|
.join('');
|
|
464
569
|
if (textOnly) {
|
|
465
|
-
ctx
|
|
570
|
+
const segment = appendAssistantTextSegment(ctx, textOnly);
|
|
571
|
+
ctx.pendingOutputChunk = (ctx.pendingOutputChunk || '') + segment;
|
|
466
572
|
pushTrace(ctx, `[${agentLabel}] gemini text (filtered)`);
|
|
467
573
|
}
|
|
468
574
|
break;
|
|
@@ -471,7 +577,8 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
471
577
|
if (event.delta) {
|
|
472
578
|
pushTrace(ctx, `[${agentLabel}] gemini delta text`);
|
|
473
579
|
}
|
|
474
|
-
ctx
|
|
580
|
+
const segment = appendAssistantTextSegment(ctx, event.content || '');
|
|
581
|
+
ctx.pendingOutputChunk = (ctx.pendingOutputChunk || '') + segment;
|
|
475
582
|
}
|
|
476
583
|
else if (event.type === 'result') {
|
|
477
584
|
ctx.geminiResultSeen = true;
|
|
@@ -542,25 +649,21 @@ export function extractFromEvent(cli, event, ctx, agentLabel, empTag = {}) {
|
|
|
542
649
|
const shouldCommitText = stepText && (event.part.reason !== 'tool-calls'
|
|
543
650
|
|| (!!ctx.opencodeTextAfterLastTool && !!ctx.opencodeHadToolErrorInStep));
|
|
544
651
|
if (shouldCommitText) {
|
|
545
|
-
ctx
|
|
546
|
-
ctx.pendingOutputChunk = (ctx.pendingOutputChunk || '') +
|
|
652
|
+
const segment = appendAssistantTextSegment(ctx, stepText);
|
|
653
|
+
ctx.pendingOutputChunk = (ctx.pendingOutputChunk || '') + segment;
|
|
547
654
|
}
|
|
548
655
|
else if (stepText) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
}
|
|
561
|
-
else {
|
|
562
|
-
pushTrace(ctx, `[${agentLabel}] opencode buffered text discarded before tool call (${stepText.length} chars)`);
|
|
563
|
-
}
|
|
656
|
+
const thinkingTool = {
|
|
657
|
+
icon: '💭',
|
|
658
|
+
label: buildPreview(stepText, 80) || 'thinking...',
|
|
659
|
+
toolType: 'thinking',
|
|
660
|
+
detail: stepText,
|
|
661
|
+
};
|
|
662
|
+
ctx.toolLog.push(thinkingTool);
|
|
663
|
+
syncLiveTools(ctx);
|
|
664
|
+
broadcast('agent_tool', { agentId: agentLabel, ...thinkingTool, ...empTag });
|
|
665
|
+
const phase = ctx.opencodeTextAfterLastTool ? 'post-tool' : 'pre-tool';
|
|
666
|
+
pushTrace(ctx, `[${agentLabel}] opencode ${phase} intermediate text (${stepText.length} chars)`);
|
|
564
667
|
}
|
|
565
668
|
finalizeOpencodePendingTools(ctx, agentLabel, empTag);
|
|
566
669
|
ctx.opencodeStepText = '';
|
|
@@ -708,8 +811,8 @@ function pushToolLabel(labels, label, cli, event, ctx) {
|
|
|
708
811
|
function extractToolLabels(cli, event, ctx = null) {
|
|
709
812
|
const item = event.item || event.part || event;
|
|
710
813
|
const labels = [];
|
|
711
|
-
if (cli === 'codex' && event.type === 'item.completed' && item) {
|
|
712
|
-
if (item.type === 'web_search') {
|
|
814
|
+
if (cli === 'codex' && (event.type === 'item.started' || event.type === 'item.completed') && item) {
|
|
815
|
+
if (event.type === 'item.completed' && item.type === 'web_search') {
|
|
713
816
|
const action = item.action?.type || '';
|
|
714
817
|
if (action === 'search') {
|
|
715
818
|
const query = item.query || item.action?.query || 'search';
|
|
@@ -729,11 +832,11 @@ function extractToolLabels(cli, event, ctx = null) {
|
|
|
729
832
|
labels.push({ icon: '🔍', label: buildPreview(query, 60), toolType: 'search', detail: query });
|
|
730
833
|
}
|
|
731
834
|
}
|
|
732
|
-
if (item.type === 'reasoning') {
|
|
835
|
+
if (event.type === 'item.completed' && item.type === 'reasoning') {
|
|
733
836
|
const detail = String(item.text || '').replace(/\*+/g, '').trim();
|
|
734
837
|
labels.push({ icon: '💭', label: buildPreview(detail, 60) || 'thinking...', toolType: 'thinking', detail });
|
|
735
838
|
}
|
|
736
|
-
if (item.type === 'command_execution') {
|
|
839
|
+
if (event.type === 'item.completed' && item.type === 'command_execution') {
|
|
737
840
|
const command = String(item.command || 'exec');
|
|
738
841
|
const output = item.aggregated_output ? String(item.aggregated_output) : '';
|
|
739
842
|
const detail = output ? `$ ${command}\n${output}` : command;
|
|
@@ -753,14 +856,19 @@ function extractToolLabels(cli, event, ctx = null) {
|
|
|
753
856
|
});
|
|
754
857
|
}
|
|
755
858
|
if (item.type === 'collab_tool_call') {
|
|
756
|
-
const
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
859
|
+
const tool = String(item.tool || item.name || 'subagent');
|
|
860
|
+
const ref = `codex:collab:${item.id || tool}`;
|
|
861
|
+
const isStarted = event.type === 'item.started' || item.status === 'in_progress';
|
|
862
|
+
const receiverIds = Array.isArray(item.receiver_thread_ids) ? item.receiver_thread_ids.join(', ') : '';
|
|
863
|
+
const detail = appendDetail(item.sender_thread_id ? `sender: ${item.sender_thread_id}` : '', receiverIds ? `receivers: ${receiverIds}` : '', formatJsonDetail('agents', item.agents_states), item.prompt ? `prompt: ${clipText(String(item.prompt), 300)}` : '');
|
|
864
|
+
labels.push({
|
|
865
|
+
icon: isStarted ? '🤖' : '✅',
|
|
866
|
+
label: isStarted ? `${tool}...` : `${tool} done`,
|
|
867
|
+
toolType: 'subagent',
|
|
868
|
+
stepRef: ref,
|
|
869
|
+
status: isStarted ? 'running' : 'done',
|
|
870
|
+
...(detail ? { detail } : {}),
|
|
871
|
+
});
|
|
764
872
|
}
|
|
765
873
|
}
|
|
766
874
|
// [P0-1.3] Codex item.started: emit running label (paired with 1.4 stepRef)
|
|
@@ -775,6 +883,40 @@ function extractToolLabels(cli, event, ctx = null) {
|
|
|
775
883
|
if (event.type === 'system') {
|
|
776
884
|
const status = String(event.status || '');
|
|
777
885
|
const subtype = String(event.subtype || event.event || '');
|
|
886
|
+
if (subtype === 'task_started') {
|
|
887
|
+
const taskId = event.task_id || event.id || event.tool_use_id || 'unknown';
|
|
888
|
+
const description = event.description || event.input?.description || event.task_type || 'subagent';
|
|
889
|
+
const detail = appendDetail(event.task_type ? `type: ${event.task_type}` : '', event.tool_use_id ? `tool_use_id: ${event.tool_use_id}` : '', event.prompt ? `prompt: ${clipText(String(event.prompt), 300)}` : '');
|
|
890
|
+
pushToolLabel(labels, {
|
|
891
|
+
icon: '🤖',
|
|
892
|
+
label: `subagent: ${buildPreview(description, 60)}`,
|
|
893
|
+
toolType: 'subagent',
|
|
894
|
+
stepRef: `claude:task:${taskId}`,
|
|
895
|
+
status: 'running',
|
|
896
|
+
...(detail ? { detail } : {}),
|
|
897
|
+
}, cli, event, ctx);
|
|
898
|
+
}
|
|
899
|
+
if (subtype === 'task_notification') {
|
|
900
|
+
const taskId = event.task_id || event.id || event.tool_use_id || 'unknown';
|
|
901
|
+
const rawStatus = String(event.status || 'completed');
|
|
902
|
+
const failed = ['failed', 'error', 'cancelled', 'canceled'].includes(rawStatus);
|
|
903
|
+
const description = event.description || event.summary || event.task_type || 'subagent';
|
|
904
|
+
const usage = event.usage || {};
|
|
905
|
+
const usageDetail = [
|
|
906
|
+
usage.total_tokens != null ? `${usage.total_tokens} tok` : '',
|
|
907
|
+
usage.tool_uses != null ? `${usage.tool_uses} tools` : '',
|
|
908
|
+
usage.duration_ms != null ? `${(Number(usage.duration_ms) / 1000).toFixed(1)}s` : '',
|
|
909
|
+
].filter(Boolean).join(' · ');
|
|
910
|
+
const detail = appendDetail(event.summary ? `summary: ${event.summary}` : '', event.output_file ? `output_file: ${event.output_file}` : '', usageDetail);
|
|
911
|
+
pushToolLabel(labels, {
|
|
912
|
+
icon: failed ? '❌' : '✅',
|
|
913
|
+
label: `subagent: ${buildPreview(description, 60)}`,
|
|
914
|
+
toolType: 'subagent',
|
|
915
|
+
stepRef: `claude:task:${taskId}`,
|
|
916
|
+
status: failed ? 'error' : 'done',
|
|
917
|
+
...(detail ? { detail } : {}),
|
|
918
|
+
}, cli, event, ctx);
|
|
919
|
+
}
|
|
778
920
|
if (status === 'compacting' || subtype === 'compacting') {
|
|
779
921
|
pushToolLabel(labels, { icon: '🗜️', label: 'compacting...', toolType: 'tool' }, cli, event, ctx);
|
|
780
922
|
}
|
|
@@ -788,14 +930,30 @@ function extractToolLabels(cli, event, ctx = null) {
|
|
|
788
930
|
if (ctx)
|
|
789
931
|
ctx.hasClaudeStreamEvents = true;
|
|
790
932
|
const cb = event.event.content_block;
|
|
791
|
-
if (cb?.type === 'tool_use')
|
|
792
|
-
|
|
933
|
+
if (cb?.type === 'tool_use') {
|
|
934
|
+
const isAgent = cb.name === 'Agent';
|
|
935
|
+
pushToolLabel(labels, {
|
|
936
|
+
icon: isAgent ? '🤖' : '🔧',
|
|
937
|
+
label: isAgent ? 'subagent' : (cb.name || 'tool'),
|
|
938
|
+
toolType: isAgent ? 'subagent' : 'tool',
|
|
939
|
+
stepRef: cb.id ? `claude:tooluse:${cb.id}` : undefined,
|
|
940
|
+
}, cli, event, ctx);
|
|
941
|
+
}
|
|
793
942
|
// thinking: don't emit placeholder — buffer in extractFromEvent will emit with real content
|
|
794
943
|
}
|
|
795
944
|
if (event.type === 'assistant' && event.message?.content && !ctx?.hasClaudeStreamEvents) {
|
|
796
945
|
for (const block of event.message.content) {
|
|
797
|
-
if (block.type === 'tool_use')
|
|
798
|
-
|
|
946
|
+
if (block.type === 'tool_use') {
|
|
947
|
+
const isAgent = block.name === 'Agent';
|
|
948
|
+
const description = block.input?.description || block.input?.subagent_type || 'subagent';
|
|
949
|
+
pushToolLabel(labels, {
|
|
950
|
+
icon: isAgent ? '🤖' : '🔧',
|
|
951
|
+
label: isAgent ? `subagent: ${buildPreview(description, 60)}` : (block.name || 'tool'),
|
|
952
|
+
toolType: isAgent ? 'subagent' : 'tool',
|
|
953
|
+
stepRef: block.id ? `claude:tooluse:${block.id}` : undefined,
|
|
954
|
+
...(isAgent && block.input?.prompt ? { detail: `prompt: ${clipText(String(block.input.prompt), 300)}` } : {}),
|
|
955
|
+
}, cli, event, ctx);
|
|
956
|
+
}
|
|
799
957
|
if (block.type === 'thinking') {
|
|
800
958
|
const text = (block.thinking || '').trim();
|
|
801
959
|
pushToolLabel(labels, { icon: '💭', label: buildPreview(text, 80) || 'thinking...', toolType: 'thinking', detail: text }, cli, event, ctx);
|
|
@@ -829,6 +987,40 @@ function extractToolLabels(cli, event, ctx = null) {
|
|
|
829
987
|
}
|
|
830
988
|
}
|
|
831
989
|
if (cli === 'opencode') {
|
|
990
|
+
const isTaskToolUse = event.type === 'tool_use' && event.part?.tool === 'task';
|
|
991
|
+
const isTaskToolResult = event.type === 'tool_result'
|
|
992
|
+
&& event.part?.callID
|
|
993
|
+
&& ctx?.opencodeTaskCallIds?.has(event.part.callID);
|
|
994
|
+
if (isTaskToolUse || isTaskToolResult) {
|
|
995
|
+
const part = event.part;
|
|
996
|
+
const callID = part.callID || part.id || 'task';
|
|
997
|
+
if (isTaskToolResult && !part.state)
|
|
998
|
+
return labels;
|
|
999
|
+
if (isTaskToolUse && ctx) {
|
|
1000
|
+
if (!ctx.opencodeTaskCallIds)
|
|
1001
|
+
ctx.opencodeTaskCallIds = new Set();
|
|
1002
|
+
ctx.opencodeTaskCallIds.add(callID);
|
|
1003
|
+
}
|
|
1004
|
+
const state = part.state || {};
|
|
1005
|
+
const input = state.input || {};
|
|
1006
|
+
const status = String(state.status || (event.type === 'tool_result' ? 'completed' : 'completed'));
|
|
1007
|
+
const failed = isOpencodeToolFailure(part) || ['error', 'failed', 'cancelled', 'canceled'].includes(status);
|
|
1008
|
+
const subagentType = input.subagent_type || 'general';
|
|
1009
|
+
const description = input.description || state.title || part.tool || 'task';
|
|
1010
|
+
const resultText = event.type === 'tool_result'
|
|
1011
|
+
? extractText(part.content || part.output || state.output)
|
|
1012
|
+
: '';
|
|
1013
|
+
const detail = appendDetail(formatOpenCodeTaskDetail(part), resultText ? `result: ${resultText}` : '');
|
|
1014
|
+
labels.push({
|
|
1015
|
+
icon: failed ? '❌' : (status === 'running' || status === 'in_progress' ? '🤖' : '✅'),
|
|
1016
|
+
label: `subagent[${subagentType}]: ${buildPreview(description, 60)}`,
|
|
1017
|
+
toolType: 'subagent',
|
|
1018
|
+
stepRef: `opencode:call:${callID}`,
|
|
1019
|
+
...(detail ? { detail } : {}),
|
|
1020
|
+
status: failed ? 'error' : (status === 'running' || status === 'in_progress' ? 'running' : 'done'),
|
|
1021
|
+
});
|
|
1022
|
+
return labels;
|
|
1023
|
+
}
|
|
832
1024
|
if (event.type === 'tool_use' && event.part) {
|
|
833
1025
|
const ref = event.part.callID
|
|
834
1026
|
? `opencode:call:${event.part.callID}`
|
|
@@ -933,7 +1125,7 @@ function extractText(content) {
|
|
|
933
1125
|
}
|
|
934
1126
|
return '';
|
|
935
1127
|
}
|
|
936
|
-
export function extractFromAcpUpdate(params) {
|
|
1128
|
+
export function extractFromAcpUpdate(params, ctx = null) {
|
|
937
1129
|
const update = params?.update;
|
|
938
1130
|
if (!update)
|
|
939
1131
|
return null;
|
|
@@ -952,20 +1144,35 @@ export function extractFromAcpUpdate(params) {
|
|
|
952
1144
|
}
|
|
953
1145
|
case 'tool_call': {
|
|
954
1146
|
const toolName = update.name || 'tool';
|
|
1147
|
+
const rawInput = update.rawInput || update.input || {};
|
|
1148
|
+
const isSubagentTask = rawInput?.agent_type === 'task' || rawInput?.agentType === 'task';
|
|
1149
|
+
const displayLabel = isSubagentTask
|
|
1150
|
+
? `subagent: ${update.title || rawInput.description || rawInput.name || toolName}`
|
|
1151
|
+
: update.title || toolName;
|
|
1152
|
+
if (isSubagentTask && update.toolCallId && ctx) {
|
|
1153
|
+
if (!ctx.acpSubagentToolCallIds)
|
|
1154
|
+
ctx.acpSubagentToolCallIds = new Set();
|
|
1155
|
+
if (!ctx.acpSubagentLabels)
|
|
1156
|
+
ctx.acpSubagentLabels = new Map();
|
|
1157
|
+
ctx.acpSubagentToolCallIds.add(update.toolCallId);
|
|
1158
|
+
ctx.acpSubagentLabels.set(update.toolCallId, displayLabel);
|
|
1159
|
+
}
|
|
955
1160
|
const fullInput = update.input != null
|
|
956
1161
|
? (typeof update.input === 'object' ? JSON.stringify(update.input, null, 2) : String(update.input))
|
|
957
|
-
:
|
|
1162
|
+
: update.rawInput != null
|
|
1163
|
+
? (typeof update.rawInput === 'object' ? JSON.stringify(update.rawInput, null, 2) : String(update.rawInput))
|
|
1164
|
+
: '';
|
|
958
1165
|
// [P1-2.10] Semantic icon from tool kind/title
|
|
959
1166
|
const kindIcon = toolKindIcon(update.kind);
|
|
960
|
-
const displayLabel = update.title || toolName;
|
|
961
1167
|
// [P0-1.11] Use toolCallId for unique stepRef
|
|
962
1168
|
return {
|
|
963
1169
|
tool: {
|
|
964
|
-
icon: kindIcon || '🔧',
|
|
1170
|
+
icon: isSubagentTask ? '🤖' : (kindIcon || '🔧'),
|
|
965
1171
|
label: displayLabel,
|
|
966
|
-
toolType: 'tool',
|
|
1172
|
+
toolType: isSubagentTask ? 'subagent' : 'tool',
|
|
967
1173
|
detail: fullInput,
|
|
968
1174
|
stepRef: `acp:callid:${update.toolCallId || update.id || toolName}`,
|
|
1175
|
+
...(isSubagentTask ? { status: 'running' } : {}),
|
|
969
1176
|
},
|
|
970
1177
|
};
|
|
971
1178
|
}
|
|
@@ -979,14 +1186,17 @@ export function extractFromAcpUpdate(params) {
|
|
|
979
1186
|
failed: { icon: '❌', status: 'error' },
|
|
980
1187
|
};
|
|
981
1188
|
const mapped = statusMap[update.status] || { icon: '❔', status: update.status || 'unknown' };
|
|
1189
|
+
const toolCallId = update.toolCallId || update.id || update.name || 'done';
|
|
1190
|
+
const isSubagentTask = !!(toolCallId && ctx?.acpSubagentToolCallIds?.has(toolCallId));
|
|
1191
|
+
const subagentLabel = toolCallId ? ctx?.acpSubagentLabels?.get(toolCallId) : '';
|
|
982
1192
|
// [P1-2.9] Extract content from tool result
|
|
983
1193
|
const resultText = update.content ? extractText(update.content) : '';
|
|
984
1194
|
return {
|
|
985
1195
|
tool: {
|
|
986
1196
|
icon: mapped.icon,
|
|
987
|
-
label: update.name || update.id || 'done',
|
|
988
|
-
toolType: 'tool',
|
|
989
|
-
stepRef: `acp:callid:${
|
|
1197
|
+
label: isSubagentTask ? (subagentLabel || `subagent: ${update.name || update.title || 'task'}`) : update.name || update.id || 'done',
|
|
1198
|
+
toolType: isSubagentTask ? 'subagent' : 'tool',
|
|
1199
|
+
stepRef: `acp:callid:${toolCallId}`,
|
|
990
1200
|
status: mapped.status,
|
|
991
1201
|
...(resultText ? { detail: buildPreview(resultText, 200) } : {}),
|
|
992
1202
|
},
|
|
@@ -1036,4 +1246,68 @@ export function extractFromAcpUpdate(params) {
|
|
|
1036
1246
|
return null;
|
|
1037
1247
|
}
|
|
1038
1248
|
}
|
|
1249
|
+
export function extractFromAcpSubagent(event) {
|
|
1250
|
+
if (!event?.type || !String(event.type).startsWith('subagent.'))
|
|
1251
|
+
return null;
|
|
1252
|
+
const data = event.data || {};
|
|
1253
|
+
const display = data.agentDisplayName || data.agentName || 'subagent';
|
|
1254
|
+
const agentName = data.agentName || display;
|
|
1255
|
+
switch (event.type) {
|
|
1256
|
+
case 'subagent.selected':
|
|
1257
|
+
return {
|
|
1258
|
+
tool: {
|
|
1259
|
+
icon: '🎯',
|
|
1260
|
+
label: `selected: ${display}`,
|
|
1261
|
+
toolType: 'subagent',
|
|
1262
|
+
stepRef: `acp:subagent:selection:${agentName}`,
|
|
1263
|
+
status: 'done',
|
|
1264
|
+
detail: `tools: ${Array.isArray(data.tools) ? data.tools.join(', ') : 'all'}`,
|
|
1265
|
+
},
|
|
1266
|
+
};
|
|
1267
|
+
case 'subagent.deselected':
|
|
1268
|
+
return {
|
|
1269
|
+
tool: {
|
|
1270
|
+
icon: '⏭',
|
|
1271
|
+
label: `deselected: ${display}`,
|
|
1272
|
+
toolType: 'subagent',
|
|
1273
|
+
stepRef: `acp:subagent:selection:${agentName}`,
|
|
1274
|
+
status: 'done',
|
|
1275
|
+
},
|
|
1276
|
+
};
|
|
1277
|
+
case 'subagent.started':
|
|
1278
|
+
return {
|
|
1279
|
+
tool: {
|
|
1280
|
+
icon: '🤖',
|
|
1281
|
+
label: `subagent: ${display}`,
|
|
1282
|
+
toolType: 'subagent',
|
|
1283
|
+
stepRef: `acp:subagent:${data.toolCallId || agentName}`,
|
|
1284
|
+
status: 'running',
|
|
1285
|
+
...(data.agentDescription ? { detail: data.agentDescription } : {}),
|
|
1286
|
+
},
|
|
1287
|
+
};
|
|
1288
|
+
case 'subagent.completed':
|
|
1289
|
+
return {
|
|
1290
|
+
tool: {
|
|
1291
|
+
icon: '✅',
|
|
1292
|
+
label: `subagent: ${display}`,
|
|
1293
|
+
toolType: 'subagent',
|
|
1294
|
+
stepRef: `acp:subagent:${data.toolCallId || agentName}`,
|
|
1295
|
+
status: 'done',
|
|
1296
|
+
},
|
|
1297
|
+
};
|
|
1298
|
+
case 'subagent.failed':
|
|
1299
|
+
return {
|
|
1300
|
+
tool: {
|
|
1301
|
+
icon: '❌',
|
|
1302
|
+
label: `subagent: ${display}`,
|
|
1303
|
+
toolType: 'subagent',
|
|
1304
|
+
stepRef: `acp:subagent:${data.toolCallId || agentName}`,
|
|
1305
|
+
status: 'error',
|
|
1306
|
+
detail: `error: ${data.error || ''}`,
|
|
1307
|
+
},
|
|
1308
|
+
};
|
|
1309
|
+
default:
|
|
1310
|
+
return null;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1039
1313
|
//# sourceMappingURL=events.js.map
|