@oh-my-pi/pi-coding-agent 17.2.8 → 17.2.10
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 +94 -1
- package/dist/{CHANGELOG-0b0w17se.md → CHANGELOG-rhwzpexa.md} +94 -1
- package/dist/cli.js +13216 -15614
- package/dist/types/async/job-manager.d.ts +12 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/discovery/agents.d.ts +11 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/loader.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +10 -0
- package/dist/types/hindsight/state.d.ts +0 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/lsp/utils.d.ts +8 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/modes/acp/acp-agent.d.ts +1 -1
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
- package/dist/types/modes/acp/acp-mode.d.ts +1 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +38 -0
- package/dist/types/modes/components/agent-hub-renderer.d.ts +41 -0
- package/dist/types/modes/components/agent-hub.d.ts +12 -5
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/session-observer-registry.d.ts +2 -0
- package/dist/types/registry/agent-lifecycle.d.ts +1 -1
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +8 -4
- package/dist/types/session/session-entries.d.ts +10 -0
- package/dist/types/session/session-loader.d.ts +11 -1
- package/dist/types/session/session-manager.d.ts +9 -1
- package/dist/types/session/session-tools.d.ts +10 -1
- package/dist/types/session/turn-recovery.d.ts +6 -2
- package/dist/types/slash-commands/acp-builtins.d.ts +1 -1
- package/dist/types/slash-commands/available-commands.d.ts +1 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +2 -3
- package/dist/types/task/read-only-policy.d.ts +3 -0
- package/dist/types/task/structured-subagent.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/launch.d.ts +3 -0
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/read.d.ts +3 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +21 -3
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/changelog.d.ts +3 -2
- package/dist/types/utils/late-cleanup.d.ts +2 -0
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +4 -3
- package/dist/types/web/scrapers/readthedocs.d.ts +0 -3
- package/dist/types/web/search/providers/browser-headers.d.ts +2 -3
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/api-demo.ts +5 -6
- package/examples/extensions/chalk-logger.ts +1 -1
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/package.json +15 -31
- package/scripts/bundle-dist.ts +1 -11
- package/scripts/omp +11 -2
- package/src/advisor/runtime.ts +54 -0
- package/src/async/job-manager.ts +26 -0
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +24 -2
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/flag-tables.ts +4 -0
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/help-extra.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +4 -4
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +3 -57
- package/src/cli/usage-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli/worktree-cli.ts +1 -1
- package/src/commands/say.ts +1 -1
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/cli.ts +1 -1
- package/src/config/config-file.ts +2 -2
- package/src/config/keybindings.ts +3 -3
- package/src/config/model-discovery.ts +36 -2
- package/src/config/model-registry.ts +4 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/discovery/agents.ts +73 -3
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +5 -4
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +1 -1
- package/src/discovery/claude.ts +8 -5
- package/src/discovery/cursor.ts +8 -5
- package/src/discovery/gemini.ts +11 -8
- package/src/discovery/vscode.ts +1 -0
- package/src/discovery/windsurf.ts +4 -2
- package/src/edit/hashline/filesystem.ts +7 -7
- package/src/eval/agent-bridge.ts +1 -3
- package/src/eval/jl/prelude.jl +4 -4
- package/src/eval/js/shared/prelude.txt +2 -2
- package/src/eval/py/prelude.py +0 -3
- package/src/eval/py/runner.py +38 -1
- package/src/eval/rb/prelude.rb +1 -2
- package/src/extensibility/custom-commands/loader.ts +4 -4
- package/src/extensibility/custom-commands/types.ts +5 -5
- package/src/extensibility/custom-tools/loader.ts +4 -4
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -6
- package/src/extensibility/extensions/types.ts +39 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +23 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/hindsight/state.ts +2 -22
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +33 -0
- package/src/launch/terminal-output.ts +1 -1
- package/src/lsp/client.ts +2 -2
- package/src/lsp/utils.ts +29 -0
- package/src/main.ts +85 -21
- package/src/markit/converters/docx.ts +1 -1
- package/src/markit/converters/epub.ts +1 -1
- package/src/markit/converters/pptx.ts +1 -1
- package/src/markit/converters/xlsx.ts +1 -1
- package/src/modes/acp/acp-agent.ts +7 -6
- package/src/modes/acp/acp-client-bridge.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/acp/acp-mode.ts +1 -1
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +670 -192
- package/src/modes/components/agent-transcript-viewer.ts +1 -3
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/bordered-loader.ts +1 -1
- package/src/modes/components/custom-editor.ts +2 -2
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/hook-input.ts +1 -1
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/session-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -3
- package/src/modes/controllers/event-controller.ts +188 -7
- package/src/modes/controllers/extension-ui-controller.ts +4 -3
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +40 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/print-mode.ts +29 -12
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/session-observer-registry.ts +5 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +35 -10
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +11 -5
- package/src/session/agent-session-types.ts +8 -0
- package/src/session/agent-session.ts +177 -188
- package/src/session/session-entries.ts +10 -0
- package/src/session/session-listing.ts +1 -1
- package/src/session/session-loader.ts +74 -8
- package/src/session/session-manager.ts +22 -2
- package/src/session/session-paths.ts +105 -110
- package/src/session/session-tools.ts +28 -1
- package/src/session/settings-stream-fn.ts +7 -3
- package/src/session/turn-recovery.ts +236 -18
- package/src/session/unexpected-stop-classifier.ts +12 -3
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/helpers/stats-dashboard.ts +2 -1
- package/src/task/agents.ts +1 -1
- package/src/task/executor.ts +173 -47
- package/src/task/index.ts +9 -28
- package/src/task/isolation-runner.ts +43 -12
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +31 -6
- package/src/task/types.ts +4 -0
- package/src/tiny/worker.ts +1 -1
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-interceptor.ts +8 -4
- package/src/tools/bash.ts +6 -6
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +76 -19
- package/src/tools/browser/readable.ts +9 -9
- package/src/tools/browser/tab-supervisor.ts +12 -3
- package/src/tools/browser/tab-worker-entry.ts +1 -1
- package/src/tools/browser/tab-worker.ts +101 -12
- package/src/tools/fetch.ts +1 -1
- package/src/tools/glob.ts +4 -2
- package/src/tools/path-utils.ts +22 -5
- package/src/tools/read.ts +22 -5
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +38 -9
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/changelog.ts +5 -4
- package/src/utils/clipboard.ts +10 -2
- package/src/utils/external-editor.ts +4 -2
- package/src/utils/jj.ts +1 -1
- package/src/utils/late-cleanup.ts +17 -0
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +202 -58
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/hackage.ts +1 -12
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +2 -1
- package/src/web/scrapers/twitter.ts +2 -2
- package/src/web/scrapers/types.ts +1 -1
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +12 -39
- package/src/web/search/providers/codex.ts +3 -26
- package/src/web/search/providers/duckduckgo.ts +1 -1
- package/src/web/search/providers/ecosia.ts +2 -2
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/firecrawl.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +2 -2
- package/src/web/search/providers/perplexity.ts +1 -1
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/startpage.ts +2 -2
- package/src/markit/converters/mammoth.d.ts +0 -24
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { Ellipsis, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { formatDuration, formatNumber, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { getRoleInfo } from "../../config/model-roles";
|
|
5
|
+
import type { Settings } from "../../config/settings";
|
|
6
|
+
import { type AgentRef, MAIN_AGENT_ID } from "../../registry/agent-registry";
|
|
7
|
+
import { parseThinkingLevel } from "../../thinking";
|
|
8
|
+
import { replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../../tools/render-utils";
|
|
9
|
+
import type { ObservableSession } from "../session-observer-registry";
|
|
10
|
+
import { theme } from "../theme/theme";
|
|
11
|
+
import type { AgentMetrics } from "./agent-hub-projection";
|
|
12
|
+
|
|
13
|
+
export interface RosterRender {
|
|
14
|
+
lines: string[];
|
|
15
|
+
hitRows: Array<number | undefined>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Legacy progress snapshots may omit counters; snapshot absence remains distinct. */
|
|
19
|
+
export function metricNumber(value: number | undefined): number {
|
|
20
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Compute the max content width for the current terminal, accounting for chrome. */
|
|
24
|
+
export function contentWidth(): number {
|
|
25
|
+
return Math.max(TRUNCATE_LENGTHS.SHORT, (process.stdout.columns || 80) - 6);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Remove terminal controls and normalize a value before it reaches the TUI. */
|
|
29
|
+
export function sanitizeDisplayText(text: string): string {
|
|
30
|
+
return replaceTabs(sanitizeText(text)).replace(/[\r\n]+/g, " ");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Sanitize a line for TUI display and truncate it to the viewport width. */
|
|
34
|
+
export function sanitizeLine(text: string, maxWidth?: number): string {
|
|
35
|
+
return truncateToWidth(sanitizeDisplayText(text), maxWidth ?? contentWidth());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function clampHubLine(line: string, width: number): string {
|
|
39
|
+
return truncateToWidth(line.replace(/[\r\n]+/g, " "), Math.max(1, width), Ellipsis.Omit);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Status glyph, colored per theme status conventions. The title-line counts spell out the words. */
|
|
43
|
+
export function statusGlyph(status: AgentRef["status"]): string {
|
|
44
|
+
switch (status) {
|
|
45
|
+
case "running":
|
|
46
|
+
return theme.fg("accent", theme.status.running);
|
|
47
|
+
case "idle":
|
|
48
|
+
return theme.fg("success", theme.status.enabled);
|
|
49
|
+
case "parked":
|
|
50
|
+
return theme.fg("muted", theme.status.shadowed);
|
|
51
|
+
case "aborted":
|
|
52
|
+
return theme.fg("error", theme.status.aborted);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function statusText(status: AgentRef["status"], text: string): string {
|
|
57
|
+
switch (status) {
|
|
58
|
+
case "running":
|
|
59
|
+
return theme.fg("accent", text);
|
|
60
|
+
case "idle":
|
|
61
|
+
return theme.fg("success", text);
|
|
62
|
+
case "parked":
|
|
63
|
+
return theme.fg("muted", text);
|
|
64
|
+
case "aborted":
|
|
65
|
+
return theme.fg("error", text);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Model id + thinking level (`sonnet-4-6 ◒ high`), level colored per theme. */
|
|
70
|
+
export function formatModelBadge(modelId: string, level: ThinkingLevel | undefined): string {
|
|
71
|
+
const model = theme.fg("muted", sanitizeDisplayText(modelId));
|
|
72
|
+
if (!level || level === ThinkingLevel.Off || level === ThinkingLevel.Inherit) return model;
|
|
73
|
+
const display = theme.thinking[level as keyof typeof theme.thinking] ?? level;
|
|
74
|
+
return `${model} ${theme.getThinkingBorderColor(level)(display)}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Textual model-role tag; color reinforces (but never replaces) the label. */
|
|
78
|
+
export function formatRoleBadge(role: string, settings: Settings): string {
|
|
79
|
+
const info = getRoleInfo(role, settings);
|
|
80
|
+
return theme.fg(info.color ?? "muted", sanitizeDisplayText(info.tag ?? info.name ?? role));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Format a resolved selector, preserving provider identity when requested. */
|
|
84
|
+
export function formatResolvedModelBadge(
|
|
85
|
+
resolved: string,
|
|
86
|
+
preserveProvider = false,
|
|
87
|
+
fallbackLevel?: ThinkingLevel,
|
|
88
|
+
): string {
|
|
89
|
+
const cleanResolved = sanitizeDisplayText(resolved);
|
|
90
|
+
// Model ids may themselves contain colons (`qwen3:14b`), so only treat the
|
|
91
|
+
// suffix as a thinking level when it parses as one.
|
|
92
|
+
const colon = cleanResolved.lastIndexOf(":");
|
|
93
|
+
const explicitLevel = colon >= 0 ? parseThinkingLevel(cleanResolved.slice(colon + 1)) : undefined;
|
|
94
|
+
const selector = explicitLevel !== undefined ? cleanResolved.slice(0, colon) : cleanResolved;
|
|
95
|
+
const label = preserveProvider ? selector : selector.slice(selector.indexOf("/") + 1);
|
|
96
|
+
return formatModelBadge(label, explicitLevel ?? fallbackLevel);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Resolved model + reasoning level for a hub row. Exact executor progress is
|
|
101
|
+
* authoritative (and survives completion); direct live sessions are the
|
|
102
|
+
* fallback for agents without an observer snapshot.
|
|
103
|
+
*/
|
|
104
|
+
export function modelBadge(ref: AgentRef, observed: ObservableSession | undefined): string | undefined {
|
|
105
|
+
const progress = observed?.progress;
|
|
106
|
+
const liveThinkingLevel = ref.session?.thinkingLevel;
|
|
107
|
+
const fallbackSelector =
|
|
108
|
+
ref.session?.retryFallbackModel ??
|
|
109
|
+
(progress?.resolvedModelIsFallback ? progress.resolvedModel : undefined) ??
|
|
110
|
+
(ref.history?.resolvedModelIsFallback ? ref.history.resolvedModel : undefined);
|
|
111
|
+
if (fallbackSelector) {
|
|
112
|
+
return `${theme.fg("warning", "fallback →")} ${formatResolvedModelBadge(fallbackSelector, true, liveThinkingLevel)}`;
|
|
113
|
+
}
|
|
114
|
+
const resolvedModel = progress?.resolvedModel ?? ref.history?.resolvedModel;
|
|
115
|
+
if (resolvedModel) return formatResolvedModelBadge(resolvedModel, false, liveThinkingLevel);
|
|
116
|
+
const model = ref.session?.model;
|
|
117
|
+
if (!model) return undefined;
|
|
118
|
+
const level = model.thinking ? liveThinkingLevel : undefined;
|
|
119
|
+
return formatModelBadge(model.id, level);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function formatMetricDuration(metrics: AgentMetrics): string | undefined {
|
|
123
|
+
const durationMs = metricNumber(metrics.durationMs);
|
|
124
|
+
if (durationMs <= 0) return undefined;
|
|
125
|
+
const label = metrics.durationKind === "active" ? "active" : metrics.durationKind === "span" ? "span" : "duration";
|
|
126
|
+
return `${formatDuration(durationMs)} ${label}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function formatCost(cost: number): string {
|
|
130
|
+
const amount = metricNumber(cost);
|
|
131
|
+
if (amount < 0.01) return `$${amount.toFixed(4)}`;
|
|
132
|
+
if (amount < 1) return `$${amount.toFixed(3)}`;
|
|
133
|
+
return `$${amount.toFixed(2)}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function formatMetrics(metrics: AgentMetrics): string {
|
|
137
|
+
return [
|
|
138
|
+
formatCost(metrics.cost),
|
|
139
|
+
formatMetricDuration(metrics) ?? "time —",
|
|
140
|
+
`${formatNumber(metrics.requests)} req`,
|
|
141
|
+
`${formatNumber(metrics.tools)} tools`,
|
|
142
|
+
`${formatNumber(metrics.tokens)} tok`,
|
|
143
|
+
].join(theme.sep.dot);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function contextGauge(tokens: number, window: number): string {
|
|
147
|
+
const ratio = Math.max(0, Math.min(1, tokens / window));
|
|
148
|
+
const filled = Math.round(ratio * 10);
|
|
149
|
+
return `${theme.fg("accent", "━".repeat(filled))}${theme.fg("dim", "─".repeat(10 - filled))} ${formatNumber(tokens)}/${formatNumber(window)} ${Math.round(ratio * 100)}%`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Fit a child-id preview without joining an arbitrarily large child set. */
|
|
153
|
+
export function formatChildIds(children: readonly AgentRef[], width: number): string {
|
|
154
|
+
const max = Math.max(1, width);
|
|
155
|
+
let shown = 0;
|
|
156
|
+
let text = "";
|
|
157
|
+
while (shown < children.length) {
|
|
158
|
+
const id = sanitizeLine(children[shown].id, max);
|
|
159
|
+
const candidate = text ? `${text}, ${id}` : id;
|
|
160
|
+
const remaining = children.length - shown - 1;
|
|
161
|
+
const suffix = remaining > 0 ? `, … +${remaining}` : "";
|
|
162
|
+
if (visibleWidth(candidate + suffix) > max) {
|
|
163
|
+
const includesCurrent = text.length === 0;
|
|
164
|
+
const omitted = children.length - shown - Number(includesCurrent);
|
|
165
|
+
return truncateToWidth(`${includesCurrent ? id : text}${omitted > 0 ? `, … +${omitted}` : ""}`, max);
|
|
166
|
+
}
|
|
167
|
+
text = candidate;
|
|
168
|
+
shown++;
|
|
169
|
+
}
|
|
170
|
+
return text;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Bash `tree`-style ancestry prefix, clipped from the left on pathological depth. */
|
|
174
|
+
export function treeBranch(
|
|
175
|
+
ref: AgentRef,
|
|
176
|
+
maxWidth: number,
|
|
177
|
+
depthById: ReadonlyMap<string, number>,
|
|
178
|
+
parentById: ReadonlyMap<string, string>,
|
|
179
|
+
lastSiblingById: ReadonlyMap<string, boolean>,
|
|
180
|
+
): string {
|
|
181
|
+
if ((depthById.get(ref.id) ?? 0) === 0) return "";
|
|
182
|
+
const segments: string[] = [lastSiblingById.get(ref.id) ? "└── " : "├── "];
|
|
183
|
+
const ancestry = new Set<string>();
|
|
184
|
+
let parent = parentById.get(ref.id);
|
|
185
|
+
while (parent && parentById.get(parent) !== MAIN_AGENT_ID && !ancestry.has(parent)) {
|
|
186
|
+
ancestry.add(parent);
|
|
187
|
+
segments.push(lastSiblingById.get(parent) ? " " : "│ ");
|
|
188
|
+
parent = parentById.get(parent);
|
|
189
|
+
}
|
|
190
|
+
const maxSegments = Math.max(1, Math.floor(Math.max(4, maxWidth - 2) / 4));
|
|
191
|
+
const omitted = Math.max(0, segments.length - maxSegments);
|
|
192
|
+
const prefix = segments.slice(0, maxSegments).reverse().join("");
|
|
193
|
+
return theme.fg("dim", `${omitted > 0 ? "… " : ""}${prefix}`);
|
|
194
|
+
}
|