@oh-my-pi/pi-coding-agent 15.10.0 → 15.10.1
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 +75 -1
- package/dist/types/cli/dry-balance-cli.d.ts +15 -1
- package/dist/types/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +2 -2
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/config/api-key-resolver.d.ts +34 -0
- package/dist/types/config/model-registry.d.ts +17 -1
- package/dist/types/config/settings-schema.d.ts +9 -0
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/lsp/utils.d.ts +3 -2
- package/dist/types/modes/components/chat-block.d.ts +64 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -0
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/transcript-container.d.ts +11 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +15 -5
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +18 -5
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/session/messages.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/slash-commands/types.d.ts +4 -6
- package/dist/types/task/executor.d.ts +7 -0
- package/dist/types/task/index.d.ts +1 -0
- package/dist/types/task/render.d.ts +3 -2
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/find.d.ts +8 -4
- package/dist/types/tools/grouped-file-output.d.ts +95 -12
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -9
- package/dist/types/tools/render-utils.d.ts +5 -9
- package/dist/types/tools/search.d.ts +4 -0
- package/dist/types/tools/sqlite-reader.d.ts +1 -0
- package/dist/types/tools/todo.d.ts +3 -2
- package/dist/types/tools/write.d.ts +3 -0
- package/dist/types/tui/output-block.d.ts +16 -4
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -1
- package/package.json +9 -9
- package/src/auto-thinking/classifier.ts +5 -1
- package/src/cli/dry-balance-cli.ts +52 -17
- package/src/cli/gallery-cli.ts +4 -1
- package/src/cli/gallery-fixtures/misc.ts +29 -0
- package/src/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +2 -2
- package/src/commit/changelog/generate.ts +2 -2
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +33 -9
- package/src/commit/pipeline.ts +4 -4
- package/src/config/api-key-resolver.ts +58 -0
- package/src/config/model-registry.ts +25 -2
- package/src/config/settings-schema.ts +10 -0
- package/src/config/settings.ts +20 -2
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +1 -0
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +40 -54
- package/src/edit/renderer.ts +82 -78
- package/src/eval/__tests__/llm-bridge.test.ts +90 -31
- package/src/eval/llm-bridge.ts +8 -3
- package/src/goals/tools/goal-tool.ts +36 -26
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/lsp/utils.ts +3 -2
- package/src/main.ts +9 -7
- package/src/memories/index.ts +12 -5
- package/src/mnemopi/backend.ts +5 -1
- package/src/modes/acp/acp-agent.ts +33 -26
- package/src/modes/components/assistant-message.ts +2 -9
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/copy-selector.ts +1 -44
- package/src/modes/components/custom-editor.ts +23 -0
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +799 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/read-tool-group.ts +20 -4
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/tips.txt +1 -0
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +68 -88
- package/src/modes/components/transcript-container.ts +84 -24
- package/src/modes/components/user-message.ts +1 -2
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +57 -55
- package/src/modes/controllers/event-controller.ts +41 -40
- package/src/modes/controllers/extension-ui-controller.ts +10 -73
- package/src/modes/controllers/input-controller.ts +124 -119
- package/src/modes/controllers/mcp-command-controller.ts +69 -60
- package/src/modes/controllers/selector-controller.ts +23 -25
- package/src/modes/controllers/streaming-reveal.ts +212 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/interactive-mode.ts +169 -94
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +8 -4
- package/src/modes/types.ts +18 -7
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/ui-helpers.ts +44 -46
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/plan-mode-active.md +67 -58
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/sdk.ts +11 -37
- package/src/session/agent-session.ts +82 -6
- package/src/session/messages.ts +26 -0
- package/src/session/session-manager.ts +13 -5
- package/src/slash-commands/builtin-registry.ts +36 -9
- package/src/slash-commands/types.ts +4 -6
- package/src/task/executor.ts +5 -2
- package/src/task/index.ts +4 -0
- package/src/task/render.ts +212 -147
- package/src/tools/archive-reader.ts +64 -0
- package/src/tools/ask.ts +119 -164
- package/src/tools/ast-edit.ts +98 -71
- package/src/tools/ast-grep.ts +37 -43
- package/src/tools/bash.ts +50 -6
- package/src/tools/debug.ts +20 -8
- package/src/tools/fetch.ts +297 -7
- package/src/tools/find.ts +44 -30
- package/src/tools/gh-renderer.ts +81 -42
- package/src/tools/grouped-file-output.ts +272 -48
- package/src/tools/image-gen.ts +150 -103
- package/src/tools/inspect-image-renderer.ts +63 -41
- package/src/tools/inspect-image.ts +8 -1
- package/src/tools/job.ts +3 -4
- package/src/tools/memory-render.ts +4 -1
- package/src/tools/plan-mode-guard.ts +21 -39
- package/src/tools/read.ts +23 -16
- package/src/tools/render-utils.ts +21 -37
- package/src/tools/resolve.ts +14 -0
- package/src/tools/search-tool-bm25.ts +36 -23
- package/src/tools/search.ts +80 -78
- package/src/tools/sqlite-reader.ts +9 -12
- package/src/tools/todo.ts +118 -52
- package/src/tools/write.ts +81 -62
- package/src/tui/output-block.ts +60 -13
- package/src/tui/status-line.ts +5 -1
- package/src/utils/commit-message-generator.ts +9 -1
- package/src/utils/enhanced-paste.ts +202 -0
- package/src/utils/title-generator.ts +2 -1
- package/src/web/search/providers/anthropic.ts +25 -19
- package/src/web/search/providers/exa.ts +11 -3
- package/src/web/search/providers/kimi.ts +28 -17
- package/src/web/search/providers/parallel.ts +35 -24
- package/src/web/search/providers/synthetic.ts +8 -6
- package/src/web/search/providers/tavily.ts +9 -8
- package/src/web/search/providers/zai.ts +8 -6
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
1
4
|
import { inflateSync, strFromU8 } from "fflate";
|
|
2
5
|
|
|
6
|
+
import { formatBytes } from "./render-utils";
|
|
3
7
|
import { ToolError } from "./tool-errors";
|
|
4
8
|
|
|
5
9
|
export type ArchiveFormat = "zip" | "tar" | "tar.gz";
|
|
@@ -123,11 +127,21 @@ function getArchiveFormatFromPath(filePath: string): ArchiveFormat | undefined {
|
|
|
123
127
|
return undefined;
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
export function formatArchiveEntryLines(entries: readonly ArchiveDirectoryEntry[]): string[] {
|
|
131
|
+
return entries.map(entry => {
|
|
132
|
+
if (entry.isDirectory) return `${entry.name}/`;
|
|
133
|
+
|
|
134
|
+
const sizeSuffix = entry.size > 0 ? ` (${formatBytes(entry.size)})` : "";
|
|
135
|
+
return `${entry.name}${sizeSuffix}`;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
126
139
|
const ZIP_LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
|
127
140
|
const ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014b50;
|
|
128
141
|
const ZIP64_EOCD_SIGNATURE = 0x06064b50;
|
|
129
142
|
const ZIP64_EOCD_LOCATOR_SIGNATURE = 0x07064b50;
|
|
130
143
|
const ZIP_EOCD_SIGNATURE = 0x06054b50;
|
|
144
|
+
const ZIP_DATA_DESCRIPTOR_SIGNATURE = 0x08074b50;
|
|
131
145
|
const ZIP_EOCD_MIN_LENGTH = 22;
|
|
132
146
|
const ZIP_EOCD_MAX_COMMENT_LENGTH = 0xffff;
|
|
133
147
|
const ZIP64_EOCD_LOCATOR_LENGTH = 20;
|
|
@@ -167,6 +181,37 @@ function readUInt32LE(bytes: Uint8Array, offset: number): number {
|
|
|
167
181
|
return (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;
|
|
168
182
|
}
|
|
169
183
|
|
|
184
|
+
function bytesMatchAscii(bytes: Uint8Array, offset: number, value: string): boolean {
|
|
185
|
+
if (bytes.byteLength < offset + value.length) return false;
|
|
186
|
+
for (let index = 0; index < value.length; index++) {
|
|
187
|
+
if (bytes[offset + index] !== value.charCodeAt(index)) return false;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function sniffArchiveFormat(bytes: Uint8Array): ArchiveFormat | undefined {
|
|
193
|
+
if (bytes.byteLength >= 4) {
|
|
194
|
+
const signature = readUInt32LE(bytes, 0);
|
|
195
|
+
if (
|
|
196
|
+
signature === ZIP_LOCAL_FILE_HEADER_SIGNATURE ||
|
|
197
|
+
signature === ZIP_EOCD_SIGNATURE ||
|
|
198
|
+
signature === ZIP_DATA_DESCRIPTOR_SIGNATURE
|
|
199
|
+
) {
|
|
200
|
+
return "zip";
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (bytes.byteLength >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {
|
|
205
|
+
return "tar.gz";
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (bytesMatchAscii(bytes, 257, "ustar")) {
|
|
209
|
+
return "tar";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
170
215
|
function readUInt64LEAsNumber(bytes: Uint8Array, offset: number): number {
|
|
171
216
|
const value = readUInt32LE(bytes, offset) + readUInt32LE(bytes, offset + 4) * ZIP_UINT32_RANGE;
|
|
172
217
|
if (!Number.isSafeInteger(value)) {
|
|
@@ -627,3 +672,22 @@ export async function openArchive(filePath: string): Promise<ArchiveReader> {
|
|
|
627
672
|
format === "zip" ? await readZipEntries(filePath) : await readTarEntries(await Bun.file(filePath).bytes());
|
|
628
673
|
return new ArchiveReader(format, entries);
|
|
629
674
|
}
|
|
675
|
+
|
|
676
|
+
export async function listArchiveRoot(
|
|
677
|
+
bytes: Uint8Array,
|
|
678
|
+
format: ArchiveFormat,
|
|
679
|
+
opts: { limit?: number } = {},
|
|
680
|
+
): Promise<string> {
|
|
681
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "omp-archive-"));
|
|
682
|
+
const tempPath = path.join(tempDir, `payload.${format}`);
|
|
683
|
+
try {
|
|
684
|
+
await Bun.write(tempPath, bytes);
|
|
685
|
+
const archive = await openArchive(tempPath);
|
|
686
|
+
const entries = archive.listDirectory("");
|
|
687
|
+
const limitedEntries = opts.limit !== undefined && opts.limit > 0 ? entries.slice(0, opts.limit) : entries;
|
|
688
|
+
const lines = formatArchiveEntryLines(limitedEntries);
|
|
689
|
+
return lines.length > 0 ? lines.join("\n") : "(empty archive directory)";
|
|
690
|
+
} finally {
|
|
691
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
692
|
+
}
|
|
693
|
+
}
|
package/src/tools/ask.ts
CHANGED
|
@@ -16,22 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
19
|
-
import {
|
|
20
|
-
type Component,
|
|
21
|
-
Container,
|
|
22
|
-
Markdown,
|
|
23
|
-
type MarkdownTheme,
|
|
24
|
-
renderInlineMarkdown,
|
|
25
|
-
TERMINAL,
|
|
26
|
-
Text,
|
|
27
|
-
} from "@oh-my-pi/pi-tui";
|
|
19
|
+
import { type Component, Markdown, type MarkdownTheme, renderInlineMarkdown, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
28
20
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
29
21
|
import * as z from "zod/v4";
|
|
30
22
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
31
23
|
import type { ExtensionUISelectItem } from "../extensibility/extensions";
|
|
32
24
|
import { getMarkdownTheme, type Theme, theme } from "../modes/theme/theme";
|
|
33
25
|
import askDescription from "../prompts/tools/ask.md" with { type: "text" };
|
|
34
|
-
import { renderStatusLine } from "../tui";
|
|
26
|
+
import { framedBlock, renderStatusLine } from "../tui";
|
|
35
27
|
import type { ToolSession } from ".";
|
|
36
28
|
import { formatErrorMessage, formatMeta, formatTitle } from "./render-utils";
|
|
37
29
|
import { ToolAbortError } from "./tool-errors";
|
|
@@ -626,23 +618,14 @@ interface AskRenderArgs {
|
|
|
626
618
|
}>;
|
|
627
619
|
}
|
|
628
620
|
|
|
629
|
-
/** Render custom
|
|
630
|
-
function
|
|
631
|
-
uiTheme: Theme,
|
|
632
|
-
prefix: string,
|
|
633
|
-
customInput: string,
|
|
634
|
-
isLastEntry: boolean,
|
|
635
|
-
includeLeadingNewline = true,
|
|
636
|
-
): string {
|
|
621
|
+
/** Render a custom free-text answer as a status line plus indented continuation rows. */
|
|
622
|
+
function renderCustomInputLines(uiTheme: Theme, customInput: string): string[] {
|
|
637
623
|
const lines = customInput.split("\n");
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
text += `\n${prefix}${continuationIndent} ${uiTheme.fg("toolOutput", lines[i])}`;
|
|
644
|
-
}
|
|
645
|
-
return text;
|
|
624
|
+
const out: string[] = [
|
|
625
|
+
` ${uiTheme.styledSymbol("status.success", "success")} ${uiTheme.fg("toolOutput", lines[0] ?? "")}`,
|
|
626
|
+
];
|
|
627
|
+
for (let i = 1; i < lines.length; i++) out.push(` ${uiTheme.fg("toolOutput", lines[i])}`);
|
|
628
|
+
return out;
|
|
646
629
|
}
|
|
647
630
|
|
|
648
631
|
/**
|
|
@@ -654,25 +637,38 @@ function optionMarker(uiTheme: Theme, multi: boolean | undefined, selected: bool
|
|
|
654
637
|
return selected ? uiTheme.radio.selected : uiTheme.radio.unselected;
|
|
655
638
|
}
|
|
656
639
|
|
|
640
|
+
/** Render the offered options for a question form as flat marker bullets (no tree guides). */
|
|
641
|
+
function renderQuestionOptionLines(
|
|
642
|
+
uiTheme: Theme,
|
|
643
|
+
mdTheme: MarkdownTheme,
|
|
644
|
+
options: AskRenderOption[],
|
|
645
|
+
multi: boolean | undefined,
|
|
646
|
+
): string[] {
|
|
647
|
+
const out: string[] = [];
|
|
648
|
+
for (const opt of options) {
|
|
649
|
+
const optLabel = renderInlineMarkdown(opt.label, mdTheme, t => uiTheme.fg("muted", t));
|
|
650
|
+
out.push(` ${uiTheme.fg("dim", optionMarker(uiTheme, multi, false))} ${optLabel}`);
|
|
651
|
+
if (opt.description?.trim()) {
|
|
652
|
+
const description = renderInlineMarkdown(opt.description.trim(), mdTheme, t => uiTheme.fg("dim", t));
|
|
653
|
+
out.push(` ${uiTheme.fg("dim", "↳")} ${description}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return out;
|
|
657
|
+
}
|
|
658
|
+
|
|
657
659
|
/**
|
|
658
660
|
* Render the answered option list for a question: every offered option with its
|
|
659
|
-
* selection marker filled in, plus any custom free-text answer.
|
|
660
|
-
*
|
|
661
|
-
* reads in place rather than as a detached summary block.
|
|
662
|
-
*
|
|
663
|
-
* `linePrefix` is the indent that precedes each entry's tree branch — a single
|
|
664
|
-
* leading space for top-level (single-question) entries, or the question's
|
|
665
|
-
* vertical continuation for nested (multi-question) entries.
|
|
661
|
+
* selection marker filled in, plus any custom free-text answer. Flat marker
|
|
662
|
+
* bullets — the frame is the container, so no tree guides are drawn.
|
|
666
663
|
*/
|
|
667
|
-
function
|
|
664
|
+
function renderAnswerOptionLines(
|
|
668
665
|
uiTheme: Theme,
|
|
669
666
|
mdTheme: MarkdownTheme,
|
|
670
|
-
linePrefix: string,
|
|
671
667
|
options: string[] | undefined,
|
|
672
668
|
selectedOptions: string[] | undefined,
|
|
673
669
|
multi: boolean | undefined,
|
|
674
670
|
customInput: string | undefined,
|
|
675
|
-
): string {
|
|
671
|
+
): string[] {
|
|
676
672
|
const selected = new Set(selectedOptions ?? []);
|
|
677
673
|
// Prefer the full recorded option set; fall back to the selected labels when
|
|
678
674
|
// details omit the options array.
|
|
@@ -680,26 +676,21 @@ function renderAnswerOptions(
|
|
|
680
676
|
|
|
681
677
|
// Nothing was chosen (and no custom answer) → a lone cancelled marker.
|
|
682
678
|
if (selected.size === 0 && customInput === undefined) {
|
|
683
|
-
return
|
|
679
|
+
return [` ${uiTheme.styledSymbol("status.warning", "warning")} ${uiTheme.fg("warning", "Cancelled")}`];
|
|
684
680
|
}
|
|
685
681
|
|
|
686
|
-
|
|
687
|
-
for (
|
|
688
|
-
const label = list[i];
|
|
682
|
+
const out: string[] = [];
|
|
683
|
+
for (const label of list) {
|
|
689
684
|
const isSelected = selected.has(label);
|
|
690
|
-
const isLastEntry = i === list.length - 1 && customInput === undefined;
|
|
691
|
-
const branch = isLastEntry ? uiTheme.tree.last : uiTheme.tree.branch;
|
|
692
685
|
const marker = optionMarker(uiTheme, multi, isSelected);
|
|
693
686
|
const markerStyled = isSelected ? uiTheme.fg("success", marker) : uiTheme.fg("dim", marker);
|
|
694
687
|
const labelStyled = renderInlineMarkdown(label, mdTheme, t =>
|
|
695
688
|
isSelected ? uiTheme.fg("toolOutput", t) : uiTheme.fg("muted", t),
|
|
696
689
|
);
|
|
697
|
-
|
|
690
|
+
out.push(` ${markerStyled} ${labelStyled}`);
|
|
698
691
|
}
|
|
699
|
-
if (customInput !== undefined)
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
return text;
|
|
692
|
+
if (customInput !== undefined) out.push(...renderCustomInputLines(uiTheme, customInput));
|
|
693
|
+
return out;
|
|
703
694
|
}
|
|
704
695
|
|
|
705
696
|
export const askToolRenderer = {
|
|
@@ -708,80 +699,58 @@ export const askToolRenderer = {
|
|
|
708
699
|
const label = formatTitle("Ask", uiTheme);
|
|
709
700
|
const mdTheme = getMarkdownTheme();
|
|
710
701
|
const accentStyle = { color: (t: string) => uiTheme.fg("accent", t) };
|
|
702
|
+
const md = (text: string, width: number) =>
|
|
703
|
+
new Markdown(text, 1, 0, mdTheme, accentStyle).render(Math.max(1, width - 3 + 1));
|
|
711
704
|
|
|
712
|
-
// Multi-part questions
|
|
705
|
+
// Multi-part questions: one divider-labelled section per question.
|
|
713
706
|
if (args.questions && args.questions.length > 0) {
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
container.addChild(
|
|
729
|
-
new Text(` ${uiTheme.fg("dim", qBranch)} ${uiTheme.fg("dim", `[${q.id}]`)}${metaStr}`, 0, 0),
|
|
730
|
-
);
|
|
731
|
-
container.addChild(new Markdown(q.question, 3, 0, mdTheme, accentStyle));
|
|
732
|
-
|
|
733
|
-
if (q.options?.length) {
|
|
734
|
-
let optText = "";
|
|
735
|
-
for (let j = 0; j < q.options.length; j++) {
|
|
736
|
-
const opt = q.options[j];
|
|
737
|
-
const isLastOpt = j === q.options.length - 1;
|
|
738
|
-
const optBranch = isLastOpt ? uiTheme.tree.last : uiTheme.tree.branch;
|
|
739
|
-
const optLabel = renderInlineMarkdown(opt.label, mdTheme, t => uiTheme.fg("muted", t));
|
|
740
|
-
optText += `\n ${uiTheme.fg("dim", continuation)} ${uiTheme.fg("dim", optBranch)} ${uiTheme.fg("dim", optionMarker(uiTheme, q.multi, false))} ${optLabel}`;
|
|
741
|
-
if (opt.description?.trim()) {
|
|
742
|
-
const optContinuation = isLastOpt ? " " : uiTheme.tree.vertical;
|
|
743
|
-
const description = renderInlineMarkdown(opt.description.trim(), mdTheme, t =>
|
|
744
|
-
uiTheme.fg("dim", t),
|
|
745
|
-
);
|
|
746
|
-
optText += `\n ${uiTheme.fg("dim", continuation)} ${uiTheme.fg("dim", optContinuation)} ${uiTheme.fg("dim", "↳")} ${description}`;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
container.addChild(new Text(optText, 0, 0));
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
return container;
|
|
707
|
+
const questions = args.questions;
|
|
708
|
+
const header = `${label} ${uiTheme.fg("muted", `${questions.length} questions`)}`;
|
|
709
|
+
return framedBlock(uiTheme, width => {
|
|
710
|
+
const sections = questions.map(q => {
|
|
711
|
+
const meta: string[] = [];
|
|
712
|
+
if (q.multi) meta.push("multi");
|
|
713
|
+
if (q.options?.length) meta.push(`options:${q.options.length}`);
|
|
714
|
+
const metaStr = meta.length > 0 ? uiTheme.fg("dim", ` · ${meta.join(" · ")}`) : "";
|
|
715
|
+
const lines = md(q.question, width);
|
|
716
|
+
if (q.options?.length) lines.push(...renderQuestionOptionLines(uiTheme, mdTheme, q.options, q.multi));
|
|
717
|
+
return { label: `${uiTheme.fg("dim", `[${q.id}]`)}${metaStr}`, lines };
|
|
718
|
+
});
|
|
719
|
+
return { header, sections, state: "pending", borderColor: "borderMuted", width };
|
|
720
|
+
});
|
|
753
721
|
}
|
|
754
722
|
|
|
755
723
|
// Single question
|
|
756
724
|
if (!args.question) {
|
|
757
|
-
|
|
725
|
+
const errorLine = formatErrorMessage("No question provided", uiTheme);
|
|
726
|
+
return framedBlock(uiTheme, width => ({
|
|
727
|
+
header: errorLine,
|
|
728
|
+
sections: [],
|
|
729
|
+
state: "error",
|
|
730
|
+
borderColor: "error",
|
|
731
|
+
width,
|
|
732
|
+
}));
|
|
758
733
|
}
|
|
759
734
|
|
|
760
|
-
const
|
|
735
|
+
const question = args.question;
|
|
761
736
|
const meta: string[] = [];
|
|
762
737
|
if (args.multi) meta.push("multi");
|
|
763
738
|
if (args.options?.length) meta.push(`options:${args.options.length}`);
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
container.addChild(new Text(optText, 0, 0));
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
return container;
|
|
739
|
+
const header = `${label}${formatMeta(meta, uiTheme)}`;
|
|
740
|
+
const questionOptions = args.options;
|
|
741
|
+
const multi = args.multi;
|
|
742
|
+
return framedBlock(uiTheme, width => {
|
|
743
|
+
const bodyLines = md(question, width);
|
|
744
|
+
if (questionOptions?.length)
|
|
745
|
+
bodyLines.push(...renderQuestionOptionLines(uiTheme, mdTheme, questionOptions, multi));
|
|
746
|
+
return {
|
|
747
|
+
header,
|
|
748
|
+
sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
|
|
749
|
+
state: "pending",
|
|
750
|
+
borderColor: "borderMuted",
|
|
751
|
+
width,
|
|
752
|
+
};
|
|
753
|
+
});
|
|
785
754
|
},
|
|
786
755
|
|
|
787
756
|
renderResult(
|
|
@@ -792,56 +761,47 @@ export const askToolRenderer = {
|
|
|
792
761
|
const { details } = result;
|
|
793
762
|
const mdTheme = getMarkdownTheme();
|
|
794
763
|
const accentStyle = { color: (t: string) => uiTheme.fg("accent", t) };
|
|
764
|
+
const md = (text: string, width: number) =>
|
|
765
|
+
new Markdown(text, 1, 0, mdTheme, accentStyle).render(Math.max(1, width - 3 + 1));
|
|
795
766
|
|
|
796
767
|
if (!details) {
|
|
797
768
|
const txt = result.content[0];
|
|
798
769
|
const fallback = txt?.type === "text" && txt.text ? txt.text : "";
|
|
799
770
|
const header = renderStatusLine({ icon: "warning", title: "Ask" }, uiTheme);
|
|
800
|
-
|
|
771
|
+
const body = fallback ? `\n${uiTheme.fg("dim", fallback)}` : "";
|
|
772
|
+
return new Text(`${header}${body}`, 0, 0);
|
|
801
773
|
}
|
|
802
774
|
|
|
803
|
-
// Multi-part results
|
|
775
|
+
// Multi-part results: one divider-labelled section per question.
|
|
804
776
|
if (details.results && details.results.length > 0) {
|
|
805
|
-
const
|
|
777
|
+
const results = details.results;
|
|
778
|
+
const hasAnySelection = results.some(
|
|
806
779
|
r => r.customInput !== undefined || (r.selectedOptions && r.selectedOptions.length > 0),
|
|
807
780
|
);
|
|
808
781
|
const header = renderStatusLine(
|
|
809
782
|
{
|
|
810
783
|
icon: hasAnySelection ? "success" : "warning",
|
|
811
784
|
title: "Ask",
|
|
812
|
-
meta: [`${
|
|
785
|
+
meta: [`${results.length} questions`],
|
|
813
786
|
},
|
|
814
787
|
uiTheme,
|
|
815
788
|
);
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
mdTheme,
|
|
833
|
-
linePrefix,
|
|
834
|
-
r.options,
|
|
835
|
-
r.selectedOptions,
|
|
836
|
-
r.multi,
|
|
837
|
-
r.customInput,
|
|
838
|
-
),
|
|
839
|
-
0,
|
|
840
|
-
0,
|
|
841
|
-
),
|
|
842
|
-
);
|
|
843
|
-
}
|
|
844
|
-
return container;
|
|
789
|
+
return framedBlock(uiTheme, width => {
|
|
790
|
+
const sections = results.map(r => {
|
|
791
|
+
const lines = md(r.question, width);
|
|
792
|
+
lines.push(
|
|
793
|
+
...renderAnswerOptionLines(uiTheme, mdTheme, r.options, r.selectedOptions, r.multi, r.customInput),
|
|
794
|
+
);
|
|
795
|
+
return { label: uiTheme.fg("dim", `[${r.id}]`), lines };
|
|
796
|
+
});
|
|
797
|
+
return {
|
|
798
|
+
header,
|
|
799
|
+
sections,
|
|
800
|
+
state: hasAnySelection ? "success" : "warning",
|
|
801
|
+
borderColor: "borderMuted",
|
|
802
|
+
width,
|
|
803
|
+
};
|
|
804
|
+
});
|
|
845
805
|
}
|
|
846
806
|
|
|
847
807
|
// Single question result
|
|
@@ -851,29 +811,24 @@ export const askToolRenderer = {
|
|
|
851
811
|
return new Text(fallback, 0, 0);
|
|
852
812
|
}
|
|
853
813
|
|
|
814
|
+
const question = details.question;
|
|
854
815
|
const hasSelection =
|
|
855
816
|
details.customInput !== undefined || (details.selectedOptions && details.selectedOptions.length > 0);
|
|
856
817
|
const header = renderStatusLine({ icon: hasSelection ? "success" : "warning", title: "Ask" }, uiTheme);
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
0,
|
|
873
|
-
0,
|
|
874
|
-
),
|
|
875
|
-
);
|
|
876
|
-
|
|
877
|
-
return container;
|
|
818
|
+
const dOptions = details.options;
|
|
819
|
+
const dSelected = details.selectedOptions;
|
|
820
|
+
const dMulti = details.multi;
|
|
821
|
+
const dCustom = details.customInput;
|
|
822
|
+
return framedBlock(uiTheme, width => {
|
|
823
|
+
const bodyLines = md(question, width);
|
|
824
|
+
bodyLines.push(...renderAnswerOptionLines(uiTheme, mdTheme, dOptions, dSelected, dMulti, dCustom));
|
|
825
|
+
return {
|
|
826
|
+
header,
|
|
827
|
+
sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
|
|
828
|
+
state: hasSelection ? "success" : "warning",
|
|
829
|
+
borderColor: "borderMuted",
|
|
830
|
+
width,
|
|
831
|
+
};
|
|
832
|
+
});
|
|
878
833
|
},
|
|
879
834
|
};
|