@oh-my-pi/pi-coding-agent 8.0.16 → 8.1.0
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 +105 -0
- package/package.json +14 -11
- package/scripts/generate-wasm-b64.ts +24 -0
- package/src/capability/context-file.ts +1 -1
- package/src/capability/extension-module.ts +1 -1
- package/src/capability/extension.ts +1 -1
- package/src/capability/hook.ts +1 -1
- package/src/capability/instruction.ts +1 -1
- package/src/capability/mcp.ts +1 -1
- package/src/capability/prompt.ts +1 -1
- package/src/capability/rule.ts +1 -1
- package/src/capability/settings.ts +1 -1
- package/src/capability/skill.ts +1 -1
- package/src/capability/slash-command.ts +1 -1
- package/src/capability/ssh.ts +1 -1
- package/src/capability/system-prompt.ts +1 -1
- package/src/capability/tool.ts +1 -1
- package/src/cli/args.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -5
- package/src/commit/agentic/agent.ts +309 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +359 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +26 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +40 -0
- package/src/commit/agentic/state.ts +74 -0
- package/src/commit/agentic/tools/analyze-file.ts +131 -0
- package/src/commit/agentic/tools/git-file-diff.ts +194 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +84 -0
- package/src/commit/agentic/tools/index.ts +56 -0
- package/src/commit/agentic/tools/propose-changelog.ts +128 -0
- package/src/commit/agentic/tools/propose-commit.ts +154 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/split-commit.ts +284 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +200 -0
- package/src/commit/analysis/conventional.ts +169 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +114 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +36 -0
- package/src/commit/changelog/generate.ts +112 -0
- package/src/commit/changelog/index.ts +233 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +93 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/git/errors.ts +11 -0
- package/src/commit/git/index.ts +217 -0
- package/src/commit/git/operations.ts +53 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
- package/src/commit/map-reduce/index.ts +63 -0
- package/src/commit/map-reduce/map-phase.ts +193 -0
- package/src/commit/map-reduce/reduce-phase.ts +147 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +84 -0
- package/src/commit/pipeline.ts +242 -0
- package/src/commit/prompts/analysis-system.md +155 -0
- package/src/commit/prompts/analysis-user.md +41 -0
- package/src/commit/prompts/changelog-system.md +56 -0
- package/src/commit/prompts/changelog-user.md +19 -0
- package/src/commit/prompts/file-observer-system.md +26 -0
- package/src/commit/prompts/file-observer-user.md +9 -0
- package/src/commit/prompts/reduce-system.md +60 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +4 -0
- package/src/commit/prompts/summary-system.md +52 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/types.ts +109 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/config/file-lock.ts +111 -0
- package/src/config/model-registry.ts +16 -7
- package/src/config/settings-manager.ts +115 -40
- package/src/config.ts +5 -5
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/builtin.ts +1 -1
- package/src/discovery/claude.ts +1 -1
- package/src/discovery/cline.ts +1 -1
- package/src/discovery/codex.ts +1 -1
- package/src/discovery/cursor.ts +1 -1
- package/src/discovery/gemini.ts +1 -1
- package/src/discovery/github.ts +1 -1
- package/src/discovery/index.ts +11 -11
- package/src/discovery/mcp-json.ts +1 -1
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/vscode.ts +1 -1
- package/src/discovery/windsurf.ts +1 -1
- package/src/extensibility/custom-commands/loader.ts +1 -1
- package/src/extensibility/custom-commands/types.ts +1 -1
- package/src/extensibility/custom-tools/loader.ts +1 -1
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/loader.ts +1 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/loader.ts +1 -1
- package/src/extensibility/hooks/types.ts +3 -3
- package/src/index.ts +10 -10
- package/src/ipy/executor.ts +97 -1
- package/src/lsp/index.ts +1 -1
- package/src/lsp/render.ts +90 -46
- package/src/main.ts +16 -3
- package/src/mcp/loader.ts +3 -3
- package/src/migrations.ts +3 -3
- package/src/modes/components/assistant-message.ts +29 -1
- package/src/modes/components/tool-execution.ts +5 -3
- package/src/modes/components/tree-selector.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -3
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-mode.ts +1 -4
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/mermaid-cache.ts +89 -0
- package/src/modes/theme/theme.ts +2 -0
- package/src/modes/types.ts +2 -2
- package/src/patch/index.ts +3 -9
- package/src/patch/shared.ts +33 -5
- package/src/prompts/tools/task.md +2 -0
- package/src/sdk.ts +60 -22
- package/src/session/agent-session.ts +3 -3
- package/src/session/agent-storage.ts +32 -28
- package/src/session/artifacts.ts +24 -1
- package/src/session/auth-storage.ts +25 -10
- package/src/session/storage-migration.ts +12 -53
- package/src/system-prompt.ts +2 -2
- package/src/task/.executor.ts.kate-swp +0 -0
- package/src/task/executor.ts +1 -1
- package/src/task/index.ts +10 -1
- package/src/task/output-manager.ts +94 -0
- package/src/task/render.ts +7 -12
- package/src/task/worker.ts +1 -1
- package/src/tools/ask.ts +35 -13
- package/src/tools/bash.ts +80 -87
- package/src/tools/calculator.ts +42 -40
- package/src/tools/complete.ts +1 -1
- package/src/tools/fetch.ts +67 -104
- package/src/tools/find.ts +83 -86
- package/src/tools/grep.ts +80 -96
- package/src/tools/index.ts +10 -7
- package/src/tools/ls.ts +39 -65
- package/src/tools/notebook.ts +48 -64
- package/src/tools/output-utils.ts +1 -1
- package/src/tools/python.ts +71 -183
- package/src/tools/read.ts +74 -15
- package/src/tools/render-utils.ts +1 -15
- package/src/tools/ssh.ts +43 -24
- package/src/tools/todo-write.ts +27 -15
- package/src/tools/write.ts +93 -64
- package/src/tui/code-cell.ts +115 -0
- package/src/tui/file-list.ts +48 -0
- package/src/tui/index.ts +11 -0
- package/src/tui/output-block.ts +73 -0
- package/src/tui/status-line.ts +40 -0
- package/src/tui/tree-list.ts +56 -0
- package/src/tui/types.ts +17 -0
- package/src/tui/utils.ts +49 -0
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +1 -0
- package/src/web/search/auth.ts +1 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/render.ts +119 -163
- package/tsconfig.json +0 -42
package/src/tools/ls.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import nodePath from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
4
|
-
import {
|
|
4
|
+
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
5
5
|
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
6
6
|
import { ToolError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
7
|
+
import { renderFileList, renderStatusLine } from "@oh-my-pi/pi-coding-agent/tui";
|
|
7
8
|
import { type Component, Text } from "@oh-my-pi/pi-tui";
|
|
8
9
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
9
10
|
import { Type } from "@sinclair/typebox";
|
|
10
|
-
import type { ToolSession } from "
|
|
11
|
+
import type { ToolSession } from ".";
|
|
11
12
|
import { applyListLimit } from "./list-limit";
|
|
12
13
|
import { resolveToCwd } from "./path-utils";
|
|
13
14
|
import {
|
|
@@ -16,10 +17,6 @@ import {
|
|
|
16
17
|
formatCount,
|
|
17
18
|
formatEmptyMessage,
|
|
18
19
|
formatErrorMessage,
|
|
19
|
-
formatExpandHint,
|
|
20
|
-
formatMeta,
|
|
21
|
-
formatMoreItems,
|
|
22
|
-
formatTruncationSuffix,
|
|
23
20
|
PREVIEW_LIMITS,
|
|
24
21
|
} from "./render-utils";
|
|
25
22
|
import { toolResult } from "./tool-result";
|
|
@@ -214,13 +211,9 @@ const COLLAPSED_LIST_LIMIT = PREVIEW_LIMITS.COLLAPSED_ITEMS;
|
|
|
214
211
|
export const lsToolRenderer = {
|
|
215
212
|
inline: true,
|
|
216
213
|
renderCall(args: LsRenderArgs, uiTheme: Theme): Component {
|
|
217
|
-
const label = uiTheme.fg("toolTitle", uiTheme.bold("Ls"));
|
|
218
|
-
let text = `${uiTheme.format.bullet} ${label} ${uiTheme.fg("accent", args.path || ".")}`;
|
|
219
|
-
|
|
220
214
|
const meta: string[] = [];
|
|
221
215
|
if (args.limit !== undefined) meta.push(`limit:${args.limit}`);
|
|
222
|
-
text
|
|
223
|
-
|
|
216
|
+
const text = renderStatusLine({ icon: "pending", title: "Ls", description: args.path || ".", meta }, uiTheme);
|
|
224
217
|
return new Text(text, 0, 0);
|
|
225
218
|
},
|
|
226
219
|
|
|
@@ -228,19 +221,22 @@ export const lsToolRenderer = {
|
|
|
228
221
|
result: { content: Array<{ type: string; text?: string }>; details?: LsToolDetails; isError?: boolean },
|
|
229
222
|
{ expanded }: RenderResultOptions,
|
|
230
223
|
uiTheme: Theme,
|
|
224
|
+
args?: LsRenderArgs,
|
|
231
225
|
): Component {
|
|
232
226
|
const details = result.details;
|
|
233
227
|
const textContent = result.content?.find((c) => c.type === "text")?.text ?? "";
|
|
234
228
|
|
|
235
229
|
if (result.isError) {
|
|
236
|
-
|
|
230
|
+
const header = renderStatusLine({ icon: "error", title: "Ls", description: args?.path || "." }, uiTheme);
|
|
231
|
+
return new Text([header, formatErrorMessage(textContent, uiTheme)].join("\n"), 0, 0);
|
|
237
232
|
}
|
|
238
233
|
|
|
239
234
|
if (
|
|
240
235
|
(!textContent || textContent.trim() === "" || textContent.trim() === "(empty directory)") &&
|
|
241
236
|
(!details?.entries || details.entries.length === 0)
|
|
242
237
|
) {
|
|
243
|
-
|
|
238
|
+
const header = renderStatusLine({ icon: "warning", title: "Ls", description: args?.path || "." }, uiTheme);
|
|
239
|
+
return new Text([header, formatEmptyMessage("Empty directory", uiTheme)].join("\n"), 0, 0);
|
|
244
240
|
}
|
|
245
241
|
|
|
246
242
|
let entries: string[] = details?.entries ? [...details.entries] : [];
|
|
@@ -252,7 +248,8 @@ export const lsToolRenderer = {
|
|
|
252
248
|
}
|
|
253
249
|
|
|
254
250
|
if (entries.length === 0) {
|
|
255
|
-
|
|
251
|
+
const header = renderStatusLine({ icon: "warning", title: "Ls", description: args?.path || "." }, uiTheme);
|
|
252
|
+
return new Text([header, formatEmptyMessage("Empty directory", uiTheme)].join("\n"), 0, 0);
|
|
256
253
|
}
|
|
257
254
|
|
|
258
255
|
let dirCount = details?.dirCount;
|
|
@@ -260,8 +257,11 @@ export const lsToolRenderer = {
|
|
|
260
257
|
if (dirCount === undefined || fileCount === undefined) {
|
|
261
258
|
dirCount = 0;
|
|
262
259
|
fileCount = 0;
|
|
263
|
-
for (
|
|
264
|
-
|
|
260
|
+
for (let i = 0; i < entries.length; i++) {
|
|
261
|
+
const entry = entries[i];
|
|
262
|
+
const raw = rawEntries?.[i] ?? entry;
|
|
263
|
+
const name = raw.split(" (")[0];
|
|
264
|
+
if (name.endsWith("/")) {
|
|
265
265
|
dirCount += 1;
|
|
266
266
|
} else {
|
|
267
267
|
fileCount += 1;
|
|
@@ -272,62 +272,36 @@ export const lsToolRenderer = {
|
|
|
272
272
|
const truncation = details?.meta?.truncation;
|
|
273
273
|
const limits = details?.meta?.limits;
|
|
274
274
|
const truncated = Boolean(details?.entryLimitReached || truncation || limits?.resultLimit || limits?.headLimit);
|
|
275
|
-
const icon = truncated
|
|
276
|
-
? uiTheme.styledSymbol("status.warning", "warning")
|
|
277
|
-
: uiTheme.styledSymbol("status.success", "success");
|
|
278
|
-
|
|
279
275
|
const summaryText = [formatCount("dir", dirCount ?? 0), formatCount("file", fileCount ?? 0)].join(
|
|
280
276
|
uiTheme.sep.dot,
|
|
281
277
|
);
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
|
|
278
|
+
const meta = truncated ? [summaryText, uiTheme.fg("warning", "truncated")] : [summaryText];
|
|
279
|
+
const header = renderStatusLine(
|
|
280
|
+
{ icon: truncated ? "warning" : "success", title: "Ls", description: args?.path || ".", meta },
|
|
281
|
+
uiTheme,
|
|
282
|
+
);
|
|
285
283
|
|
|
286
|
-
|
|
284
|
+
const fileLines = renderFileList(
|
|
285
|
+
{
|
|
286
|
+
files: entries.map((entry, index) => ({
|
|
287
|
+
path: entry,
|
|
288
|
+
isDirectory: (rawEntries?.[index] ?? entry).endsWith("/"),
|
|
289
|
+
})),
|
|
290
|
+
expanded,
|
|
291
|
+
maxCollapsed: COLLAPSED_LIST_LIMIT,
|
|
292
|
+
},
|
|
293
|
+
uiTheme,
|
|
294
|
+
);
|
|
287
295
|
|
|
288
296
|
const truncationReasons: string[] = [];
|
|
289
|
-
if (limits?.resultLimit) {
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
if (truncation) {
|
|
293
|
-
truncationReasons.push(`output cap ${formatBytes(truncation.outputBytes)}`);
|
|
294
|
-
}
|
|
295
|
-
if (truncation?.artifactId) {
|
|
296
|
-
truncationReasons.push(`full output: artifact://${truncation.artifactId}`);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const hasTruncation = truncationReasons.length > 0;
|
|
300
|
-
|
|
301
|
-
for (let i = 0; i < maxEntries; i++) {
|
|
302
|
-
const entry = entries[i];
|
|
303
|
-
const rawEntry = rawEntries?.[i] ?? entry;
|
|
304
|
-
const isLast = i === maxEntries - 1 && !hasMoreEntries && !hasTruncation;
|
|
305
|
-
const branch = isLast ? uiTheme.tree.last : uiTheme.tree.branch;
|
|
306
|
-
const isDir = rawEntry.endsWith("/");
|
|
307
|
-
const entryPath = isDir ? rawEntry.slice(0, -1) : rawEntry;
|
|
308
|
-
const lang = isDir ? undefined : getLanguageFromPath(entryPath);
|
|
309
|
-
const entryIcon = isDir
|
|
310
|
-
? uiTheme.fg("accent", uiTheme.icon.folder)
|
|
311
|
-
: uiTheme.fg("muted", uiTheme.getLangIcon(lang));
|
|
312
|
-
const entryColor = isDir ? "accent" : "toolOutput";
|
|
313
|
-
text += `\n ${uiTheme.fg("dim", branch)} ${entryIcon} ${uiTheme.fg(entryColor, entry)}`;
|
|
314
|
-
}
|
|
297
|
+
if (limits?.resultLimit) truncationReasons.push(`entry limit ${limits.resultLimit.reached}`);
|
|
298
|
+
if (truncation) truncationReasons.push(`output cap ${formatBytes(truncation.outputBytes)}`);
|
|
299
|
+
if (truncation?.artifactId) truncationReasons.push(`full output: artifact://${truncation.artifactId}`);
|
|
315
300
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
text += `\n ${uiTheme.fg("dim", moreEntriesBranch)} ${uiTheme.fg(
|
|
319
|
-
"muted",
|
|
320
|
-
formatMoreItems(entries.length - maxEntries, "entry", uiTheme),
|
|
321
|
-
)}`;
|
|
322
|
-
}
|
|
301
|
+
const extraLines =
|
|
302
|
+
truncationReasons.length > 0 ? [uiTheme.fg("warning", `truncated: ${truncationReasons.join(", ")}`)] : [];
|
|
323
303
|
|
|
324
|
-
|
|
325
|
-
text += `\n ${uiTheme.fg("dim", uiTheme.tree.last)} ${uiTheme.fg(
|
|
326
|
-
"warning",
|
|
327
|
-
`truncated: ${truncationReasons.join(", ")}`,
|
|
328
|
-
)}`;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return new Text(text, 0, 0);
|
|
304
|
+
return new Text([header, ...fileLines, ...extraLines].join("\n"), 0, 0);
|
|
332
305
|
},
|
|
306
|
+
mergeCallAndResult: true,
|
|
333
307
|
};
|
package/src/tools/notebook.ts
CHANGED
|
@@ -3,19 +3,13 @@ import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
|
3
3
|
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
4
4
|
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
5
5
|
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/sdk";
|
|
6
|
+
import { renderCodeCell, renderStatusLine } from "@oh-my-pi/pi-coding-agent/tui";
|
|
6
7
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
7
8
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
8
9
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
9
10
|
import { type Static, Type } from "@sinclair/typebox";
|
|
10
11
|
import { resolveToCwd } from "./path-utils";
|
|
11
|
-
import {
|
|
12
|
-
formatCount,
|
|
13
|
-
formatErrorMessage,
|
|
14
|
-
formatExpandHint,
|
|
15
|
-
formatMeta,
|
|
16
|
-
formatMoreItems,
|
|
17
|
-
PREVIEW_LIMITS,
|
|
18
|
-
} from "./render-utils";
|
|
12
|
+
import { formatCount, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
|
|
19
13
|
|
|
20
14
|
const notebookSchema = Type.Object({
|
|
21
15
|
action: StringEnum(["edit", "insert", "delete"], {
|
|
@@ -200,57 +194,31 @@ export class NotebookTool implements AgentTool<typeof notebookSchema, NotebookTo
|
|
|
200
194
|
|
|
201
195
|
interface NotebookRenderArgs {
|
|
202
196
|
action: string;
|
|
203
|
-
notebookPath
|
|
197
|
+
notebookPath?: string;
|
|
198
|
+
notebook_path?: string;
|
|
204
199
|
cellNumber?: number;
|
|
200
|
+
cell_index?: number;
|
|
205
201
|
cellType?: string;
|
|
202
|
+
cell_type?: string;
|
|
206
203
|
content?: string;
|
|
207
204
|
}
|
|
208
205
|
|
|
209
206
|
const COLLAPSED_TEXT_LIMIT = PREVIEW_LIMITS.COLLAPSED_LINES * 2;
|
|
210
207
|
|
|
211
|
-
function normalizeCellLines(lines: string[]): string[] {
|
|
212
|
-
return lines.map((line) => (line.endsWith("\n") ? line.slice(0, -1) : line));
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function renderCellPreview(lines: string[], expanded: boolean, uiTheme: Theme): string {
|
|
216
|
-
const normalized = normalizeCellLines(lines);
|
|
217
|
-
if (normalized.length === 0) {
|
|
218
|
-
return `\n ${uiTheme.fg("dim", uiTheme.tree.last)} ${uiTheme.fg("muted", "(empty cell)")}`;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const maxLines = expanded ? normalized.length : Math.min(normalized.length, COLLAPSED_TEXT_LIMIT);
|
|
222
|
-
let text = "";
|
|
223
|
-
|
|
224
|
-
for (let i = 0; i < maxLines; i++) {
|
|
225
|
-
const isLast = i === maxLines - 1 && (expanded || normalized.length <= maxLines);
|
|
226
|
-
const branch = isLast ? uiTheme.tree.last : uiTheme.tree.branch;
|
|
227
|
-
const line = normalized[i];
|
|
228
|
-
text += `\n ${uiTheme.fg("dim", branch)} ${uiTheme.fg("toolOutput", line)}`;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const remaining = normalized.length - maxLines;
|
|
232
|
-
if (remaining > 0) {
|
|
233
|
-
text += `\n ${uiTheme.fg("dim", uiTheme.tree.last)} ${uiTheme.fg(
|
|
234
|
-
"muted",
|
|
235
|
-
formatMoreItems(remaining, "line", uiTheme),
|
|
236
|
-
)}`;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return text;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
208
|
export const notebookToolRenderer = {
|
|
243
209
|
renderCall(args: NotebookRenderArgs, uiTheme: Theme): Component {
|
|
244
|
-
const label = uiTheme.fg("toolTitle", uiTheme.bold("Notebook"));
|
|
245
|
-
let text = `${label} ${uiTheme.fg("accent", args.action || "?")}`;
|
|
246
|
-
|
|
247
210
|
const meta: string[] = [];
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
211
|
+
const notebookPath = args.notebookPath ?? args.notebook_path;
|
|
212
|
+
const cellNumber = args.cellNumber ?? args.cell_index;
|
|
213
|
+
const cellType = args.cellType ?? args.cell_type;
|
|
214
|
+
meta.push(`in ${notebookPath || "?"}`);
|
|
215
|
+
if (cellNumber !== undefined) meta.push(`cell:${cellNumber}`);
|
|
216
|
+
if (cellType) meta.push(`type:${cellType}`);
|
|
217
|
+
|
|
218
|
+
const text = renderStatusLine(
|
|
219
|
+
{ icon: "pending", title: "Notebook", description: args.action || "?", meta },
|
|
220
|
+
uiTheme,
|
|
221
|
+
);
|
|
254
222
|
return new Text(text, 0, 0);
|
|
255
223
|
},
|
|
256
224
|
|
|
@@ -258,10 +226,13 @@ export const notebookToolRenderer = {
|
|
|
258
226
|
result: { content: Array<{ type: string; text?: string }>; details?: NotebookToolDetails },
|
|
259
227
|
{ expanded }: RenderResultOptions,
|
|
260
228
|
uiTheme: Theme,
|
|
229
|
+
args?: NotebookRenderArgs,
|
|
261
230
|
): Component {
|
|
262
231
|
const content = result.content?.[0];
|
|
263
232
|
if (content?.type === "text" && content.text?.startsWith("Error:")) {
|
|
264
|
-
|
|
233
|
+
const notebookPath = args?.notebookPath ?? args?.notebook_path ?? "?";
|
|
234
|
+
const header = renderStatusLine({ icon: "error", title: "Notebook", description: notebookPath }, uiTheme);
|
|
235
|
+
return new Text([header, formatErrorMessage(content.text, uiTheme)].join("\n"), 0, 0);
|
|
265
236
|
}
|
|
266
237
|
|
|
267
238
|
const details = result.details;
|
|
@@ -269,25 +240,38 @@ export const notebookToolRenderer = {
|
|
|
269
240
|
const cellIndex = details?.cellIndex;
|
|
270
241
|
const cellType = details?.cellType;
|
|
271
242
|
const totalCells = details?.totalCells;
|
|
272
|
-
const cellSource = details?.cellSource;
|
|
273
|
-
const lineCount = cellSource
|
|
274
|
-
const canExpand = cellSource !== undefined && cellSource.length > COLLAPSED_TEXT_LIMIT;
|
|
243
|
+
const cellSource = details?.cellSource ?? [];
|
|
244
|
+
const lineCount = cellSource.length;
|
|
275
245
|
|
|
276
|
-
const icon = uiTheme.styledSymbol("status.success", "success");
|
|
277
246
|
const actionLabel = action === "insert" ? "Inserted" : action === "delete" ? "Deleted" : "Edited";
|
|
278
247
|
const cellLabel = cellType || "cell";
|
|
279
|
-
const summaryParts = [`${actionLabel} ${cellLabel}
|
|
280
|
-
if (lineCount
|
|
248
|
+
const summaryParts = [`${actionLabel} ${cellLabel} ${cellIndex ?? "?"}`];
|
|
249
|
+
if (lineCount > 0) summaryParts.push(formatCount("line", lineCount));
|
|
281
250
|
if (totalCells !== undefined) summaryParts.push(`${totalCells} total`);
|
|
282
|
-
const summaryText = summaryParts.join(uiTheme.sep.dot);
|
|
283
251
|
|
|
284
|
-
const
|
|
285
|
-
|
|
252
|
+
const outputLines = summaryParts.map((part) => uiTheme.fg("dim", part));
|
|
253
|
+
const codeText = cellSource.join("");
|
|
254
|
+
const language = cellType === "markdown" ? "markdown" : undefined;
|
|
286
255
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
256
|
+
const notebookPath = args?.notebookPath ?? args?.notebook_path;
|
|
257
|
+
const notebookLabel = notebookPath ? `${actionLabel} ${notebookPath}` : "Notebook";
|
|
258
|
+
return {
|
|
259
|
+
render: (width: number) =>
|
|
260
|
+
renderCodeCell(
|
|
261
|
+
{
|
|
262
|
+
code: codeText,
|
|
263
|
+
language,
|
|
264
|
+
title: notebookLabel,
|
|
265
|
+
status: "complete",
|
|
266
|
+
output: outputLines.join("\n"),
|
|
267
|
+
codeMaxLines: expanded ? Number.POSITIVE_INFINITY : COLLAPSED_TEXT_LIMIT,
|
|
268
|
+
expanded,
|
|
269
|
+
width,
|
|
270
|
+
},
|
|
271
|
+
uiTheme,
|
|
272
|
+
),
|
|
273
|
+
invalidate: () => {},
|
|
274
|
+
};
|
|
292
275
|
},
|
|
276
|
+
mergeCallAndResult: true,
|
|
293
277
|
};
|
package/src/tools/python.ts
CHANGED
|
@@ -6,18 +6,19 @@ import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibilit
|
|
|
6
6
|
import { executePython, getPreludeDocs, type PythonExecutorOptions } from "@oh-my-pi/pi-coding-agent/ipy/executor";
|
|
7
7
|
import type { PreludeHelper, PythonStatusEvent } from "@oh-my-pi/pi-coding-agent/ipy/kernel";
|
|
8
8
|
import { truncateToVisualLines } from "@oh-my-pi/pi-coding-agent/modes/components/visual-truncate";
|
|
9
|
-
import {
|
|
9
|
+
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
10
10
|
import pythonDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/python.md" with { type: "text" };
|
|
11
11
|
import { OutputSink, type OutputSummary } from "@oh-my-pi/pi-coding-agent/session/streaming-output";
|
|
12
12
|
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
13
13
|
import { ToolAbortError, ToolError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
14
|
+
import { getTreeBranch, getTreeContinuePrefix, renderCodeCell } from "@oh-my-pi/pi-coding-agent/tui";
|
|
14
15
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
15
|
-
import { Text, truncateToWidth
|
|
16
|
+
import { Text, truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
16
17
|
import { type Static, Type } from "@sinclair/typebox";
|
|
17
|
-
import type { ToolSession } from "
|
|
18
|
+
import type { ToolSession } from ".";
|
|
18
19
|
import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
|
|
19
20
|
import { resolveToCwd } from "./path-utils";
|
|
20
|
-
import {
|
|
21
|
+
import { shortenPath, ToolUIKit, truncate } from "./render-utils";
|
|
21
22
|
import { toolResult } from "./tool-result";
|
|
22
23
|
import { DEFAULT_MAX_BYTES } from "./truncate";
|
|
23
24
|
|
|
@@ -740,56 +741,6 @@ function renderStatusEvents(events: PythonStatusEvent[], theme: Theme, expanded:
|
|
|
740
741
|
return lines;
|
|
741
742
|
}
|
|
742
743
|
|
|
743
|
-
function applyCellBackground(line: string, width: number, bgFn?: (text: string) => string): string {
|
|
744
|
-
if (!bgFn) return line;
|
|
745
|
-
if (width <= 0) return bgFn(line);
|
|
746
|
-
const paddingNeeded = Math.max(0, width - visibleWidth(line));
|
|
747
|
-
const padded = line + " ".repeat(paddingNeeded);
|
|
748
|
-
return bgFn(padded);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
function highlightPythonCode(code?: string): string[] {
|
|
752
|
-
return highlightCode(code ?? "", "python");
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
function formatCellStatus(cell: PythonCellResult, ui: ToolUIKit, spinnerFrame?: number): string | undefined {
|
|
756
|
-
switch (cell.status) {
|
|
757
|
-
case "pending":
|
|
758
|
-
return `${ui.statusIcon("pending")} ${ui.theme.fg("muted", "pending")}`;
|
|
759
|
-
case "running":
|
|
760
|
-
return `${ui.statusIcon("running", spinnerFrame)} ${ui.theme.fg("muted", "running")}`;
|
|
761
|
-
case "complete":
|
|
762
|
-
return ui.statusIcon("success");
|
|
763
|
-
case "error":
|
|
764
|
-
return ui.statusIcon("error");
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
function formatCellHeader(
|
|
769
|
-
cell: PythonCellResult,
|
|
770
|
-
index: number,
|
|
771
|
-
total: number,
|
|
772
|
-
ui: ToolUIKit,
|
|
773
|
-
spinnerFrame?: number,
|
|
774
|
-
workdirLabel?: string,
|
|
775
|
-
): string {
|
|
776
|
-
const indexLabel = ui.theme.fg("accent", `[${index + 1}/${total}]`);
|
|
777
|
-
const title = cell.title ? ` ${cell.title}` : "";
|
|
778
|
-
const metaParts: string[] = [];
|
|
779
|
-
if (workdirLabel) {
|
|
780
|
-
metaParts.push(ui.theme.fg("dim", workdirLabel));
|
|
781
|
-
}
|
|
782
|
-
if (cell.durationMs !== undefined) {
|
|
783
|
-
metaParts.push(ui.theme.fg("dim", `(${ui.formatDuration(cell.durationMs)})`));
|
|
784
|
-
}
|
|
785
|
-
const statusLabel = formatCellStatus(cell, ui, spinnerFrame);
|
|
786
|
-
if (statusLabel) {
|
|
787
|
-
metaParts.push(statusLabel);
|
|
788
|
-
}
|
|
789
|
-
const meta = metaParts.length > 0 ? ` ${metaParts.join(ui.theme.fg("dim", ui.theme.sep.dot))}` : "";
|
|
790
|
-
return `${indexLabel}${title}${meta}`;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
744
|
function formatCellOutputLines(
|
|
794
745
|
cell: PythonCellResult,
|
|
795
746
|
expanded: boolean,
|
|
@@ -808,101 +759,6 @@ function formatCellOutputLines(
|
|
|
808
759
|
return { lines: outputLines, hiddenCount };
|
|
809
760
|
}
|
|
810
761
|
|
|
811
|
-
function renderCellBlock(
|
|
812
|
-
cell: PythonCellResult,
|
|
813
|
-
index: number,
|
|
814
|
-
total: number,
|
|
815
|
-
ui: ToolUIKit,
|
|
816
|
-
options: {
|
|
817
|
-
expanded: boolean;
|
|
818
|
-
previewLines: number;
|
|
819
|
-
spinnerFrame?: number;
|
|
820
|
-
showOutput: boolean;
|
|
821
|
-
workdirLabel?: string;
|
|
822
|
-
width: number;
|
|
823
|
-
bgFn?: (text: string) => string;
|
|
824
|
-
},
|
|
825
|
-
): string[] {
|
|
826
|
-
const { expanded, previewLines, spinnerFrame, showOutput, workdirLabel, width, bgFn } = options;
|
|
827
|
-
const h = ui.theme.boxSharp.horizontal;
|
|
828
|
-
const v = ui.theme.boxSharp.vertical;
|
|
829
|
-
const cap = h.repeat(3);
|
|
830
|
-
const border = (text: string) => ui.theme.fg("dim", text);
|
|
831
|
-
const lineWidth = Math.max(0, width);
|
|
832
|
-
|
|
833
|
-
const buildBarLine = (leftChar: string, label?: string): string => {
|
|
834
|
-
const left = border(`${leftChar}${cap}`);
|
|
835
|
-
if (lineWidth <= 0) return left;
|
|
836
|
-
const rawLabel = label ? ` ${label} ` : " ";
|
|
837
|
-
const maxLabelWidth = Math.max(0, lineWidth - visibleWidth(left));
|
|
838
|
-
const trimmedLabel = truncateToWidth(rawLabel, maxLabelWidth, ui.theme.format.ellipsis);
|
|
839
|
-
const fillCount = Math.max(0, lineWidth - visibleWidth(left + trimmedLabel));
|
|
840
|
-
return `${left}${trimmedLabel}${border(h.repeat(fillCount))}`;
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
const lines: string[] = [];
|
|
844
|
-
lines.push(
|
|
845
|
-
applyCellBackground(
|
|
846
|
-
buildBarLine(ui.theme.boxSharp.topLeft, formatCellHeader(cell, index, total, ui, spinnerFrame, workdirLabel)),
|
|
847
|
-
lineWidth,
|
|
848
|
-
bgFn,
|
|
849
|
-
),
|
|
850
|
-
);
|
|
851
|
-
|
|
852
|
-
const codePrefix = border(`${v} `);
|
|
853
|
-
const codeWidth = Math.max(0, lineWidth - visibleWidth(codePrefix));
|
|
854
|
-
const codeLines = highlightPythonCode(cell.code);
|
|
855
|
-
for (const line of codeLines) {
|
|
856
|
-
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
857
|
-
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
const statusLines = renderStatusEvents(cell.statusEvents ?? [], ui.theme, expanded);
|
|
861
|
-
const outputContent = formatCellOutputLines(cell, expanded, previewLines, ui.theme);
|
|
862
|
-
const hasOutput = outputContent.lines.length > 0;
|
|
863
|
-
const hasStatus = statusLines.length > 0;
|
|
864
|
-
const showOutputSection = showOutput && (hasOutput || hasStatus);
|
|
865
|
-
|
|
866
|
-
if (showOutputSection) {
|
|
867
|
-
lines.push(
|
|
868
|
-
applyCellBackground(
|
|
869
|
-
buildBarLine(ui.theme.boxSharp.teeRight, ui.theme.fg("toolTitle", "Output")),
|
|
870
|
-
lineWidth,
|
|
871
|
-
bgFn,
|
|
872
|
-
),
|
|
873
|
-
);
|
|
874
|
-
|
|
875
|
-
for (const line of outputContent.lines) {
|
|
876
|
-
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
877
|
-
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
878
|
-
}
|
|
879
|
-
if (!expanded && outputContent.hiddenCount > 0) {
|
|
880
|
-
const hint = ui.theme.fg(
|
|
881
|
-
"dim",
|
|
882
|
-
`${ui.theme.format.ellipsis} ${outputContent.hiddenCount} more lines (ctrl+o to expand)`,
|
|
883
|
-
);
|
|
884
|
-
lines.push(
|
|
885
|
-
applyCellBackground(
|
|
886
|
-
`${codePrefix}${truncateToWidth(hint, codeWidth, ui.theme.format.ellipsis)}`,
|
|
887
|
-
lineWidth,
|
|
888
|
-
bgFn,
|
|
889
|
-
),
|
|
890
|
-
);
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
for (const line of statusLines) {
|
|
894
|
-
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
895
|
-
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
const bottomLeft = border(`${ui.theme.boxSharp.bottomLeft}${cap}`);
|
|
900
|
-
const bottomFillCount = Math.max(0, lineWidth - visibleWidth(bottomLeft));
|
|
901
|
-
const bottomLine = `${bottomLeft}${border(h.repeat(bottomFillCount))}`;
|
|
902
|
-
lines.push(applyCellBackground(bottomLine, lineWidth, bgFn));
|
|
903
|
-
return lines;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
762
|
export const pythonToolRenderer = {
|
|
907
763
|
renderCall(args: PythonRenderArgs, uiTheme: Theme): Component {
|
|
908
764
|
const ui = new ToolUIKit(uiTheme);
|
|
@@ -937,23 +793,24 @@ export const pythonToolRenderer = {
|
|
|
937
793
|
const lines: string[] = [];
|
|
938
794
|
for (let i = 0; i < cells.length; i++) {
|
|
939
795
|
const cell = cells[i];
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
showOutput: false,
|
|
952
|
-
workdirLabel: i === 0 ? workdirLabel : undefined,
|
|
796
|
+
const cellTitle = cell.title;
|
|
797
|
+
const combinedTitle =
|
|
798
|
+
cellTitle && workdirLabel ? `${workdirLabel} · ${cellTitle}` : (cellTitle ?? workdirLabel);
|
|
799
|
+
const cellLines = renderCodeCell(
|
|
800
|
+
{
|
|
801
|
+
code: cell.code,
|
|
802
|
+
language: "python",
|
|
803
|
+
index: i,
|
|
804
|
+
total: cells.length,
|
|
805
|
+
title: combinedTitle,
|
|
806
|
+
status: "pending",
|
|
953
807
|
width,
|
|
954
|
-
|
|
955
|
-
|
|
808
|
+
codeMaxLines: PYTHON_DEFAULT_PREVIEW_LINES,
|
|
809
|
+
expanded: true,
|
|
810
|
+
},
|
|
811
|
+
uiTheme,
|
|
956
812
|
);
|
|
813
|
+
lines.push(...cellLines);
|
|
957
814
|
if (i < cells.length - 1) {
|
|
958
815
|
lines.push("");
|
|
959
816
|
}
|
|
@@ -975,7 +832,7 @@ export const pythonToolRenderer = {
|
|
|
975
832
|
|
|
976
833
|
const expanded = renderContext?.expanded ?? options.expanded;
|
|
977
834
|
const previewLines = renderContext?.previewLines ?? PYTHON_DEFAULT_PREVIEW_LINES;
|
|
978
|
-
const output = renderContext?.output ?? (result.content?.find((c) => c.type === "text")?.text ?? "").
|
|
835
|
+
const output = renderContext?.output ?? (result.content?.find((c) => c.type === "text")?.text ?? "").trimEnd();
|
|
979
836
|
|
|
980
837
|
const jsonOutputs = details?.jsonOutputs ?? [];
|
|
981
838
|
const jsonLines = jsonOutputs.flatMap((value, index) => {
|
|
@@ -1015,23 +872,42 @@ export const pythonToolRenderer = {
|
|
|
1015
872
|
const lines: string[] = [];
|
|
1016
873
|
for (let i = 0; i < cellResults.length; i++) {
|
|
1017
874
|
const cell = cellResults[i];
|
|
1018
|
-
const
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
875
|
+
const statusLines = renderStatusEvents(cell.statusEvents ?? [], uiTheme, expanded);
|
|
876
|
+
const outputContent = formatCellOutputLines(cell, expanded, previewLines, uiTheme);
|
|
877
|
+
const outputLines = [...outputContent.lines];
|
|
878
|
+
if (!expanded && outputContent.hiddenCount > 0) {
|
|
879
|
+
outputLines.push(
|
|
880
|
+
uiTheme.fg(
|
|
881
|
+
"dim",
|
|
882
|
+
`${uiTheme.format.ellipsis} ${outputContent.hiddenCount} more lines (ctrl+o to expand)`,
|
|
883
|
+
),
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
if (statusLines.length > 0) {
|
|
887
|
+
if (outputLines.length > 0) {
|
|
888
|
+
outputLines.push(uiTheme.fg("dim", "Status"));
|
|
889
|
+
}
|
|
890
|
+
outputLines.push(...statusLines);
|
|
891
|
+
}
|
|
892
|
+
const cellLines = renderCodeCell(
|
|
893
|
+
{
|
|
894
|
+
code: cell.code,
|
|
895
|
+
language: "python",
|
|
896
|
+
index: i,
|
|
897
|
+
total: cellResults.length,
|
|
898
|
+
title: cell.title,
|
|
899
|
+
status: cell.status,
|
|
1029
900
|
spinnerFrame: options.spinnerFrame,
|
|
1030
|
-
|
|
901
|
+
duration: cell.durationMs,
|
|
902
|
+
output: outputLines.length > 0 ? outputLines.join("\n") : undefined,
|
|
903
|
+
outputMaxLines: outputLines.length,
|
|
904
|
+
codeMaxLines: expanded ? Number.POSITIVE_INFINITY : PYTHON_DEFAULT_PREVIEW_LINES,
|
|
905
|
+
expanded,
|
|
1031
906
|
width,
|
|
1032
|
-
|
|
1033
|
-
|
|
907
|
+
},
|
|
908
|
+
uiTheme,
|
|
1034
909
|
);
|
|
910
|
+
lines.push(...cellLines);
|
|
1035
911
|
if (i < cellResults.length - 1) {
|
|
1036
912
|
lines.push("");
|
|
1037
913
|
}
|
|
@@ -1066,7 +942,9 @@ export const pythonToolRenderer = {
|
|
|
1066
942
|
}
|
|
1067
943
|
|
|
1068
944
|
if (!combinedOutput && statusLines.length > 0) {
|
|
1069
|
-
const lines = [...statusLines, timeoutLine, warningLine].filter(
|
|
945
|
+
const lines = [uiTheme.fg("dim", "Status"), ...statusLines, timeoutLine, warningLine].filter(
|
|
946
|
+
Boolean,
|
|
947
|
+
) as string[];
|
|
1070
948
|
return new Text(lines.join("\n"), 0, 0);
|
|
1071
949
|
}
|
|
1072
950
|
|
|
@@ -1075,7 +953,12 @@ export const pythonToolRenderer = {
|
|
|
1075
953
|
.split("\n")
|
|
1076
954
|
.map((line) => uiTheme.fg("toolOutput", line))
|
|
1077
955
|
.join("\n");
|
|
1078
|
-
const lines = [
|
|
956
|
+
const lines = [
|
|
957
|
+
styledOutput,
|
|
958
|
+
...(statusLines.length > 0 ? [uiTheme.fg("dim", "Status"), ...statusLines] : []),
|
|
959
|
+
timeoutLine,
|
|
960
|
+
warningLine,
|
|
961
|
+
].filter(Boolean) as string[];
|
|
1079
962
|
return new Text(lines.join("\n"), 0, 0);
|
|
1080
963
|
}
|
|
1081
964
|
|
|
@@ -1107,8 +990,13 @@ export const pythonToolRenderer = {
|
|
|
1107
990
|
outputLines.push(truncateToWidth(skippedLine, width, uiTheme.fg("dim", uiTheme.format.ellipsis)));
|
|
1108
991
|
}
|
|
1109
992
|
outputLines.push(...cachedLines);
|
|
1110
|
-
|
|
1111
|
-
outputLines.push(
|
|
993
|
+
if (statusLines.length > 0) {
|
|
994
|
+
outputLines.push(
|
|
995
|
+
truncateToWidth(uiTheme.fg("dim", "Status"), width, uiTheme.fg("dim", uiTheme.format.ellipsis)),
|
|
996
|
+
);
|
|
997
|
+
for (const statusLine of statusLines) {
|
|
998
|
+
outputLines.push(truncateToWidth(statusLine, width, uiTheme.fg("dim", uiTheme.format.ellipsis)));
|
|
999
|
+
}
|
|
1112
1000
|
}
|
|
1113
1001
|
if (timeoutLine) {
|
|
1114
1002
|
outputLines.push(truncateToWidth(timeoutLine, width, uiTheme.fg("dim", uiTheme.format.ellipsis)));
|