@duckmind/dm-windows-x64 0.60.6 → 0.60.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +70 -123
- package/extensions/dm-9router-ext/src/index.js +410 -5
- package/extensions/dm-caveman/extensions/caveman.js +283 -12
- package/extensions/dm-cliproxy/index.js +182 -2
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
- package/extensions/dm-cliproxy/src/apply.js +228 -1
- package/extensions/dm-cliproxy/src/cache.js +42 -1
- package/extensions/dm-cliproxy/src/commands.js +50 -2
- package/extensions/dm-cliproxy/src/compat.js +81 -1
- package/extensions/dm-cliproxy/src/config.js +192 -2
- package/extensions/dm-cliproxy/src/conflicts.js +46 -1
- package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
- package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
- package/extensions/dm-cliproxy/src/log.js +23 -1
- package/extensions/dm-cliproxy/src/status-quota.js +77 -1
- package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
- package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
- package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
- package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
- package/extensions/dm-context/src/context.js +144 -1
- package/extensions/dm-context/src/index.js +339 -7
- package/extensions/dm-context/src/utils.js +9 -1
- package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
- package/extensions/dm-cua/index.js +75 -6
- package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
- package/extensions/dm-cua/src/browser-install.mjs +331 -2
- package/extensions/dm-fff/src/index.js +688 -12
- package/extensions/dm-fff/src/query.js +60 -1
- package/extensions/dm-goal/src/goal.js +894 -23
- package/extensions/dm-image2/index.js +103 -9
- package/extensions/dm-image2/src/image-lib.mjs +1275 -8
- package/extensions/dm-subagents/install.mjs +62 -8
- package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
- package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
- package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
- package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
- package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
- package/extensions/dm-subagents/src/agents/agents.js +1139 -11
- package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
- package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
- package/extensions/dm-subagents/src/agents/identity.js +29 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
- package/extensions/dm-subagents/src/agents/skills.js +614 -6
- package/extensions/dm-subagents/src/extension/config.js +35 -2
- package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
- package/extensions/dm-subagents/src/extension/doctor.js +172 -15
- package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
- package/extensions/dm-subagents/src/extension/index.js +521 -359
- package/extensions/dm-subagents/src/extension/rpc.js +266 -7
- package/extensions/dm-subagents/src/extension/schemas.js +275 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
- package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
- package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
- package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
- package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
- package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
- package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
- package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
- package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
- package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
- package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
- package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
- package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
- package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
- package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
- package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
- package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
- package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
- package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
- package/extensions/dm-subagents/src/shared/formatters.js +98 -7
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
- package/extensions/dm-subagents/src/shared/model-info.js +62 -1
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
- package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
- package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
- package/extensions/dm-subagents/src/shared/settings.js +198 -11
- package/extensions/dm-subagents/src/shared/status-format.js +53 -1
- package/extensions/dm-subagents/src/shared/types.js +184 -6
- package/extensions/dm-subagents/src/shared/utils.js +462 -2
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
- package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
- package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
- package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
- package/extensions/dm-subagents/src/tui/render.js +1542 -4
- package/extensions/dm-usage/index.js +1294 -9
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
- package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
- package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
- package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
- package/extensions/greedysearch-dm/bin/search.mjs +620 -540
- package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
- package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
- package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
- package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
- package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
- package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
- package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
- package/extensions/greedysearch-dm/index.js +123 -23
- package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
- package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
- package/extensions/greedysearch-dm/src/github.mjs +222 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
- package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
- package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
- package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
- package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
- package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
- package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
- package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
- package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
- package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
- package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
- package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
- package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
- package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
- package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
- package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
- package/package.json +1 -1
|
@@ -1,4 +1,1542 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
|
|
3
|
-
`).find((Y)=>Y.trim())?.trim()??""}function N0($,Y){if($.detached)return $.detachedReason?`Detached: ${$.detachedReason}`:"Detached";if($.interrupted)return"Paused";if($.exitCode!==0)return`Error: ${$.error??(I0(Y)||`exit ${$.exitCode}`)}`;if($.acceptance?.status&&$.acceptance.status!=="not-required")return`Done · acceptance: ${$.acceptance.status}`;if(e($.task,Y))return"Done (no text output)";return"Done"}function R0($,Y,Z,Q=$.progress?.status==="running",X=D$($.progress??$.progressSummary),U){if(Q){if(U!==void 0)return Z.fg("accent",o((X??0)+U));return Z.fg("accent",o(X))}if($.detached)return Z.fg("warning","■");if($.interrupted)return Z.fg("warning","■");if($.exitCode!==0)return Z.fg("error","✗");if(e($.task,Y))return Z.fg("warning","✓");return Z.fg("success","✓")}function D0($){let Y=L$($);return C$($,p()-4,!1,Y)??r($,Y)??"thinking…"}function Y2($){return JSON.stringify({asyncDir:$.asyncDir,status:$.status,activityState:$.activityState,lastActivityAt:$.lastActivityAt,currentTool:$.currentTool,currentToolStartedAt:$.currentToolStartedAt,currentPath:$.currentPath,turnCount:$.turnCount,toolCount:$.toolCount,mode:$.mode,agents:$.agents,currentStep:$.currentStep,chainStepCount:$.chainStepCount,parallelGroups:$.parallelGroups,steps:$.steps,nestedChildren:$.nestedChildren,stepsTotal:$.stepsTotal,runningSteps:$.runningSteps,completedSteps:$.completedSteps,activeParallelGroup:$.activeParallelGroup,startedAt:$.startedAt,updatedAt:$.updatedAt,totalTokens:$.totalTokens})}function L0($){let Y=[...new Set($)];if(Y.length===1&&$.length>1)return`${Y[0]} ×${$.length}`;if($.length>3)return`${$.slice(0,2).join(", ")} +${$.length-2} more`;return $.join(", ")}function T$($){if($.mode==="parallel")return"parallel";if($.mode==="chain")return"chain";if($.mode==="single"&&$.agents?.length===1)return $.agents[0];if($.agents?.length)return L0($.agents);return $.mode??"subagent"}function S$($){let Y=[];if($.currentTool&&$.currentToolStartedAt!==void 0&&$.updatedAt!==void 0)Y.push(`${$.currentTool} ${b(Math.max(0,$.updatedAt-$.currentToolStartedAt))}`);else if($.currentTool)Y.push($.currentTool);if($.currentPath)Y.push(v($.currentPath));if($.turnCount!==void 0)Y.push(`${$.turnCount} turns`);if($.toolCount!==void 0)Y.push(`${$.toolCount} tools`);let Z=r($,$.updatedAt);if(Z&&Y.length)return`${Z} · ${Y.join(" · ")}`;if(Z)return Z;if(Y.length)return Y.join(" · ");if($.status==="running")return"thinking…";if($.status==="queued")return"queued…";if($.status==="paused")return"Paused";if($.status==="failed")return"Failed";return"Done"}function w$($,Y){return i(Y,$.index,$.toolCount,$.turnCount,$.tokens?.total,$.lastActivityAt,$.currentToolStartedAt,$.durationMs)}function C0($){let Y;for(let[Z,Q]of($??[]).entries())Y=i(Y,w$(Q,Z));return Y}function T0($){return i($.updatedAt,$.lastActivityAt,$.toolCount,$.turnCount,$.totalTokens?.total,$.currentStep,$.runningSteps,$.completedSteps,C0($.steps))}function l$($){let Y;for(let Z of $)Y=i(Y,T0(Z));return Y}function P$($,Y){if($.status==="running")return Y.fg("accent",o(T0($)));if($.status==="queued")return Y.fg("muted","◦");if($.status==="complete")return Y.fg("success","✓");if($.status==="paused")return Y.fg("warning","■");return Y.fg("error","✗")}function F$($,Y,Z){if($==="running")return Y.fg("accent",o(Z));if($==="complete"||$==="completed")return Y.fg("success","✓");if($==="failed")return Y.fg("error","✗");if($==="paused")return Y.fg("warning","■");return Y.fg("muted","◦")}function W$($,Y){if($==="running")return Y.fg("accent","running");if($==="complete"||$==="completed")return Y.fg("success","complete");if($==="failed")return Y.fg("error","failed");if($==="paused")return Y.fg("warning","paused");return Y.fg("dim",$)}function a0($,Y){let Z=[];if($.currentTool&&$.currentToolStartedAt!==void 0&&Y!==void 0)Z.push(`${$.currentTool} ${b(Math.max(0,Y-$.currentToolStartedAt))}`);else if($.currentTool)Z.push($.currentTool);if($.currentPath)Z.push(v($.currentPath));if($.turnCount!==void 0)Z.push(`${$.turnCount} turns`);if($.toolCount!==void 0)Z.push(`${$.toolCount} tools`);if($.tokens?.total)Z.push(v$($.tokens.total));let Q=r($,Y);if(Q&&Z.length)return`${Q} · ${Z.join(" · ")}`;if(Q)return Q;return Z.join(" · ")}function S0($,Y,Z=!1,Q=p()){if(!$.steps?.length)return[];let X=$.chainStepCount??$.steps.length,U=[];for(let q of e0(X,$.steps.length,$.parallelGroups)){let V=$.steps.slice(q.start,q.start+q.count);if(q.isParallel){let G=q0(V);U.push(` ${F$(G,Y,C0(V))} Step ${q.stepIndex+1}/${X}: ${d(Y,"parallel group")} ${Y.fg("dim","·")} ${Y.fg("dim",U0(V,q.count))}`);continue}let z=V[0];if(!z){U.push(` ${Y.fg("dim",`◦ Step ${q.stepIndex+1}/${X}: pending`)}`);continue}U.push(...w0($,Y,z,"Step",q.stepIndex+1,X,Z,Q))}return U}function z0($,Y,Z=!1,Q=p()){if(!$.steps?.length)return[];if($.mode!=="parallel"&&$.mode!=="chain")return[];if($.mode==="chain"&&!$.activeParallelGroup&&$.parallelGroups?.length)return S0($,Y,Z,Q);let X=$.stepsTotal??$.steps.length,U=[];for(let[q,V]of $.steps.entries()){let z=q===$.steps.length-1?"└":"├",G=a0(V,$.updatedAt),_=$.mode==="parallel"||$.activeParallelGroup?"Agent":"Step",M=E$(Y,V.model,V.thinking);U.push(` ${Y.fg("dim",`${z} ${F$(V.status,Y,w$(V,q))} ${_} ${q+1}/${X}: ${V.agent} · ${W$(V.status,Y)}${M}${G?` · ${G}`:""}`)}`);for(let B of A$(V.children,Y,Q,Z,$.updatedAt,Z?8:1))U.push(` ${B}`)}return U}function s0($){if(!$||!$.startsWith("[")||!$.endsWith("]"))return;let Y=$.slice(1,-1).trim();if(!Y)return 0;return Y.split("+").map((Z)=>Z.trim()).filter(Boolean).length}function k$($){if($.workflowGraph?.nodes?.length){let Q=[],X=0;for(let U of $.workflowGraph.nodes){if(U.stepIndex===void 0)continue;if(U.kind==="parallel-group"||U.kind==="dynamic-parallel-group"){let V=(U.children??[]).map((_)=>_.flatIndex).filter((_)=>typeof _==="number"),z=V.length?Math.min(...V):X,G=U.children?.length??0;Q.push({stepIndex:U.stepIndex,start:z,count:G,isParallel:!0,status:U.status,label:U.label,error:U.error}),X=Math.max(X,z+G);continue}let q=U.flatIndex??X;Q.push({stepIndex:U.stepIndex,start:q,count:1,isParallel:!1,status:U.status,label:U.label,error:U.error}),X=Math.max(X,q+1)}if(Q.length)return Q.sort((U,q)=>U.stepIndex-q.stepIndex)}if(!$.chainAgents?.length)return[];let Y=[],Z=0;for(let Q=0;Q<$.chainAgents.length;Q++){let X=$.chainAgents[Q],U=s0(X),q=U??1;Y.push({stepIndex:Q,start:Z,count:q,isParallel:U!==void 0}),Z+=q}return Y}function t0($){if($.mode!=="chain")return!1;if($.currentStepIndex===void 0)return!1;return k$($).some((Y)=>Y.stepIndex===$.currentStepIndex&&Y.isParallel)}function e0($,Y,Z=[]){let Q=[],X=0;for(let U=0;U<$;U++){let q=Z.find((V)=>V.stepIndex===U);if(q){Q.push({stepIndex:U,start:q.start,count:q.count,isParallel:!0}),X=Math.max(X,q.start+q.count);continue}Q.push({stepIndex:U,start:X,count:X<Y?1:0,isParallel:!1}),X++}return Q}function R$($){let Y=$.progress?.status;if(Y==="completed")return!0;if(Y==="running"||Y==="pending")return!1;if($.interrupted||$.detached)return!1;return $.exitCode===0}function V$($,Y){return $.workflowGraph?.nodes.some((Z)=>Y.includes(Z.status))??!1}function P0($,Y){if($.mode!=="chain"||!Y.hasParallelInChain||Y.showActiveGroupOnly)return;let Z=[];for(let Q of k$($)){if(Q.isParallel&&Q.count===0){Z.push({kind:"placeholder",rowNumber:Q.stepIndex+1,stepLabel:`Step ${Q.stepIndex+1}`,agentName:Q.label??$.chainAgents?.[Q.stepIndex]??`step-${Q.stepIndex+1}`,status:Q.status??"pending",error:Q.error});continue}for(let X=Q.start;X<Q.start+Q.count;X++)Z.push({kind:"result",resultIndex:X,rowNumber:X+1,agentName:$.results[X]?.agent??$.chainAgents?.[Q.stepIndex]??`step-${Q.stepIndex+1}`})}return Z}function y0($,Y){let Z=k$($),Q=$.mode==="chain"&&Z.some((_)=>_.isParallel),X=t0($),U=$.mode==="parallel"||X?"Agent":"Step";if($.mode==="parallel"){let _=$.totalSteps??$.results.length,M=Array(_).fill("pending");for(let W of $.progress??[])if(W.index>=0&&W.index<_)M[W.index]=W.status;for(let W=0;W<$.results.length;W++){let E=$.results[W],F=$.progress?.find((S)=>S.index===W)||$.progress?.find((S)=>S.agent===E.agent&&S.status==="running"),C=E.progress?.index??F?.index??W;if(C<0||C>=_)continue;let I=E.progress?.status??(E.interrupted||E.detached?"detached":E.exitCode===0?"completed":"failed");M[C]=I}let B=M.filter((W)=>W==="running").length,K=M.filter((W)=>W==="completed").length;return{headerLabel:Y?`${s(B)} · ${K}/${_} done`:`${K}/${_} done`,itemTitle:U,totalCount:_,hasParallelInChain:Q,activeParallelGroup:X,groupStartIndex:0,groupEndIndex:_,showActiveGroupOnly:!1}}if(X){let _=$.currentStepIndex,M=Z[_],B=M?.count??1,K=M?.start??0,D=K+B,W=0,E=0;for(let I=K;I<D;I++){let S=$.progress?.find((O)=>O.index===I),N=$.results.find((O)=>O.progress?.index===I);if(S?.status==="running"){W++;continue}if(S?.status==="completed"){E++;continue}if(N&&R$(N))E++}let F=$.totalSteps??$.chainAgents?.length??1;return{headerLabel:Y?`step ${_+1}/${F} · parallel group: ${s(W)} · ${E}/${B} done`:`step ${_+1}/${F} · parallel group: ${E}/${B} done`,itemTitle:U,totalCount:B,hasParallelInChain:Q,activeParallelGroup:X,groupStartIndex:K,groupEndIndex:D,showActiveGroupOnly:!0}}if($.mode==="chain"&&$.chainAgents?.length){let _=$.totalSteps??$.chainAgents.length,M=Z.filter((D)=>{if(D.status&&D.status!=="completed")return!1;if(D.count===0)return D.status==="completed";for(let W=D.start;W<D.start+D.count;W++){let E=$.progress?.find((C)=>C.index===W),F=$.results.find((C)=>C.progress?.index===W)??$.results[W];if(E?.status==="running"||E?.status==="pending"||E?.status==="failed")return!1;if(!F||!R$(F))return!1}return!0}).length,B=$.currentStepIndex!==void 0?$.currentStepIndex+1:Math.min(_,M+(Y?1:0));return{headerLabel:Y?`step ${B}/${_}`:`step ${M}/${_}`,itemTitle:U,totalCount:_,hasParallelInChain:Q,activeParallelGroup:X,groupStartIndex:0,groupEndIndex:$.results.length,showActiveGroupOnly:!1}}let q=$.totalSteps??$.results.length,V=$.currentStepIndex!==void 0?$.currentStepIndex+1:Math.min(q,$.results.filter(R$).length+(Y?1:0)),z=$.results.filter(R$).length;return{headerLabel:Y?`step ${V}/${q}`:`step ${z}/${q}`,itemTitle:U,totalCount:q,hasParallelInChain:Q,activeParallelGroup:X,groupStartIndex:0,groupEndIndex:$.results.length,showActiveGroupOnly:!1}}function y$($,Y,Z,Q){if($.mode==="chain"&&Y.hasParallelInChain){let X=k$($).find((U)=>Z>=U.start&&Z<U.start+U.count);if(X?.isParallel)return`Agent ${Z-X.start+1}/${X.count}`;if(X)return`Step ${X.stepIndex+1}`}if(Y.itemTitle==="Agent")return`Agent ${Y.activeParallelGroup?Math.max(1,Q-Y.groupStartIndex):Q}/${Y.totalCount}`;return`Step ${Q}`}function f$($,Y){let Z=[],Q=$.stepsTotal??($.agents?.length??1);if($.activeParallelGroup){let X=$.runningSteps??($.status==="running"?1:0),U=$.completedSteps??($.status==="complete"?Q:0);if($.mode==="parallel"){if($.status==="running"&&X>0)Z.push(s(X));if(Q>0)Z.push(`${U}/${Q} done`)}else{let V=($.currentStep!==void 0?$.parallelGroups?.find((_)=>$.currentStep>=_.start&&$.currentStep<_.start+_.count):$.parallelGroups?.find((_)=>_.start===0))?.stepIndex??$.currentStep??0,z=$.chainStepCount??Q,G=[`${U}/${Q} done`];if($.status==="running"&&X>0)G.unshift(s(X));Z.push(`step ${V+1}/${z} · parallel group: ${G.join(" · ")}`)}}else if($.currentStep!==void 0)if($.mode==="chain"&&$.parallelGroups?.length){let X=$.chainStepCount??Q;Z.push(`step ${Q0($.currentStep,X,$.parallelGroups)+1}/${X}`)}else Z.push(`step ${$.currentStep+1}/${Q}`);else if(Q>1)Z.push(`steps ${Q}`);if($.toolCount!==void 0)Z.push(n$($.toolCount));if($.totalTokens?.total)Z.push(v$($.totalTokens.total));if($.startedAt!==void 0&&$.updatedAt!==void 0)Z.push(b(Math.max(0,$.updatedAt-$.startedAt)));return M$(Y,Z)}function f0($,Y){return M$($,[Y.turnCount!==void 0?`${Y.turnCount} turns`:"",Y.toolCount!==void 0?n$(Y.toolCount):"",Y.tokens?.total?v$(Y.tokens.total):"",Y.durationMs!==void 0?b(Y.durationMs):""])}function E$($,Y,Z){let Q=Y0(Y,Z);return Q?$.fg("dim",` (${Q})`):""}function v0($,Y,Z,Q){let X=C$($,Y,Z,Q);if(X)return X;let U=r($,Q);if(U)return U;if($.status==="running")return"thinking…";return""}function $1($,Y){if(typeof Y.index!=="number")return;return F0.join($.asyncDir,`output-${Y.index}.log`)}function Y1($){if($.agent)return $.agent;if($.agents?.length)return L0($.agents);return $.id}function G0($,Y,Z){if($==="running")return Y.fg("accent",o(Z));if($==="complete"||$==="completed")return Y.fg("success","✓");if($==="failed")return Y.fg("error","✗");if($==="paused")return Y.fg("warning","■");return Y.fg("muted","◦")}function Z1($){return i($.lastUpdate,$.lastActivityAt,$.currentStep,$.toolCount,$.turnCount,$.totalTokens?.total,$.currentToolStartedAt)}function K0($,Y,Z){let Q=[];if($.currentTool&&$.currentToolStartedAt!==void 0&&Z!==void 0)Q.push(`${$.currentTool} ${b(Math.max(0,Z-$.currentToolStartedAt))}`);else if($.currentTool)Q.push($.currentTool);if($.currentPath)Q.push(v($.currentPath));if($.turnCount!==void 0)Q.push(`${$.turnCount} turns`);if($.toolCount!==void 0)Q.push(`${$.toolCount} tools`);let X=r($,Z);if(X&&Q.length)return`${X} · ${Q.join(" · ")}`;if(X)return X;if(Q.length)return Q.join(" · ");if(Y==="running")return"thinking…";if(Y==="queued"||Y==="pending")return"queued…";if(Y==="paused")return"Paused";if(Y==="failed")return"Failed";return"Done"}function A$($,Y,Z,Q,X,U=Q?12:1){if(!$?.length||U<=0)return[];if(!Q){let G=B$($);return G?[Y.fg("dim",`↳ ${G}`)]:[]}let q=[],V=2,z=(G,_,M)=>{if(!G?.length||q.length>=U)return;if(_>V){let B=B$(G);if(B&&q.length<U)q.push(Y.fg("dim",`${M}↳ ${B}`));return}for(let B=0;B<G.length;B++){let K=G[B];if(q.length>=U){let E=B$(G.slice(B));if(E)q[q.length-1]=Y.fg("dim",`${M}↳ ${E}`);return}let D=K0(K,K.state,X??K.lastUpdate),W=K.error?` · ${K.error}`:"";if(q.push(Y.fg("dim",`${M}↳ ${G0(K.state,Y,Z1(K))} ${Y1(K)} · ${K.state} · ${D}${W}`)),_===V){let E=B$([...K.steps?.flatMap((F)=>F.children??[])??[],...K.children??[]]);if(E&&q.length<U)q.push(Y.fg("dim",`${M} ↳ ${E}`));continue}for(let E of K.steps??[]){if(q.length>=U)return;q.push(Y.fg("dim",`${M} ↳ ${G0(E.status,Y)} ${E.agent} · ${E.status} · ${K0(E,E.status,X??K.lastUpdate)}`)),z(E.children,_+1,`${M} `)}z(K.children,_+1,`${M} `)}};return z($,0,""),q.map((G)=>L(G,Z))}function w0($,Y,Z,Q,X,U,q,V){let z=W$(Z.status,Y),G=f0(Y,Z),_=E$(Y,Z.model,Z.thinking),M=[` ${F$(Z.status,Y,w$(Z,X-1))} ${Q} ${X}/${U}: ${d(Y,Z.agent)} ${Y.fg("dim","·")} ${z}${_}${G?` ${Y.fg("dim","·")} ${G}`:""}`],B=v0(Z,V,q,$.updatedAt);if(B)M.push(` ${Y.fg("dim",`⎿ ${B}`)}`);for(let K of A$(Z.children,Y,V,q,$.updatedAt))M.push(` ${K}`);if(Z.status==="running"){if(!q)M.push(` ${Y.fg("accent",H$())}`);let K=$1($,Z);if(K)M.push(` ${Y.fg("dim",`output: ${v(K)}`)}`);if(q){let D=r(Z,$.updatedAt);if(D&&D!==B)M.push(` ${Y.fg("accent",D)}`);for(let W of Z.recentTools?.slice(-3)??[]){let E=Math.max(40,V-30),F=W.args.length<=E?W.args:`${W.args.slice(0,E)}...`;M.push(` ${Y.fg("dim",`${W.tool}${F?`: ${F}`:""}`)}`)}for(let W of Z.recentOutput?.slice(-5)??[])M.push(` ${Y.fg("dim",W)}`)}}return M}function Q1($,Y,Z,Q){if(!$.steps?.length)return[` ${Y.fg("dim",`⎿ ${S$($)}`)}`,...A$($.nestedChildren,Y,Q,Z,$.updatedAt).map((G)=>` ${G}`)];if($.mode==="chain"&&!$.activeParallelGroup&&$.parallelGroups?.length)return S0($,Y,Z,Q);let X=$.stepsTotal??$.steps.length,U=$.mode==="parallel"||$.activeParallelGroup?"Agent":"Step",q=[];for(let[G,_]of $.steps.entries())q.push(...w0($,Y,_,U,G+1,X,Z,Q));let V=new Set($.steps.flatMap((G)=>G.children?.map((_)=>_.id)??[])),z=$.nestedChildren?.filter((G)=>!V.has(G.id))??[];for(let G of A$(z,Y,Q,Z,$.updatedAt))q.push(` ${G}`);return q}function k0($,Y,Z,Q){let X=f$($,Y),U=$.mode==="chain"?$.chainStepCount:$.stepsTotal??$.agents?.length??$.steps?.length,q=T$($),V=`async subagent ${q}${U&&U>1?` (${U})`:""}`;return[`${Y.fg("toolTitle",d(Y,V))} ${Y.fg("dim","· background")}`,`${P$($,Y)} ${d(Y,q)}${X?` ${Y.fg("dim","·")} ${X}`:""}`,...Q1($,Y,Q,Z)].map((z)=>L(z,Z))}function X1($,Y,Z){let Q=k0($,Y,Z,!1);if(Q.length<=10||!$.steps?.length||$.mode!=="parallel"&&!$.activeParallelGroup)return Q;let X=$.stepsTotal??$.steps.length,U=$.mode==="parallel"||$.activeParallelGroup?"Agent":"Step",q=Q.slice(0,2);for(let[V,z]of $.steps.entries()){let G=W$(z.status,Y),_=v0(z,Z,!1,$.updatedAt),M=f0(Y,z),B=_?` ${Y.fg("dim","·")} ${Y.fg("dim",_)}`:"",K=E$(Y,z.model,z.thinking);q.push(` ${F$(z.status,Y,w$(z,V))} ${U} ${V+1}/${X}: ${d(Y,z.agent)} ${Y.fg("dim","·")} ${G}${K}${B}${M?` ${Y.fg("dim","·")} ${M}`:""}`);for(let D of A$(z.children,Y,Z,!1,$.updatedAt))q.push(` ${D}`)}if($.steps.some((V)=>V.status==="running"))q.push(Y.fg("accent",` ${H$()}`));return q.map((V)=>L(V,Z))}var q1=19,c;function x0(){c=void 0}function U1(){let $=process.stdout.rows||30;return Math.max(1,$-q1)}function j0(){return process.stdout.rows||30}function b0(){return process.stdout.columns||120}function V1($){return c?.expanded===$&&c.rows===j0()&&c.columns===b0()}function o$($){return{running:$.filter((Y)=>Y.status==="running"),queued:$.filter((Y)=>Y.status==="queued"),complete:$.filter((Y)=>Y.status==="complete"),failed:$.filter((Y)=>Y.status==="failed"),paused:$.filter((Y)=>Y.status==="paused")}}function p$($,Y,Z){let Q=o$($),X=Q.running.length>0||Q.queued.length>0,U=Q.running.length>0?o(l$(Q.running)):X?"●":"○",q=[];if(Q.running.length>0)q.push(`${Q.running.length}/${$.length} running`);if(Q.queued.length>0)q.push(`${Q.queued.length} queued`);if(Q.failed.length>0)q.push(`${Q.failed.length} failed`);if(Q.paused.length>0)q.push(`${Q.paused.length} paused`);if(!X&&Q.complete.length>0)q.push(`${Q.complete.length}/${$.length} done`);return[L(`${Y.fg(X?"accent":"dim",U)} ${Y.fg(X?"accent":"dim","subagents")} (${q.join(", ")||`${$.length} total`})`,Z)]}function J0($){return[...$.filter((Y)=>Y.status==="running"),...$.filter((Y)=>Y.status==="queued"),...$.filter((Y)=>Y.status!=="running"&&Y.status!=="queued")]}function t($){return $.asyncId}function u$($){return $?.status==="running"||$?.status==="queued"}function H1($,Y,Z){if(Z<=0)return[];let Q=new Map($.map((q)=>[t(q),q])),X=[],U=(q)=>{if(X.includes(q)||!Q.has(q))return;X.push(q)};for(let q of Y){if(!u$(Q.get(q)))continue;if(U(q),X.length>=Z)return X}for(let q of J0($)){if(!u$(q))continue;let V=t(q);if(U(V),X.length>=Z)break}if(X.length>=Z)return X;for(let q of Y){if(u$(Q.get(q)))continue;if(U(q),X.length>=Z)return X}for(let q of J0($)){let V=t(q);if(U(V),X.length>=Z)break}return X}function _1($,Y,Z){let Q=o$($),X=Q.running.length>0||Q.queued.length>0,U=Q.running.length>0?o(l$(Q.running)):X?"●":"○",q=[];if(Q.running.length>0)q.push(s(Q.running.length));if(Q.queued.length>0)q.push(`${Q.queued.length} queued`);if(!X){if(Q.failed.length>0)q.push(`${Q.failed.length} failed`);if(Q.paused.length>0)q.push(`${Q.paused.length} paused`);if(Q.complete.length>0)q.push(`${Q.complete.length}/${$.length} done`)}return L(`${Y.fg(X?"accent":"dim",U)} ${Y.fg(X?"accent":"dim","Async agents")} ${Y.fg("dim","·")} ${Y.fg("dim",q.join(", ")||`${$.length} total`)}`,Z)}function z1($,Y,Z){let Q=f$($,Y),X=S$($),U=$.status==="complete"?"done":$.status,q=[d(Y,T$($)),Y.fg("dim",U),Q,X&&X.toLowerCase()!==U?Y.fg("dim",X):""].filter(Boolean);return L(` ${P$($,Y)} ${q.join(` ${Y.fg("dim","·")} `)}`,Z)}function G1($,Y,Z){let Q=o$($),X=[];if(Q.running.length>0)X.push(`${Q.running.length} running`);if(Q.queued.length>0)X.push(`${Q.queued.length} queued`);let U=Q.complete.length+Q.failed.length+Q.paused.length;if(U>0)X.push(`${U} finished`);return L(Y.fg("dim",` +${$.length} more${X.length?` (${X.join(", ")})`:""}`),Z)}function B0($,Y,Z,Q,X){let U=Math.max(1,Q);if(U===1)return{lines:p$($,Y,Z),visibleJobKeys:[]};let q=U-1,V=H1($,X,q),z=new Map($.map((K)=>[t(K),K])),G=V.map((K)=>z.get(K)).filter((K)=>Boolean(K)),_=$.filter((K)=>!V.includes(t(K)));if(_.length>0&&G.length>=q&&q>0)G=G.slice(0,q-1),V=G.map(t),_=$.filter((K)=>!V.includes(t(K)));let B=[_1($,Y,Z),...G.map((K)=>z1(K,Y,Z))];if(_.length>0&&B.length<U)B.push(G1(_,Y,Z));while(B.length<U)B.push(" ");return{lines:B.slice(0,U),visibleJobKeys:V}}function c0($){return Math.max(10,Math.min(14,Math.floor($*0.35)))}function A0($,Y,Z,Q){let X=process.stdout.rows||30,U=Q?Math.max(12,Math.min(24,Math.floor(X*0.55))):c0(X);if($.length<=U)return $;let q=Math.max(1,U-1),V=$.length-q,z=Q?`… ${V} live-detail lines hidden`:`… ${V} lines hidden · ${W0()} expands`;return[...$.slice(0,q),L(Y.fg("dim",z),Z)]}function K1($,Y,Z,Q,X){if(X)return x0(),A0(Y,Z,Q,!0);let U=V1(X),q=j0(),V=b0(),z=U1();if(U&&c?.tier==="single-line")return p$($,Z,Q);if(U&&c?.tier==="progressive"&&c.lockedRows!==void 0){let M=B0($,Z,Q,c.lockedRows,c.visibleJobKeys);return c.visibleJobKeys=M.visibleJobKeys,M.lines}if(Y.length<=z)return c={expanded:X,rows:q,columns:V,tier:"full",visibleJobKeys:[]},A0(Y,Z,Q,!1);if(z<=2)return c={expanded:X,rows:q,columns:V,tier:"single-line",visibleJobKeys:[]},p$($,Z,Q);let G=Math.min(z,c0(q)),_=B0($,Z,Q,G,[]);return c={expanded:X,rows:q,columns:V,tier:"progressive",lockedRows:G,visibleJobKeys:_.visibleJobKeys},_.lines}function J1($,Y){return(Z,Q)=>{let X=p(),U=Y?M0($,Q,X,!0):$.length===1?X1($[0],Q,X):M0($,Q,X,!1),q=new U$;for(let V of K1($,U,Q,X,Y))q.addChild(new J(V,1,0));return q}}function M0($,Y,Z=p(),Q=!1){if($.length===0)return[];if($.length===1)return k0($[0],Y,Z,Q);let X=$.filter((F)=>F.status==="running"),U=$.filter((F)=>F.status==="queued"),q=$.filter((F)=>F.status!=="running"&&F.status!=="queued"),V=[],z=X.length>0||U.length>0,G=X.length>0?o(l$(X)):z?"●":"○";V.push(L(`${Y.fg(z?"accent":"dim",G)} ${Y.fg(z?"accent":"dim","Async agents")} ${Y.fg("dim","· background")}`,Z));let _=[],M=0,B=0,K=!1,D=t$;for(let F of X){if(D<=0){M++;continue}let C=f$(F,Y);_.push([`${P$(F,Y)} ${d(Y,T$(F))}${C?` ${Y.fg("dim","·")} ${C}`:""}`,` ${Y.fg("dim",`⎿ ${S$(F)}`)}`,...z0(F,Y,Q,Z)]),D--}if(U.length>0&&D>0)_.push([`${Y.fg("muted","◦")} ${Y.fg("dim",`${U.length} queued`)}`]),K=!0,D--;for(let F of q){if(D<=0){B++;continue}let C=f$(F,Y);_.push([`${P$(F,Y)} ${d(Y,T$(F))}${C?` ${Y.fg("dim","·")} ${C}`:""}`,` ${Y.fg("dim",`⎿ ${S$(F)}`)}`,...z0(F,Y,Q,Z)]),D--}let W=U.length>0&&!K?U.length:0,E=M+B+W;if(E>0){let F=[];if(M>0)F.push(`${M} running`);if(W>0)F.push(`${W} queued`);if(B>0)F.push(`${B} finished`);_.push([Y.fg("dim",`+${E} more (${F.join(", ")})`)])}for(let F=0;F<_.length;F++){let C=_[F],I=F===_.length-1,S=I?"└─":"├─",N=I?" ":"│ ";V.push(L(`${Y.fg("dim",S)} ${C[0]}`,Z));for(let O of C.slice(1))V.push(L(`${Y.fg("dim",N)} ${O}`,Z))}return V}function Z2($,Y){if(Y.length===0){if(x0(),$.hasUI)$.ui.setWidget(j$,void 0);return}if(!$.hasUI)return;$.ui.setWidget(j$,J1(Y,$.ui.getToolsExpanded?.()??!1))}function B1($,Y,Z,Q){let X=Y.truncation?.text||a(Y),U=Y.progress||Y.progressSummary,q=Y.progress?.status==="running",V=$.context==="fork"?Z.fg("warning"," [fork]"):"",z=M$(Z,[Y.usage?.turns?`⟳ ${Y.usage.turns}`:"",h$(Z,U)]),G=new U$,_=p()-4,M=E$(Z,Y.model);if(G.addChild(new J(L(`${R0(Y,X,Z,q,void 0,Q)} ${Z.fg("toolTitle",Z.bold(Y.agent))}${M}${V}${z?` ${Z.fg("dim","·")} ${z}`:""}`,_),0,0)),q&&Y.progress){let K=L$(Y.progress),D=D0(Y.progress);G.addChild(new J(L(Z.fg("dim",` ⎿ ${D}`),_),0,0));let W=r(Y.progress,K);if(W&&W!==D)G.addChild(new J(L(Z.fg("dim",` ${W}`),_),0,0));if(G.addChild(new J(L(Z.fg("accent",` ${H$()}`),_),0,0)),Y.artifactPaths)G.addChild(new J(L(Z.fg("dim",` output: ${v(Y.artifactPaths.outputPath)}`),_),0,0));return G}G.addChild(new J(L(Z.fg("dim",` ⎿ ${N0(Y,X)}`),_),0,0));let B=I0(X);if(B&&Y.exitCode===0&&!e(Y.task,X))G.addChild(new J(L(Z.fg("dim",` ${B}`),_),0,0));if(Y.sessionFile)G.addChild(new J(L(Z.fg("dim",` session: ${v(Y.sessionFile)}`),_),0,0));if(Y.artifactPaths)G.addChild(new J(L(Z.fg("dim",` output: ${v(Y.artifactPaths.outputPath)}`),_),0,0));if(Y.truncation?.artifactPath)G.addChild(new J(L(Z.fg("dim",` full output: ${v(Y.truncation.artifactPath)}`),_),0,0));return G}function A1($,Y,Z){let Q=$.progress?.some((I)=>I.status==="running")||$.results.some((I)=>I.progress?.status==="running")||V$($,["running"]),X=$.results.some((I)=>I.exitCode!==0&&I.progress?.status!=="running")||V$($,["failed"]),U=$.results.some((I)=>(I.interrupted||I.detached)&&I.progress?.status!=="running")||V$($,["paused","detached"]),q=$.progressSummary;if(!q){let I=!1,S={toolCount:0,tokens:0,durationMs:0};for(let N of $.results){let O=N.progress||N.progressSummary;if(!O)continue;I=!0,S.toolCount+=O.toolCount,S.tokens+=O.tokens,S.durationMs=$.mode==="chain"?S.durationMs+O.durationMs:Math.max(S.durationMs,O.durationMs)}if(I)q=S}let V=y0($,Q),z=V.itemTitle,G=M$(Y,[V.headerLabel,h$(Y,q),O0($.totalCost)]),_=Q?Y.fg("accent",o(Z!==void 0?(i(D$(q),$.currentStepIndex)??0)+Z:i(D$(q),$.currentStepIndex))):X?Y.fg("error","✗"):U?Y.fg("warning","■"):Y.fg("success","✓"),M=$.context==="fork"?Y.fg("warning"," [fork]"):"",B=new U$,K=p()-4;B.addChild(new J(L(`${_} ${Y.fg("toolTitle",Y.bold($.mode))}${M}${G?` ${Y.fg("dim","·")} ${G}`:""}`,K),0,0));let D=V.hasParallelInChain||!$.chainAgents?.length,W=V.showActiveGroupOnly?V.groupStartIndex:0,E=V.showActiveGroupOnly?V.groupEndIndex:D?$.results.length:$.chainAgents.length,F=P0($,V),C=F??Array.from({length:E-W},(I,S)=>{let N=W+S,O=$.results[N],R=z.toLowerCase(),m=V.showActiveGroupOnly?N-V.groupStartIndex+1:N+1;return{kind:"result",resultIndex:N,rowNumber:m,agentName:D?O?.agent||`${R}-${m}`:$.chainAgents[N]||O?.agent||`${R}-${m}`}});for(let I of C){if(I.kind==="placeholder"){let T=F$(I.status,Y),Y$=W$(I.status,Y);if(B.addChild(new J(L(` ${T} ${I.stepLabel}: ${d(Y,I.agentName)} ${Y.fg("dim","·")} ${Y$}`,K),0,0)),I.error)B.addChild(new J(L(Y.fg("error",` ⎿ Error: ${I.error}`),K),0,0));continue}let S=I.resultIndex,N=$.results[S],O=I.rowNumber,R=I.agentName;if(!N){let T=F?y$($,V,S,O):`${z} ${O}`;B.addChild(new J(L(Y.fg("dim",` ◦ ${T}: ${R} · pending`),K),0,0));continue}let m=a(N),$$=$.progress?.find((T)=>T.index===S)||$.progress?.find((T)=>T.agent===N.agent&&T.status==="running"),x=N.progress||$$||N.progressSummary,_$=x&&"status"in x&&x.status==="running",z$=x&&"status"in x&&x.status==="pending",H=N.progress?.index!==void 0?N.progress.index+1:$$?.index!==void 0?$$.index+1:S+1,y=h$(Y,x),A=z$?Y.fg("dim","◦"):R0(N,m,Y,_$,D$(x),Z),k=z$?` ${Y.fg("dim","· pending")}`:"",w=y$($,V,S,H),n=`${A} ${w}: ${d(Y,R)}${y?` ${Y.fg("dim","·")} ${y}`:""}${k}`;if(B.addChild(new J(L(` ${n}`,K),0,0)),_$&&x&&"status"in x){let T=D0(x);B.addChild(new J(L(Y.fg("dim",` ⎿ ${T}`),K),0,0)),B.addChild(new J(L(Y.fg("accent",` ${H$()}`),K),0,0))}else if(!z$&&(N.exitCode!==0||N.interrupted||N.detached||e(N.task,m)))B.addChild(new J(L(Y.fg(N.exitCode!==0?"error":"dim",` ⎿ ${N0(N,m)}`),K),0,0));let P=d$(N.task);if(P)B.addChild(new J(L(Y.fg("dim",` output: ${P}`),K),0,0));if(N.artifactPaths)B.addChild(new J(L(Y.fg("dim",` output: ${v(N.artifactPaths.outputPath)}`),K),0,0))}if($.artifacts)B.addChild(new J(L(Y.fg("dim",` artifacts: ${v($.artifacts.dir)}`),K),0,0));return B}function Q2($,Y,Z,Q){let X=$.details;if(!X||!X.results.length){let H=$.content[0],y=H?.type==="text"?H.text:"(no output)",A=X?.context==="fork"?`${Z.fg("warning","[fork]")} `:"",k=p()-4;if(!y.includes(`
|
|
4
|
-
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { getMarkdownTheme, keyText } from "@duckmind/dm-coding-agent";
|
|
3
|
+
import { Container, Markdown, Spacer, Text, visibleWidth } from "@duckmind/dm-tui";
|
|
4
|
+
import {
|
|
5
|
+
MAX_WIDGET_JOBS,
|
|
6
|
+
WIDGET_KEY
|
|
7
|
+
} from "../shared/types.js";
|
|
8
|
+
import { formatTokens, formatUsage, formatDuration, formatModelThinking, formatToolCall, shortenPath } from "../shared/formatters.js";
|
|
9
|
+
import { getDisplayItems, getSingleResultOutput } from "../shared/utils.js";
|
|
10
|
+
import { flatToLogicalStepIndex } from "../runs/background/parallel-groups.js";
|
|
11
|
+
import { formatNestedAggregate } from "../runs/shared/nested-render.js";
|
|
12
|
+
import { aggregateStepStatus, formatActivityLabel, formatAgentRunningLabel, formatParallelOutcome } from "../shared/status-format.js";
|
|
13
|
+
function liveDetailKeyText() {
|
|
14
|
+
return keyText("app.tools.expand");
|
|
15
|
+
}
|
|
16
|
+
function liveDetailHintText() {
|
|
17
|
+
return `Press ${liveDetailKeyText()} for live detail`;
|
|
18
|
+
}
|
|
19
|
+
function getTermWidth() {
|
|
20
|
+
return process.stdout.columns || 120;
|
|
21
|
+
}
|
|
22
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
23
|
+
function truncLine(text, maxWidth) {
|
|
24
|
+
if (visibleWidth(text) <= maxWidth)
|
|
25
|
+
return text;
|
|
26
|
+
const targetWidth = maxWidth - 1;
|
|
27
|
+
let result = "";
|
|
28
|
+
let currentWidth = 0;
|
|
29
|
+
let activeStyles = [];
|
|
30
|
+
let i = 0;
|
|
31
|
+
while (i < text.length) {
|
|
32
|
+
const ansiMatch = text.slice(i).match(/^\x1b\[[0-9;]*m/);
|
|
33
|
+
if (ansiMatch) {
|
|
34
|
+
const code = ansiMatch[0];
|
|
35
|
+
result += code;
|
|
36
|
+
if (code === "\x1B[0m" || code === "\x1B[m") {
|
|
37
|
+
activeStyles = [];
|
|
38
|
+
} else {
|
|
39
|
+
activeStyles.push(code);
|
|
40
|
+
}
|
|
41
|
+
i += code.length;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
let end = i;
|
|
45
|
+
while (end < text.length && !text.slice(end).match(/^\x1b\[[0-9;]*m/)) {
|
|
46
|
+
end++;
|
|
47
|
+
}
|
|
48
|
+
const textPortion = text.slice(i, end);
|
|
49
|
+
for (const seg of segmenter.segment(textPortion)) {
|
|
50
|
+
const grapheme = seg.segment;
|
|
51
|
+
const graphemeWidth = visibleWidth(grapheme);
|
|
52
|
+
if (currentWidth + graphemeWidth > targetWidth) {
|
|
53
|
+
return result + activeStyles.join("") + "…";
|
|
54
|
+
}
|
|
55
|
+
result += grapheme;
|
|
56
|
+
currentWidth += graphemeWidth;
|
|
57
|
+
}
|
|
58
|
+
i = end;
|
|
59
|
+
}
|
|
60
|
+
return result + activeStyles.join("") + "…";
|
|
61
|
+
}
|
|
62
|
+
function wrapPlainText(text, maxWidth) {
|
|
63
|
+
if (maxWidth <= 0)
|
|
64
|
+
return [""];
|
|
65
|
+
const lines = [];
|
|
66
|
+
for (const rawLine of text.split(`
|
|
67
|
+
`)) {
|
|
68
|
+
if (rawLine.length === 0) {
|
|
69
|
+
lines.push("");
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
let current = "";
|
|
73
|
+
let currentWidth = 0;
|
|
74
|
+
for (const seg of segmenter.segment(rawLine)) {
|
|
75
|
+
const grapheme = seg.segment;
|
|
76
|
+
const graphemeWidth = visibleWidth(grapheme);
|
|
77
|
+
if (currentWidth > 0 && currentWidth + graphemeWidth > maxWidth) {
|
|
78
|
+
lines.push(current);
|
|
79
|
+
current = grapheme;
|
|
80
|
+
currentWidth = graphemeWidth;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
current += grapheme;
|
|
84
|
+
currentWidth += graphemeWidth;
|
|
85
|
+
}
|
|
86
|
+
lines.push(current);
|
|
87
|
+
}
|
|
88
|
+
return lines;
|
|
89
|
+
}
|
|
90
|
+
const RUNNING_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
91
|
+
const STATIC_RUNNING_GLYPH = "●";
|
|
92
|
+
function runningSeed(...values) {
|
|
93
|
+
let seed;
|
|
94
|
+
for (const value of values) {
|
|
95
|
+
if (value === undefined || !Number.isFinite(value))
|
|
96
|
+
continue;
|
|
97
|
+
seed = (seed ?? 0) + Math.trunc(value);
|
|
98
|
+
}
|
|
99
|
+
return seed;
|
|
100
|
+
}
|
|
101
|
+
function runningGlyph(seed) {
|
|
102
|
+
if (seed === undefined)
|
|
103
|
+
return STATIC_RUNNING_GLYPH;
|
|
104
|
+
return RUNNING_FRAMES[Math.abs(seed) % RUNNING_FRAMES.length];
|
|
105
|
+
}
|
|
106
|
+
function progressRunningSeed(progress) {
|
|
107
|
+
if (!progress)
|
|
108
|
+
return;
|
|
109
|
+
return runningSeed(progress.index, progress.toolCount, progress.tokens, progress.durationMs, progress.lastActivityAt, progress.currentToolStartedAt, progress.turnCount);
|
|
110
|
+
}
|
|
111
|
+
export function clearLegacyResultAnimationTimer(context) {
|
|
112
|
+
const timer = context.state.subagentResultAnimationTimer;
|
|
113
|
+
if (!timer)
|
|
114
|
+
return;
|
|
115
|
+
clearInterval(timer);
|
|
116
|
+
context.state.subagentResultAnimationTimer = undefined;
|
|
117
|
+
}
|
|
118
|
+
function extractOutputTarget(task) {
|
|
119
|
+
const writeToMatch = task.match(/\[Write to:\s*([^\]\n]+)\]/i);
|
|
120
|
+
if (writeToMatch?.[1]?.trim())
|
|
121
|
+
return writeToMatch[1].trim();
|
|
122
|
+
const findingsMatch = task.match(/Write your findings to(?: exactly this path)?:\s*([^\r\n]+)/i);
|
|
123
|
+
if (findingsMatch?.[1]?.trim())
|
|
124
|
+
return findingsMatch[1].trim();
|
|
125
|
+
const outputMatch = task.match(/[Oo]utput(?:\s+to)?\s*:\s*(\S+)/i);
|
|
126
|
+
if (outputMatch?.[1]?.trim())
|
|
127
|
+
return outputMatch[1].trim();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
function hasEmptyTextOutputWithoutOutputTarget(task, output) {
|
|
131
|
+
if (output.trim())
|
|
132
|
+
return false;
|
|
133
|
+
return !extractOutputTarget(task);
|
|
134
|
+
}
|
|
135
|
+
function getToolCallLines(result, expanded) {
|
|
136
|
+
if (result.messages) {
|
|
137
|
+
return getDisplayItems(result.messages).filter((item) => item.type === "tool").map((item) => formatToolCall(item.name, item.args, expanded));
|
|
138
|
+
}
|
|
139
|
+
return result.toolCalls?.map((toolCall) => expanded ? toolCall.expandedText : toolCall.text) ?? [];
|
|
140
|
+
}
|
|
141
|
+
function snapshotNowForProgress(progress) {
|
|
142
|
+
if (progress.currentToolStartedAt !== undefined && progress.durationMs !== undefined)
|
|
143
|
+
return progress.currentToolStartedAt + progress.durationMs;
|
|
144
|
+
return progress.lastActivityAt;
|
|
145
|
+
}
|
|
146
|
+
function formatCurrentToolLine(progress, availableWidth, expanded, snapshotNow) {
|
|
147
|
+
if (!progress.currentTool)
|
|
148
|
+
return;
|
|
149
|
+
const maxToolArgsLen = Math.max(50, availableWidth - 20);
|
|
150
|
+
const toolArgsPreview = progress.currentToolArgs ? expanded || progress.currentToolArgs.length <= maxToolArgsLen ? progress.currentToolArgs : `${progress.currentToolArgs.slice(0, maxToolArgsLen)}...` : "";
|
|
151
|
+
const durationSuffix = progress.currentToolStartedAt !== undefined && snapshotNow !== undefined ? ` | ${formatDuration(Math.max(0, snapshotNow - progress.currentToolStartedAt))}` : "";
|
|
152
|
+
return toolArgsPreview ? `${progress.currentTool}: ${toolArgsPreview}${durationSuffix}` : `${progress.currentTool}${durationSuffix}`;
|
|
153
|
+
}
|
|
154
|
+
function buildLiveStatusLine(progress, snapshotNow) {
|
|
155
|
+
if (progress.lastActivityAt !== undefined && snapshotNow !== undefined)
|
|
156
|
+
return formatActivityLabel(progress.lastActivityAt, progress.activityState, snapshotNow);
|
|
157
|
+
if (progress.activityState === "needs_attention")
|
|
158
|
+
return "needs attention";
|
|
159
|
+
if (progress.activityState === "active_long_running")
|
|
160
|
+
return "active but long-running";
|
|
161
|
+
if (progress.lastActivityAt !== undefined)
|
|
162
|
+
return "active";
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
function themeBold(theme, text) {
|
|
166
|
+
return theme.bold?.(text) ?? text;
|
|
167
|
+
}
|
|
168
|
+
function statJoin(theme, parts) {
|
|
169
|
+
return parts.filter(Boolean).map((part) => theme.fg("dim", part)).join(` ${theme.fg("dim", "·")} `);
|
|
170
|
+
}
|
|
171
|
+
function formatTokenStat(tokens) {
|
|
172
|
+
return `${formatTokens(tokens)} token`;
|
|
173
|
+
}
|
|
174
|
+
function formatToolUseStat(count) {
|
|
175
|
+
return `${count} tool use${count === 1 ? "" : "s"}`;
|
|
176
|
+
}
|
|
177
|
+
function formatTotalCostStat(totalCost) {
|
|
178
|
+
if (!totalCost || totalCost.inputTokens === 0 && totalCost.outputTokens === 0 && totalCost.costUsd === 0)
|
|
179
|
+
return "";
|
|
180
|
+
const parts = [];
|
|
181
|
+
if (totalCost.inputTokens)
|
|
182
|
+
parts.push(`in:${formatTokens(totalCost.inputTokens)}`);
|
|
183
|
+
if (totalCost.outputTokens)
|
|
184
|
+
parts.push(`out:${formatTokens(totalCost.outputTokens)}`);
|
|
185
|
+
if (totalCost.costUsd)
|
|
186
|
+
parts.push(`$${totalCost.costUsd.toFixed(4)}`);
|
|
187
|
+
return parts.join(" ");
|
|
188
|
+
}
|
|
189
|
+
function formatProgressStats(theme, progress, includeDuration = true) {
|
|
190
|
+
if (!progress)
|
|
191
|
+
return "";
|
|
192
|
+
const parts = [];
|
|
193
|
+
if (progress.toolCount > 0)
|
|
194
|
+
parts.push(formatToolUseStat(progress.toolCount));
|
|
195
|
+
if (progress.tokens > 0)
|
|
196
|
+
parts.push(formatTokenStat(progress.tokens));
|
|
197
|
+
if (includeDuration && progress.durationMs > 0)
|
|
198
|
+
parts.push(formatDuration(progress.durationMs));
|
|
199
|
+
return statJoin(theme, parts);
|
|
200
|
+
}
|
|
201
|
+
function firstOutputLine(text) {
|
|
202
|
+
return text.split(`
|
|
203
|
+
`).find((line) => line.trim())?.trim() ?? "";
|
|
204
|
+
}
|
|
205
|
+
function resultStatusLine(result, output) {
|
|
206
|
+
if (result.detached)
|
|
207
|
+
return result.detachedReason ? `Detached: ${result.detachedReason}` : "Detached";
|
|
208
|
+
if (result.interrupted)
|
|
209
|
+
return "Paused";
|
|
210
|
+
if (result.exitCode !== 0)
|
|
211
|
+
return `Error: ${result.error ?? (firstOutputLine(output) || `exit ${result.exitCode}`)}`;
|
|
212
|
+
if (result.acceptance?.status && result.acceptance.status !== "not-required")
|
|
213
|
+
return `Done · acceptance: ${result.acceptance.status}`;
|
|
214
|
+
if (hasEmptyTextOutputWithoutOutputTarget(result.task, output))
|
|
215
|
+
return "Done (no text output)";
|
|
216
|
+
return "Done";
|
|
217
|
+
}
|
|
218
|
+
function resultGlyph(result, output, theme, running = result.progress?.status === "running", seed = progressRunningSeed(result.progress ?? result.progressSummary), frame) {
|
|
219
|
+
if (running) {
|
|
220
|
+
if (frame !== undefined)
|
|
221
|
+
return theme.fg("accent", runningGlyph((seed ?? 0) + frame));
|
|
222
|
+
return theme.fg("accent", runningGlyph(seed));
|
|
223
|
+
}
|
|
224
|
+
if (result.detached)
|
|
225
|
+
return theme.fg("warning", "■");
|
|
226
|
+
if (result.interrupted)
|
|
227
|
+
return theme.fg("warning", "■");
|
|
228
|
+
if (result.exitCode !== 0)
|
|
229
|
+
return theme.fg("error", "✗");
|
|
230
|
+
if (hasEmptyTextOutputWithoutOutputTarget(result.task, output))
|
|
231
|
+
return theme.fg("warning", "✓");
|
|
232
|
+
return theme.fg("success", "✓");
|
|
233
|
+
}
|
|
234
|
+
function compactCurrentActivity(progress) {
|
|
235
|
+
const snapshotNow = snapshotNowForProgress(progress);
|
|
236
|
+
return formatCurrentToolLine(progress, getTermWidth() - 4, false, snapshotNow) ?? buildLiveStatusLine(progress, snapshotNow) ?? "thinking…";
|
|
237
|
+
}
|
|
238
|
+
export function widgetRenderKey(job) {
|
|
239
|
+
return JSON.stringify({
|
|
240
|
+
asyncDir: job.asyncDir,
|
|
241
|
+
status: job.status,
|
|
242
|
+
activityState: job.activityState,
|
|
243
|
+
lastActivityAt: job.lastActivityAt,
|
|
244
|
+
currentTool: job.currentTool,
|
|
245
|
+
currentToolStartedAt: job.currentToolStartedAt,
|
|
246
|
+
currentPath: job.currentPath,
|
|
247
|
+
turnCount: job.turnCount,
|
|
248
|
+
toolCount: job.toolCount,
|
|
249
|
+
mode: job.mode,
|
|
250
|
+
agents: job.agents,
|
|
251
|
+
currentStep: job.currentStep,
|
|
252
|
+
chainStepCount: job.chainStepCount,
|
|
253
|
+
parallelGroups: job.parallelGroups,
|
|
254
|
+
steps: job.steps,
|
|
255
|
+
nestedChildren: job.nestedChildren,
|
|
256
|
+
stepsTotal: job.stepsTotal,
|
|
257
|
+
runningSteps: job.runningSteps,
|
|
258
|
+
completedSteps: job.completedSteps,
|
|
259
|
+
activeParallelGroup: job.activeParallelGroup,
|
|
260
|
+
startedAt: job.startedAt,
|
|
261
|
+
updatedAt: job.updatedAt,
|
|
262
|
+
totalTokens: job.totalTokens
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function formatWidgetAgents(agents) {
|
|
266
|
+
const distinct = [...new Set(agents)];
|
|
267
|
+
if (distinct.length === 1 && agents.length > 1)
|
|
268
|
+
return `${distinct[0]} ×${agents.length}`;
|
|
269
|
+
if (agents.length > 3)
|
|
270
|
+
return `${agents.slice(0, 2).join(", ")} +${agents.length - 2} more`;
|
|
271
|
+
return agents.join(", ");
|
|
272
|
+
}
|
|
273
|
+
function widgetJobName(job) {
|
|
274
|
+
if (job.mode === "parallel")
|
|
275
|
+
return "parallel";
|
|
276
|
+
if (job.mode === "chain")
|
|
277
|
+
return "chain";
|
|
278
|
+
if (job.mode === "single" && job.agents?.length === 1)
|
|
279
|
+
return job.agents[0];
|
|
280
|
+
if (job.agents?.length)
|
|
281
|
+
return formatWidgetAgents(job.agents);
|
|
282
|
+
return job.mode ?? "subagent";
|
|
283
|
+
}
|
|
284
|
+
function widgetActivity(job) {
|
|
285
|
+
const facts = [];
|
|
286
|
+
if (job.currentTool && job.currentToolStartedAt !== undefined && job.updatedAt !== undefined)
|
|
287
|
+
facts.push(`${job.currentTool} ${formatDuration(Math.max(0, job.updatedAt - job.currentToolStartedAt))}`);
|
|
288
|
+
else if (job.currentTool)
|
|
289
|
+
facts.push(job.currentTool);
|
|
290
|
+
if (job.currentPath)
|
|
291
|
+
facts.push(shortenPath(job.currentPath));
|
|
292
|
+
if (job.turnCount !== undefined)
|
|
293
|
+
facts.push(`${job.turnCount} turns`);
|
|
294
|
+
if (job.toolCount !== undefined)
|
|
295
|
+
facts.push(`${job.toolCount} tools`);
|
|
296
|
+
const activity = buildLiveStatusLine(job, job.updatedAt);
|
|
297
|
+
if (activity && facts.length)
|
|
298
|
+
return `${activity} · ${facts.join(" · ")}`;
|
|
299
|
+
if (activity)
|
|
300
|
+
return activity;
|
|
301
|
+
if (facts.length)
|
|
302
|
+
return facts.join(" · ");
|
|
303
|
+
if (job.status === "running")
|
|
304
|
+
return "thinking…";
|
|
305
|
+
if (job.status === "queued")
|
|
306
|
+
return "queued…";
|
|
307
|
+
if (job.status === "paused")
|
|
308
|
+
return "Paused";
|
|
309
|
+
if (job.status === "failed")
|
|
310
|
+
return "Failed";
|
|
311
|
+
return "Done";
|
|
312
|
+
}
|
|
313
|
+
function widgetStepRunningSeed(step, fallbackIndex) {
|
|
314
|
+
return runningSeed(fallbackIndex, step.index, step.toolCount, step.turnCount, step.tokens?.total, step.lastActivityAt, step.currentToolStartedAt, step.durationMs);
|
|
315
|
+
}
|
|
316
|
+
function widgetStepsRunningSeed(steps) {
|
|
317
|
+
let seed;
|
|
318
|
+
for (const [index, step] of (steps ?? []).entries())
|
|
319
|
+
seed = runningSeed(seed, widgetStepRunningSeed(step, index));
|
|
320
|
+
return seed;
|
|
321
|
+
}
|
|
322
|
+
function widgetJobRunningSeed(job) {
|
|
323
|
+
return runningSeed(job.updatedAt, job.lastActivityAt, job.toolCount, job.turnCount, job.totalTokens?.total, job.currentStep, job.runningSteps, job.completedSteps, widgetStepsRunningSeed(job.steps));
|
|
324
|
+
}
|
|
325
|
+
function widgetJobsRunningSeed(jobs) {
|
|
326
|
+
let seed;
|
|
327
|
+
for (const job of jobs)
|
|
328
|
+
seed = runningSeed(seed, widgetJobRunningSeed(job));
|
|
329
|
+
return seed;
|
|
330
|
+
}
|
|
331
|
+
function widgetStatusGlyph(job, theme) {
|
|
332
|
+
if (job.status === "running")
|
|
333
|
+
return theme.fg("accent", runningGlyph(widgetJobRunningSeed(job)));
|
|
334
|
+
if (job.status === "queued")
|
|
335
|
+
return theme.fg("muted", "◦");
|
|
336
|
+
if (job.status === "complete")
|
|
337
|
+
return theme.fg("success", "✓");
|
|
338
|
+
if (job.status === "paused")
|
|
339
|
+
return theme.fg("warning", "■");
|
|
340
|
+
return theme.fg("error", "✗");
|
|
341
|
+
}
|
|
342
|
+
function widgetStepGlyph(status, theme, seed) {
|
|
343
|
+
if (status === "running")
|
|
344
|
+
return theme.fg("accent", runningGlyph(seed));
|
|
345
|
+
if (status === "complete" || status === "completed")
|
|
346
|
+
return theme.fg("success", "✓");
|
|
347
|
+
if (status === "failed")
|
|
348
|
+
return theme.fg("error", "✗");
|
|
349
|
+
if (status === "paused")
|
|
350
|
+
return theme.fg("warning", "■");
|
|
351
|
+
return theme.fg("muted", "◦");
|
|
352
|
+
}
|
|
353
|
+
function widgetStepStatus(status, theme) {
|
|
354
|
+
if (status === "running")
|
|
355
|
+
return theme.fg("accent", "running");
|
|
356
|
+
if (status === "complete" || status === "completed")
|
|
357
|
+
return theme.fg("success", "complete");
|
|
358
|
+
if (status === "failed")
|
|
359
|
+
return theme.fg("error", "failed");
|
|
360
|
+
if (status === "paused")
|
|
361
|
+
return theme.fg("warning", "paused");
|
|
362
|
+
return theme.fg("dim", status);
|
|
363
|
+
}
|
|
364
|
+
function widgetStepActivity(step, snapshotNow) {
|
|
365
|
+
const facts = [];
|
|
366
|
+
if (step.currentTool && step.currentToolStartedAt !== undefined && snapshotNow !== undefined)
|
|
367
|
+
facts.push(`${step.currentTool} ${formatDuration(Math.max(0, snapshotNow - step.currentToolStartedAt))}`);
|
|
368
|
+
else if (step.currentTool)
|
|
369
|
+
facts.push(step.currentTool);
|
|
370
|
+
if (step.currentPath)
|
|
371
|
+
facts.push(shortenPath(step.currentPath));
|
|
372
|
+
if (step.turnCount !== undefined)
|
|
373
|
+
facts.push(`${step.turnCount} turns`);
|
|
374
|
+
if (step.toolCount !== undefined)
|
|
375
|
+
facts.push(`${step.toolCount} tools`);
|
|
376
|
+
if (step.tokens?.total)
|
|
377
|
+
facts.push(formatTokenStat(step.tokens.total));
|
|
378
|
+
const activity = buildLiveStatusLine(step, snapshotNow);
|
|
379
|
+
if (activity && facts.length)
|
|
380
|
+
return `${activity} · ${facts.join(" · ")}`;
|
|
381
|
+
if (activity)
|
|
382
|
+
return activity;
|
|
383
|
+
return facts.join(" · ");
|
|
384
|
+
}
|
|
385
|
+
function widgetChainDetails(job, theme, expanded = false, width = getTermWidth()) {
|
|
386
|
+
if (!job.steps?.length)
|
|
387
|
+
return [];
|
|
388
|
+
const total = job.chainStepCount ?? job.steps.length;
|
|
389
|
+
const lines = [];
|
|
390
|
+
for (const span of buildAsyncChainStepSpans(total, job.steps.length, job.parallelGroups)) {
|
|
391
|
+
const steps = job.steps.slice(span.start, span.start + span.count);
|
|
392
|
+
if (span.isParallel) {
|
|
393
|
+
const status = aggregateStepStatus(steps);
|
|
394
|
+
lines.push(` ${widgetStepGlyph(status, theme, widgetStepsRunningSeed(steps))} Step ${span.stepIndex + 1}/${total}: ${themeBold(theme, "parallel group")} ${theme.fg("dim", "·")} ${theme.fg("dim", formatParallelOutcome(steps, span.count))}`);
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
const step = steps[0];
|
|
398
|
+
if (!step) {
|
|
399
|
+
lines.push(` ${theme.fg("dim", `◦ Step ${span.stepIndex + 1}/${total}: pending`)}`);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
lines.push(...foregroundStyleWidgetStepLines(job, theme, step, "Step", span.stepIndex + 1, total, expanded, width));
|
|
403
|
+
}
|
|
404
|
+
return lines;
|
|
405
|
+
}
|
|
406
|
+
function widgetParallelAgentDetails(job, theme, expanded = false, width = getTermWidth()) {
|
|
407
|
+
if (!job.steps?.length)
|
|
408
|
+
return [];
|
|
409
|
+
if (job.mode !== "parallel" && job.mode !== "chain")
|
|
410
|
+
return [];
|
|
411
|
+
if (job.mode === "chain" && !job.activeParallelGroup && job.parallelGroups?.length)
|
|
412
|
+
return widgetChainDetails(job, theme, expanded, width);
|
|
413
|
+
const total = job.stepsTotal ?? job.steps.length;
|
|
414
|
+
const lines = [];
|
|
415
|
+
for (const [index, step] of job.steps.entries()) {
|
|
416
|
+
const marker = index === job.steps.length - 1 ? "└" : "├";
|
|
417
|
+
const activity = widgetStepActivity(step, job.updatedAt);
|
|
418
|
+
const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
|
|
419
|
+
const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
|
|
420
|
+
lines.push(` ${theme.fg("dim", `${marker} ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${step.agent} · ${widgetStepStatus(step.status, theme)}${modelDisplay}${activity ? ` · ${activity}` : ""}`)}`);
|
|
421
|
+
for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt, expanded ? 8 : 1))
|
|
422
|
+
lines.push(` ${nestedLine}`);
|
|
423
|
+
}
|
|
424
|
+
return lines;
|
|
425
|
+
}
|
|
426
|
+
function parseParallelGroupAgentCount(label) {
|
|
427
|
+
if (!label || !label.startsWith("[") || !label.endsWith("]"))
|
|
428
|
+
return;
|
|
429
|
+
const inner = label.slice(1, -1).trim();
|
|
430
|
+
if (!inner)
|
|
431
|
+
return 0;
|
|
432
|
+
return inner.split("+").map((part) => part.trim()).filter(Boolean).length;
|
|
433
|
+
}
|
|
434
|
+
function buildChainStepSpans(details) {
|
|
435
|
+
if (details.workflowGraph?.nodes?.length) {
|
|
436
|
+
const spans = [];
|
|
437
|
+
let flatCursor = 0;
|
|
438
|
+
for (const node of details.workflowGraph.nodes) {
|
|
439
|
+
if (node.stepIndex === undefined)
|
|
440
|
+
continue;
|
|
441
|
+
if (node.kind === "parallel-group" || node.kind === "dynamic-parallel-group") {
|
|
442
|
+
const childFlatIndexes = (node.children ?? []).map((child) => child.flatIndex).filter((value) => typeof value === "number");
|
|
443
|
+
const start = childFlatIndexes.length ? Math.min(...childFlatIndexes) : flatCursor;
|
|
444
|
+
const count = node.children?.length ?? 0;
|
|
445
|
+
spans.push({ stepIndex: node.stepIndex, start, count, isParallel: true, status: node.status, label: node.label, error: node.error });
|
|
446
|
+
flatCursor = Math.max(flatCursor, start + count);
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
const start = node.flatIndex ?? flatCursor;
|
|
450
|
+
spans.push({ stepIndex: node.stepIndex, start, count: 1, isParallel: false, status: node.status, label: node.label, error: node.error });
|
|
451
|
+
flatCursor = Math.max(flatCursor, start + 1);
|
|
452
|
+
}
|
|
453
|
+
if (spans.length)
|
|
454
|
+
return spans.sort((left, right) => left.stepIndex - right.stepIndex);
|
|
455
|
+
}
|
|
456
|
+
if (!details.chainAgents?.length)
|
|
457
|
+
return [];
|
|
458
|
+
const spans = [];
|
|
459
|
+
let start = 0;
|
|
460
|
+
for (let stepIndex = 0;stepIndex < details.chainAgents.length; stepIndex++) {
|
|
461
|
+
const label = details.chainAgents[stepIndex];
|
|
462
|
+
const parsedCount = parseParallelGroupAgentCount(label);
|
|
463
|
+
const count = parsedCount ?? 1;
|
|
464
|
+
spans.push({ stepIndex, start, count, isParallel: parsedCount !== undefined });
|
|
465
|
+
start += count;
|
|
466
|
+
}
|
|
467
|
+
return spans;
|
|
468
|
+
}
|
|
469
|
+
function isChainParallelGroupActive(details) {
|
|
470
|
+
if (details.mode !== "chain")
|
|
471
|
+
return false;
|
|
472
|
+
if (details.currentStepIndex === undefined)
|
|
473
|
+
return false;
|
|
474
|
+
return buildChainStepSpans(details).some((span) => span.stepIndex === details.currentStepIndex && span.isParallel);
|
|
475
|
+
}
|
|
476
|
+
function buildAsyncChainStepSpans(total, stepCount, parallelGroups = []) {
|
|
477
|
+
const spans = [];
|
|
478
|
+
let flatIndex = 0;
|
|
479
|
+
for (let stepIndex = 0;stepIndex < total; stepIndex++) {
|
|
480
|
+
const group = parallelGroups.find((candidate) => candidate.stepIndex === stepIndex);
|
|
481
|
+
if (group) {
|
|
482
|
+
spans.push({ stepIndex, start: group.start, count: group.count, isParallel: true });
|
|
483
|
+
flatIndex = Math.max(flatIndex, group.start + group.count);
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
spans.push({ stepIndex, start: flatIndex, count: flatIndex < stepCount ? 1 : 0, isParallel: false });
|
|
487
|
+
flatIndex++;
|
|
488
|
+
}
|
|
489
|
+
return spans;
|
|
490
|
+
}
|
|
491
|
+
function isDoneResult(result) {
|
|
492
|
+
const status = result.progress?.status;
|
|
493
|
+
if (status === "completed")
|
|
494
|
+
return true;
|
|
495
|
+
if (status === "running" || status === "pending")
|
|
496
|
+
return false;
|
|
497
|
+
if (result.interrupted || result.detached)
|
|
498
|
+
return false;
|
|
499
|
+
return result.exitCode === 0;
|
|
500
|
+
}
|
|
501
|
+
function workflowGraphHasStatus(details, statuses) {
|
|
502
|
+
return details.workflowGraph?.nodes.some((node) => statuses.includes(node.status)) ?? false;
|
|
503
|
+
}
|
|
504
|
+
function buildChainRenderEntries(details, label) {
|
|
505
|
+
if (details.mode !== "chain" || !label.hasParallelInChain || label.showActiveGroupOnly)
|
|
506
|
+
return;
|
|
507
|
+
const entries = [];
|
|
508
|
+
for (const span of buildChainStepSpans(details)) {
|
|
509
|
+
if (span.isParallel && span.count === 0) {
|
|
510
|
+
entries.push({
|
|
511
|
+
kind: "placeholder",
|
|
512
|
+
rowNumber: span.stepIndex + 1,
|
|
513
|
+
stepLabel: `Step ${span.stepIndex + 1}`,
|
|
514
|
+
agentName: span.label ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`,
|
|
515
|
+
status: span.status ?? "pending",
|
|
516
|
+
error: span.error
|
|
517
|
+
});
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
for (let index = span.start;index < span.start + span.count; index++) {
|
|
521
|
+
entries.push({
|
|
522
|
+
kind: "result",
|
|
523
|
+
resultIndex: index,
|
|
524
|
+
rowNumber: index + 1,
|
|
525
|
+
agentName: details.results[index]?.agent ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return entries;
|
|
530
|
+
}
|
|
531
|
+
function buildMultiProgressLabel(details, hasRunning) {
|
|
532
|
+
const stepSpans = buildChainStepSpans(details);
|
|
533
|
+
const hasParallelInChain = details.mode === "chain" && stepSpans.some((span) => span.isParallel);
|
|
534
|
+
const activeParallelGroup = isChainParallelGroupActive(details);
|
|
535
|
+
const itemTitle = details.mode === "parallel" || activeParallelGroup ? "Agent" : "Step";
|
|
536
|
+
if (details.mode === "parallel") {
|
|
537
|
+
const totalCount = details.totalSteps ?? details.results.length;
|
|
538
|
+
const statuses = new Array(totalCount).fill("pending");
|
|
539
|
+
for (const progress of details.progress ?? []) {
|
|
540
|
+
if (progress.index >= 0 && progress.index < totalCount)
|
|
541
|
+
statuses[progress.index] = progress.status;
|
|
542
|
+
}
|
|
543
|
+
for (let i = 0;i < details.results.length; i++) {
|
|
544
|
+
const result = details.results[i];
|
|
545
|
+
const progressFromArray = details.progress?.find((progress) => progress.index === i) || details.progress?.find((progress) => progress.agent === result.agent && progress.status === "running");
|
|
546
|
+
const index = result.progress?.index ?? progressFromArray?.index ?? i;
|
|
547
|
+
if (index < 0 || index >= totalCount)
|
|
548
|
+
continue;
|
|
549
|
+
const status = result.progress?.status ?? (result.interrupted || result.detached ? "detached" : result.exitCode === 0 ? "completed" : "failed");
|
|
550
|
+
statuses[index] = status;
|
|
551
|
+
}
|
|
552
|
+
const running = statuses.filter((status) => status === "running").length;
|
|
553
|
+
const done = statuses.filter((status) => status === "completed").length;
|
|
554
|
+
const headerLabel = hasRunning ? `${formatAgentRunningLabel(running)} · ${done}/${totalCount} done` : `${done}/${totalCount} done`;
|
|
555
|
+
return { headerLabel, itemTitle, totalCount, hasParallelInChain, activeParallelGroup, groupStartIndex: 0, groupEndIndex: totalCount, showActiveGroupOnly: false };
|
|
556
|
+
}
|
|
557
|
+
if (activeParallelGroup) {
|
|
558
|
+
const currentStepIndex = details.currentStepIndex;
|
|
559
|
+
const span = stepSpans[currentStepIndex];
|
|
560
|
+
const groupSize = span?.count ?? 1;
|
|
561
|
+
const groupStart = span?.start ?? 0;
|
|
562
|
+
const groupEnd = groupStart + groupSize;
|
|
563
|
+
let running = 0;
|
|
564
|
+
let done = 0;
|
|
565
|
+
for (let index = groupStart;index < groupEnd; index++) {
|
|
566
|
+
const progressEntry = details.progress?.find((progress) => progress.index === index);
|
|
567
|
+
const resultEntry = details.results.find((result) => result.progress?.index === index);
|
|
568
|
+
if (progressEntry?.status === "running") {
|
|
569
|
+
running++;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (progressEntry?.status === "completed") {
|
|
573
|
+
done++;
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
if (resultEntry && isDoneResult(resultEntry))
|
|
577
|
+
done++;
|
|
578
|
+
}
|
|
579
|
+
const totalSteps = details.totalSteps ?? details.chainAgents?.length ?? 1;
|
|
580
|
+
const headerLabel = hasRunning ? `step ${currentStepIndex + 1}/${totalSteps} · parallel group: ${formatAgentRunningLabel(running)} · ${done}/${groupSize} done` : `step ${currentStepIndex + 1}/${totalSteps} · parallel group: ${done}/${groupSize} done`;
|
|
581
|
+
return { headerLabel, itemTitle, totalCount: groupSize, hasParallelInChain, activeParallelGroup, groupStartIndex: groupStart, groupEndIndex: groupEnd, showActiveGroupOnly: true };
|
|
582
|
+
}
|
|
583
|
+
if (details.mode === "chain" && details.chainAgents?.length) {
|
|
584
|
+
const totalCount = details.totalSteps ?? details.chainAgents.length;
|
|
585
|
+
const doneLogical = stepSpans.filter((span) => {
|
|
586
|
+
if (span.status && span.status !== "completed")
|
|
587
|
+
return false;
|
|
588
|
+
if (span.count === 0)
|
|
589
|
+
return span.status === "completed";
|
|
590
|
+
for (let index = span.start;index < span.start + span.count; index++) {
|
|
591
|
+
const progressEntry = details.progress?.find((progress) => progress.index === index);
|
|
592
|
+
const resultEntry = details.results.find((result) => result.progress?.index === index) ?? details.results[index];
|
|
593
|
+
if (progressEntry?.status === "running" || progressEntry?.status === "pending" || progressEntry?.status === "failed")
|
|
594
|
+
return false;
|
|
595
|
+
if (!resultEntry || !isDoneResult(resultEntry))
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
return true;
|
|
599
|
+
}).length;
|
|
600
|
+
const currentStep = details.currentStepIndex !== undefined ? details.currentStepIndex + 1 : Math.min(totalCount, doneLogical + (hasRunning ? 1 : 0));
|
|
601
|
+
const headerLabel = hasRunning ? `step ${currentStep}/${totalCount}` : `step ${doneLogical}/${totalCount}`;
|
|
602
|
+
return { headerLabel, itemTitle, totalCount, hasParallelInChain, activeParallelGroup, groupStartIndex: 0, groupEndIndex: details.results.length, showActiveGroupOnly: false };
|
|
603
|
+
}
|
|
604
|
+
const totalCount = details.totalSteps ?? details.results.length;
|
|
605
|
+
const currentStep = details.currentStepIndex !== undefined ? details.currentStepIndex + 1 : Math.min(totalCount, details.results.filter(isDoneResult).length + (hasRunning ? 1 : 0));
|
|
606
|
+
const done = details.results.filter(isDoneResult).length;
|
|
607
|
+
const headerLabel = hasRunning ? `step ${currentStep}/${totalCount}` : `step ${done}/${totalCount}`;
|
|
608
|
+
return { headerLabel, itemTitle, totalCount, hasParallelInChain, activeParallelGroup, groupStartIndex: 0, groupEndIndex: details.results.length, showActiveGroupOnly: false };
|
|
609
|
+
}
|
|
610
|
+
function resultRowLabel(details, label, resultIndex, stepNumber) {
|
|
611
|
+
if (details.mode === "chain" && label.hasParallelInChain) {
|
|
612
|
+
const span = buildChainStepSpans(details).find((candidate) => resultIndex >= candidate.start && resultIndex < candidate.start + candidate.count);
|
|
613
|
+
if (span?.isParallel)
|
|
614
|
+
return `Agent ${resultIndex - span.start + 1}/${span.count}`;
|
|
615
|
+
if (span)
|
|
616
|
+
return `Step ${span.stepIndex + 1}`;
|
|
617
|
+
}
|
|
618
|
+
if (label.itemTitle === "Agent") {
|
|
619
|
+
const localStepNumber = label.activeParallelGroup ? Math.max(1, stepNumber - label.groupStartIndex) : stepNumber;
|
|
620
|
+
return `Agent ${localStepNumber}/${label.totalCount}`;
|
|
621
|
+
}
|
|
622
|
+
return `Step ${stepNumber}`;
|
|
623
|
+
}
|
|
624
|
+
function widgetStats(job, theme) {
|
|
625
|
+
const parts = [];
|
|
626
|
+
const stepsTotal = job.stepsTotal ?? (job.agents?.length ?? 1);
|
|
627
|
+
if (job.activeParallelGroup) {
|
|
628
|
+
const running = job.runningSteps ?? (job.status === "running" ? 1 : 0);
|
|
629
|
+
const done = job.completedSteps ?? (job.status === "complete" ? stepsTotal : 0);
|
|
630
|
+
if (job.mode === "parallel") {
|
|
631
|
+
if (job.status === "running" && running > 0)
|
|
632
|
+
parts.push(formatAgentRunningLabel(running));
|
|
633
|
+
if (stepsTotal > 0)
|
|
634
|
+
parts.push(`${done}/${stepsTotal} done`);
|
|
635
|
+
} else {
|
|
636
|
+
const activeGroup = job.currentStep !== undefined ? job.parallelGroups?.find((group) => job.currentStep >= group.start && job.currentStep < group.start + group.count) : job.parallelGroups?.find((group) => group.start === 0);
|
|
637
|
+
const logicalStep = activeGroup?.stepIndex ?? job.currentStep ?? 0;
|
|
638
|
+
const total = job.chainStepCount ?? stepsTotal;
|
|
639
|
+
const groupParts = [`${done}/${stepsTotal} done`];
|
|
640
|
+
if (job.status === "running" && running > 0)
|
|
641
|
+
groupParts.unshift(formatAgentRunningLabel(running));
|
|
642
|
+
parts.push(`step ${logicalStep + 1}/${total} · parallel group: ${groupParts.join(" · ")}`);
|
|
643
|
+
}
|
|
644
|
+
} else if (job.currentStep !== undefined) {
|
|
645
|
+
if (job.mode === "chain" && job.parallelGroups?.length) {
|
|
646
|
+
const total = job.chainStepCount ?? stepsTotal;
|
|
647
|
+
parts.push(`step ${flatToLogicalStepIndex(job.currentStep, total, job.parallelGroups) + 1}/${total}`);
|
|
648
|
+
} else {
|
|
649
|
+
parts.push(`step ${job.currentStep + 1}/${stepsTotal}`);
|
|
650
|
+
}
|
|
651
|
+
} else if (stepsTotal > 1) {
|
|
652
|
+
parts.push(`steps ${stepsTotal}`);
|
|
653
|
+
}
|
|
654
|
+
if (job.toolCount !== undefined)
|
|
655
|
+
parts.push(formatToolUseStat(job.toolCount));
|
|
656
|
+
if (job.totalTokens?.total)
|
|
657
|
+
parts.push(formatTokenStat(job.totalTokens.total));
|
|
658
|
+
if (job.startedAt !== undefined && job.updatedAt !== undefined)
|
|
659
|
+
parts.push(formatDuration(Math.max(0, job.updatedAt - job.startedAt)));
|
|
660
|
+
return statJoin(theme, parts);
|
|
661
|
+
}
|
|
662
|
+
function widgetStepStats(theme, step) {
|
|
663
|
+
return statJoin(theme, [
|
|
664
|
+
step.turnCount !== undefined ? `${step.turnCount} turns` : "",
|
|
665
|
+
step.toolCount !== undefined ? formatToolUseStat(step.toolCount) : "",
|
|
666
|
+
step.tokens?.total ? formatTokenStat(step.tokens.total) : "",
|
|
667
|
+
step.durationMs !== undefined ? formatDuration(step.durationMs) : ""
|
|
668
|
+
]);
|
|
669
|
+
}
|
|
670
|
+
function modelThinkingBadge(theme, model, thinking) {
|
|
671
|
+
const label = formatModelThinking(model, thinking);
|
|
672
|
+
return label ? theme.fg("dim", ` (${label})`) : "";
|
|
673
|
+
}
|
|
674
|
+
function widgetStepActivityLine(step, width, expanded, snapshotNow) {
|
|
675
|
+
const toolLine = formatCurrentToolLine(step, width, expanded, snapshotNow);
|
|
676
|
+
if (toolLine)
|
|
677
|
+
return toolLine;
|
|
678
|
+
const activity = buildLiveStatusLine(step, snapshotNow);
|
|
679
|
+
if (activity)
|
|
680
|
+
return activity;
|
|
681
|
+
if (step.status === "running")
|
|
682
|
+
return "thinking…";
|
|
683
|
+
return "";
|
|
684
|
+
}
|
|
685
|
+
function widgetOutputPath(job, step) {
|
|
686
|
+
if (typeof step.index !== "number")
|
|
687
|
+
return;
|
|
688
|
+
return path.join(job.asyncDir, `output-${step.index}.log`);
|
|
689
|
+
}
|
|
690
|
+
function nestedRunName(run) {
|
|
691
|
+
if (run.agent)
|
|
692
|
+
return run.agent;
|
|
693
|
+
if (run.agents?.length)
|
|
694
|
+
return formatWidgetAgents(run.agents);
|
|
695
|
+
return run.id;
|
|
696
|
+
}
|
|
697
|
+
function nestedStatusGlyph(state, theme, seed) {
|
|
698
|
+
if (state === "running")
|
|
699
|
+
return theme.fg("accent", runningGlyph(seed));
|
|
700
|
+
if (state === "complete" || state === "completed")
|
|
701
|
+
return theme.fg("success", "✓");
|
|
702
|
+
if (state === "failed")
|
|
703
|
+
return theme.fg("error", "✗");
|
|
704
|
+
if (state === "paused")
|
|
705
|
+
return theme.fg("warning", "■");
|
|
706
|
+
return theme.fg("muted", "◦");
|
|
707
|
+
}
|
|
708
|
+
function nestedRunSeed(run) {
|
|
709
|
+
return runningSeed(run.lastUpdate, run.lastActivityAt, run.currentStep, run.toolCount, run.turnCount, run.totalTokens?.total, run.currentToolStartedAt);
|
|
710
|
+
}
|
|
711
|
+
function nestedActivity(input, state, snapshotNow) {
|
|
712
|
+
const facts = [];
|
|
713
|
+
if (input.currentTool && input.currentToolStartedAt !== undefined && snapshotNow !== undefined)
|
|
714
|
+
facts.push(`${input.currentTool} ${formatDuration(Math.max(0, snapshotNow - input.currentToolStartedAt))}`);
|
|
715
|
+
else if (input.currentTool)
|
|
716
|
+
facts.push(input.currentTool);
|
|
717
|
+
if (input.currentPath)
|
|
718
|
+
facts.push(shortenPath(input.currentPath));
|
|
719
|
+
if (input.turnCount !== undefined)
|
|
720
|
+
facts.push(`${input.turnCount} turns`);
|
|
721
|
+
if (input.toolCount !== undefined)
|
|
722
|
+
facts.push(`${input.toolCount} tools`);
|
|
723
|
+
const activity = buildLiveStatusLine(input, snapshotNow);
|
|
724
|
+
if (activity && facts.length)
|
|
725
|
+
return `${activity} · ${facts.join(" · ")}`;
|
|
726
|
+
if (activity)
|
|
727
|
+
return activity;
|
|
728
|
+
if (facts.length)
|
|
729
|
+
return facts.join(" · ");
|
|
730
|
+
if (state === "running")
|
|
731
|
+
return "thinking…";
|
|
732
|
+
if (state === "queued" || state === "pending")
|
|
733
|
+
return "queued…";
|
|
734
|
+
if (state === "paused")
|
|
735
|
+
return "Paused";
|
|
736
|
+
if (state === "failed")
|
|
737
|
+
return "Failed";
|
|
738
|
+
return "Done";
|
|
739
|
+
}
|
|
740
|
+
function formatNestedWidgetLines(children, theme, width, expanded, snapshotNow, lineBudget = expanded ? 12 : 1) {
|
|
741
|
+
if (!children?.length || lineBudget <= 0)
|
|
742
|
+
return [];
|
|
743
|
+
if (!expanded) {
|
|
744
|
+
const aggregate = formatNestedAggregate(children);
|
|
745
|
+
return aggregate ? [theme.fg("dim", `↳ ${aggregate}`)] : [];
|
|
746
|
+
}
|
|
747
|
+
const lines = [];
|
|
748
|
+
const maxDepth = 2;
|
|
749
|
+
const append = (items, depth, prefix) => {
|
|
750
|
+
if (!items?.length || lines.length >= lineBudget)
|
|
751
|
+
return;
|
|
752
|
+
if (depth > maxDepth) {
|
|
753
|
+
const aggregate = formatNestedAggregate(items);
|
|
754
|
+
if (aggregate && lines.length < lineBudget)
|
|
755
|
+
lines.push(theme.fg("dim", `${prefix}↳ ${aggregate}`));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
for (let index = 0;index < items.length; index++) {
|
|
759
|
+
const child = items[index];
|
|
760
|
+
if (lines.length >= lineBudget) {
|
|
761
|
+
const aggregate = formatNestedAggregate(items.slice(index));
|
|
762
|
+
if (aggregate)
|
|
763
|
+
lines[lines.length - 1] = theme.fg("dim", `${prefix}↳ ${aggregate}`);
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const activity = nestedActivity(child, child.state, snapshotNow ?? child.lastUpdate);
|
|
767
|
+
const error = child.error ? ` · ${child.error}` : "";
|
|
768
|
+
lines.push(theme.fg("dim", `${prefix}↳ ${nestedStatusGlyph(child.state, theme, nestedRunSeed(child))} ${nestedRunName(child)} · ${child.state} · ${activity}${error}`));
|
|
769
|
+
if (depth === maxDepth) {
|
|
770
|
+
const aggregate = formatNestedAggregate([...child.steps?.flatMap((step) => step.children ?? []) ?? [], ...child.children ?? []]);
|
|
771
|
+
if (aggregate && lines.length < lineBudget)
|
|
772
|
+
lines.push(theme.fg("dim", `${prefix} ↳ ${aggregate}`));
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
for (const step of child.steps ?? []) {
|
|
776
|
+
if (lines.length >= lineBudget)
|
|
777
|
+
return;
|
|
778
|
+
lines.push(theme.fg("dim", `${prefix} ↳ ${nestedStatusGlyph(step.status, theme)} ${step.agent} · ${step.status} · ${nestedActivity(step, step.status, snapshotNow ?? child.lastUpdate)}`));
|
|
779
|
+
append(step.children, depth + 1, `${prefix} `);
|
|
780
|
+
}
|
|
781
|
+
append(child.children, depth + 1, `${prefix} `);
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
append(children, 0, "");
|
|
785
|
+
return lines.map((line) => truncLine(line, width));
|
|
786
|
+
}
|
|
787
|
+
function foregroundStyleWidgetStepLines(job, theme, step, itemTitle, index, total, expanded, width) {
|
|
788
|
+
const status = widgetStepStatus(step.status, theme);
|
|
789
|
+
const stats = widgetStepStats(theme, step);
|
|
790
|
+
const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
|
|
791
|
+
const lines = [` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1))} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
|
|
792
|
+
const activity = widgetStepActivityLine(step, width, expanded, job.updatedAt);
|
|
793
|
+
if (activity)
|
|
794
|
+
lines.push(` ${theme.fg("dim", `⎿ ${activity}`)}`);
|
|
795
|
+
for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt)) {
|
|
796
|
+
lines.push(` ${nestedLine}`);
|
|
797
|
+
}
|
|
798
|
+
if (step.status === "running") {
|
|
799
|
+
if (!expanded)
|
|
800
|
+
lines.push(` ${theme.fg("accent", liveDetailHintText())}`);
|
|
801
|
+
const output = widgetOutputPath(job, step);
|
|
802
|
+
if (output)
|
|
803
|
+
lines.push(` ${theme.fg("dim", `output: ${shortenPath(output)}`)}`);
|
|
804
|
+
if (expanded) {
|
|
805
|
+
const liveStatus = buildLiveStatusLine(step, job.updatedAt);
|
|
806
|
+
if (liveStatus && liveStatus !== activity)
|
|
807
|
+
lines.push(` ${theme.fg("accent", liveStatus)}`);
|
|
808
|
+
for (const tool of step.recentTools?.slice(-3) ?? []) {
|
|
809
|
+
const maxArgsLen = Math.max(40, width - 30);
|
|
810
|
+
const argsPreview = tool.args.length <= maxArgsLen ? tool.args : `${tool.args.slice(0, maxArgsLen)}...`;
|
|
811
|
+
lines.push(` ${theme.fg("dim", `${tool.tool}${argsPreview ? `: ${argsPreview}` : ""}`)}`);
|
|
812
|
+
}
|
|
813
|
+
for (const line of step.recentOutput?.slice(-5) ?? []) {
|
|
814
|
+
lines.push(` ${theme.fg("dim", line)}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
return lines;
|
|
819
|
+
}
|
|
820
|
+
function foregroundStyleWidgetDetails(job, theme, expanded, width) {
|
|
821
|
+
if (!job.steps?.length)
|
|
822
|
+
return [
|
|
823
|
+
` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
|
|
824
|
+
...formatNestedWidgetLines(job.nestedChildren, theme, width, expanded, job.updatedAt).map((line) => ` ${line}`)
|
|
825
|
+
];
|
|
826
|
+
if (job.mode === "chain" && !job.activeParallelGroup && job.parallelGroups?.length)
|
|
827
|
+
return widgetChainDetails(job, theme, expanded, width);
|
|
828
|
+
const total = job.stepsTotal ?? job.steps.length;
|
|
829
|
+
const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
|
|
830
|
+
const lines = [];
|
|
831
|
+
for (const [index, step] of job.steps.entries()) {
|
|
832
|
+
lines.push(...foregroundStyleWidgetStepLines(job, theme, step, itemTitle, index + 1, total, expanded, width));
|
|
833
|
+
}
|
|
834
|
+
const attached = new Set(job.steps.flatMap((step) => step.children?.map((child) => child.id) ?? []));
|
|
835
|
+
const unattached = job.nestedChildren?.filter((child) => !attached.has(child.id)) ?? [];
|
|
836
|
+
for (const nestedLine of formatNestedWidgetLines(unattached, theme, width, expanded, job.updatedAt)) {
|
|
837
|
+
lines.push(` ${nestedLine}`);
|
|
838
|
+
}
|
|
839
|
+
return lines;
|
|
840
|
+
}
|
|
841
|
+
function buildSingleWidgetLines(job, theme, width, expanded) {
|
|
842
|
+
const stats = widgetStats(job, theme);
|
|
843
|
+
const count = job.mode === "chain" ? job.chainStepCount : job.stepsTotal ?? job.agents?.length ?? job.steps?.length;
|
|
844
|
+
const mode = widgetJobName(job);
|
|
845
|
+
const title = `async subagent ${mode}${count && count > 1 ? ` (${count})` : ""}`;
|
|
846
|
+
return [
|
|
847
|
+
`${theme.fg("toolTitle", themeBold(theme, title))} ${theme.fg("dim", "· background")}`,
|
|
848
|
+
`${widgetStatusGlyph(job, theme)} ${themeBold(theme, mode)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
|
|
849
|
+
...foregroundStyleWidgetDetails(job, theme, expanded, width)
|
|
850
|
+
].map((line) => truncLine(line, width));
|
|
851
|
+
}
|
|
852
|
+
function compactSingleWidgetLines(job, theme, width) {
|
|
853
|
+
const fullLines = buildSingleWidgetLines(job, theme, width, false);
|
|
854
|
+
if (fullLines.length <= 10 || !job.steps?.length || job.mode !== "parallel" && !job.activeParallelGroup)
|
|
855
|
+
return fullLines;
|
|
856
|
+
const total = job.stepsTotal ?? job.steps.length;
|
|
857
|
+
const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
|
|
858
|
+
const lines = fullLines.slice(0, 2);
|
|
859
|
+
for (const [index, step] of job.steps.entries()) {
|
|
860
|
+
const status = widgetStepStatus(step.status, theme);
|
|
861
|
+
const activity = widgetStepActivityLine(step, width, false, job.updatedAt);
|
|
862
|
+
const stepStats = widgetStepStats(theme, step);
|
|
863
|
+
const activitySuffix = activity ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", activity)}` : "";
|
|
864
|
+
const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
|
|
865
|
+
lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
|
|
866
|
+
for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, false, job.updatedAt))
|
|
867
|
+
lines.push(` ${nestedLine}`);
|
|
868
|
+
}
|
|
869
|
+
if (job.steps.some((step) => step.status === "running"))
|
|
870
|
+
lines.push(theme.fg("accent", ` ${liveDetailHintText()}`));
|
|
871
|
+
return lines.map((line) => truncLine(line, width));
|
|
872
|
+
}
|
|
873
|
+
const RESERVED_NON_WIDGET_ROWS = 19;
|
|
874
|
+
let widgetLayoutSession;
|
|
875
|
+
function resetWidgetLayoutSession() {
|
|
876
|
+
widgetLayoutSession = undefined;
|
|
877
|
+
}
|
|
878
|
+
function estimateAvailableWidgetRows() {
|
|
879
|
+
const rows = process.stdout.rows || 30;
|
|
880
|
+
return Math.max(1, rows - RESERVED_NON_WIDGET_ROWS);
|
|
881
|
+
}
|
|
882
|
+
function currentTerminalRows() {
|
|
883
|
+
return process.stdout.rows || 30;
|
|
884
|
+
}
|
|
885
|
+
function currentTerminalColumns() {
|
|
886
|
+
return process.stdout.columns || 120;
|
|
887
|
+
}
|
|
888
|
+
function widgetSessionMatches(expanded) {
|
|
889
|
+
return widgetLayoutSession?.expanded === expanded && widgetLayoutSession.rows === currentTerminalRows() && widgetLayoutSession.columns === currentTerminalColumns();
|
|
890
|
+
}
|
|
891
|
+
function widgetHeaderCounts(jobs) {
|
|
892
|
+
return {
|
|
893
|
+
running: jobs.filter((job) => job.status === "running"),
|
|
894
|
+
queued: jobs.filter((job) => job.status === "queued"),
|
|
895
|
+
complete: jobs.filter((job) => job.status === "complete"),
|
|
896
|
+
failed: jobs.filter((job) => job.status === "failed"),
|
|
897
|
+
paused: jobs.filter((job) => job.status === "paused")
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function buildSingleLineWidgetLines(jobs, theme, width) {
|
|
901
|
+
const counts = widgetHeaderCounts(jobs);
|
|
902
|
+
const hasActive = counts.running.length > 0 || counts.queued.length > 0;
|
|
903
|
+
const glyph = counts.running.length > 0 ? runningGlyph(widgetJobsRunningSeed(counts.running)) : hasActive ? "●" : "○";
|
|
904
|
+
const parts = [];
|
|
905
|
+
if (counts.running.length > 0)
|
|
906
|
+
parts.push(`${counts.running.length}/${jobs.length} running`);
|
|
907
|
+
if (counts.queued.length > 0)
|
|
908
|
+
parts.push(`${counts.queued.length} queued`);
|
|
909
|
+
if (counts.failed.length > 0)
|
|
910
|
+
parts.push(`${counts.failed.length} failed`);
|
|
911
|
+
if (counts.paused.length > 0)
|
|
912
|
+
parts.push(`${counts.paused.length} paused`);
|
|
913
|
+
if (!hasActive && counts.complete.length > 0)
|
|
914
|
+
parts.push(`${counts.complete.length}/${jobs.length} done`);
|
|
915
|
+
return [truncLine(`${theme.fg(hasActive ? "accent" : "dim", glyph)} ${theme.fg(hasActive ? "accent" : "dim", "subagents")} (${parts.join(", ") || `${jobs.length} total`})`, width)];
|
|
916
|
+
}
|
|
917
|
+
function orderedWidgetJobs(jobs) {
|
|
918
|
+
return [
|
|
919
|
+
...jobs.filter((job) => job.status === "running"),
|
|
920
|
+
...jobs.filter((job) => job.status === "queued"),
|
|
921
|
+
...jobs.filter((job) => job.status !== "running" && job.status !== "queued")
|
|
922
|
+
];
|
|
923
|
+
}
|
|
924
|
+
function progressiveJobKey(job) {
|
|
925
|
+
return job.asyncId;
|
|
926
|
+
}
|
|
927
|
+
function isProgressiveActiveJob(job) {
|
|
928
|
+
return job?.status === "running" || job?.status === "queued";
|
|
929
|
+
}
|
|
930
|
+
function selectProgressiveJobKeys(jobs, previousKeys, bodyRows) {
|
|
931
|
+
if (bodyRows <= 0)
|
|
932
|
+
return [];
|
|
933
|
+
const jobsByKey = new Map(jobs.map((job) => [progressiveJobKey(job), job]));
|
|
934
|
+
const selected = [];
|
|
935
|
+
const append = (key) => {
|
|
936
|
+
if (selected.includes(key) || !jobsByKey.has(key))
|
|
937
|
+
return;
|
|
938
|
+
selected.push(key);
|
|
939
|
+
};
|
|
940
|
+
for (const key of previousKeys) {
|
|
941
|
+
if (!isProgressiveActiveJob(jobsByKey.get(key)))
|
|
942
|
+
continue;
|
|
943
|
+
append(key);
|
|
944
|
+
if (selected.length >= bodyRows)
|
|
945
|
+
return selected;
|
|
946
|
+
}
|
|
947
|
+
for (const job of orderedWidgetJobs(jobs)) {
|
|
948
|
+
if (!isProgressiveActiveJob(job))
|
|
949
|
+
continue;
|
|
950
|
+
const key = progressiveJobKey(job);
|
|
951
|
+
append(key);
|
|
952
|
+
if (selected.length >= bodyRows)
|
|
953
|
+
break;
|
|
954
|
+
}
|
|
955
|
+
if (selected.length >= bodyRows)
|
|
956
|
+
return selected;
|
|
957
|
+
for (const key of previousKeys) {
|
|
958
|
+
if (isProgressiveActiveJob(jobsByKey.get(key)))
|
|
959
|
+
continue;
|
|
960
|
+
append(key);
|
|
961
|
+
if (selected.length >= bodyRows)
|
|
962
|
+
return selected;
|
|
963
|
+
}
|
|
964
|
+
for (const job of orderedWidgetJobs(jobs)) {
|
|
965
|
+
const key = progressiveJobKey(job);
|
|
966
|
+
append(key);
|
|
967
|
+
if (selected.length >= bodyRows)
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
return selected;
|
|
971
|
+
}
|
|
972
|
+
function progressiveHeaderLine(jobs, theme, width) {
|
|
973
|
+
const counts = widgetHeaderCounts(jobs);
|
|
974
|
+
const hasActive = counts.running.length > 0 || counts.queued.length > 0;
|
|
975
|
+
const glyph = counts.running.length > 0 ? runningGlyph(widgetJobsRunningSeed(counts.running)) : hasActive ? "●" : "○";
|
|
976
|
+
const parts = [];
|
|
977
|
+
if (counts.running.length > 0)
|
|
978
|
+
parts.push(formatAgentRunningLabel(counts.running.length));
|
|
979
|
+
if (counts.queued.length > 0)
|
|
980
|
+
parts.push(`${counts.queued.length} queued`);
|
|
981
|
+
if (!hasActive) {
|
|
982
|
+
if (counts.failed.length > 0)
|
|
983
|
+
parts.push(`${counts.failed.length} failed`);
|
|
984
|
+
if (counts.paused.length > 0)
|
|
985
|
+
parts.push(`${counts.paused.length} paused`);
|
|
986
|
+
if (counts.complete.length > 0)
|
|
987
|
+
parts.push(`${counts.complete.length}/${jobs.length} done`);
|
|
988
|
+
}
|
|
989
|
+
return truncLine(`${theme.fg(hasActive ? "accent" : "dim", glyph)} ${theme.fg(hasActive ? "accent" : "dim", "Async agents")} ${theme.fg("dim", "·")} ${theme.fg("dim", parts.join(", ") || `${jobs.length} total`)}`, width);
|
|
990
|
+
}
|
|
991
|
+
function progressiveJobLine(job, theme, width) {
|
|
992
|
+
const stats = widgetStats(job, theme);
|
|
993
|
+
const activity = widgetActivity(job);
|
|
994
|
+
const status = job.status === "complete" ? "done" : job.status;
|
|
995
|
+
const parts = [
|
|
996
|
+
themeBold(theme, widgetJobName(job)),
|
|
997
|
+
theme.fg("dim", status),
|
|
998
|
+
stats,
|
|
999
|
+
activity && activity.toLowerCase() !== status ? theme.fg("dim", activity) : ""
|
|
1000
|
+
].filter(Boolean);
|
|
1001
|
+
return truncLine(` ${widgetStatusGlyph(job, theme)} ${parts.join(` ${theme.fg("dim", "·")} `)}`, width);
|
|
1002
|
+
}
|
|
1003
|
+
function progressiveHiddenLine(hiddenJobs, theme, width) {
|
|
1004
|
+
const counts = widgetHeaderCounts(hiddenJobs);
|
|
1005
|
+
const parts = [];
|
|
1006
|
+
if (counts.running.length > 0)
|
|
1007
|
+
parts.push(`${counts.running.length} running`);
|
|
1008
|
+
if (counts.queued.length > 0)
|
|
1009
|
+
parts.push(`${counts.queued.length} queued`);
|
|
1010
|
+
const finished = counts.complete.length + counts.failed.length + counts.paused.length;
|
|
1011
|
+
if (finished > 0)
|
|
1012
|
+
parts.push(`${finished} finished`);
|
|
1013
|
+
return truncLine(theme.fg("dim", ` +${hiddenJobs.length} more${parts.length ? ` (${parts.join(", ")})` : ""}`), width);
|
|
1014
|
+
}
|
|
1015
|
+
function buildProgressiveWidgetLines(jobs, theme, width, lockedRows, previousKeys) {
|
|
1016
|
+
const rowCount = Math.max(1, lockedRows);
|
|
1017
|
+
if (rowCount === 1)
|
|
1018
|
+
return { lines: buildSingleLineWidgetLines(jobs, theme, width), visibleJobKeys: [] };
|
|
1019
|
+
const bodyRows = rowCount - 1;
|
|
1020
|
+
let visibleJobKeys = selectProgressiveJobKeys(jobs, previousKeys, bodyRows);
|
|
1021
|
+
const jobsByKey = new Map(jobs.map((job) => [progressiveJobKey(job), job]));
|
|
1022
|
+
let visibleJobs = visibleJobKeys.map((key) => jobsByKey.get(key)).filter((job) => Boolean(job));
|
|
1023
|
+
let hiddenJobs = jobs.filter((job) => !visibleJobKeys.includes(progressiveJobKey(job)));
|
|
1024
|
+
const needsHiddenLine = hiddenJobs.length > 0;
|
|
1025
|
+
if (needsHiddenLine && visibleJobs.length >= bodyRows && bodyRows > 0) {
|
|
1026
|
+
visibleJobs = visibleJobs.slice(0, bodyRows - 1);
|
|
1027
|
+
visibleJobKeys = visibleJobs.map(progressiveJobKey);
|
|
1028
|
+
hiddenJobs = jobs.filter((job) => !visibleJobKeys.includes(progressiveJobKey(job)));
|
|
1029
|
+
}
|
|
1030
|
+
const lines = [
|
|
1031
|
+
progressiveHeaderLine(jobs, theme, width),
|
|
1032
|
+
...visibleJobs.map((job) => progressiveJobLine(job, theme, width))
|
|
1033
|
+
];
|
|
1034
|
+
if (hiddenJobs.length > 0 && lines.length < rowCount)
|
|
1035
|
+
lines.push(progressiveHiddenLine(hiddenJobs, theme, width));
|
|
1036
|
+
while (lines.length < rowCount)
|
|
1037
|
+
lines.push(" ");
|
|
1038
|
+
return { lines: lines.slice(0, rowCount), visibleJobKeys };
|
|
1039
|
+
}
|
|
1040
|
+
function collapsedWidgetLineBudget(rows) {
|
|
1041
|
+
return Math.max(10, Math.min(14, Math.floor(rows * 0.35)));
|
|
1042
|
+
}
|
|
1043
|
+
function fitWidgetLineBudget(lines, theme, width, expanded) {
|
|
1044
|
+
const rows = process.stdout.rows || 30;
|
|
1045
|
+
const budget = expanded ? Math.max(12, Math.min(24, Math.floor(rows * 0.55))) : collapsedWidgetLineBudget(rows);
|
|
1046
|
+
if (lines.length <= budget)
|
|
1047
|
+
return lines;
|
|
1048
|
+
const visibleLines = Math.max(1, budget - 1);
|
|
1049
|
+
const hiddenCount = lines.length - visibleLines;
|
|
1050
|
+
const hint = expanded ? `… ${hiddenCount} live-detail lines hidden` : `… ${hiddenCount} lines hidden · ${liveDetailKeyText()} expands`;
|
|
1051
|
+
return [...lines.slice(0, visibleLines), truncLine(theme.fg("dim", hint), width)];
|
|
1052
|
+
}
|
|
1053
|
+
function fitAdaptiveWidgetLines(jobs, lines, theme, width, expanded) {
|
|
1054
|
+
if (expanded) {
|
|
1055
|
+
resetWidgetLayoutSession();
|
|
1056
|
+
return fitWidgetLineBudget(lines, theme, width, true);
|
|
1057
|
+
}
|
|
1058
|
+
const hasMatchingSession = widgetSessionMatches(expanded);
|
|
1059
|
+
const rows = currentTerminalRows();
|
|
1060
|
+
const columns = currentTerminalColumns();
|
|
1061
|
+
const availableRows = estimateAvailableWidgetRows();
|
|
1062
|
+
if (hasMatchingSession && widgetLayoutSession?.tier === "single-line") {
|
|
1063
|
+
return buildSingleLineWidgetLines(jobs, theme, width);
|
|
1064
|
+
}
|
|
1065
|
+
if (hasMatchingSession && widgetLayoutSession?.tier === "progressive" && widgetLayoutSession.lockedRows !== undefined) {
|
|
1066
|
+
const rendered = buildProgressiveWidgetLines(jobs, theme, width, widgetLayoutSession.lockedRows, widgetLayoutSession.visibleJobKeys);
|
|
1067
|
+
widgetLayoutSession.visibleJobKeys = rendered.visibleJobKeys;
|
|
1068
|
+
return rendered.lines;
|
|
1069
|
+
}
|
|
1070
|
+
if (lines.length <= availableRows) {
|
|
1071
|
+
widgetLayoutSession = { expanded, rows, columns, tier: "full", visibleJobKeys: [] };
|
|
1072
|
+
return fitWidgetLineBudget(lines, theme, width, false);
|
|
1073
|
+
}
|
|
1074
|
+
if (availableRows <= 2) {
|
|
1075
|
+
widgetLayoutSession = { expanded, rows, columns, tier: "single-line", visibleJobKeys: [] };
|
|
1076
|
+
return buildSingleLineWidgetLines(jobs, theme, width);
|
|
1077
|
+
}
|
|
1078
|
+
const lockedRows = Math.min(availableRows, collapsedWidgetLineBudget(rows));
|
|
1079
|
+
const rendered = buildProgressiveWidgetLines(jobs, theme, width, lockedRows, []);
|
|
1080
|
+
widgetLayoutSession = { expanded, rows, columns, tier: "progressive", lockedRows, visibleJobKeys: rendered.visibleJobKeys };
|
|
1081
|
+
return rendered.lines;
|
|
1082
|
+
}
|
|
1083
|
+
function buildWidgetComponent(jobs, expanded) {
|
|
1084
|
+
return (_tui, theme) => {
|
|
1085
|
+
const width = getTermWidth();
|
|
1086
|
+
const lines = expanded ? buildWidgetLines(jobs, theme, width, true) : jobs.length === 1 ? compactSingleWidgetLines(jobs[0], theme, width) : buildWidgetLines(jobs, theme, width, false);
|
|
1087
|
+
const container = new Container;
|
|
1088
|
+
for (const line of fitAdaptiveWidgetLines(jobs, lines, theme, width, expanded))
|
|
1089
|
+
container.addChild(new Text(line, 1, 0));
|
|
1090
|
+
return container;
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
export function buildWidgetLines(jobs, theme, width = getTermWidth(), expanded = false) {
|
|
1094
|
+
if (jobs.length === 0)
|
|
1095
|
+
return [];
|
|
1096
|
+
if (jobs.length === 1)
|
|
1097
|
+
return buildSingleWidgetLines(jobs[0], theme, width, expanded);
|
|
1098
|
+
const running = jobs.filter((job) => job.status === "running");
|
|
1099
|
+
const queued = jobs.filter((job) => job.status === "queued");
|
|
1100
|
+
const finished = jobs.filter((job) => job.status !== "running" && job.status !== "queued");
|
|
1101
|
+
const lines = [];
|
|
1102
|
+
const hasActive = running.length > 0 || queued.length > 0;
|
|
1103
|
+
const headerGlyph = running.length > 0 ? runningGlyph(widgetJobsRunningSeed(running)) : hasActive ? "●" : "○";
|
|
1104
|
+
lines.push(truncLine(`${theme.fg(hasActive ? "accent" : "dim", headerGlyph)} ${theme.fg(hasActive ? "accent" : "dim", "Async agents")} ${theme.fg("dim", "· background")}`, width));
|
|
1105
|
+
const items = [];
|
|
1106
|
+
let hiddenRunning = 0;
|
|
1107
|
+
let hiddenFinished = 0;
|
|
1108
|
+
let queuedSummaryShown = false;
|
|
1109
|
+
let slots = MAX_WIDGET_JOBS;
|
|
1110
|
+
for (const job of running) {
|
|
1111
|
+
if (slots <= 0) {
|
|
1112
|
+
hiddenRunning++;
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
const stats = widgetStats(job, theme);
|
|
1116
|
+
items.push([
|
|
1117
|
+
`${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
|
|
1118
|
+
` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
|
|
1119
|
+
...widgetParallelAgentDetails(job, theme, expanded, width)
|
|
1120
|
+
]);
|
|
1121
|
+
slots--;
|
|
1122
|
+
}
|
|
1123
|
+
if (queued.length > 0 && slots > 0) {
|
|
1124
|
+
items.push([`${theme.fg("muted", "◦")} ${theme.fg("dim", `${queued.length} queued`)}`]);
|
|
1125
|
+
queuedSummaryShown = true;
|
|
1126
|
+
slots--;
|
|
1127
|
+
}
|
|
1128
|
+
for (const job of finished) {
|
|
1129
|
+
if (slots <= 0) {
|
|
1130
|
+
hiddenFinished++;
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
const stats = widgetStats(job, theme);
|
|
1134
|
+
items.push([
|
|
1135
|
+
`${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
|
|
1136
|
+
` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
|
|
1137
|
+
...widgetParallelAgentDetails(job, theme, expanded, width)
|
|
1138
|
+
]);
|
|
1139
|
+
slots--;
|
|
1140
|
+
}
|
|
1141
|
+
const hiddenQueued = queued.length > 0 && !queuedSummaryShown ? queued.length : 0;
|
|
1142
|
+
const hiddenTotal = hiddenRunning + hiddenFinished + hiddenQueued;
|
|
1143
|
+
if (hiddenTotal > 0) {
|
|
1144
|
+
const parts = [];
|
|
1145
|
+
if (hiddenRunning > 0)
|
|
1146
|
+
parts.push(`${hiddenRunning} running`);
|
|
1147
|
+
if (hiddenQueued > 0)
|
|
1148
|
+
parts.push(`${hiddenQueued} queued`);
|
|
1149
|
+
if (hiddenFinished > 0)
|
|
1150
|
+
parts.push(`${hiddenFinished} finished`);
|
|
1151
|
+
items.push([theme.fg("dim", `+${hiddenTotal} more (${parts.join(", ")})`)]);
|
|
1152
|
+
}
|
|
1153
|
+
for (let i = 0;i < items.length; i++) {
|
|
1154
|
+
const item = items[i];
|
|
1155
|
+
const last = i === items.length - 1;
|
|
1156
|
+
const branch = last ? "└─" : "├─";
|
|
1157
|
+
const continuation = last ? " " : "│ ";
|
|
1158
|
+
lines.push(truncLine(`${theme.fg("dim", branch)} ${item[0]}`, width));
|
|
1159
|
+
for (const detail of item.slice(1)) {
|
|
1160
|
+
lines.push(truncLine(`${theme.fg("dim", continuation)} ${detail}`, width));
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
return lines;
|
|
1164
|
+
}
|
|
1165
|
+
export function renderWidget(ctx, jobs) {
|
|
1166
|
+
if (jobs.length === 0) {
|
|
1167
|
+
resetWidgetLayoutSession();
|
|
1168
|
+
if (ctx.hasUI)
|
|
1169
|
+
ctx.ui.setWidget(WIDGET_KEY, undefined);
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
if (!ctx.hasUI)
|
|
1173
|
+
return;
|
|
1174
|
+
ctx.ui.setWidget(WIDGET_KEY, buildWidgetComponent(jobs, ctx.ui.getToolsExpanded?.() ?? false));
|
|
1175
|
+
}
|
|
1176
|
+
function renderSingleCompact(d, r, theme, frame) {
|
|
1177
|
+
const output = r.truncation?.text || getSingleResultOutput(r);
|
|
1178
|
+
const progress = r.progress || r.progressSummary;
|
|
1179
|
+
const isRunning = r.progress?.status === "running";
|
|
1180
|
+
const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
|
|
1181
|
+
const stats = statJoin(theme, [
|
|
1182
|
+
r.usage?.turns ? `⟳ ${r.usage.turns}` : "",
|
|
1183
|
+
formatProgressStats(theme, progress)
|
|
1184
|
+
]);
|
|
1185
|
+
const c = new Container;
|
|
1186
|
+
const width = getTermWidth() - 4;
|
|
1187
|
+
const modelDisplay = modelThinkingBadge(theme, r.model);
|
|
1188
|
+
c.addChild(new Text(truncLine(`${resultGlyph(r, output, theme, isRunning, undefined, frame)} ${theme.fg("toolTitle", theme.bold(r.agent))}${modelDisplay}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
|
|
1189
|
+
if (isRunning && r.progress) {
|
|
1190
|
+
const progressSnapshotNow = snapshotNowForProgress(r.progress);
|
|
1191
|
+
const activity = compactCurrentActivity(r.progress);
|
|
1192
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
|
|
1193
|
+
const liveStatus = buildLiveStatusLine(r.progress, progressSnapshotNow);
|
|
1194
|
+
if (liveStatus && liveStatus !== activity)
|
|
1195
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ${liveStatus}`), width), 0, 0));
|
|
1196
|
+
c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
|
|
1197
|
+
if (r.artifactPaths)
|
|
1198
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
|
|
1199
|
+
return c;
|
|
1200
|
+
}
|
|
1201
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
|
|
1202
|
+
const preview = firstOutputLine(output);
|
|
1203
|
+
if (preview && r.exitCode === 0 && !hasEmptyTextOutputWithoutOutputTarget(r.task, output)) {
|
|
1204
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ${preview}`), width), 0, 0));
|
|
1205
|
+
}
|
|
1206
|
+
if (r.sessionFile)
|
|
1207
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` session: ${shortenPath(r.sessionFile)}`), width), 0, 0));
|
|
1208
|
+
if (r.artifactPaths)
|
|
1209
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
|
|
1210
|
+
if (r.truncation?.artifactPath)
|
|
1211
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` full output: ${shortenPath(r.truncation.artifactPath)}`), width), 0, 0));
|
|
1212
|
+
return c;
|
|
1213
|
+
}
|
|
1214
|
+
function renderMultiCompact(d, theme, frame) {
|
|
1215
|
+
const hasRunning = d.progress?.some((p) => p.status === "running") || d.results.some((r) => r.progress?.status === "running") || workflowGraphHasStatus(d, ["running"]);
|
|
1216
|
+
const failed = d.results.some((r) => r.exitCode !== 0 && r.progress?.status !== "running") || workflowGraphHasStatus(d, ["failed"]);
|
|
1217
|
+
const paused = d.results.some((r) => (r.interrupted || r.detached) && r.progress?.status !== "running") || workflowGraphHasStatus(d, ["paused", "detached"]);
|
|
1218
|
+
let totalSummary = d.progressSummary;
|
|
1219
|
+
if (!totalSummary) {
|
|
1220
|
+
let sawProgress = false;
|
|
1221
|
+
const summary = { toolCount: 0, tokens: 0, durationMs: 0 };
|
|
1222
|
+
for (const r of d.results) {
|
|
1223
|
+
const prog = r.progress || r.progressSummary;
|
|
1224
|
+
if (!prog)
|
|
1225
|
+
continue;
|
|
1226
|
+
sawProgress = true;
|
|
1227
|
+
summary.toolCount += prog.toolCount;
|
|
1228
|
+
summary.tokens += prog.tokens;
|
|
1229
|
+
summary.durationMs = d.mode === "chain" ? summary.durationMs + prog.durationMs : Math.max(summary.durationMs, prog.durationMs);
|
|
1230
|
+
}
|
|
1231
|
+
if (sawProgress)
|
|
1232
|
+
totalSummary = summary;
|
|
1233
|
+
}
|
|
1234
|
+
const multiLabel = buildMultiProgressLabel(d, hasRunning);
|
|
1235
|
+
const itemTitle = multiLabel.itemTitle;
|
|
1236
|
+
const stats = statJoin(theme, [multiLabel.headerLabel, formatProgressStats(theme, totalSummary), formatTotalCostStat(d.totalCost)]);
|
|
1237
|
+
const glyph = hasRunning ? theme.fg("accent", runningGlyph(frame !== undefined ? (runningSeed(progressRunningSeed(totalSummary), d.currentStepIndex) ?? 0) + frame : runningSeed(progressRunningSeed(totalSummary), d.currentStepIndex))) : failed ? theme.fg("error", "✗") : paused ? theme.fg("warning", "■") : theme.fg("success", "✓");
|
|
1238
|
+
const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
|
|
1239
|
+
const c = new Container;
|
|
1240
|
+
const width = getTermWidth() - 4;
|
|
1241
|
+
c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold(d.mode))}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
|
|
1242
|
+
const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
|
|
1243
|
+
const displayStart = multiLabel.showActiveGroupOnly ? multiLabel.groupStartIndex : 0;
|
|
1244
|
+
const displayEnd = multiLabel.showActiveGroupOnly ? multiLabel.groupEndIndex : useResultsDirectly ? d.results.length : d.chainAgents.length;
|
|
1245
|
+
const chainEntries = buildChainRenderEntries(d, multiLabel);
|
|
1246
|
+
const renderEntries = chainEntries ?? Array.from({ length: displayEnd - displayStart }, (_, offset) => {
|
|
1247
|
+
const i = displayStart + offset;
|
|
1248
|
+
const r = d.results[i];
|
|
1249
|
+
const fallbackLabel = itemTitle.toLowerCase();
|
|
1250
|
+
const rowNumber = multiLabel.showActiveGroupOnly ? i - multiLabel.groupStartIndex + 1 : i + 1;
|
|
1251
|
+
return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? r?.agent || `${fallbackLabel}-${rowNumber}` : d.chainAgents[i] || r?.agent || `${fallbackLabel}-${rowNumber}` };
|
|
1252
|
+
});
|
|
1253
|
+
for (const entry of renderEntries) {
|
|
1254
|
+
if (entry.kind === "placeholder") {
|
|
1255
|
+
const glyph = widgetStepGlyph(entry.status, theme);
|
|
1256
|
+
const statusLabel = widgetStepStatus(entry.status, theme);
|
|
1257
|
+
c.addChild(new Text(truncLine(` ${glyph} ${entry.stepLabel}: ${themeBold(theme, entry.agentName)} ${theme.fg("dim", "·")} ${statusLabel}`, width), 0, 0));
|
|
1258
|
+
if (entry.error)
|
|
1259
|
+
c.addChild(new Text(truncLine(theme.fg("error", ` ⎿ Error: ${entry.error}`), width), 0, 0));
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1262
|
+
const i = entry.resultIndex;
|
|
1263
|
+
const r = d.results[i];
|
|
1264
|
+
const rowNumber = entry.rowNumber;
|
|
1265
|
+
const agentName = entry.agentName;
|
|
1266
|
+
if (!r) {
|
|
1267
|
+
const pendingLabel = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`;
|
|
1268
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ◦ ${pendingLabel}: ${agentName} · pending`), width), 0, 0));
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
const output = getSingleResultOutput(r);
|
|
1272
|
+
const progressFromArray = d.progress?.find((p) => p.index === i) || d.progress?.find((p) => p.agent === r.agent && p.status === "running");
|
|
1273
|
+
const rProg = r.progress || progressFromArray || r.progressSummary;
|
|
1274
|
+
const rRunning = rProg && "status" in rProg && rProg.status === "running";
|
|
1275
|
+
const rPending = rProg && "status" in rProg && rProg.status === "pending";
|
|
1276
|
+
const stepNumber = r.progress?.index !== undefined ? r.progress.index + 1 : progressFromArray?.index !== undefined ? progressFromArray.index + 1 : i + 1;
|
|
1277
|
+
const stepStats = formatProgressStats(theme, rProg);
|
|
1278
|
+
const glyph = rPending ? theme.fg("dim", "◦") : resultGlyph(r, output, theme, rRunning, progressRunningSeed(rProg), frame);
|
|
1279
|
+
const pendingLabel = rPending ? ` ${theme.fg("dim", "· pending")}` : "";
|
|
1280
|
+
const stepLabel = resultRowLabel(d, multiLabel, i, stepNumber);
|
|
1281
|
+
const line = `${glyph} ${stepLabel}: ${themeBold(theme, agentName)}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${pendingLabel}`;
|
|
1282
|
+
c.addChild(new Text(truncLine(` ${line}`, width), 0, 0));
|
|
1283
|
+
if (rRunning && rProg && "status" in rProg) {
|
|
1284
|
+
const activity = compactCurrentActivity(rProg);
|
|
1285
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
|
|
1286
|
+
c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
|
|
1287
|
+
} else if (!rPending && (r.exitCode !== 0 || r.interrupted || r.detached || hasEmptyTextOutputWithoutOutputTarget(r.task, output))) {
|
|
1288
|
+
c.addChild(new Text(truncLine(theme.fg(r.exitCode !== 0 ? "error" : "dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
|
|
1289
|
+
}
|
|
1290
|
+
const outputTarget = extractOutputTarget(r.task);
|
|
1291
|
+
if (outputTarget)
|
|
1292
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${outputTarget}`), width), 0, 0));
|
|
1293
|
+
if (r.artifactPaths)
|
|
1294
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
|
|
1295
|
+
}
|
|
1296
|
+
if (d.artifacts)
|
|
1297
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` artifacts: ${shortenPath(d.artifacts.dir)}`), width), 0, 0));
|
|
1298
|
+
return c;
|
|
1299
|
+
}
|
|
1300
|
+
export function renderSubagentResult(result, options, theme, frame) {
|
|
1301
|
+
const d = result.details;
|
|
1302
|
+
if (!d || !d.results.length) {
|
|
1303
|
+
const t = result.content[0];
|
|
1304
|
+
const text = t?.type === "text" ? t.text : "(no output)";
|
|
1305
|
+
const contextPrefix = d?.context === "fork" ? `${theme.fg("warning", "[fork]")} ` : "";
|
|
1306
|
+
const width = getTermWidth() - 4;
|
|
1307
|
+
if (!text.includes(`
|
|
1308
|
+
`))
|
|
1309
|
+
return new Text(truncLine(`${contextPrefix}${text}`, width), 0, 0);
|
|
1310
|
+
const c = new Container;
|
|
1311
|
+
const wrapped = wrapPlainText(`${contextPrefix}${text}`, width);
|
|
1312
|
+
for (const line of wrapped)
|
|
1313
|
+
c.addChild(new Text(line, 0, 0));
|
|
1314
|
+
return c;
|
|
1315
|
+
}
|
|
1316
|
+
const expanded = options.expanded;
|
|
1317
|
+
const mdTheme = getMarkdownTheme();
|
|
1318
|
+
if (d.mode === "single" && d.results.length === 1) {
|
|
1319
|
+
const r = d.results[0];
|
|
1320
|
+
if (!expanded)
|
|
1321
|
+
return renderSingleCompact(d, r, theme, frame);
|
|
1322
|
+
const isRunning = r.progress?.status === "running";
|
|
1323
|
+
const icon = isRunning ? theme.fg("warning", "running") : r.detached ? theme.fg("warning", "detached") : r.exitCode === 0 ? theme.fg("success", "ok") : theme.fg("error", "failed");
|
|
1324
|
+
const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
|
|
1325
|
+
const output = r.truncation?.text || getSingleResultOutput(r);
|
|
1326
|
+
const progressInfo = isRunning && r.progress ? ` | ${r.progress.toolCount} tools, ${formatTokens(r.progress.tokens)} tok, ${formatDuration(r.progress.durationMs)}` : r.progressSummary ? ` | ${r.progressSummary.toolCount} tools, ${formatTokens(r.progressSummary.tokens)} tok, ${formatDuration(r.progressSummary.durationMs)}` : "";
|
|
1327
|
+
const w = getTermWidth() - 4;
|
|
1328
|
+
const fit = (text) => expanded ? text : truncLine(text, w);
|
|
1329
|
+
const toolCallLines = getToolCallLines(r, expanded);
|
|
1330
|
+
const c = new Container;
|
|
1331
|
+
c.addChild(new Text(fit(`${icon} ${theme.fg("toolTitle", theme.bold(r.agent))}${contextBadge}${progressInfo}`), 0, 0));
|
|
1332
|
+
c.addChild(new Spacer(1));
|
|
1333
|
+
const taskMaxLen = Math.max(20, w - 8);
|
|
1334
|
+
const taskPreview = expanded || r.task.length <= taskMaxLen ? r.task : `${r.task.slice(0, taskMaxLen)}...`;
|
|
1335
|
+
c.addChild(new Text(fit(theme.fg("dim", `Task: ${taskPreview}`)), 0, 0));
|
|
1336
|
+
c.addChild(new Spacer(1));
|
|
1337
|
+
if (isRunning && r.progress) {
|
|
1338
|
+
const progressSnapshotNow = snapshotNowForProgress(r.progress);
|
|
1339
|
+
const toolLine = formatCurrentToolLine(r.progress, w, expanded, progressSnapshotNow);
|
|
1340
|
+
if (toolLine) {
|
|
1341
|
+
c.addChild(new Text(fit(theme.fg("warning", `> ${toolLine}`)), 0, 0));
|
|
1342
|
+
}
|
|
1343
|
+
const liveStatusLine = buildLiveStatusLine(r.progress, progressSnapshotNow);
|
|
1344
|
+
if (liveStatusLine) {
|
|
1345
|
+
c.addChild(new Text(fit(theme.fg("accent", liveStatusLine)), 0, 0));
|
|
1346
|
+
}
|
|
1347
|
+
c.addChild(new Text(fit(theme.fg("accent", liveDetailHintText())), 0, 0));
|
|
1348
|
+
if (r.artifactPaths) {
|
|
1349
|
+
c.addChild(new Text(fit(theme.fg("dim", `Artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
|
|
1350
|
+
}
|
|
1351
|
+
if (r.progress.recentTools?.length) {
|
|
1352
|
+
for (const t of r.progress.recentTools.slice(-3)) {
|
|
1353
|
+
const maxArgsLen = Math.max(40, w - 24);
|
|
1354
|
+
const argsPreview = expanded || t.args.length <= maxArgsLen ? t.args : `${t.args.slice(0, maxArgsLen)}...`;
|
|
1355
|
+
c.addChild(new Text(fit(theme.fg("dim", `${t.tool}: ${argsPreview}`)), 0, 0));
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
for (const line of (r.progress.recentOutput ?? []).slice(-5)) {
|
|
1359
|
+
c.addChild(new Text(fit(theme.fg("dim", ` ${line}`)), 0, 0));
|
|
1360
|
+
}
|
|
1361
|
+
if (toolLine || liveStatusLine || r.progress.recentTools?.length || r.progress.recentOutput?.length || r.artifactPaths) {
|
|
1362
|
+
c.addChild(new Spacer(1));
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (expanded) {
|
|
1366
|
+
for (const line of toolCallLines) {
|
|
1367
|
+
c.addChild(new Text(fit(theme.fg("muted", line)), 0, 0));
|
|
1368
|
+
}
|
|
1369
|
+
if (toolCallLines.length)
|
|
1370
|
+
c.addChild(new Spacer(1));
|
|
1371
|
+
}
|
|
1372
|
+
if (output)
|
|
1373
|
+
c.addChild(new Markdown(output, 0, 0, mdTheme));
|
|
1374
|
+
c.addChild(new Spacer(1));
|
|
1375
|
+
if (r.skills?.length) {
|
|
1376
|
+
c.addChild(new Text(fit(theme.fg("dim", `Skills: ${r.skills.join(", ")}`)), 0, 0));
|
|
1377
|
+
}
|
|
1378
|
+
if (r.skillsWarning) {
|
|
1379
|
+
c.addChild(new Text(fit(theme.fg("warning", `Warning: ${r.skillsWarning}`)), 0, 0));
|
|
1380
|
+
}
|
|
1381
|
+
if (r.attemptedModels && r.attemptedModels.length > 1) {
|
|
1382
|
+
c.addChild(new Text(fit(theme.fg("dim", `Fallbacks: ${r.attemptedModels.join(" → ")}`)), 0, 0));
|
|
1383
|
+
}
|
|
1384
|
+
c.addChild(new Text(fit(theme.fg("dim", formatUsage(r.usage, r.model))), 0, 0));
|
|
1385
|
+
if (r.sessionFile) {
|
|
1386
|
+
c.addChild(new Text(fit(theme.fg("dim", `Session: ${shortenPath(r.sessionFile)}`)), 0, 0));
|
|
1387
|
+
}
|
|
1388
|
+
if (!isRunning && r.artifactPaths) {
|
|
1389
|
+
c.addChild(new Spacer(1));
|
|
1390
|
+
c.addChild(new Text(fit(theme.fg("dim", `Artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
|
|
1391
|
+
}
|
|
1392
|
+
return c;
|
|
1393
|
+
}
|
|
1394
|
+
if (!expanded)
|
|
1395
|
+
return renderMultiCompact(d, theme, frame);
|
|
1396
|
+
const hasRunning = d.progress?.some((p) => p.status === "running") || d.results.some((r) => r.progress?.status === "running") || workflowGraphHasStatus(d, ["running"]);
|
|
1397
|
+
const ok = d.results.filter((r) => r.progress?.status === "completed" || r.exitCode === 0 && r.progress?.status !== "running").length;
|
|
1398
|
+
const hasEmptyWithoutTarget = d.results.some((r) => r.exitCode === 0 && r.progress?.status !== "running" && hasEmptyTextOutputWithoutOutputTarget(r.task, getSingleResultOutput(r)));
|
|
1399
|
+
const hasWorkflowFailure = workflowGraphHasStatus(d, ["failed"]);
|
|
1400
|
+
const hasWorkflowPause = workflowGraphHasStatus(d, ["paused", "detached"]);
|
|
1401
|
+
const icon = hasRunning ? theme.fg("warning", "running") : hasEmptyWithoutTarget ? theme.fg("warning", "warning") : hasWorkflowFailure ? theme.fg("error", "failed") : hasWorkflowPause ? theme.fg("warning", "paused") : ok === d.results.length ? theme.fg("success", "ok") : theme.fg("error", "failed");
|
|
1402
|
+
const totalSummary = d.progressSummary || d.results.reduce((acc, r) => {
|
|
1403
|
+
const prog = r.progress || r.progressSummary;
|
|
1404
|
+
if (prog) {
|
|
1405
|
+
acc.toolCount += prog.toolCount;
|
|
1406
|
+
acc.tokens += prog.tokens;
|
|
1407
|
+
acc.durationMs = d.mode === "chain" ? acc.durationMs + prog.durationMs : Math.max(acc.durationMs, prog.durationMs);
|
|
1408
|
+
}
|
|
1409
|
+
return acc;
|
|
1410
|
+
}, { toolCount: 0, tokens: 0, durationMs: 0 });
|
|
1411
|
+
const summaryParts = [
|
|
1412
|
+
totalSummary.toolCount || totalSummary.tokens ? `${totalSummary.toolCount} tools, ${formatTokens(totalSummary.tokens)} tok, ${formatDuration(totalSummary.durationMs)}` : "",
|
|
1413
|
+
formatTotalCostStat(d.totalCost)
|
|
1414
|
+
].filter(Boolean);
|
|
1415
|
+
const summaryStr = summaryParts.length ? ` | ${summaryParts.join(", ")}` : "";
|
|
1416
|
+
const modeLabel = d.mode;
|
|
1417
|
+
const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
|
|
1418
|
+
const multiLabel = buildMultiProgressLabel(d, hasRunning);
|
|
1419
|
+
const itemTitle = multiLabel.itemTitle;
|
|
1420
|
+
const chainVis = d.chainAgents?.length && !multiLabel.hasParallelInChain ? d.chainAgents.map((agent, i) => {
|
|
1421
|
+
const result = d.results[i];
|
|
1422
|
+
const isFailed = result && result.exitCode !== 0 && result.progress?.status !== "running";
|
|
1423
|
+
const isComplete = result && result.exitCode === 0 && result.progress?.status !== "running";
|
|
1424
|
+
const isEmptyWithoutTarget = Boolean(result) && Boolean(isComplete) && hasEmptyTextOutputWithoutOutputTarget(result.task, getSingleResultOutput(result));
|
|
1425
|
+
const isCurrent = i === (d.currentStepIndex ?? d.results.length);
|
|
1426
|
+
const stepIcon = isFailed ? theme.fg("error", "failed") : isEmptyWithoutTarget ? theme.fg("warning", "warning") : isComplete ? theme.fg("success", "done") : isCurrent && hasRunning ? theme.fg("warning", "running") : theme.fg("dim", "pending");
|
|
1427
|
+
return `${stepIcon} ${agent}`;
|
|
1428
|
+
}).join(theme.fg("dim", " → ")) : null;
|
|
1429
|
+
const w = getTermWidth() - 4;
|
|
1430
|
+
const fit = (text) => expanded ? text : truncLine(text, w);
|
|
1431
|
+
const c = new Container;
|
|
1432
|
+
c.addChild(new Text(fit(`${icon} ${theme.fg("toolTitle", theme.bold(modeLabel))}${contextBadge} · ${multiLabel.headerLabel}${summaryStr}`), 0, 0));
|
|
1433
|
+
if (chainVis) {
|
|
1434
|
+
c.addChild(new Text(fit(` ${chainVis}`), 0, 0));
|
|
1435
|
+
}
|
|
1436
|
+
const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
|
|
1437
|
+
const displayStart = multiLabel.showActiveGroupOnly ? multiLabel.groupStartIndex : 0;
|
|
1438
|
+
const displayEnd = multiLabel.showActiveGroupOnly ? multiLabel.groupEndIndex : useResultsDirectly ? d.results.length : d.chainAgents.length;
|
|
1439
|
+
const chainEntries = buildChainRenderEntries(d, multiLabel);
|
|
1440
|
+
const renderEntries = chainEntries ?? Array.from({ length: displayEnd - displayStart }, (_, offset) => {
|
|
1441
|
+
const i = displayStart + offset;
|
|
1442
|
+
const r = d.results[i];
|
|
1443
|
+
const rowNumber = multiLabel.showActiveGroupOnly ? i - multiLabel.groupStartIndex + 1 : i + 1;
|
|
1444
|
+
return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? r?.agent || `step-${rowNumber}` : d.chainAgents[i] || r?.agent || `step-${rowNumber}` };
|
|
1445
|
+
});
|
|
1446
|
+
c.addChild(new Spacer(1));
|
|
1447
|
+
for (const entry of renderEntries) {
|
|
1448
|
+
if (entry.kind === "placeholder") {
|
|
1449
|
+
const statusLabel = widgetStepStatus(entry.status, theme);
|
|
1450
|
+
c.addChild(new Text(fit(` ${statusLabel} ${entry.stepLabel}: ${theme.bold(entry.agentName)}`), 0, 0));
|
|
1451
|
+
c.addChild(new Text(theme.fg(entry.status === "failed" ? "error" : "dim", ` status: ${entry.status}`), 0, 0));
|
|
1452
|
+
if (entry.error)
|
|
1453
|
+
c.addChild(new Text(theme.fg("error", ` error: ${entry.error}`), 0, 0));
|
|
1454
|
+
c.addChild(new Spacer(1));
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
const i = entry.resultIndex;
|
|
1458
|
+
const r = d.results[i];
|
|
1459
|
+
const rowNumber = entry.rowNumber;
|
|
1460
|
+
const agentName = entry.agentName;
|
|
1461
|
+
if (!r) {
|
|
1462
|
+
const pendingLabel = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`;
|
|
1463
|
+
c.addChild(new Text(fit(theme.fg("dim", ` ${pendingLabel}: ${agentName}`)), 0, 0));
|
|
1464
|
+
c.addChild(new Text(theme.fg("dim", ` status: pending`), 0, 0));
|
|
1465
|
+
c.addChild(new Spacer(1));
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
const progressFromArray = d.progress?.find((p) => p.index === i) || d.progress?.find((p) => p.agent === r.agent && p.status === "running");
|
|
1469
|
+
const rProg = r.progress || progressFromArray || r.progressSummary;
|
|
1470
|
+
const rRunning = rProg?.status === "running";
|
|
1471
|
+
const stepNumber = typeof rProg?.index === "number" ? rProg.index + 1 : i + 1;
|
|
1472
|
+
const resultOutput = getSingleResultOutput(r);
|
|
1473
|
+
const statusIcon = rRunning ? theme.fg("warning", "running") : r.exitCode !== 0 ? theme.fg("error", "failed") : hasEmptyTextOutputWithoutOutputTarget(r.task, resultOutput) ? theme.fg("warning", "warning") : theme.fg("success", "done");
|
|
1474
|
+
const stats = rProg ? ` | ${rProg.toolCount} tools, ${formatDuration(rProg.durationMs)}` : "";
|
|
1475
|
+
const modelDisplay = modelThinkingBadge(theme, r.model);
|
|
1476
|
+
const stepLabel = resultRowLabel(d, multiLabel, i, stepNumber);
|
|
1477
|
+
const stepHeader = rRunning ? `${statusIcon} ${stepLabel}: ${theme.bold(theme.fg("warning", r.agent))}${modelDisplay}${stats}` : `${statusIcon} ${stepLabel}: ${theme.bold(r.agent)}${modelDisplay}${stats}`;
|
|
1478
|
+
const toolCallLines = getToolCallLines(r, expanded);
|
|
1479
|
+
c.addChild(new Text(fit(stepHeader), 0, 0));
|
|
1480
|
+
const taskMaxLen = Math.max(20, w - 12);
|
|
1481
|
+
const taskPreview = expanded || r.task.length <= taskMaxLen ? r.task : `${r.task.slice(0, taskMaxLen)}...`;
|
|
1482
|
+
c.addChild(new Text(fit(theme.fg("dim", ` task: ${taskPreview}`)), 0, 0));
|
|
1483
|
+
const outputTarget = extractOutputTarget(r.task);
|
|
1484
|
+
if (outputTarget) {
|
|
1485
|
+
c.addChild(new Text(fit(theme.fg("dim", ` output: ${outputTarget}`)), 0, 0));
|
|
1486
|
+
}
|
|
1487
|
+
if (r.skills?.length) {
|
|
1488
|
+
c.addChild(new Text(fit(theme.fg("dim", ` skills: ${r.skills.join(", ")}`)), 0, 0));
|
|
1489
|
+
}
|
|
1490
|
+
if (r.skillsWarning) {
|
|
1491
|
+
c.addChild(new Text(fit(theme.fg("warning", ` Warning: ${r.skillsWarning}`)), 0, 0));
|
|
1492
|
+
}
|
|
1493
|
+
if (r.attemptedModels && r.attemptedModels.length > 1) {
|
|
1494
|
+
c.addChild(new Text(fit(theme.fg("dim", ` fallbacks: ${r.attemptedModels.join(" → ")}`)), 0, 0));
|
|
1495
|
+
}
|
|
1496
|
+
if (rRunning && rProg) {
|
|
1497
|
+
if (rProg.skills?.length) {
|
|
1498
|
+
c.addChild(new Text(fit(theme.fg("accent", ` skills: ${rProg.skills.join(", ")}`)), 0, 0));
|
|
1499
|
+
}
|
|
1500
|
+
const progressSnapshotNow = snapshotNowForProgress(rProg);
|
|
1501
|
+
const toolLine = formatCurrentToolLine(rProg, w, expanded, progressSnapshotNow);
|
|
1502
|
+
if (toolLine) {
|
|
1503
|
+
c.addChild(new Text(fit(theme.fg("warning", ` > ${toolLine}`)), 0, 0));
|
|
1504
|
+
}
|
|
1505
|
+
const liveStatusLine = buildLiveStatusLine(rProg, progressSnapshotNow);
|
|
1506
|
+
if (liveStatusLine) {
|
|
1507
|
+
c.addChild(new Text(fit(theme.fg("accent", ` ${liveStatusLine}`)), 0, 0));
|
|
1508
|
+
}
|
|
1509
|
+
c.addChild(new Text(fit(theme.fg("accent", ` ${liveDetailHintText()}`)), 0, 0));
|
|
1510
|
+
if (r.artifactPaths) {
|
|
1511
|
+
c.addChild(new Text(fit(theme.fg("dim", ` artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
|
|
1512
|
+
}
|
|
1513
|
+
if (rProg.recentTools?.length) {
|
|
1514
|
+
for (const t of rProg.recentTools.slice(-3)) {
|
|
1515
|
+
const maxArgsLen = Math.max(40, w - 30);
|
|
1516
|
+
const argsPreview = expanded || t.args.length <= maxArgsLen ? t.args : `${t.args.slice(0, maxArgsLen)}...`;
|
|
1517
|
+
c.addChild(new Text(fit(theme.fg("dim", ` ${t.tool}: ${argsPreview}`)), 0, 0));
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
const recentLines = (rProg.recentOutput ?? []).slice(-5);
|
|
1521
|
+
for (const line of recentLines) {
|
|
1522
|
+
c.addChild(new Text(fit(theme.fg("dim", ` ${line}`)), 0, 0));
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (!rRunning && r.artifactPaths) {
|
|
1526
|
+
c.addChild(new Text(fit(theme.fg("dim", ` artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
|
|
1527
|
+
}
|
|
1528
|
+
if (expanded && !rRunning) {
|
|
1529
|
+
for (const line of toolCallLines) {
|
|
1530
|
+
c.addChild(new Text(fit(theme.fg("muted", ` ${line}`)), 0, 0));
|
|
1531
|
+
}
|
|
1532
|
+
if (toolCallLines.length)
|
|
1533
|
+
c.addChild(new Spacer(1));
|
|
1534
|
+
}
|
|
1535
|
+
c.addChild(new Spacer(1));
|
|
1536
|
+
}
|
|
1537
|
+
if (d.artifacts) {
|
|
1538
|
+
c.addChild(new Spacer(1));
|
|
1539
|
+
c.addChild(new Text(fit(theme.fg("dim", `Artifacts dir: ${shortenPath(d.artifacts.dir)}`)), 0, 0));
|
|
1540
|
+
}
|
|
1541
|
+
return c;
|
|
1542
|
+
}
|