@astralyn/pi 0.82.2 → 0.82.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +70 -634
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +3 -2
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +3 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +31 -12
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +13 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +19 -1
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +3 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -0
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +6 -0
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/extensions/plan/constants.d.ts +31 -0
- package/dist/extensions/plan/constants.d.ts.map +1 -0
- package/dist/extensions/plan/constants.js +57 -0
- package/dist/extensions/plan/constants.js.map +1 -0
- package/dist/extensions/plan/index.d.ts +21 -0
- package/dist/extensions/plan/index.d.ts.map +1 -0
- package/dist/extensions/plan/index.js +291 -0
- package/dist/extensions/plan/index.js.map +1 -0
- package/dist/extensions/plan/schema.d.ts +15 -0
- package/dist/extensions/plan/schema.d.ts.map +1 -0
- package/dist/extensions/plan/schema.js +13 -0
- package/dist/extensions/plan/schema.js.map +1 -0
- package/dist/extensions/plan/state.d.ts +29 -0
- package/dist/extensions/plan/state.d.ts.map +1 -0
- package/dist/extensions/plan/state.js +74 -0
- package/dist/extensions/plan/state.js.map +1 -0
- package/dist/extensions/plan/storage.d.ts +18 -0
- package/dist/extensions/plan/storage.d.ts.map +1 -0
- package/dist/extensions/plan/storage.js +58 -0
- package/dist/extensions/plan/storage.js.map +1 -0
- package/dist/extensions/rewind/anchor.d.ts +29 -0
- package/dist/extensions/rewind/anchor.d.ts.map +1 -0
- package/dist/extensions/rewind/anchor.js +35 -0
- package/dist/extensions/rewind/anchor.js.map +1 -0
- package/dist/extensions/rewind/engine.d.ts +2 -6
- package/dist/extensions/rewind/engine.d.ts.map +1 -1
- package/dist/extensions/rewind/engine.js +41 -10
- package/dist/extensions/rewind/engine.js.map +1 -1
- package/dist/extensions/rewind/index.d.ts.map +1 -1
- package/dist/extensions/rewind/index.js +55 -21
- package/dist/extensions/rewind/index.js.map +1 -1
- package/dist/extensions/rewind/menu.d.ts.map +1 -1
- package/dist/extensions/rewind/menu.js +7 -2
- package/dist/extensions/rewind/menu.js.map +1 -1
- package/dist/extensions/rewind/restore.d.ts +26 -9
- package/dist/extensions/rewind/restore.d.ts.map +1 -1
- package/dist/extensions/rewind/restore.js +58 -16
- package/dist/extensions/rewind/restore.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +1 -0
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +20 -4
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +2 -13
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +4 -3
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +9 -3
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +12 -5
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +166 -41
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts +2 -5
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +8 -13
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +3 -1
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +111 -66
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts +0 -6
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +2 -3
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +32 -16
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +3 -2
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +3 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +10 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +31 -18
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/coalescing-terminal.d.ts +62 -0
- package/dist/utils/coalescing-terminal.d.ts.map +1 -0
- package/dist/utils/coalescing-terminal.js +151 -0
- package/dist/utils/coalescing-terminal.js.map +1 -0
- package/docs/bundled/README.md +38 -0
- package/docs/bundled/extensions/README.md +19 -0
- package/docs/bundled/extensions/plan.md +31 -0
- package/docs/{distribution → bundled}/extensions/question.md +0 -11
- package/docs/{distribution → bundled}/extensions/rewind.md +19 -18
- package/docs/{distribution → bundled}/extensions/router.md +1 -14
- package/docs/{distribution → bundled}/extensions/statusline.md +1 -2
- package/docs/{distribution → bundled}/extensions/subagent.md +15 -22
- package/docs/bundled/extensions/todo.md +28 -0
- package/docs/{distribution → bundled}/themes.md +4 -11
- package/docs/{distribution → bundled}/tool-presentation.md +4 -10
- package/docs/compaction.md +18 -14
- package/docs/custom-provider.md +8 -8
- package/docs/docs.json +61 -9
- package/docs/extensions.md +14 -13
- package/docs/index.md +12 -7
- package/docs/json.md +4 -4
- package/docs/providers.md +1 -1
- package/docs/rpc.md +3 -9
- package/docs/session-format.md +5 -5
- package/docs/skills.md +1 -1
- package/docs/themes.md +4 -8
- package/docs/tui.md +1 -1
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +4 -4
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/gondolin/index.ts +4 -6
- package/examples/extensions/message-renderer.ts +2 -2
- package/examples/extensions/overlay-qa-tests.ts +2 -2
- package/examples/extensions/project-trust.ts +2 -2
- package/examples/sdk/README.md +38 -44
- package/npm-shrinkwrap.json +2 -2
- package/package.json +6 -2
- package/docs/development.md +0 -68
- package/docs/distribution/README.md +0 -34
- package/docs/distribution/architecture.md +0 -102
- package/docs/distribution/extensions/README.md +0 -17
- package/docs/distribution/maintenance.md +0 -121
- package/docs/distribution/release.md +0 -85
- package/examples/extensions/subagent/README.md +0 -175
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -1009
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
- /package/docs/{distribution → bundled}/extensions/deepwiki.md +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE/F,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAEtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAyC,MAAM,YAAY,CAAC;AA8PzF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAgBhF;AAED,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EACxC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,GACd,SAAS,CAyCX","sourcesContent":["import { type Component, Container, Markdown, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"../../core/extensions/types.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getMarkdownTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { statusSummary } from \"./runner.ts\";\nimport type { SubagentParams } from \"./schema.ts\";\nimport type { SubagentDetails, SubagentRunDetails, SubagentRunStatus } from \"./types.ts\";\n\nconst SINGLE_EXCERPT_LIMIT = 200;\nconst RUN_LINE_EXCERPT_LIMIT = 64;\nconst LIVE_TAIL_LIMIT = 100;\nconst COLLAPSED_RUN_LIMIT = 4;\n\nconst ACTIVITY_GROUPS = [\n\t{ toolName: \"read\", verb: \"read\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"grep\", verb: \"searched\", singular: \"pattern\", plural: \"patterns\" },\n\t{ toolName: \"find\", verb: \"searched\", singular: \"path pattern\", plural: \"path patterns\" },\n\t{ toolName: \"ls\", verb: \"listed\", singular: \"directory\", plural: \"directories\" },\n\t{ toolName: \"bash\", verb: \"ran\", singular: \"command\", plural: \"commands\" },\n\t{ toolName: \"edit\", verb: \"edited\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"write\", verb: \"wrote\", singular: \"file\", plural: \"files\" },\n] as const;\n\nfunction singleAgentName(args: { agent?: string | null }): string {\n\treturn args.agent ?? \"general\";\n}\n\nfunction truncate(text: string, limit: number): string {\n\treturn text.length <= limit ? text : `${text.slice(0, Math.max(0, limit - 1))}…`;\n}\n\n// Transcript excerpts render inside plain Text components, so markdown\n// punctuation would show up literally; strip the common inline syntax.\nfunction stripInlineMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/```[a-zA-Z0-9-]*/gu, \"\")\n\t\t.replace(/`([^`]*)`/gu, \"$1\")\n\t\t.replace(/\\*\\*([^*]+)\\*\\*/gu, \"$1\")\n\t\t.replace(/__([^_]+)__/gu, \"$1\")\n\t\t.replace(/\\[([^\\]]+)\\]\\([^)]*\\)/gu, \"$1\")\n\t\t.replace(/^#{1,6}\\s+/gmu, \"\");\n}\n\n// Markdown tables and horizontal rules turn into symbol soup when\n// flattened onto one line; drop those lines before inline stripping.\nfunction stripBlockMarkdown(text: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.filter((line) => {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (trimmed.startsWith(\"|\")) return false;\n\t\t\treturn !(trimmed.length >= 3 && /^[-—─═=*_|:\\s]+$/u.test(trimmed));\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction excerpt(text: string, limit: number): string {\n\t// finalOutput/liveText carry model-facing truncation notices from\n\t// boundText/tailText; in the transcript an ellipsis is enough.\n\tconst cleaned = text.replace(/\\[(?:Output truncated(?:: \\d+ bytes omitted\\.)?|Earlier output omitted\\.)\\]/gu, \"…\");\n\treturn truncate(stripInlineMarkdown(stripBlockMarkdown(cleaned)).replace(/\\s+/gu, \" \").trim(), limit);\n}\n\nfunction liveTail(run: SubagentRunDetails): string | undefined {\n\tconst lines = run.liveText\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean);\n\tconst last = lines.at(-1);\n\treturn last ? excerpt(last, LIVE_TAIL_LIMIT) : undefined;\n}\n\nfunction statusMarker(status: SubagentRunStatus, theme: Theme): string {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"failed\":\n\t\t\treturn theme.fg(\"error\", \"×\");\n\t\tcase \"aborted\":\n\t\t\treturn theme.fg(\"warning\", \"■\");\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"accent\", \"●\");\n\t\tdefault:\n\t\t\treturn theme.fg(\"muted\", \"○\");\n\t}\n}\n\nfunction runTitle(run: SubagentRunDetails, theme: Theme, mode: SubagentDetails[\"mode\"]): string {\n\tconst step = mode === \"chain\" && run.step ? theme.fg(\"muted\", `${run.step}. `) : \"\";\n\treturn `${statusMarker(run.status, theme)} ${step}${theme.fg(\"accent\", run.agent)}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`;\n}\n\nfunction runProgressText(run: SubagentRunDetails): string {\n\tconst items = [`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}`];\n\tif (run.usage.totalTokens) items.push(`${formatTokens(run.usage.totalTokens)} tokens`);\n\treturn items.join(\" · \");\n}\n\nfunction runLine(run: SubagentRunDetails, theme: Theme, mode: SubagentDetails[\"mode\"]): string {\n\tlet line = runTitle(run, theme, mode);\n\tconst detail =\n\t\trun.status === \"running\"\n\t\t\t? run.currentActivity\n\t\t\t: run.status === \"failed\" || run.status === \"aborted\"\n\t\t\t\t? run.error && excerpt(run.error, RUN_LINE_EXCERPT_LIMIT)\n\t\t\t\t: run.finalOutput && excerpt(run.finalOutput, RUN_LINE_EXCERPT_LIMIT);\n\tif (detail) line += theme.fg(run.status === \"failed\" ? \"error\" : \"dim\", ` — ${detail}`);\n\tif (run.status === \"running\") line += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\tconst settled = run.status !== \"running\" && run.status !== \"queued\";\n\tif (settled && run.startedAt !== undefined && run.endedAt !== undefined) {\n\t\tline += theme.fg(\"dim\", ` · ${formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))}`);\n\t}\n\treturn line;\n}\n\n// Keep active work visible while a batch is in flight: completed runs\n// may otherwise crowd a still-running task out of the collapsed window.\nfunction selectCollapsedRuns(runs: SubagentRunDetails[], isPartial: boolean): SubagentRunDetails[] {\n\tif (runs.length <= COLLAPSED_RUN_LIMIT) return runs;\n\tif (!isPartial) return runs.slice(0, COLLAPSED_RUN_LIMIT);\n\tconst active = runs.filter((run) => run.status === \"running\" || run.status === \"queued\");\n\tconst settled = runs.filter((run) => run.status !== \"running\" && run.status !== \"queued\");\n\treturn [...active, ...settled].slice(0, COLLAPSED_RUN_LIMIT);\n}\n\nfunction singleCollapsedLines(details: SubagentDetails, theme: Theme): string[] {\n\tconst run = details.runs[0];\n\tif (!run) return [theme.fg(\"muted\", \"Initializing…\")];\n\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\tconst isInitializing =\n\t\t\trun.status === \"running\" && run.usage.turns === 0 && run.usage.toolUses === 0 && run.liveText.length === 0;\n\t\tconst lines = [\n\t\t\t`${statusMarker(run.status, theme)} ${theme.fg(\"dim\", run.currentActivity ?? (run.status === \"queued\" ? \"queued\" : isInitializing ? \"Initializing…\" : \"Thinking…\"))}`,\n\t\t];\n\t\tconst tail = liveTail(run);\n\t\tif (tail) lines.push(theme.fg(\"dim\", tail));\n\t\treturn lines;\n\t}\n\tif (run.error) return [theme.fg(\"error\", excerpt(run.error, SINGLE_EXCERPT_LIMIT))];\n\tif (run.finalOutput) return [theme.fg(\"toolOutput\", excerpt(run.finalOutput, SINGLE_EXCERPT_LIMIT))];\n\treturn [theme.fg(\"muted\", run.status)];\n}\n\nfunction activitySummaryText(details: SubagentDetails): string {\n\tconst toolCounts = new Map<string, number>();\n\tlet activityCount = 0;\n\tfor (const run of details.runs) {\n\t\tfor (const activity of run.activities) {\n\t\t\tactivityCount++;\n\t\t\ttoolCounts.set(activity.toolName, (toolCounts.get(activity.toolName) ?? 0) + 1);\n\t\t}\n\t}\n\tconst items: string[] = [];\n\tlet groupedCount = 0;\n\tfor (const group of ACTIVITY_GROUPS) {\n\t\tconst count = toolCounts.get(group.toolName) ?? 0;\n\t\tif (count === 0) continue;\n\t\tgroupedCount += count;\n\t\titems.push(`${group.verb} ${count} ${count === 1 ? group.singular : group.plural}`);\n\t}\n\tconst otherCount = activityCount - groupedCount;\n\tif (otherCount > 0) items.push(`used ${otherCount} other tool${otherCount === 1 ? \"\" : \"s\"}`);\n\tif (items.length === 0) return \"\";\n\tconst earlierCount = Math.max(0, details.usage.toolUses - activityCount);\n\tif (earlierCount > 0) items.push(`${earlierCount} earlier tool use${earlierCount === 1 ? \"\" : \"s\"}`);\n\treturn `${items[0]![0]!.toUpperCase()}${items[0]!.slice(1)}${items\n\t\t.slice(1)\n\t\t.map((item) => ` · ${item}`)\n\t\t.join(\"\")}`;\n}\n\nfunction usageText(details: SubagentDetails, includeToolUses = true): string {\n\tconst usage = details.usage;\n\tconst items: string[] = [];\n\tif (includeToolUses && usage.toolUses) items.push(`${usage.toolUses} tool use${usage.toolUses === 1 ? \"\" : \"s\"}`);\n\tif (usage.turns) items.push(`${usage.turns} turn${usage.turns === 1 ? \"\" : \"s\"}`);\n\tif (usage.output) items.push(`↓${formatTokens(usage.output)}`);\n\tif (usage.cost) items.push(`$${usage.cost.toFixed(3)}`);\n\tconst duration = details.endedAt ? Math.max(0, (details.endedAt - details.startedAt) / 1000) : undefined;\n\tif (duration !== undefined) items.push(formatDuration(duration));\n\treturn items.join(\" · \");\n}\n\nfunction formatTokens(value: number): string {\n\tif (value < 1_000) return String(value);\n\tif (value < 1_000_000) return `${(value / 1_000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}M`;\n}\n\nfunction formatDuration(seconds: number): string {\n\tif (seconds >= 90) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;\n\treturn `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;\n}\n\n// A single run's title and usage would duplicate the call header and\n// the call-level usage line, so `single` drops both and folds the\n// duration into the metadata line instead.\nfunction renderRunDetails(\n\trun: SubagentRunDetails,\n\ttheme: Theme,\n\tmode: SubagentDetails[\"mode\"],\n\tsingle: boolean,\n): Component {\n\tconst container = new Container();\n\tconst duration =\n\t\trun.startedAt !== undefined && run.endedAt !== undefined\n\t\t\t? formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))\n\t\t\t: undefined;\n\tif (!single) {\n\t\tlet title = runTitle(run, theme, mode);\n\t\tif (run.status === \"running\") title += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\telse if (duration) title += theme.fg(\"dim\", ` · ${duration}`);\n\t\tcontainer.addChild(new Text(title, 0, 0));\n\t}\n\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task\"), 0, 0));\n\tcontainer.addChild(new Text(theme.fg(\"dim\", run.prompt), 0, 0));\n\tif (run.activities.length > 0) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Activity\"), 0, 0));\n\t\tfor (const activity of run.activities) {\n\t\t\tconst marker =\n\t\t\t\tactivity.status === \"succeeded\"\n\t\t\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t\t\t: activity.status === \"failed\"\n\t\t\t\t\t\t? theme.fg(\"error\", \"×\")\n\t\t\t\t\t\t: theme.fg(\"accent\", \"●\");\n\t\t\tlet text = `${marker} ${theme.fg(\"toolOutput\", excerpt(activity.summary, 96))}`;\n\t\t\tif (activity.resultSummary) text += ` ${theme.fg(\"dim\", `· ${excerpt(activity.resultSummary, 64)}`)}`;\n\t\t\tcontainer.addChild(new Text(text, 0, 0));\n\t\t}\n\t}\n\tif (run.error) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Error: ${run.error}`), 0, 0));\n\t}\n\tif (run.finalOutput) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Response\"), 0, 0));\n\t\tcontainer.addChild(new Markdown(run.finalOutput, 0, 0, getMarkdownTheme()));\n\t}\n\tconst metadata = [\n\t\t`${run.model} · ${run.thinking}`,\n\t\trun.usage.toolUses ? `${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.turns ? `${run.usage.turns} turn${run.usage.turns === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.output ? `↓${formatTokens(run.usage.output)}` : undefined,\n\t\trun.usage.cost ? `$${run.usage.cost.toFixed(3)}` : undefined,\n\t\tsingle ? duration : undefined,\n\t]\n\t\t.filter((item): item is string => Boolean(item))\n\t\t.join(\" · \");\n\tif (metadata) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", metadata), 0, 0));\n\t}\n\treturn container;\n}\n\n// The call header stays a single line: run rows in the result area take\n// over within the first update and carry richer per-task state, so a\n// task list here would render everything twice.\nexport function renderSubagentCall(args: SubagentParams, theme: Theme): Component {\n\tlet text = theme.fg(\"toolTitle\", theme.bold(\"Subagent \"));\n\tconst modes = [args.prompt != null && \"prompt\", args.tasks != null && \"tasks\", args.chain != null && \"chain\"].filter(\n\t\t(mode): mode is string => Boolean(mode),\n\t);\n\tif (modes.length > 1) {\n\t\ttext += theme.fg(\"error\", `invalid · ${modes.join(\" + \")}`);\n\t} else if (args.tasks) {\n\t\ttext += theme.fg(\"accent\", `parallel · ${args.tasks.length} tasks`);\n\t} else if (args.chain) {\n\t\ttext += theme.fg(\"accent\", `chain · ${args.chain.length} steps`);\n\t} else {\n\t\ttext += theme.fg(\"accent\", singleAgentName(args));\n\t\tif (args.description) text += theme.fg(\"dim\", ` · ${truncate(args.description, 72)}`);\n\t}\n\treturn new Text(text, 0, 0);\n}\n\nexport function renderSubagentResult(\n\tresult: AgentToolResult<SubagentDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tisError: boolean,\n): Component {\n\tconst details = result.details;\n\tif (!details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\");\n\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t}\n\tif (!options.expanded) {\n\t\tconst lines: string[] = [];\n\t\tif (details.mode === \"single\") {\n\t\t\tlines.push(...singleCollapsedLines(details, theme));\n\t\t} else {\n\t\t\tlines.push(theme.fg(isError ? \"error\" : options.isPartial ? \"accent\" : \"muted\", statusSummary(details)));\n\t\t\tconst shown = selectCollapsedRuns(details.runs, Boolean(options.isPartial));\n\t\t\tfor (const run of shown) lines.push(runLine(run, theme, details.mode));\n\t\t\tconst hidden = details.runs.length - shown.length;\n\t\t\tif (hidden > 0) lines.push(theme.fg(\"muted\", `+${hidden} more`));\n\t\t}\n\t\tconst activitySummary = activitySummaryText(details);\n\t\tif (activitySummary) lines.push(theme.fg(\"dim\", activitySummary));\n\t\tconst usage = usageText(details, !activitySummary);\n\t\tif (usage) lines.push(theme.fg(\"dim\", usage));\n\t\tif (!options.isPartial) lines.push(theme.fg(\"muted\", `(${keyHint(\"app.tools.expand\", \"to expand\")})`));\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0);\n\t}\n\tconst container = new Container();\n\tconst single = details.mode === \"single\" && details.runs.length === 1;\n\tif (!single) {\n\t\tcontainer.addChild(new Text(theme.fg(isError ? \"error\" : \"toolTitle\", statusSummary(details)), 0, 0));\n\t}\n\tdetails.runs.forEach((run, index) => {\n\t\tif (!single || index > 0) container.addChild(new Spacer(1));\n\t\tcontainer.addChild(renderRunDetails(run, theme, details.mode, single));\n\t});\n\tif (!single) {\n\t\tconst usage = usageText(details);\n\t\tif (usage) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", usage), 0, 0));\n\t\t}\n\t}\n\treturn container;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE/F,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAEtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAyC,MAAM,YAAY,CAAC;AAsXzF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAqBhF;AAED,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EACxC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,GACd,SAAS,CAmDX","sourcesContent":["import { type Component, Container, Markdown, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"../../core/extensions/types.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getMarkdownTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { statusSummary } from \"./runner.ts\";\nimport type { SubagentParams } from \"./schema.ts\";\nimport type { SubagentDetails, SubagentRunDetails, SubagentRunStatus } from \"./types.ts\";\n\nconst SINGLE_EXCERPT_LIMIT = 200;\nconst RUN_LINE_EXCERPT_LIMIT = 64;\nconst LIVE_TAIL_LIMIT = 100;\nconst COLLAPSED_RUN_LIMIT = 4;\n\nconst ACTIVITY_GROUPS = [\n\t{ toolName: \"read\", verb: \"read\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"grep\", verb: \"searched\", singular: \"pattern\", plural: \"patterns\" },\n\t{ toolName: \"find\", verb: \"searched\", singular: \"path pattern\", plural: \"path patterns\" },\n\t{ toolName: \"ls\", verb: \"listed\", singular: \"directory\", plural: \"directories\" },\n\t{ toolName: \"bash\", verb: \"ran\", singular: \"command\", plural: \"commands\" },\n\t{ toolName: \"edit\", verb: \"edited\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"write\", verb: \"wrote\", singular: \"file\", plural: \"files\" },\n] as const;\n\n// Display-only: profile names stay lowercase everywhere the model sees\n// them; the transcript shows \"general\" as \"General\", \"code-reviewer\" as\n// \"Code Reviewer\".\nfunction displayAgentName(name: string): string {\n\treturn name\n\t\t.split(/[-_]/u)\n\t\t.filter(Boolean)\n\t\t.map((word) => `${word[0]?.toUpperCase() ?? \"\"}${word.slice(1)}`)\n\t\t.join(\" \");\n}\n\nfunction singleAgentName(args: { agent?: string | null }): string {\n\treturn displayAgentName(args.agent ?? \"general\");\n}\n\nfunction truncate(text: string, limit: number): string {\n\treturn text.length <= limit ? text : `${text.slice(0, Math.max(0, limit - 1))}…`;\n}\n\n// Transcript excerpts render inside plain Text components, so markdown\n// punctuation would show up literally; strip the common inline syntax.\nfunction stripInlineMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/```[a-zA-Z0-9-]*/gu, \"\")\n\t\t.replace(/`([^`]*)`/gu, \"$1\")\n\t\t.replace(/\\*\\*([^*]+)\\*\\*/gu, \"$1\")\n\t\t.replace(/__([^_]+)__/gu, \"$1\")\n\t\t.replace(/\\[([^\\]]+)\\]\\([^)]*\\)/gu, \"$1\")\n\t\t.replace(/^#{1,6}\\s+/gmu, \"\");\n}\n\n// Markdown tables and horizontal rules turn into symbol soup when\n// flattened onto one line; drop those lines before inline stripping.\nfunction stripBlockMarkdown(text: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.filter((line) => {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (trimmed.startsWith(\"|\")) return false;\n\t\t\treturn !(trimmed.length >= 3 && /^[-—─═=*_|:\\s]+$/u.test(trimmed));\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction excerpt(text: string, limit: number): string {\n\t// finalOutput/liveText carry model-facing truncation notices from\n\t// boundText/tailText; in the transcript an ellipsis is enough.\n\tconst cleaned = text.replace(/\\[(?:Output truncated(?:: \\d+ bytes omitted\\.)?|Earlier output omitted\\.)\\]/gu, \"…\");\n\treturn truncate(stripInlineMarkdown(stripBlockMarkdown(cleaned)).replace(/\\s+/gu, \" \").trim(), limit);\n}\n\nfunction liveTail(run: SubagentRunDetails): string | undefined {\n\tconst lines = run.liveText\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean);\n\tconst last = lines.at(-1);\n\treturn last ? excerpt(last, LIVE_TAIL_LIMIT) : undefined;\n}\n\n// Completed-run excerpts read better cut at a sentence boundary than\n// mid-word; fall back to a hard truncate when no boundary lands in the\n// second half of the window.\nfunction leadingSentences(text: string, limit: number): string {\n\tconst cleaned = excerpt(text, Number.MAX_SAFE_INTEGER);\n\tif (cleaned.length <= limit) return cleaned;\n\tconst window = cleaned.slice(0, limit);\n\tlet boundary = -1;\n\tfor (const match of window.matchAll(/[.!?。!?](?=\\s|$)/gu)) {\n\t\tboundary = (match.index ?? 0) + match[0].length;\n\t}\n\tif (boundary >= limit / 2) return window.slice(0, boundary).trimEnd();\n\treturn truncate(window, limit);\n}\n\nconst VERIFY_COMMAND_PATTERN = /\\b(test|lint|typecheck|tsc|vitest|jest|pytest|build|check|fmt|format|compile)\\b/iu;\nconst INSPECT_COMMAND_PATTERN = /\\b(rg|grep|find|git (?:diff|status|log|show)|ls|tree|cat|head|tail)\\b/iu;\nconst RETRY_MARKER_PATTERN = /^Retrying\\b/u;\nconst STREAM_MARKERS = new Set([\"Thinking…\", \"Writing response…\"]);\n\n// Translates raw tool traffic into what the worker is doing right now, so\n// the collapsed card reads as a phase instead of a command line. Modelled\n// on tool-type classification; the raw tool summary stays as evidence on\n// the next line.\nfunction runIntent(run: SubagentRunDetails): string {\n\tconst current = run.currentActivity;\n\tif (current && RETRY_MARKER_PATTERN.test(current)) return current;\n\tconst running = [...run.activities].reverse().find((activity) => activity.status === \"running\");\n\tif (running) {\n\t\tif (running.toolName === \"edit\" || running.toolName === \"write\") return \"Applying changes\";\n\t\tif (running.toolName === \"bash\") {\n\t\t\tif (VERIFY_COMMAND_PATTERN.test(running.summary)) return \"Verifying changes\";\n\t\t\treturn INSPECT_COMMAND_PATTERN.test(running.summary) ? \"Exploring code\" : \"Running commands\";\n\t\t}\n\t\treturn \"Exploring code\";\n\t}\n\tconst recent = run.activities.slice(-5);\n\tif (current && STREAM_MARKERS.has(current)) {\n\t\tif (recent.some((activity) => activity.status === \"failed\")) return \"Investigating a failure\";\n\t\treturn current;\n\t}\n\tif (recent.some((activity) => activity.status === \"failed\")) return \"Investigating a failure\";\n\tif (recent.some((activity) => activity.toolName === \"edit\" || activity.toolName === \"write\"))\n\t\treturn \"Reviewing changes\";\n\tif (recent.length > 0) return \"Exploring code\";\n\treturn current ?? \"Thinking…\";\n}\n\n// The raw tool summary backs up the intent line; suppress it when it would\n// just repeat a stream/retry marker.\nfunction runEvidence(run: SubagentRunDetails): string | undefined {\n\tconst current = run.currentActivity;\n\tif (!current || STREAM_MARKERS.has(current) || RETRY_MARKER_PATTERN.test(current)) return undefined;\n\treturn current;\n}\n\nfunction liveElapsed(run: SubagentRunDetails): string | undefined {\n\tif (run.startedAt === undefined) return undefined;\n\tconst end = run.endedAt ?? Date.now();\n\treturn formatDuration(Math.max(0, (end - run.startedAt) / 1000));\n}\n\n// The tool shell already paints a call-level status dot (● in\n// warning/success/error), so `●` is off-limits here: `›` marks where the\n// work currently is, and the remaining glyphs are terminal states.\nfunction statusMarker(status: SubagentRunStatus, theme: Theme): string {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"failed\":\n\t\t\treturn theme.fg(\"error\", \"×\");\n\t\tcase \"aborted\":\n\t\t\treturn theme.fg(\"warning\", \"■\");\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"accent\", \"›\");\n\t\tdefault:\n\t\t\treturn theme.fg(\"muted\", \"○\");\n\t}\n}\n\nfunction runTitle(run: SubagentRunDetails, theme: Theme, index?: number): string {\n\tconst number = index === undefined ? \"\" : theme.fg(\"dim\", `${index} · `);\n\treturn `${statusMarker(run.status, theme)} ${number}${theme.fg(\"accent\", displayAgentName(run.agent))}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`;\n}\n\nfunction runProgressText(run: SubagentRunDetails): string {\n\tconst items = [`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}`];\n\tif (run.usage.totalTokens) items.push(`${formatTokens(run.usage.totalTokens)} tokens`);\n\treturn items.join(\" · \");\n}\n\nfunction runLine(run: SubagentRunDetails, theme: Theme, index?: number): string {\n\tlet line = runTitle(run, theme, index);\n\tconst detail =\n\t\trun.status === \"running\"\n\t\t\t? runIntent(run)\n\t\t\t: run.status === \"failed\" || run.status === \"aborted\"\n\t\t\t\t? run.error && excerpt(run.error, RUN_LINE_EXCERPT_LIMIT)\n\t\t\t\t: run.finalOutput && excerpt(run.finalOutput, RUN_LINE_EXCERPT_LIMIT);\n\tif (detail) line += theme.fg(run.status === \"failed\" ? \"error\" : \"dim\", ` — ${detail}`);\n\tif (run.status === \"running\") {\n\t\tline += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\tconst elapsed = liveElapsed(run);\n\t\tif (elapsed) line += theme.fg(\"dim\", ` · ${elapsed}`);\n\t}\n\tconst settled = run.status !== \"running\" && run.status !== \"queued\";\n\tif (settled && run.startedAt !== undefined && run.endedAt !== undefined) {\n\t\tline += theme.fg(\"dim\", ` · ${formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))}`);\n\t}\n\treturn line;\n}\n\n// Keep active work visible while a batch is in flight: completed runs\n// may otherwise crowd a still-running task out of the collapsed window.\nfunction selectCollapsedRuns(runs: SubagentRunDetails[], isPartial: boolean): SubagentRunDetails[] {\n\tif (runs.length <= COLLAPSED_RUN_LIMIT) return runs;\n\tif (!isPartial) return runs.slice(0, COLLAPSED_RUN_LIMIT);\n\tconst active = runs.filter((run) => run.status === \"running\" || run.status === \"queued\");\n\tconst settled = runs.filter((run) => run.status !== \"running\" && run.status !== \"queued\");\n\treturn [...active, ...settled].slice(0, COLLAPSED_RUN_LIMIT);\n}\n\nfunction singleCollapsedLines(details: SubagentDetails, theme: Theme): string[] {\n\tconst run = details.runs[0];\n\tif (!run) return [theme.fg(\"muted\", \"Initializing…\")];\n\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\tconst isInitializing =\n\t\t\trun.status === \"running\" && run.usage.turns === 0 && run.usage.toolUses === 0 && run.liveText.length === 0;\n\t\tconst intent =\n\t\t\trun.status === \"queued\"\n\t\t\t\t? (run.currentActivity ?? \"queued\")\n\t\t\t\t: isInitializing\n\t\t\t\t\t? \"Initializing…\"\n\t\t\t\t\t: runIntent(run);\n\t\t// No status marker here: the shell's call-level dot already covers\n\t\t// the whole card, and a single run has nothing to disambiguate.\n\t\tlet status = theme.fg(\"dim\", intent);\n\t\tif (run.status === \"running\" && !isInitializing) {\n\t\t\tstatus += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\t\tconst elapsed = liveElapsed(run);\n\t\t\tif (elapsed) status += theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t}\n\t\tconst lines = [status];\n\t\tconst evidence = runEvidence(run);\n\t\tif (evidence && evidence !== intent)\n\t\t\tlines.push(`${theme.fg(\"accent\", \"›\")} ${theme.fg(\"dim\", excerpt(evidence, LIVE_TAIL_LIMIT))}`);\n\t\tconst tail = liveTail(run);\n\t\tif (tail) lines.push(theme.fg(\"dim\", tail));\n\t\treturn lines;\n\t}\n\tif (run.error) return [theme.fg(\"error\", excerpt(run.error, SINGLE_EXCERPT_LIMIT))];\n\tif (run.finalOutput) return [theme.fg(\"toolOutput\", leadingSentences(run.finalOutput, SINGLE_EXCERPT_LIMIT))];\n\treturn [theme.fg(\"muted\", run.status)];\n}\n\nfunction activitySummaryText(details: SubagentDetails): string {\n\tconst toolCounts = new Map<string, number>();\n\tlet activityCount = 0;\n\tfor (const run of details.runs) {\n\t\tfor (const activity of run.activities) {\n\t\t\tactivityCount++;\n\t\t\ttoolCounts.set(activity.toolName, (toolCounts.get(activity.toolName) ?? 0) + 1);\n\t\t}\n\t}\n\tconst items: string[] = [];\n\tlet groupedCount = 0;\n\tfor (const group of ACTIVITY_GROUPS) {\n\t\tconst count = toolCounts.get(group.toolName) ?? 0;\n\t\tif (count === 0) continue;\n\t\tgroupedCount += count;\n\t\titems.push(`${group.verb} ${count} ${count === 1 ? group.singular : group.plural}`);\n\t}\n\tconst otherCount = activityCount - groupedCount;\n\tif (otherCount > 0) items.push(`used ${otherCount} other tool${otherCount === 1 ? \"\" : \"s\"}`);\n\tif (items.length === 0) return \"\";\n\tconst earlierCount = Math.max(0, details.usage.toolUses - activityCount);\n\tif (earlierCount > 0) items.push(`${earlierCount} earlier tool use${earlierCount === 1 ? \"\" : \"s\"}`);\n\treturn `${items[0]![0]!.toUpperCase()}${items[0]!.slice(1)}${items\n\t\t.slice(1)\n\t\t.map((item) => ` · ${item}`)\n\t\t.join(\"\")}`;\n}\n\nfunction usageText(details: SubagentDetails, includeToolUses = true): string {\n\tconst usage = details.usage;\n\tconst items: string[] = [];\n\tif (includeToolUses && usage.toolUses) items.push(`${usage.toolUses} tool use${usage.toolUses === 1 ? \"\" : \"s\"}`);\n\tif (usage.turns) items.push(`${usage.turns} turn${usage.turns === 1 ? \"\" : \"s\"}`);\n\tif (usage.output) items.push(`↓${formatTokens(usage.output)}`);\n\tif (usage.contextTokens) items.push(`ctx:${formatTokens(usage.contextTokens)}`);\n\tif (usage.cost) items.push(`$${usage.cost.toFixed(3)}`);\n\tconst duration = details.endedAt ? Math.max(0, (details.endedAt - details.startedAt) / 1000) : undefined;\n\tif (duration !== undefined) items.push(formatDuration(duration));\n\treturn items.join(\" · \");\n}\n\nfunction formatTokens(value: number): string {\n\tif (value < 1_000) return String(value);\n\tif (value < 1_000_000) return `${(value / 1_000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}M`;\n}\n\nfunction formatDuration(seconds: number): string {\n\tif (seconds >= 90) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;\n\treturn `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;\n}\n\n// A single run's title and usage would duplicate the call header and\n// the call-level usage line, so `single` drops both and folds the\n// duration into the metadata line instead. Multi-run sections carry a\n// numbered `──` header that matches the table of contents above them.\nfunction renderRunDetails(run: SubagentRunDetails, theme: Theme, single: boolean, index?: number): Component {\n\tconst container = new Container();\n\tconst duration =\n\t\trun.startedAt !== undefined && run.endedAt !== undefined\n\t\t\t? formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))\n\t\t\t: undefined;\n\tif (!single) {\n\t\tconst label = index === undefined ? \"\" : `${index} · `;\n\t\tcontainer.addChild(\n\t\t\tnew Text(\n\t\t\t\t`${theme.fg(\"dim\", `── ${label}`)}${theme.fg(\"accent\", displayAgentName(run.agent))}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task\"), 0, 0));\n\tcontainer.addChild(new Text(theme.fg(\"dim\", run.prompt), 0, 0));\n\tif (run.activities.length > 0) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Activity\"), 0, 0));\n\t\tfor (const activity of run.activities) {\n\t\t\tconst marker =\n\t\t\t\tactivity.status === \"succeeded\"\n\t\t\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t\t\t: activity.status === \"failed\"\n\t\t\t\t\t\t? theme.fg(\"error\", \"×\")\n\t\t\t\t\t\t: theme.fg(\"accent\", \"›\");\n\t\t\tlet text = `${marker} ${theme.fg(\"toolOutput\", excerpt(activity.summary, 96))}`;\n\t\t\tif (activity.resultSummary) {\n\t\t\t\tconst color = activity.status === \"failed\" ? \"error\" : \"dim\";\n\t\t\t\ttext += ` ${theme.fg(color, `· ${excerpt(activity.resultSummary, 64)}`)}`;\n\t\t\t}\n\t\t\tif (activity.endedAt !== undefined && activity.endedAt - activity.startedAt >= 1_000) {\n\t\t\t\ttext += ` ${theme.fg(\"dim\", `· ${formatDuration((activity.endedAt - activity.startedAt) / 1000)}`)}`;\n\t\t\t}\n\t\t\tcontainer.addChild(new Text(text, 0, 0));\n\t\t}\n\t}\n\t// The live tail is the \"now\" end of the timeline, so it sits after the\n\t// activity list; once the run settles, Response takes its place.\n\tif (run.status === \"running\" && run.liveText) {\n\t\tconst tail = run.liveText\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.slice(-4);\n\t\tif (tail.length > 0) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tfor (const line of tail) {\n\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", excerpt(line, LIVE_TAIL_LIMIT)), 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\tif (run.error) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Error: ${run.error}`), 0, 0));\n\t}\n\tif (run.finalOutput) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Response\"), 0, 0));\n\t\tcontainer.addChild(new Markdown(run.finalOutput, 0, 0, getMarkdownTheme()));\n\t}\n\tconst metadata = [\n\t\t`${run.model} · ${run.thinking}`,\n\t\trun.cwd ? `cwd: ${run.cwd}` : undefined,\n\t\trun.usage.toolUses ? `${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.turns ? `${run.usage.turns} turn${run.usage.turns === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.output ? `↓${formatTokens(run.usage.output)}` : undefined,\n\t\trun.usage.contextTokens ? `ctx:${formatTokens(run.usage.contextTokens)}` : undefined,\n\t\trun.usage.cost ? `$${run.usage.cost.toFixed(3)}` : undefined,\n\t\tsingle ? duration : undefined,\n\t]\n\t\t.filter((item): item is string => Boolean(item))\n\t\t.join(\" · \");\n\tif (metadata) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", metadata), 0, 0));\n\t}\n\treturn container;\n}\n\n// The call header stays a single line: run rows in the result area take\n// over within the first update and carry richer per-task state, so a\n// task list here would render everything twice. The task count alone\n// distinguishes a batch from a single delegation.\nexport function renderSubagentCall(args: SubagentParams, theme: Theme): Component {\n\tconst modes = [args.prompt != null && \"prompt\", args.tasks != null && \"tasks\"].filter((mode): mode is string =>\n\t\tBoolean(mode),\n\t);\n\tif (modes.length > 1) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"Subagent \"))}${theme.fg(\"error\", `invalid · ${modes.join(\" + \")}`)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tif (args.tasks) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"Multi-Agent\"))}${theme.fg(\"dim\", ` · ${args.tasks.length} task${args.tasks.length === 1 ? \"\" : \"s\"}`)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tlet text = theme.fg(\"toolTitle\", theme.bold(`${singleAgentName(args)} Agent`));\n\tif (args.description) text += theme.fg(\"dim\", ` · ${truncate(args.description, 72)}`);\n\treturn new Text(text, 0, 0);\n}\n\nexport function renderSubagentResult(\n\tresult: AgentToolResult<SubagentDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tisError: boolean,\n): Component {\n\tconst details = result.details;\n\tif (!details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\");\n\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t}\n\tif (!options.expanded) {\n\t\tconst lines: string[] = [];\n\t\tif (details.mode === \"single\") {\n\t\t\tlines.push(...singleCollapsedLines(details, theme));\n\t\t} else {\n\t\t\tlet header = statusSummary(details);\n\t\t\tif (options.isPartial) {\n\t\t\t\theader += ` · ${formatDuration(Math.max(0, (Date.now() - details.startedAt) / 1000))}`;\n\t\t\t}\n\t\t\tlines.push(theme.fg(isError ? \"error\" : options.isPartial ? \"accent\" : \"muted\", header));\n\t\t\tconst shown = selectCollapsedRuns(details.runs, Boolean(options.isPartial));\n\t\t\tfor (const run of shown) lines.push(runLine(run, theme));\n\t\t\tconst hidden = details.runs.length - shown.length;\n\t\t\tif (hidden > 0) lines.push(theme.fg(\"muted\", `+${hidden} more`));\n\t\t}\n\t\tconst activitySummary = activitySummaryText(details);\n\t\tif (activitySummary) lines.push(theme.fg(\"dim\", activitySummary));\n\t\tconst usage = usageText(details, !activitySummary);\n\t\tif (usage) lines.push(theme.fg(\"dim\", usage));\n\t\tif (!options.isPartial) lines.push(theme.fg(\"muted\", `(${keyHint(\"app.tools.expand\", \"to expand\")})`));\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0);\n\t}\n\tconst container = new Container();\n\tconst single = details.mode === \"single\" && details.runs.length === 1;\n\tif (!single) {\n\t\tcontainer.addChild(new Text(theme.fg(isError ? \"error\" : \"toolTitle\", statusSummary(details)), 0, 0));\n\t\t// Numbered table of contents: the TUI cannot jump, but matching the\n\t\t// numbers against the `──` section headers below makes an 8-run\n\t\t// batch navigable by eye.\n\t\tdetails.runs.forEach((run, index) => {\n\t\t\tcontainer.addChild(new Text(runLine(run, theme, index + 1), 0, 0));\n\t\t});\n\t}\n\tdetails.runs.forEach((run, index) => {\n\t\tif (!single || index > 0) container.addChild(new Spacer(1));\n\t\tcontainer.addChild(renderRunDetails(run, theme, single, single ? undefined : index + 1));\n\t});\n\tif (!single) {\n\t\tconst usage = usageText(details);\n\t\tif (usage) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", usage), 0, 0));\n\t\t}\n\t}\n\treturn container;\n}\n"]}
|
|
@@ -15,8 +15,18 @@ const ACTIVITY_GROUPS = [
|
|
|
15
15
|
{ toolName: "edit", verb: "edited", singular: "file", plural: "files" },
|
|
16
16
|
{ toolName: "write", verb: "wrote", singular: "file", plural: "files" },
|
|
17
17
|
];
|
|
18
|
+
// Display-only: profile names stay lowercase everywhere the model sees
|
|
19
|
+
// them; the transcript shows "general" as "General", "code-reviewer" as
|
|
20
|
+
// "Code Reviewer".
|
|
21
|
+
function displayAgentName(name) {
|
|
22
|
+
return name
|
|
23
|
+
.split(/[-_]/u)
|
|
24
|
+
.filter(Boolean)
|
|
25
|
+
.map((word) => `${word[0]?.toUpperCase() ?? ""}${word.slice(1)}`)
|
|
26
|
+
.join(" ");
|
|
27
|
+
}
|
|
18
28
|
function singleAgentName(args) {
|
|
19
|
-
return args.agent ?? "general";
|
|
29
|
+
return displayAgentName(args.agent ?? "general");
|
|
20
30
|
}
|
|
21
31
|
function truncate(text, limit) {
|
|
22
32
|
return text.length <= limit ? text : `${text.slice(0, Math.max(0, limit - 1))}…`;
|
|
@@ -59,6 +69,76 @@ function liveTail(run) {
|
|
|
59
69
|
const last = lines.at(-1);
|
|
60
70
|
return last ? excerpt(last, LIVE_TAIL_LIMIT) : undefined;
|
|
61
71
|
}
|
|
72
|
+
// Completed-run excerpts read better cut at a sentence boundary than
|
|
73
|
+
// mid-word; fall back to a hard truncate when no boundary lands in the
|
|
74
|
+
// second half of the window.
|
|
75
|
+
function leadingSentences(text, limit) {
|
|
76
|
+
const cleaned = excerpt(text, Number.MAX_SAFE_INTEGER);
|
|
77
|
+
if (cleaned.length <= limit)
|
|
78
|
+
return cleaned;
|
|
79
|
+
const window = cleaned.slice(0, limit);
|
|
80
|
+
let boundary = -1;
|
|
81
|
+
for (const match of window.matchAll(/[.!?。!?](?=\s|$)/gu)) {
|
|
82
|
+
boundary = (match.index ?? 0) + match[0].length;
|
|
83
|
+
}
|
|
84
|
+
if (boundary >= limit / 2)
|
|
85
|
+
return window.slice(0, boundary).trimEnd();
|
|
86
|
+
return truncate(window, limit);
|
|
87
|
+
}
|
|
88
|
+
const VERIFY_COMMAND_PATTERN = /\b(test|lint|typecheck|tsc|vitest|jest|pytest|build|check|fmt|format|compile)\b/iu;
|
|
89
|
+
const INSPECT_COMMAND_PATTERN = /\b(rg|grep|find|git (?:diff|status|log|show)|ls|tree|cat|head|tail)\b/iu;
|
|
90
|
+
const RETRY_MARKER_PATTERN = /^Retrying\b/u;
|
|
91
|
+
const STREAM_MARKERS = new Set(["Thinking…", "Writing response…"]);
|
|
92
|
+
// Translates raw tool traffic into what the worker is doing right now, so
|
|
93
|
+
// the collapsed card reads as a phase instead of a command line. Modelled
|
|
94
|
+
// on tool-type classification; the raw tool summary stays as evidence on
|
|
95
|
+
// the next line.
|
|
96
|
+
function runIntent(run) {
|
|
97
|
+
const current = run.currentActivity;
|
|
98
|
+
if (current && RETRY_MARKER_PATTERN.test(current))
|
|
99
|
+
return current;
|
|
100
|
+
const running = [...run.activities].reverse().find((activity) => activity.status === "running");
|
|
101
|
+
if (running) {
|
|
102
|
+
if (running.toolName === "edit" || running.toolName === "write")
|
|
103
|
+
return "Applying changes";
|
|
104
|
+
if (running.toolName === "bash") {
|
|
105
|
+
if (VERIFY_COMMAND_PATTERN.test(running.summary))
|
|
106
|
+
return "Verifying changes";
|
|
107
|
+
return INSPECT_COMMAND_PATTERN.test(running.summary) ? "Exploring code" : "Running commands";
|
|
108
|
+
}
|
|
109
|
+
return "Exploring code";
|
|
110
|
+
}
|
|
111
|
+
const recent = run.activities.slice(-5);
|
|
112
|
+
if (current && STREAM_MARKERS.has(current)) {
|
|
113
|
+
if (recent.some((activity) => activity.status === "failed"))
|
|
114
|
+
return "Investigating a failure";
|
|
115
|
+
return current;
|
|
116
|
+
}
|
|
117
|
+
if (recent.some((activity) => activity.status === "failed"))
|
|
118
|
+
return "Investigating a failure";
|
|
119
|
+
if (recent.some((activity) => activity.toolName === "edit" || activity.toolName === "write"))
|
|
120
|
+
return "Reviewing changes";
|
|
121
|
+
if (recent.length > 0)
|
|
122
|
+
return "Exploring code";
|
|
123
|
+
return current ?? "Thinking…";
|
|
124
|
+
}
|
|
125
|
+
// The raw tool summary backs up the intent line; suppress it when it would
|
|
126
|
+
// just repeat a stream/retry marker.
|
|
127
|
+
function runEvidence(run) {
|
|
128
|
+
const current = run.currentActivity;
|
|
129
|
+
if (!current || STREAM_MARKERS.has(current) || RETRY_MARKER_PATTERN.test(current))
|
|
130
|
+
return undefined;
|
|
131
|
+
return current;
|
|
132
|
+
}
|
|
133
|
+
function liveElapsed(run) {
|
|
134
|
+
if (run.startedAt === undefined)
|
|
135
|
+
return undefined;
|
|
136
|
+
const end = run.endedAt ?? Date.now();
|
|
137
|
+
return formatDuration(Math.max(0, (end - run.startedAt) / 1000));
|
|
138
|
+
}
|
|
139
|
+
// The tool shell already paints a call-level status dot (● in
|
|
140
|
+
// warning/success/error), so `●` is off-limits here: `›` marks where the
|
|
141
|
+
// work currently is, and the remaining glyphs are terminal states.
|
|
62
142
|
function statusMarker(status, theme) {
|
|
63
143
|
switch (status) {
|
|
64
144
|
case "completed":
|
|
@@ -68,14 +148,14 @@ function statusMarker(status, theme) {
|
|
|
68
148
|
case "aborted":
|
|
69
149
|
return theme.fg("warning", "■");
|
|
70
150
|
case "running":
|
|
71
|
-
return theme.fg("accent", "
|
|
151
|
+
return theme.fg("accent", "›");
|
|
72
152
|
default:
|
|
73
153
|
return theme.fg("muted", "○");
|
|
74
154
|
}
|
|
75
155
|
}
|
|
76
|
-
function runTitle(run, theme,
|
|
77
|
-
const
|
|
78
|
-
return `${statusMarker(run.status, theme)} ${
|
|
156
|
+
function runTitle(run, theme, index) {
|
|
157
|
+
const number = index === undefined ? "" : theme.fg("dim", `${index} · `);
|
|
158
|
+
return `${statusMarker(run.status, theme)} ${number}${theme.fg("accent", displayAgentName(run.agent))}${theme.fg("dim", ` · ${truncate(run.description, 48)}`)}`;
|
|
79
159
|
}
|
|
80
160
|
function runProgressText(run) {
|
|
81
161
|
const items = [`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? "" : "s"}`];
|
|
@@ -83,17 +163,21 @@ function runProgressText(run) {
|
|
|
83
163
|
items.push(`${formatTokens(run.usage.totalTokens)} tokens`);
|
|
84
164
|
return items.join(" · ");
|
|
85
165
|
}
|
|
86
|
-
function runLine(run, theme,
|
|
87
|
-
let line = runTitle(run, theme,
|
|
166
|
+
function runLine(run, theme, index) {
|
|
167
|
+
let line = runTitle(run, theme, index);
|
|
88
168
|
const detail = run.status === "running"
|
|
89
|
-
? run
|
|
169
|
+
? runIntent(run)
|
|
90
170
|
: run.status === "failed" || run.status === "aborted"
|
|
91
171
|
? run.error && excerpt(run.error, RUN_LINE_EXCERPT_LIMIT)
|
|
92
172
|
: run.finalOutput && excerpt(run.finalOutput, RUN_LINE_EXCERPT_LIMIT);
|
|
93
173
|
if (detail)
|
|
94
174
|
line += theme.fg(run.status === "failed" ? "error" : "dim", ` — ${detail}`);
|
|
95
|
-
if (run.status === "running")
|
|
175
|
+
if (run.status === "running") {
|
|
96
176
|
line += theme.fg("dim", ` · ${runProgressText(run)}`);
|
|
177
|
+
const elapsed = liveElapsed(run);
|
|
178
|
+
if (elapsed)
|
|
179
|
+
line += theme.fg("dim", ` · ${elapsed}`);
|
|
180
|
+
}
|
|
97
181
|
const settled = run.status !== "running" && run.status !== "queued";
|
|
98
182
|
if (settled && run.startedAt !== undefined && run.endedAt !== undefined) {
|
|
99
183
|
line += theme.fg("dim", ` · ${formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))}`);
|
|
@@ -117,9 +201,24 @@ function singleCollapsedLines(details, theme) {
|
|
|
117
201
|
return [theme.fg("muted", "Initializing…")];
|
|
118
202
|
if (run.status === "running" || run.status === "queued") {
|
|
119
203
|
const isInitializing = run.status === "running" && run.usage.turns === 0 && run.usage.toolUses === 0 && run.liveText.length === 0;
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
204
|
+
const intent = run.status === "queued"
|
|
205
|
+
? (run.currentActivity ?? "queued")
|
|
206
|
+
: isInitializing
|
|
207
|
+
? "Initializing…"
|
|
208
|
+
: runIntent(run);
|
|
209
|
+
// No status marker here: the shell's call-level dot already covers
|
|
210
|
+
// the whole card, and a single run has nothing to disambiguate.
|
|
211
|
+
let status = theme.fg("dim", intent);
|
|
212
|
+
if (run.status === "running" && !isInitializing) {
|
|
213
|
+
status += theme.fg("dim", ` · ${runProgressText(run)}`);
|
|
214
|
+
const elapsed = liveElapsed(run);
|
|
215
|
+
if (elapsed)
|
|
216
|
+
status += theme.fg("dim", ` · ${elapsed}`);
|
|
217
|
+
}
|
|
218
|
+
const lines = [status];
|
|
219
|
+
const evidence = runEvidence(run);
|
|
220
|
+
if (evidence && evidence !== intent)
|
|
221
|
+
lines.push(`${theme.fg("accent", "›")} ${theme.fg("dim", excerpt(evidence, LIVE_TAIL_LIMIT))}`);
|
|
123
222
|
const tail = liveTail(run);
|
|
124
223
|
if (tail)
|
|
125
224
|
lines.push(theme.fg("dim", tail));
|
|
@@ -128,7 +227,7 @@ function singleCollapsedLines(details, theme) {
|
|
|
128
227
|
if (run.error)
|
|
129
228
|
return [theme.fg("error", excerpt(run.error, SINGLE_EXCERPT_LIMIT))];
|
|
130
229
|
if (run.finalOutput)
|
|
131
|
-
return [theme.fg("toolOutput",
|
|
230
|
+
return [theme.fg("toolOutput", leadingSentences(run.finalOutput, SINGLE_EXCERPT_LIMIT))];
|
|
132
231
|
return [theme.fg("muted", run.status)];
|
|
133
232
|
}
|
|
134
233
|
function activitySummaryText(details) {
|
|
@@ -171,6 +270,8 @@ function usageText(details, includeToolUses = true) {
|
|
|
171
270
|
items.push(`${usage.turns} turn${usage.turns === 1 ? "" : "s"}`);
|
|
172
271
|
if (usage.output)
|
|
173
272
|
items.push(`↓${formatTokens(usage.output)}`);
|
|
273
|
+
if (usage.contextTokens)
|
|
274
|
+
items.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
174
275
|
if (usage.cost)
|
|
175
276
|
items.push(`$${usage.cost.toFixed(3)}`);
|
|
176
277
|
const duration = details.endedAt ? Math.max(0, (details.endedAt - details.startedAt) / 1000) : undefined;
|
|
@@ -192,19 +293,16 @@ function formatDuration(seconds) {
|
|
|
192
293
|
}
|
|
193
294
|
// A single run's title and usage would duplicate the call header and
|
|
194
295
|
// the call-level usage line, so `single` drops both and folds the
|
|
195
|
-
// duration into the metadata line instead.
|
|
196
|
-
|
|
296
|
+
// duration into the metadata line instead. Multi-run sections carry a
|
|
297
|
+
// numbered `──` header that matches the table of contents above them.
|
|
298
|
+
function renderRunDetails(run, theme, single, index) {
|
|
197
299
|
const container = new Container();
|
|
198
300
|
const duration = run.startedAt !== undefined && run.endedAt !== undefined
|
|
199
301
|
? formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))
|
|
200
302
|
: undefined;
|
|
201
303
|
if (!single) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
title += theme.fg("dim", ` · ${runProgressText(run)}`);
|
|
205
|
-
else if (duration)
|
|
206
|
-
title += theme.fg("dim", ` · ${duration}`);
|
|
207
|
-
container.addChild(new Text(title, 0, 0));
|
|
304
|
+
const label = index === undefined ? "" : `${index} · `;
|
|
305
|
+
container.addChild(new Text(`${theme.fg("dim", `── ${label}`)}${theme.fg("accent", displayAgentName(run.agent))}${theme.fg("dim", ` · ${truncate(run.description, 48)}`)}`, 0, 0));
|
|
208
306
|
}
|
|
209
307
|
container.addChild(new Text(theme.fg("muted", "Task"), 0, 0));
|
|
210
308
|
container.addChild(new Text(theme.fg("dim", run.prompt), 0, 0));
|
|
@@ -216,13 +314,33 @@ function renderRunDetails(run, theme, mode, single) {
|
|
|
216
314
|
? theme.fg("success", "✓")
|
|
217
315
|
: activity.status === "failed"
|
|
218
316
|
? theme.fg("error", "×")
|
|
219
|
-
: theme.fg("accent", "
|
|
317
|
+
: theme.fg("accent", "›");
|
|
220
318
|
let text = `${marker} ${theme.fg("toolOutput", excerpt(activity.summary, 96))}`;
|
|
221
|
-
if (activity.resultSummary)
|
|
222
|
-
|
|
319
|
+
if (activity.resultSummary) {
|
|
320
|
+
const color = activity.status === "failed" ? "error" : "dim";
|
|
321
|
+
text += ` ${theme.fg(color, `· ${excerpt(activity.resultSummary, 64)}`)}`;
|
|
322
|
+
}
|
|
323
|
+
if (activity.endedAt !== undefined && activity.endedAt - activity.startedAt >= 1_000) {
|
|
324
|
+
text += ` ${theme.fg("dim", `· ${formatDuration((activity.endedAt - activity.startedAt) / 1000)}`)}`;
|
|
325
|
+
}
|
|
223
326
|
container.addChild(new Text(text, 0, 0));
|
|
224
327
|
}
|
|
225
328
|
}
|
|
329
|
+
// The live tail is the "now" end of the timeline, so it sits after the
|
|
330
|
+
// activity list; once the run settles, Response takes its place.
|
|
331
|
+
if (run.status === "running" && run.liveText) {
|
|
332
|
+
const tail = run.liveText
|
|
333
|
+
.split("\n")
|
|
334
|
+
.map((line) => line.trim())
|
|
335
|
+
.filter(Boolean)
|
|
336
|
+
.slice(-4);
|
|
337
|
+
if (tail.length > 0) {
|
|
338
|
+
container.addChild(new Spacer(1));
|
|
339
|
+
for (const line of tail) {
|
|
340
|
+
container.addChild(new Text(theme.fg("dim", excerpt(line, LIVE_TAIL_LIMIT)), 0, 0));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
226
344
|
if (run.error) {
|
|
227
345
|
container.addChild(new Spacer(1));
|
|
228
346
|
container.addChild(new Text(theme.fg("error", `Error: ${run.error}`), 0, 0));
|
|
@@ -234,9 +352,11 @@ function renderRunDetails(run, theme, mode, single) {
|
|
|
234
352
|
}
|
|
235
353
|
const metadata = [
|
|
236
354
|
`${run.model} · ${run.thinking}`,
|
|
355
|
+
run.cwd ? `cwd: ${run.cwd}` : undefined,
|
|
237
356
|
run.usage.toolUses ? `${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? "" : "s"}` : undefined,
|
|
238
357
|
run.usage.turns ? `${run.usage.turns} turn${run.usage.turns === 1 ? "" : "s"}` : undefined,
|
|
239
358
|
run.usage.output ? `↓${formatTokens(run.usage.output)}` : undefined,
|
|
359
|
+
run.usage.contextTokens ? `ctx:${formatTokens(run.usage.contextTokens)}` : undefined,
|
|
240
360
|
run.usage.cost ? `$${run.usage.cost.toFixed(3)}` : undefined,
|
|
241
361
|
single ? duration : undefined,
|
|
242
362
|
]
|
|
@@ -250,24 +370,19 @@ function renderRunDetails(run, theme, mode, single) {
|
|
|
250
370
|
}
|
|
251
371
|
// The call header stays a single line: run rows in the result area take
|
|
252
372
|
// over within the first update and carry richer per-task state, so a
|
|
253
|
-
// task list here would render everything twice.
|
|
373
|
+
// task list here would render everything twice. The task count alone
|
|
374
|
+
// distinguishes a batch from a single delegation.
|
|
254
375
|
export function renderSubagentCall(args, theme) {
|
|
255
|
-
|
|
256
|
-
const modes = [args.prompt != null && "prompt", args.tasks != null && "tasks", args.chain != null && "chain"].filter((mode) => Boolean(mode));
|
|
376
|
+
const modes = [args.prompt != null && "prompt", args.tasks != null && "tasks"].filter((mode) => Boolean(mode));
|
|
257
377
|
if (modes.length > 1) {
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
else if (args.tasks) {
|
|
261
|
-
text += theme.fg("accent", `parallel · ${args.tasks.length} tasks`);
|
|
262
|
-
}
|
|
263
|
-
else if (args.chain) {
|
|
264
|
-
text += theme.fg("accent", `chain · ${args.chain.length} steps`);
|
|
378
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("Subagent "))}${theme.fg("error", `invalid · ${modes.join(" + ")}`)}`, 0, 0);
|
|
265
379
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (args.description)
|
|
269
|
-
text += theme.fg("dim", ` · ${truncate(args.description, 72)}`);
|
|
380
|
+
if (args.tasks) {
|
|
381
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("Multi-Agent"))}${theme.fg("dim", ` · ${args.tasks.length} task${args.tasks.length === 1 ? "" : "s"}`)}`, 0, 0);
|
|
270
382
|
}
|
|
383
|
+
let text = theme.fg("toolTitle", theme.bold(`${singleAgentName(args)} Agent`));
|
|
384
|
+
if (args.description)
|
|
385
|
+
text += theme.fg("dim", ` · ${truncate(args.description, 72)}`);
|
|
271
386
|
return new Text(text, 0, 0);
|
|
272
387
|
}
|
|
273
388
|
export function renderSubagentResult(result, options, theme, isError) {
|
|
@@ -282,10 +397,14 @@ export function renderSubagentResult(result, options, theme, isError) {
|
|
|
282
397
|
lines.push(...singleCollapsedLines(details, theme));
|
|
283
398
|
}
|
|
284
399
|
else {
|
|
285
|
-
|
|
400
|
+
let header = statusSummary(details);
|
|
401
|
+
if (options.isPartial) {
|
|
402
|
+
header += ` · ${formatDuration(Math.max(0, (Date.now() - details.startedAt) / 1000))}`;
|
|
403
|
+
}
|
|
404
|
+
lines.push(theme.fg(isError ? "error" : options.isPartial ? "accent" : "muted", header));
|
|
286
405
|
const shown = selectCollapsedRuns(details.runs, Boolean(options.isPartial));
|
|
287
406
|
for (const run of shown)
|
|
288
|
-
lines.push(runLine(run, theme
|
|
407
|
+
lines.push(runLine(run, theme));
|
|
289
408
|
const hidden = details.runs.length - shown.length;
|
|
290
409
|
if (hidden > 0)
|
|
291
410
|
lines.push(theme.fg("muted", `+${hidden} more`));
|
|
@@ -304,11 +423,17 @@ export function renderSubagentResult(result, options, theme, isError) {
|
|
|
304
423
|
const single = details.mode === "single" && details.runs.length === 1;
|
|
305
424
|
if (!single) {
|
|
306
425
|
container.addChild(new Text(theme.fg(isError ? "error" : "toolTitle", statusSummary(details)), 0, 0));
|
|
426
|
+
// Numbered table of contents: the TUI cannot jump, but matching the
|
|
427
|
+
// numbers against the `──` section headers below makes an 8-run
|
|
428
|
+
// batch navigable by eye.
|
|
429
|
+
details.runs.forEach((run, index) => {
|
|
430
|
+
container.addChild(new Text(runLine(run, theme, index + 1), 0, 0));
|
|
431
|
+
});
|
|
307
432
|
}
|
|
308
433
|
details.runs.forEach((run, index) => {
|
|
309
434
|
if (!single || index > 0)
|
|
310
435
|
container.addChild(new Spacer(1));
|
|
311
|
-
container.addChild(renderRunDetails(run, theme,
|
|
436
|
+
container.addChild(renderRunDetails(run, theme, single, single ? undefined : index + 1));
|
|
312
437
|
});
|
|
313
438
|
if (!single) {
|
|
314
439
|
const usage = usageText(details);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, Markdown, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"../../core/extensions/types.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getMarkdownTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { statusSummary } from \"./runner.ts\";\nimport type { SubagentParams } from \"./schema.ts\";\nimport type { SubagentDetails, SubagentRunDetails, SubagentRunStatus } from \"./types.ts\";\n\nconst SINGLE_EXCERPT_LIMIT = 200;\nconst RUN_LINE_EXCERPT_LIMIT = 64;\nconst LIVE_TAIL_LIMIT = 100;\nconst COLLAPSED_RUN_LIMIT = 4;\n\nconst ACTIVITY_GROUPS = [\n\t{ toolName: \"read\", verb: \"read\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"grep\", verb: \"searched\", singular: \"pattern\", plural: \"patterns\" },\n\t{ toolName: \"find\", verb: \"searched\", singular: \"path pattern\", plural: \"path patterns\" },\n\t{ toolName: \"ls\", verb: \"listed\", singular: \"directory\", plural: \"directories\" },\n\t{ toolName: \"bash\", verb: \"ran\", singular: \"command\", plural: \"commands\" },\n\t{ toolName: \"edit\", verb: \"edited\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"write\", verb: \"wrote\", singular: \"file\", plural: \"files\" },\n] as const;\n\nfunction singleAgentName(args: { agent?: string | null }): string {\n\treturn args.agent ?? \"general\";\n}\n\nfunction truncate(text: string, limit: number): string {\n\treturn text.length <= limit ? text : `${text.slice(0, Math.max(0, limit - 1))}…`;\n}\n\n// Transcript excerpts render inside plain Text components, so markdown\n// punctuation would show up literally; strip the common inline syntax.\nfunction stripInlineMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/```[a-zA-Z0-9-]*/gu, \"\")\n\t\t.replace(/`([^`]*)`/gu, \"$1\")\n\t\t.replace(/\\*\\*([^*]+)\\*\\*/gu, \"$1\")\n\t\t.replace(/__([^_]+)__/gu, \"$1\")\n\t\t.replace(/\\[([^\\]]+)\\]\\([^)]*\\)/gu, \"$1\")\n\t\t.replace(/^#{1,6}\\s+/gmu, \"\");\n}\n\n// Markdown tables and horizontal rules turn into symbol soup when\n// flattened onto one line; drop those lines before inline stripping.\nfunction stripBlockMarkdown(text: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.filter((line) => {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (trimmed.startsWith(\"|\")) return false;\n\t\t\treturn !(trimmed.length >= 3 && /^[-—─═=*_|:\\s]+$/u.test(trimmed));\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction excerpt(text: string, limit: number): string {\n\t// finalOutput/liveText carry model-facing truncation notices from\n\t// boundText/tailText; in the transcript an ellipsis is enough.\n\tconst cleaned = text.replace(/\\[(?:Output truncated(?:: \\d+ bytes omitted\\.)?|Earlier output omitted\\.)\\]/gu, \"…\");\n\treturn truncate(stripInlineMarkdown(stripBlockMarkdown(cleaned)).replace(/\\s+/gu, \" \").trim(), limit);\n}\n\nfunction liveTail(run: SubagentRunDetails): string | undefined {\n\tconst lines = run.liveText\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean);\n\tconst last = lines.at(-1);\n\treturn last ? excerpt(last, LIVE_TAIL_LIMIT) : undefined;\n}\n\nfunction statusMarker(status: SubagentRunStatus, theme: Theme): string {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"failed\":\n\t\t\treturn theme.fg(\"error\", \"×\");\n\t\tcase \"aborted\":\n\t\t\treturn theme.fg(\"warning\", \"■\");\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"accent\", \"●\");\n\t\tdefault:\n\t\t\treturn theme.fg(\"muted\", \"○\");\n\t}\n}\n\nfunction runTitle(run: SubagentRunDetails, theme: Theme, mode: SubagentDetails[\"mode\"]): string {\n\tconst step = mode === \"chain\" && run.step ? theme.fg(\"muted\", `${run.step}. `) : \"\";\n\treturn `${statusMarker(run.status, theme)} ${step}${theme.fg(\"accent\", run.agent)}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`;\n}\n\nfunction runProgressText(run: SubagentRunDetails): string {\n\tconst items = [`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}`];\n\tif (run.usage.totalTokens) items.push(`${formatTokens(run.usage.totalTokens)} tokens`);\n\treturn items.join(\" · \");\n}\n\nfunction runLine(run: SubagentRunDetails, theme: Theme, mode: SubagentDetails[\"mode\"]): string {\n\tlet line = runTitle(run, theme, mode);\n\tconst detail =\n\t\trun.status === \"running\"\n\t\t\t? run.currentActivity\n\t\t\t: run.status === \"failed\" || run.status === \"aborted\"\n\t\t\t\t? run.error && excerpt(run.error, RUN_LINE_EXCERPT_LIMIT)\n\t\t\t\t: run.finalOutput && excerpt(run.finalOutput, RUN_LINE_EXCERPT_LIMIT);\n\tif (detail) line += theme.fg(run.status === \"failed\" ? \"error\" : \"dim\", ` — ${detail}`);\n\tif (run.status === \"running\") line += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\tconst settled = run.status !== \"running\" && run.status !== \"queued\";\n\tif (settled && run.startedAt !== undefined && run.endedAt !== undefined) {\n\t\tline += theme.fg(\"dim\", ` · ${formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))}`);\n\t}\n\treturn line;\n}\n\n// Keep active work visible while a batch is in flight: completed runs\n// may otherwise crowd a still-running task out of the collapsed window.\nfunction selectCollapsedRuns(runs: SubagentRunDetails[], isPartial: boolean): SubagentRunDetails[] {\n\tif (runs.length <= COLLAPSED_RUN_LIMIT) return runs;\n\tif (!isPartial) return runs.slice(0, COLLAPSED_RUN_LIMIT);\n\tconst active = runs.filter((run) => run.status === \"running\" || run.status === \"queued\");\n\tconst settled = runs.filter((run) => run.status !== \"running\" && run.status !== \"queued\");\n\treturn [...active, ...settled].slice(0, COLLAPSED_RUN_LIMIT);\n}\n\nfunction singleCollapsedLines(details: SubagentDetails, theme: Theme): string[] {\n\tconst run = details.runs[0];\n\tif (!run) return [theme.fg(\"muted\", \"Initializing…\")];\n\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\tconst isInitializing =\n\t\t\trun.status === \"running\" && run.usage.turns === 0 && run.usage.toolUses === 0 && run.liveText.length === 0;\n\t\tconst lines = [\n\t\t\t`${statusMarker(run.status, theme)} ${theme.fg(\"dim\", run.currentActivity ?? (run.status === \"queued\" ? \"queued\" : isInitializing ? \"Initializing…\" : \"Thinking…\"))}`,\n\t\t];\n\t\tconst tail = liveTail(run);\n\t\tif (tail) lines.push(theme.fg(\"dim\", tail));\n\t\treturn lines;\n\t}\n\tif (run.error) return [theme.fg(\"error\", excerpt(run.error, SINGLE_EXCERPT_LIMIT))];\n\tif (run.finalOutput) return [theme.fg(\"toolOutput\", excerpt(run.finalOutput, SINGLE_EXCERPT_LIMIT))];\n\treturn [theme.fg(\"muted\", run.status)];\n}\n\nfunction activitySummaryText(details: SubagentDetails): string {\n\tconst toolCounts = new Map<string, number>();\n\tlet activityCount = 0;\n\tfor (const run of details.runs) {\n\t\tfor (const activity of run.activities) {\n\t\t\tactivityCount++;\n\t\t\ttoolCounts.set(activity.toolName, (toolCounts.get(activity.toolName) ?? 0) + 1);\n\t\t}\n\t}\n\tconst items: string[] = [];\n\tlet groupedCount = 0;\n\tfor (const group of ACTIVITY_GROUPS) {\n\t\tconst count = toolCounts.get(group.toolName) ?? 0;\n\t\tif (count === 0) continue;\n\t\tgroupedCount += count;\n\t\titems.push(`${group.verb} ${count} ${count === 1 ? group.singular : group.plural}`);\n\t}\n\tconst otherCount = activityCount - groupedCount;\n\tif (otherCount > 0) items.push(`used ${otherCount} other tool${otherCount === 1 ? \"\" : \"s\"}`);\n\tif (items.length === 0) return \"\";\n\tconst earlierCount = Math.max(0, details.usage.toolUses - activityCount);\n\tif (earlierCount > 0) items.push(`${earlierCount} earlier tool use${earlierCount === 1 ? \"\" : \"s\"}`);\n\treturn `${items[0]![0]!.toUpperCase()}${items[0]!.slice(1)}${items\n\t\t.slice(1)\n\t\t.map((item) => ` · ${item}`)\n\t\t.join(\"\")}`;\n}\n\nfunction usageText(details: SubagentDetails, includeToolUses = true): string {\n\tconst usage = details.usage;\n\tconst items: string[] = [];\n\tif (includeToolUses && usage.toolUses) items.push(`${usage.toolUses} tool use${usage.toolUses === 1 ? \"\" : \"s\"}`);\n\tif (usage.turns) items.push(`${usage.turns} turn${usage.turns === 1 ? \"\" : \"s\"}`);\n\tif (usage.output) items.push(`↓${formatTokens(usage.output)}`);\n\tif (usage.cost) items.push(`$${usage.cost.toFixed(3)}`);\n\tconst duration = details.endedAt ? Math.max(0, (details.endedAt - details.startedAt) / 1000) : undefined;\n\tif (duration !== undefined) items.push(formatDuration(duration));\n\treturn items.join(\" · \");\n}\n\nfunction formatTokens(value: number): string {\n\tif (value < 1_000) return String(value);\n\tif (value < 1_000_000) return `${(value / 1_000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}M`;\n}\n\nfunction formatDuration(seconds: number): string {\n\tif (seconds >= 90) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;\n\treturn `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;\n}\n\n// A single run's title and usage would duplicate the call header and\n// the call-level usage line, so `single` drops both and folds the\n// duration into the metadata line instead.\nfunction renderRunDetails(\n\trun: SubagentRunDetails,\n\ttheme: Theme,\n\tmode: SubagentDetails[\"mode\"],\n\tsingle: boolean,\n): Component {\n\tconst container = new Container();\n\tconst duration =\n\t\trun.startedAt !== undefined && run.endedAt !== undefined\n\t\t\t? formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))\n\t\t\t: undefined;\n\tif (!single) {\n\t\tlet title = runTitle(run, theme, mode);\n\t\tif (run.status === \"running\") title += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\telse if (duration) title += theme.fg(\"dim\", ` · ${duration}`);\n\t\tcontainer.addChild(new Text(title, 0, 0));\n\t}\n\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task\"), 0, 0));\n\tcontainer.addChild(new Text(theme.fg(\"dim\", run.prompt), 0, 0));\n\tif (run.activities.length > 0) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Activity\"), 0, 0));\n\t\tfor (const activity of run.activities) {\n\t\t\tconst marker =\n\t\t\t\tactivity.status === \"succeeded\"\n\t\t\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t\t\t: activity.status === \"failed\"\n\t\t\t\t\t\t? theme.fg(\"error\", \"×\")\n\t\t\t\t\t\t: theme.fg(\"accent\", \"●\");\n\t\t\tlet text = `${marker} ${theme.fg(\"toolOutput\", excerpt(activity.summary, 96))}`;\n\t\t\tif (activity.resultSummary) text += ` ${theme.fg(\"dim\", `· ${excerpt(activity.resultSummary, 64)}`)}`;\n\t\t\tcontainer.addChild(new Text(text, 0, 0));\n\t\t}\n\t}\n\tif (run.error) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Error: ${run.error}`), 0, 0));\n\t}\n\tif (run.finalOutput) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Response\"), 0, 0));\n\t\tcontainer.addChild(new Markdown(run.finalOutput, 0, 0, getMarkdownTheme()));\n\t}\n\tconst metadata = [\n\t\t`${run.model} · ${run.thinking}`,\n\t\trun.usage.toolUses ? `${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.turns ? `${run.usage.turns} turn${run.usage.turns === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.output ? `↓${formatTokens(run.usage.output)}` : undefined,\n\t\trun.usage.cost ? `$${run.usage.cost.toFixed(3)}` : undefined,\n\t\tsingle ? duration : undefined,\n\t]\n\t\t.filter((item): item is string => Boolean(item))\n\t\t.join(\" · \");\n\tif (metadata) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", metadata), 0, 0));\n\t}\n\treturn container;\n}\n\n// The call header stays a single line: run rows in the result area take\n// over within the first update and carry richer per-task state, so a\n// task list here would render everything twice.\nexport function renderSubagentCall(args: SubagentParams, theme: Theme): Component {\n\tlet text = theme.fg(\"toolTitle\", theme.bold(\"Subagent \"));\n\tconst modes = [args.prompt != null && \"prompt\", args.tasks != null && \"tasks\", args.chain != null && \"chain\"].filter(\n\t\t(mode): mode is string => Boolean(mode),\n\t);\n\tif (modes.length > 1) {\n\t\ttext += theme.fg(\"error\", `invalid · ${modes.join(\" + \")}`);\n\t} else if (args.tasks) {\n\t\ttext += theme.fg(\"accent\", `parallel · ${args.tasks.length} tasks`);\n\t} else if (args.chain) {\n\t\ttext += theme.fg(\"accent\", `chain · ${args.chain.length} steps`);\n\t} else {\n\t\ttext += theme.fg(\"accent\", singleAgentName(args));\n\t\tif (args.description) text += theme.fg(\"dim\", ` · ${truncate(args.description, 72)}`);\n\t}\n\treturn new Text(text, 0, 0);\n}\n\nexport function renderSubagentResult(\n\tresult: AgentToolResult<SubagentDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tisError: boolean,\n): Component {\n\tconst details = result.details;\n\tif (!details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\");\n\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t}\n\tif (!options.expanded) {\n\t\tconst lines: string[] = [];\n\t\tif (details.mode === \"single\") {\n\t\t\tlines.push(...singleCollapsedLines(details, theme));\n\t\t} else {\n\t\t\tlines.push(theme.fg(isError ? \"error\" : options.isPartial ? \"accent\" : \"muted\", statusSummary(details)));\n\t\t\tconst shown = selectCollapsedRuns(details.runs, Boolean(options.isPartial));\n\t\t\tfor (const run of shown) lines.push(runLine(run, theme, details.mode));\n\t\t\tconst hidden = details.runs.length - shown.length;\n\t\t\tif (hidden > 0) lines.push(theme.fg(\"muted\", `+${hidden} more`));\n\t\t}\n\t\tconst activitySummary = activitySummaryText(details);\n\t\tif (activitySummary) lines.push(theme.fg(\"dim\", activitySummary));\n\t\tconst usage = usageText(details, !activitySummary);\n\t\tif (usage) lines.push(theme.fg(\"dim\", usage));\n\t\tif (!options.isPartial) lines.push(theme.fg(\"muted\", `(${keyHint(\"app.tools.expand\", \"to expand\")})`));\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0);\n\t}\n\tconst container = new Container();\n\tconst single = details.mode === \"single\" && details.runs.length === 1;\n\tif (!single) {\n\t\tcontainer.addChild(new Text(theme.fg(isError ? \"error\" : \"toolTitle\", statusSummary(details)), 0, 0));\n\t}\n\tdetails.runs.forEach((run, index) => {\n\t\tif (!single || index > 0) container.addChild(new Spacer(1));\n\t\tcontainer.addChild(renderRunDetails(run, theme, details.mode, single));\n\t});\n\tif (!single) {\n\t\tconst usage = usageText(details);\n\t\tif (usage) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", usage), 0, 0));\n\t\t}\n\t}\n\treturn container;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, Markdown, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderResultOptions } from \"../../core/extensions/types.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getMarkdownTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { statusSummary } from \"./runner.ts\";\nimport type { SubagentParams } from \"./schema.ts\";\nimport type { SubagentDetails, SubagentRunDetails, SubagentRunStatus } from \"./types.ts\";\n\nconst SINGLE_EXCERPT_LIMIT = 200;\nconst RUN_LINE_EXCERPT_LIMIT = 64;\nconst LIVE_TAIL_LIMIT = 100;\nconst COLLAPSED_RUN_LIMIT = 4;\n\nconst ACTIVITY_GROUPS = [\n\t{ toolName: \"read\", verb: \"read\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"grep\", verb: \"searched\", singular: \"pattern\", plural: \"patterns\" },\n\t{ toolName: \"find\", verb: \"searched\", singular: \"path pattern\", plural: \"path patterns\" },\n\t{ toolName: \"ls\", verb: \"listed\", singular: \"directory\", plural: \"directories\" },\n\t{ toolName: \"bash\", verb: \"ran\", singular: \"command\", plural: \"commands\" },\n\t{ toolName: \"edit\", verb: \"edited\", singular: \"file\", plural: \"files\" },\n\t{ toolName: \"write\", verb: \"wrote\", singular: \"file\", plural: \"files\" },\n] as const;\n\n// Display-only: profile names stay lowercase everywhere the model sees\n// them; the transcript shows \"general\" as \"General\", \"code-reviewer\" as\n// \"Code Reviewer\".\nfunction displayAgentName(name: string): string {\n\treturn name\n\t\t.split(/[-_]/u)\n\t\t.filter(Boolean)\n\t\t.map((word) => `${word[0]?.toUpperCase() ?? \"\"}${word.slice(1)}`)\n\t\t.join(\" \");\n}\n\nfunction singleAgentName(args: { agent?: string | null }): string {\n\treturn displayAgentName(args.agent ?? \"general\");\n}\n\nfunction truncate(text: string, limit: number): string {\n\treturn text.length <= limit ? text : `${text.slice(0, Math.max(0, limit - 1))}…`;\n}\n\n// Transcript excerpts render inside plain Text components, so markdown\n// punctuation would show up literally; strip the common inline syntax.\nfunction stripInlineMarkdown(text: string): string {\n\treturn text\n\t\t.replace(/```[a-zA-Z0-9-]*/gu, \"\")\n\t\t.replace(/`([^`]*)`/gu, \"$1\")\n\t\t.replace(/\\*\\*([^*]+)\\*\\*/gu, \"$1\")\n\t\t.replace(/__([^_]+)__/gu, \"$1\")\n\t\t.replace(/\\[([^\\]]+)\\]\\([^)]*\\)/gu, \"$1\")\n\t\t.replace(/^#{1,6}\\s+/gmu, \"\");\n}\n\n// Markdown tables and horizontal rules turn into symbol soup when\n// flattened onto one line; drop those lines before inline stripping.\nfunction stripBlockMarkdown(text: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.filter((line) => {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (trimmed.startsWith(\"|\")) return false;\n\t\t\treturn !(trimmed.length >= 3 && /^[-—─═=*_|:\\s]+$/u.test(trimmed));\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction excerpt(text: string, limit: number): string {\n\t// finalOutput/liveText carry model-facing truncation notices from\n\t// boundText/tailText; in the transcript an ellipsis is enough.\n\tconst cleaned = text.replace(/\\[(?:Output truncated(?:: \\d+ bytes omitted\\.)?|Earlier output omitted\\.)\\]/gu, \"…\");\n\treturn truncate(stripInlineMarkdown(stripBlockMarkdown(cleaned)).replace(/\\s+/gu, \" \").trim(), limit);\n}\n\nfunction liveTail(run: SubagentRunDetails): string | undefined {\n\tconst lines = run.liveText\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean);\n\tconst last = lines.at(-1);\n\treturn last ? excerpt(last, LIVE_TAIL_LIMIT) : undefined;\n}\n\n// Completed-run excerpts read better cut at a sentence boundary than\n// mid-word; fall back to a hard truncate when no boundary lands in the\n// second half of the window.\nfunction leadingSentences(text: string, limit: number): string {\n\tconst cleaned = excerpt(text, Number.MAX_SAFE_INTEGER);\n\tif (cleaned.length <= limit) return cleaned;\n\tconst window = cleaned.slice(0, limit);\n\tlet boundary = -1;\n\tfor (const match of window.matchAll(/[.!?。!?](?=\\s|$)/gu)) {\n\t\tboundary = (match.index ?? 0) + match[0].length;\n\t}\n\tif (boundary >= limit / 2) return window.slice(0, boundary).trimEnd();\n\treturn truncate(window, limit);\n}\n\nconst VERIFY_COMMAND_PATTERN = /\\b(test|lint|typecheck|tsc|vitest|jest|pytest|build|check|fmt|format|compile)\\b/iu;\nconst INSPECT_COMMAND_PATTERN = /\\b(rg|grep|find|git (?:diff|status|log|show)|ls|tree|cat|head|tail)\\b/iu;\nconst RETRY_MARKER_PATTERN = /^Retrying\\b/u;\nconst STREAM_MARKERS = new Set([\"Thinking…\", \"Writing response…\"]);\n\n// Translates raw tool traffic into what the worker is doing right now, so\n// the collapsed card reads as a phase instead of a command line. Modelled\n// on tool-type classification; the raw tool summary stays as evidence on\n// the next line.\nfunction runIntent(run: SubagentRunDetails): string {\n\tconst current = run.currentActivity;\n\tif (current && RETRY_MARKER_PATTERN.test(current)) return current;\n\tconst running = [...run.activities].reverse().find((activity) => activity.status === \"running\");\n\tif (running) {\n\t\tif (running.toolName === \"edit\" || running.toolName === \"write\") return \"Applying changes\";\n\t\tif (running.toolName === \"bash\") {\n\t\t\tif (VERIFY_COMMAND_PATTERN.test(running.summary)) return \"Verifying changes\";\n\t\t\treturn INSPECT_COMMAND_PATTERN.test(running.summary) ? \"Exploring code\" : \"Running commands\";\n\t\t}\n\t\treturn \"Exploring code\";\n\t}\n\tconst recent = run.activities.slice(-5);\n\tif (current && STREAM_MARKERS.has(current)) {\n\t\tif (recent.some((activity) => activity.status === \"failed\")) return \"Investigating a failure\";\n\t\treturn current;\n\t}\n\tif (recent.some((activity) => activity.status === \"failed\")) return \"Investigating a failure\";\n\tif (recent.some((activity) => activity.toolName === \"edit\" || activity.toolName === \"write\"))\n\t\treturn \"Reviewing changes\";\n\tif (recent.length > 0) return \"Exploring code\";\n\treturn current ?? \"Thinking…\";\n}\n\n// The raw tool summary backs up the intent line; suppress it when it would\n// just repeat a stream/retry marker.\nfunction runEvidence(run: SubagentRunDetails): string | undefined {\n\tconst current = run.currentActivity;\n\tif (!current || STREAM_MARKERS.has(current) || RETRY_MARKER_PATTERN.test(current)) return undefined;\n\treturn current;\n}\n\nfunction liveElapsed(run: SubagentRunDetails): string | undefined {\n\tif (run.startedAt === undefined) return undefined;\n\tconst end = run.endedAt ?? Date.now();\n\treturn formatDuration(Math.max(0, (end - run.startedAt) / 1000));\n}\n\n// The tool shell already paints a call-level status dot (● in\n// warning/success/error), so `●` is off-limits here: `›` marks where the\n// work currently is, and the remaining glyphs are terminal states.\nfunction statusMarker(status: SubagentRunStatus, theme: Theme): string {\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn theme.fg(\"success\", \"✓\");\n\t\tcase \"failed\":\n\t\t\treturn theme.fg(\"error\", \"×\");\n\t\tcase \"aborted\":\n\t\t\treturn theme.fg(\"warning\", \"■\");\n\t\tcase \"running\":\n\t\t\treturn theme.fg(\"accent\", \"›\");\n\t\tdefault:\n\t\t\treturn theme.fg(\"muted\", \"○\");\n\t}\n}\n\nfunction runTitle(run: SubagentRunDetails, theme: Theme, index?: number): string {\n\tconst number = index === undefined ? \"\" : theme.fg(\"dim\", `${index} · `);\n\treturn `${statusMarker(run.status, theme)} ${number}${theme.fg(\"accent\", displayAgentName(run.agent))}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`;\n}\n\nfunction runProgressText(run: SubagentRunDetails): string {\n\tconst items = [`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}`];\n\tif (run.usage.totalTokens) items.push(`${formatTokens(run.usage.totalTokens)} tokens`);\n\treturn items.join(\" · \");\n}\n\nfunction runLine(run: SubagentRunDetails, theme: Theme, index?: number): string {\n\tlet line = runTitle(run, theme, index);\n\tconst detail =\n\t\trun.status === \"running\"\n\t\t\t? runIntent(run)\n\t\t\t: run.status === \"failed\" || run.status === \"aborted\"\n\t\t\t\t? run.error && excerpt(run.error, RUN_LINE_EXCERPT_LIMIT)\n\t\t\t\t: run.finalOutput && excerpt(run.finalOutput, RUN_LINE_EXCERPT_LIMIT);\n\tif (detail) line += theme.fg(run.status === \"failed\" ? \"error\" : \"dim\", ` — ${detail}`);\n\tif (run.status === \"running\") {\n\t\tline += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\tconst elapsed = liveElapsed(run);\n\t\tif (elapsed) line += theme.fg(\"dim\", ` · ${elapsed}`);\n\t}\n\tconst settled = run.status !== \"running\" && run.status !== \"queued\";\n\tif (settled && run.startedAt !== undefined && run.endedAt !== undefined) {\n\t\tline += theme.fg(\"dim\", ` · ${formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))}`);\n\t}\n\treturn line;\n}\n\n// Keep active work visible while a batch is in flight: completed runs\n// may otherwise crowd a still-running task out of the collapsed window.\nfunction selectCollapsedRuns(runs: SubagentRunDetails[], isPartial: boolean): SubagentRunDetails[] {\n\tif (runs.length <= COLLAPSED_RUN_LIMIT) return runs;\n\tif (!isPartial) return runs.slice(0, COLLAPSED_RUN_LIMIT);\n\tconst active = runs.filter((run) => run.status === \"running\" || run.status === \"queued\");\n\tconst settled = runs.filter((run) => run.status !== \"running\" && run.status !== \"queued\");\n\treturn [...active, ...settled].slice(0, COLLAPSED_RUN_LIMIT);\n}\n\nfunction singleCollapsedLines(details: SubagentDetails, theme: Theme): string[] {\n\tconst run = details.runs[0];\n\tif (!run) return [theme.fg(\"muted\", \"Initializing…\")];\n\tif (run.status === \"running\" || run.status === \"queued\") {\n\t\tconst isInitializing =\n\t\t\trun.status === \"running\" && run.usage.turns === 0 && run.usage.toolUses === 0 && run.liveText.length === 0;\n\t\tconst intent =\n\t\t\trun.status === \"queued\"\n\t\t\t\t? (run.currentActivity ?? \"queued\")\n\t\t\t\t: isInitializing\n\t\t\t\t\t? \"Initializing…\"\n\t\t\t\t\t: runIntent(run);\n\t\t// No status marker here: the shell's call-level dot already covers\n\t\t// the whole card, and a single run has nothing to disambiguate.\n\t\tlet status = theme.fg(\"dim\", intent);\n\t\tif (run.status === \"running\" && !isInitializing) {\n\t\t\tstatus += theme.fg(\"dim\", ` · ${runProgressText(run)}`);\n\t\t\tconst elapsed = liveElapsed(run);\n\t\t\tif (elapsed) status += theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t}\n\t\tconst lines = [status];\n\t\tconst evidence = runEvidence(run);\n\t\tif (evidence && evidence !== intent)\n\t\t\tlines.push(`${theme.fg(\"accent\", \"›\")} ${theme.fg(\"dim\", excerpt(evidence, LIVE_TAIL_LIMIT))}`);\n\t\tconst tail = liveTail(run);\n\t\tif (tail) lines.push(theme.fg(\"dim\", tail));\n\t\treturn lines;\n\t}\n\tif (run.error) return [theme.fg(\"error\", excerpt(run.error, SINGLE_EXCERPT_LIMIT))];\n\tif (run.finalOutput) return [theme.fg(\"toolOutput\", leadingSentences(run.finalOutput, SINGLE_EXCERPT_LIMIT))];\n\treturn [theme.fg(\"muted\", run.status)];\n}\n\nfunction activitySummaryText(details: SubagentDetails): string {\n\tconst toolCounts = new Map<string, number>();\n\tlet activityCount = 0;\n\tfor (const run of details.runs) {\n\t\tfor (const activity of run.activities) {\n\t\t\tactivityCount++;\n\t\t\ttoolCounts.set(activity.toolName, (toolCounts.get(activity.toolName) ?? 0) + 1);\n\t\t}\n\t}\n\tconst items: string[] = [];\n\tlet groupedCount = 0;\n\tfor (const group of ACTIVITY_GROUPS) {\n\t\tconst count = toolCounts.get(group.toolName) ?? 0;\n\t\tif (count === 0) continue;\n\t\tgroupedCount += count;\n\t\titems.push(`${group.verb} ${count} ${count === 1 ? group.singular : group.plural}`);\n\t}\n\tconst otherCount = activityCount - groupedCount;\n\tif (otherCount > 0) items.push(`used ${otherCount} other tool${otherCount === 1 ? \"\" : \"s\"}`);\n\tif (items.length === 0) return \"\";\n\tconst earlierCount = Math.max(0, details.usage.toolUses - activityCount);\n\tif (earlierCount > 0) items.push(`${earlierCount} earlier tool use${earlierCount === 1 ? \"\" : \"s\"}`);\n\treturn `${items[0]![0]!.toUpperCase()}${items[0]!.slice(1)}${items\n\t\t.slice(1)\n\t\t.map((item) => ` · ${item}`)\n\t\t.join(\"\")}`;\n}\n\nfunction usageText(details: SubagentDetails, includeToolUses = true): string {\n\tconst usage = details.usage;\n\tconst items: string[] = [];\n\tif (includeToolUses && usage.toolUses) items.push(`${usage.toolUses} tool use${usage.toolUses === 1 ? \"\" : \"s\"}`);\n\tif (usage.turns) items.push(`${usage.turns} turn${usage.turns === 1 ? \"\" : \"s\"}`);\n\tif (usage.output) items.push(`↓${formatTokens(usage.output)}`);\n\tif (usage.contextTokens) items.push(`ctx:${formatTokens(usage.contextTokens)}`);\n\tif (usage.cost) items.push(`$${usage.cost.toFixed(3)}`);\n\tconst duration = details.endedAt ? Math.max(0, (details.endedAt - details.startedAt) / 1000) : undefined;\n\tif (duration !== undefined) items.push(formatDuration(duration));\n\treturn items.join(\" · \");\n}\n\nfunction formatTokens(value: number): string {\n\tif (value < 1_000) return String(value);\n\tif (value < 1_000_000) return `${(value / 1_000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}M`;\n}\n\nfunction formatDuration(seconds: number): string {\n\tif (seconds >= 90) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;\n\treturn `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;\n}\n\n// A single run's title and usage would duplicate the call header and\n// the call-level usage line, so `single` drops both and folds the\n// duration into the metadata line instead. Multi-run sections carry a\n// numbered `──` header that matches the table of contents above them.\nfunction renderRunDetails(run: SubagentRunDetails, theme: Theme, single: boolean, index?: number): Component {\n\tconst container = new Container();\n\tconst duration =\n\t\trun.startedAt !== undefined && run.endedAt !== undefined\n\t\t\t? formatDuration(Math.max(0, (run.endedAt - run.startedAt) / 1000))\n\t\t\t: undefined;\n\tif (!single) {\n\t\tconst label = index === undefined ? \"\" : `${index} · `;\n\t\tcontainer.addChild(\n\t\t\tnew Text(\n\t\t\t\t`${theme.fg(\"dim\", `── ${label}`)}${theme.fg(\"accent\", displayAgentName(run.agent))}${theme.fg(\"dim\", ` · ${truncate(run.description, 48)}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Task\"), 0, 0));\n\tcontainer.addChild(new Text(theme.fg(\"dim\", run.prompt), 0, 0));\n\tif (run.activities.length > 0) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Activity\"), 0, 0));\n\t\tfor (const activity of run.activities) {\n\t\t\tconst marker =\n\t\t\t\tactivity.status === \"succeeded\"\n\t\t\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t\t\t: activity.status === \"failed\"\n\t\t\t\t\t\t? theme.fg(\"error\", \"×\")\n\t\t\t\t\t\t: theme.fg(\"accent\", \"›\");\n\t\t\tlet text = `${marker} ${theme.fg(\"toolOutput\", excerpt(activity.summary, 96))}`;\n\t\t\tif (activity.resultSummary) {\n\t\t\t\tconst color = activity.status === \"failed\" ? \"error\" : \"dim\";\n\t\t\t\ttext += ` ${theme.fg(color, `· ${excerpt(activity.resultSummary, 64)}`)}`;\n\t\t\t}\n\t\t\tif (activity.endedAt !== undefined && activity.endedAt - activity.startedAt >= 1_000) {\n\t\t\t\ttext += ` ${theme.fg(\"dim\", `· ${formatDuration((activity.endedAt - activity.startedAt) / 1000)}`)}`;\n\t\t\t}\n\t\t\tcontainer.addChild(new Text(text, 0, 0));\n\t\t}\n\t}\n\t// The live tail is the \"now\" end of the timeline, so it sits after the\n\t// activity list; once the run settles, Response takes its place.\n\tif (run.status === \"running\" && run.liveText) {\n\t\tconst tail = run.liveText\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.slice(-4);\n\t\tif (tail.length > 0) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tfor (const line of tail) {\n\t\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", excerpt(line, LIVE_TAIL_LIMIT)), 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\tif (run.error) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Error: ${run.error}`), 0, 0));\n\t}\n\tif (run.finalOutput) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"muted\", \"Response\"), 0, 0));\n\t\tcontainer.addChild(new Markdown(run.finalOutput, 0, 0, getMarkdownTheme()));\n\t}\n\tconst metadata = [\n\t\t`${run.model} · ${run.thinking}`,\n\t\trun.cwd ? `cwd: ${run.cwd}` : undefined,\n\t\trun.usage.toolUses ? `${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.turns ? `${run.usage.turns} turn${run.usage.turns === 1 ? \"\" : \"s\"}` : undefined,\n\t\trun.usage.output ? `↓${formatTokens(run.usage.output)}` : undefined,\n\t\trun.usage.contextTokens ? `ctx:${formatTokens(run.usage.contextTokens)}` : undefined,\n\t\trun.usage.cost ? `$${run.usage.cost.toFixed(3)}` : undefined,\n\t\tsingle ? duration : undefined,\n\t]\n\t\t.filter((item): item is string => Boolean(item))\n\t\t.join(\" · \");\n\tif (metadata) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", metadata), 0, 0));\n\t}\n\treturn container;\n}\n\n// The call header stays a single line: run rows in the result area take\n// over within the first update and carry richer per-task state, so a\n// task list here would render everything twice. The task count alone\n// distinguishes a batch from a single delegation.\nexport function renderSubagentCall(args: SubagentParams, theme: Theme): Component {\n\tconst modes = [args.prompt != null && \"prompt\", args.tasks != null && \"tasks\"].filter((mode): mode is string =>\n\t\tBoolean(mode),\n\t);\n\tif (modes.length > 1) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"Subagent \"))}${theme.fg(\"error\", `invalid · ${modes.join(\" + \")}`)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tif (args.tasks) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"Multi-Agent\"))}${theme.fg(\"dim\", ` · ${args.tasks.length} task${args.tasks.length === 1 ? \"\" : \"s\"}`)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tlet text = theme.fg(\"toolTitle\", theme.bold(`${singleAgentName(args)} Agent`));\n\tif (args.description) text += theme.fg(\"dim\", ` · ${truncate(args.description, 72)}`);\n\treturn new Text(text, 0, 0);\n}\n\nexport function renderSubagentResult(\n\tresult: AgentToolResult<SubagentDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tisError: boolean,\n): Component {\n\tconst details = result.details;\n\tif (!details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\");\n\t\treturn new Text(text?.type === \"text\" ? text.text : \"(no output)\", 0, 0);\n\t}\n\tif (!options.expanded) {\n\t\tconst lines: string[] = [];\n\t\tif (details.mode === \"single\") {\n\t\t\tlines.push(...singleCollapsedLines(details, theme));\n\t\t} else {\n\t\t\tlet header = statusSummary(details);\n\t\t\tif (options.isPartial) {\n\t\t\t\theader += ` · ${formatDuration(Math.max(0, (Date.now() - details.startedAt) / 1000))}`;\n\t\t\t}\n\t\t\tlines.push(theme.fg(isError ? \"error\" : options.isPartial ? \"accent\" : \"muted\", header));\n\t\t\tconst shown = selectCollapsedRuns(details.runs, Boolean(options.isPartial));\n\t\t\tfor (const run of shown) lines.push(runLine(run, theme));\n\t\t\tconst hidden = details.runs.length - shown.length;\n\t\t\tif (hidden > 0) lines.push(theme.fg(\"muted\", `+${hidden} more`));\n\t\t}\n\t\tconst activitySummary = activitySummaryText(details);\n\t\tif (activitySummary) lines.push(theme.fg(\"dim\", activitySummary));\n\t\tconst usage = usageText(details, !activitySummary);\n\t\tif (usage) lines.push(theme.fg(\"dim\", usage));\n\t\tif (!options.isPartial) lines.push(theme.fg(\"muted\", `(${keyHint(\"app.tools.expand\", \"to expand\")})`));\n\t\treturn new Text(lines.join(\"\\n\"), 0, 0);\n\t}\n\tconst container = new Container();\n\tconst single = details.mode === \"single\" && details.runs.length === 1;\n\tif (!single) {\n\t\tcontainer.addChild(new Text(theme.fg(isError ? \"error\" : \"toolTitle\", statusSummary(details)), 0, 0));\n\t\t// Numbered table of contents: the TUI cannot jump, but matching the\n\t\t// numbers against the `──` section headers below makes an 8-run\n\t\t// batch navigable by eye.\n\t\tdetails.runs.forEach((run, index) => {\n\t\t\tcontainer.addChild(new Text(runLine(run, theme, index + 1), 0, 0));\n\t\t});\n\t}\n\tdetails.runs.forEach((run, index) => {\n\t\tif (!single || index > 0) container.addChild(new Spacer(1));\n\t\tcontainer.addChild(renderRunDetails(run, theme, single, single ? undefined : index + 1));\n\t});\n\tif (!single) {\n\t\tconst usage = usageText(details);\n\t\tif (usage) {\n\t\t\tcontainer.addChild(new Spacer(1));\n\t\t\tcontainer.addChild(new Text(theme.fg(\"dim\", usage), 0, 0));\n\t\t}\n\t}\n\treturn container;\n}\n"]}
|