@oh-my-pi/pi-coding-agent 15.8.3 → 15.9.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 +113 -31
- package/dist/types/capability/skill.d.ts +7 -0
- package/dist/types/cli/update-cli.d.ts +15 -1
- package/dist/types/config/append-only-context-mode.d.ts +8 -0
- package/dist/types/config/model-registry.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +15 -0
- package/dist/types/config/settings-schema.d.ts +38 -24
- package/dist/types/debug/protocol-probe.d.ts +38 -0
- package/dist/types/debug/terminal-info.d.ts +34 -0
- package/dist/types/exa/mcp-client.d.ts +2 -1
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/extensibility/shared-events.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mcp/json-rpc.d.ts +6 -1
- package/dist/types/mcp/tool-bridge.d.ts +4 -0
- package/dist/types/mcp/transports/stdio.d.ts +16 -7
- package/dist/types/mnemopi/state.d.ts +2 -2
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
- package/dist/types/modes/components/assistant-message.d.ts +3 -2
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -0
- package/dist/types/modes/components/hook-selector.d.ts +11 -0
- package/dist/types/modes/components/plugin-settings.d.ts +40 -8
- package/dist/types/modes/components/session-selector.d.ts +8 -3
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/todo-reminder.d.ts +1 -1
- package/dist/types/modes/components/transcript-container.d.ts +36 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +20 -1
- package/dist/types/modes/utils/keybinding-matchers.d.ts +4 -0
- package/dist/types/plan-mode/plan-handoff.d.ts +20 -0
- package/dist/types/session/agent-session.d.ts +5 -2
- package/dist/types/session/history-storage.d.ts +3 -4
- package/dist/types/session/indexed-session-storage.d.ts +59 -0
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/redis-session-storage.d.ts +12 -85
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/session-storage.d.ts +5 -7
- package/dist/types/session/sql-session-storage.d.ts +16 -85
- package/dist/types/slash-commands/types.d.ts +17 -4
- package/dist/types/task/executor.d.ts +9 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/telemetry-export.d.ts +19 -0
- package/dist/types/tiny/compiled-runtime.d.ts +35 -0
- package/dist/types/tiny/text.d.ts +17 -0
- package/dist/types/tools/ask.d.ts +1 -0
- package/dist/types/tools/index.d.ts +4 -2
- package/dist/types/tools/path-utils.d.ts +1 -1
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/tools/{todo-write.d.ts → todo.d.ts} +18 -18
- package/dist/types/utils/session-color.d.ts +7 -2
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +2 -2
- package/dist/types/web/search/providers/base.d.ts +14 -0
- package/dist/types/web/search/providers/exa.d.ts +9 -0
- package/dist/types/web/search/providers/perplexity.d.ts +2 -2
- package/dist/types/web/search/types.d.ts +66 -1
- package/package.json +15 -9
- package/scripts/build-binary.ts +12 -0
- package/src/capability/skill.ts +7 -0
- package/src/cli/args.ts +1 -1
- package/src/cli/session-picker.ts +1 -0
- package/src/cli/update-cli.ts +54 -2
- package/src/commands/completions.ts +1 -1
- package/src/config/append-only-context-mode.ts +37 -0
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +24 -57
- package/src/debug/index.ts +67 -1
- package/src/debug/protocol-probe.ts +267 -0
- package/src/debug/terminal-info.ts +127 -0
- package/src/exa/mcp-client.ts +11 -5
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +3 -3
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/types.ts +11 -0
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/skills.ts +3 -3
- package/src/index.ts +1 -0
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/main.ts +16 -2
- package/src/mcp/json-rpc.ts +8 -0
- package/src/mcp/render.ts +3 -0
- package/src/mcp/tool-bridge.ts +10 -2
- package/src/mcp/transports/http.ts +33 -16
- package/src/mcp/transports/stdio.ts +37 -12
- package/src/mnemopi/state.ts +4 -4
- package/src/modes/acp/acp-agent.ts +168 -3
- package/src/modes/acp/acp-event-mapper.ts +7 -7
- package/src/modes/components/agent-dashboard.ts +103 -31
- package/src/modes/components/assistant-message.ts +3 -2
- package/src/modes/components/extensions/extension-dashboard.ts +56 -10
- package/src/modes/components/history-search.ts +128 -14
- package/src/modes/components/hook-selector.ts +149 -14
- package/src/modes/components/plugin-settings.ts +270 -36
- package/src/modes/components/session-selector.ts +81 -19
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +2 -1
- package/src/modes/components/status-line.ts +1 -1
- package/src/modes/components/tips.txt +6 -2
- package/src/modes/components/todo-reminder.ts +1 -1
- package/src/modes/components/tool-execution.ts +9 -4
- package/src/modes/components/transcript-container.ts +109 -0
- package/src/modes/controllers/command-controller.ts +4 -3
- package/src/modes/controllers/event-controller.ts +12 -7
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/input-controller.ts +10 -5
- package/src/modes/controllers/selector-controller.ts +30 -19
- package/src/modes/controllers/todo-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +56 -9
- package/src/modes/print-mode.ts +5 -0
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/theme.ts +48 -8
- package/src/modes/utils/keybinding-matchers.ts +10 -0
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/plan-mode/plan-handoff.ts +37 -0
- package/src/priority.json +4 -0
- package/src/prompts/goals/goal-continuation.md +1 -1
- package/src/prompts/steering/user-interjection.md +10 -0
- package/src/prompts/system/agent-creation-architect.md +1 -26
- package/src/prompts/system/eager-todo.md +3 -3
- package/src/prompts/system/orchestrate-notice.md +5 -5
- package/src/prompts/system/plan-mode-approved.md +14 -17
- package/src/prompts/system/plan-mode-reference.md +3 -6
- package/src/prompts/system/subagent-system-prompt.md +11 -0
- package/src/prompts/system/system-prompt.md +143 -145
- package/src/prompts/system/title-system.md +3 -2
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/browser.md +33 -30
- package/src/prompts/tools/render-mermaid.md +2 -2
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +3 -1
- package/src/prompts/tools/{todo-write.md → todo.md} +5 -5
- package/src/sdk.ts +6 -21
- package/src/session/agent-session.ts +44 -21
- package/src/session/history-storage.ts +11 -18
- package/src/session/indexed-session-storage.ts +430 -0
- package/src/session/messages.ts +80 -0
- package/src/session/redis-session-storage.ts +66 -377
- package/src/session/session-manager.ts +109 -23
- package/src/session/session-storage.ts +148 -68
- package/src/session/sql-session-storage.ts +131 -382
- package/src/slash-commands/helpers/todo.ts +2 -2
- package/src/slash-commands/types.ts +27 -10
- package/src/task/executor.ts +9 -1
- package/src/task/index.ts +51 -1
- package/src/telemetry-export.ts +126 -0
- package/src/tiny/compiled-runtime.ts +179 -0
- package/src/tiny/text.ts +112 -1
- package/src/tiny/worker.ts +24 -2
- package/src/tools/ask.ts +133 -87
- package/src/tools/fetch.ts +17 -4
- package/src/tools/find.ts +2 -2
- package/src/tools/index.ts +6 -4
- package/src/tools/memory-recall.ts +1 -1
- package/src/tools/memory-reflect.ts +1 -1
- package/src/tools/path-utils.ts +16 -7
- package/src/tools/renderers.ts +2 -2
- package/src/tools/search.ts +6 -3
- package/src/tools/ssh.ts +26 -10
- package/src/tools/{todo-write.ts → todo.ts} +32 -35
- package/src/tools/write.ts +14 -2
- package/src/tui/status-line.ts +15 -4
- package/src/utils/session-color.ts +39 -14
- package/src/utils/title-generator.ts +9 -2
- package/src/web/search/index.ts +4 -2
- package/src/web/search/provider.ts +19 -35
- package/src/web/search/providers/base.ts +17 -0
- package/src/web/search/providers/exa.ts +111 -7
- package/src/web/search/providers/perplexity.ts +8 -4
- package/src/web/search/types.ts +74 -32
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
6
|
Container,
|
|
7
|
+
Ellipsis,
|
|
7
8
|
extractPrintableText,
|
|
8
9
|
fuzzyFilter,
|
|
9
10
|
Markdown,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
Spacer,
|
|
16
17
|
Text,
|
|
17
18
|
type TUI,
|
|
19
|
+
truncateToWidth,
|
|
18
20
|
visibleWidth,
|
|
19
21
|
wrapTextWithAnsi,
|
|
20
22
|
} from "@oh-my-pi/pi-tui";
|
|
@@ -71,6 +73,17 @@ export interface HookSelectorOptions {
|
|
|
71
73
|
/** Indices into the original options that cannot be selected: they render
|
|
72
74
|
* dimmed, are skipped during navigation, and reject enter/timeout. */
|
|
73
75
|
disabledIndices?: readonly number[];
|
|
76
|
+
/** Render a leading radio/checkbox marker before each markable option,
|
|
77
|
+
* matching the ask transcript. "radio" fills the marker on the cursor row
|
|
78
|
+
* (single-choice); "checkbox" reflects {@link checkedIndices} per row
|
|
79
|
+
* (multi-select). Options at or beyond {@link markableCount} keep the plain
|
|
80
|
+
* cursor prefix — used for trailing control rows like "Other"/"Done". */
|
|
81
|
+
selectionMarker?: "radio" | "checkbox";
|
|
82
|
+
/** For `selectionMarker: "checkbox"`: original-indices currently checked. */
|
|
83
|
+
checkedIndices?: readonly number[];
|
|
84
|
+
/** Number of leading options (original order) that receive a selection
|
|
85
|
+
* marker. Defaults to every option when {@link selectionMarker} is set. */
|
|
86
|
+
markableCount?: number;
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
export interface HookSelectorOption {
|
|
@@ -140,6 +153,9 @@ export class HookSelectorComponent extends Container {
|
|
|
140
153
|
#searchQuery = "";
|
|
141
154
|
#selectedIndex: number;
|
|
142
155
|
#disabledIndices: Set<number>;
|
|
156
|
+
#selectionMarker: "radio" | "checkbox" | undefined;
|
|
157
|
+
#checkedIndices: Set<number>;
|
|
158
|
+
#markableCount: number;
|
|
143
159
|
#maxVisible: number;
|
|
144
160
|
#listContainer: Container | undefined;
|
|
145
161
|
#outlinedList: OutlinedList | undefined;
|
|
@@ -171,6 +187,13 @@ export class HookSelectorComponent extends Container {
|
|
|
171
187
|
index => Number.isInteger(index) && index >= 0 && index < this.#options.length,
|
|
172
188
|
),
|
|
173
189
|
);
|
|
190
|
+
this.#selectionMarker = opts?.selectionMarker;
|
|
191
|
+
this.#checkedIndices = new Set(
|
|
192
|
+
(opts?.checkedIndices ?? []).filter(
|
|
193
|
+
index => Number.isInteger(index) && index >= 0 && index < this.#options.length,
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
this.#markableCount = Math.max(0, Math.min(opts?.markableCount ?? this.#options.length, this.#options.length));
|
|
174
197
|
this.#selectedIndex = this.#coerceSelectedIndex(opts?.initialIndex ?? 0);
|
|
175
198
|
this.#maxVisible = Math.max(3, opts?.maxVisible ?? 12);
|
|
176
199
|
this.#onSelectCallback = onSelect;
|
|
@@ -278,20 +301,71 @@ export class HookSelectorComponent extends Container {
|
|
|
278
301
|
isSelected: boolean,
|
|
279
302
|
isDisabled: boolean,
|
|
280
303
|
mdTheme: MarkdownTheme,
|
|
304
|
+
descRows: number | "full",
|
|
305
|
+
renderWidth?: number,
|
|
306
|
+
index?: number,
|
|
281
307
|
): string[] {
|
|
282
308
|
const textColor = isDisabled ? "dim" : isSelected ? "accent" : "text";
|
|
283
309
|
const prefixColor = isDisabled ? "dim" : "accent";
|
|
284
310
|
const label = renderInlineMarkdown(option.label, mdTheme, t => theme.fg(textColor, t));
|
|
285
|
-
const
|
|
311
|
+
const marker = index !== undefined ? this.#renderMarkerPrefix(index, isSelected, isDisabled) : undefined;
|
|
312
|
+
const prefix = marker ?? (isSelected ? theme.fg(prefixColor, `${theme.nav.cursor} `) : " ");
|
|
286
313
|
const lines = [prefix + label];
|
|
287
|
-
if (option.description) {
|
|
288
|
-
const descriptionColor = isDisabled ? "dim" : "muted";
|
|
289
|
-
|
|
290
|
-
|
|
314
|
+
if (option.description && descRows !== 0) {
|
|
315
|
+
const descriptionColor: ThemeColor = isDisabled ? "dim" : "muted";
|
|
316
|
+
if (descRows === "full") {
|
|
317
|
+
const description = renderInlineMarkdown(option.description, mdTheme, t => theme.fg(descriptionColor, t));
|
|
318
|
+
lines.push(` ${description}`);
|
|
319
|
+
} else {
|
|
320
|
+
lines.push(
|
|
321
|
+
...this.#wrapDescriptionRows(option.description, descRows, descriptionColor, mdTheme, renderWidth),
|
|
322
|
+
);
|
|
323
|
+
}
|
|
291
324
|
}
|
|
292
325
|
return lines;
|
|
293
326
|
}
|
|
294
327
|
|
|
328
|
+
/** Styled leading marker (`"<glyph> "`) for a markable option row, or
|
|
329
|
+
* `undefined` when no marker applies (control rows beyond `markableCount`,
|
|
330
|
+
* or when {@link selectionMarker} is unset) so the caller falls back to the
|
|
331
|
+
* classic cursor prefix. Radio fills on the cursor row; checkbox reflects
|
|
332
|
+
* the per-row checked state, with the cursor row drawn in accent. */
|
|
333
|
+
#renderMarkerPrefix(index: number, isSelected: boolean, isDisabled: boolean): string | undefined {
|
|
334
|
+
if (this.#selectionMarker === undefined || index >= this.#markableCount) return undefined;
|
|
335
|
+
if (this.#selectionMarker === "radio") {
|
|
336
|
+
const glyph = isSelected ? theme.radio.selected : theme.radio.unselected;
|
|
337
|
+
const color = isDisabled ? "dim" : isSelected ? "accent" : "dim";
|
|
338
|
+
return theme.fg(color, `${glyph} `);
|
|
339
|
+
}
|
|
340
|
+
const checked = this.#checkedIndices.has(index);
|
|
341
|
+
const glyph = checked ? theme.checkbox.checked : theme.checkbox.unchecked;
|
|
342
|
+
const color = isDisabled ? "dim" : isSelected ? "accent" : checked ? "success" : "dim";
|
|
343
|
+
return theme.fg(color, `${glyph} `);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Wrap an option description into indented rows, truncating to `maxRows`
|
|
347
|
+
* with an ellipsis. Pre-wrapping (rather than emitting one long line that the
|
|
348
|
+
* list re-wraps) lets compact mode bound how much of the highlighted option's
|
|
349
|
+
* detail is shown, so every option label stays on screen on short terminals. */
|
|
350
|
+
#wrapDescriptionRows(
|
|
351
|
+
description: string,
|
|
352
|
+
maxRows: number,
|
|
353
|
+
color: ThemeColor,
|
|
354
|
+
mdTheme: MarkdownTheme,
|
|
355
|
+
renderWidth = this.#lastRenderWidth,
|
|
356
|
+
): string[] {
|
|
357
|
+
if (maxRows <= 0) return [];
|
|
358
|
+
const indent = " ";
|
|
359
|
+
const innerWidth = Math.max(1, (renderWidth ?? 80) - 2);
|
|
360
|
+
const bodyWidth = Math.max(1, innerWidth - indent.length);
|
|
361
|
+
const colored = renderInlineMarkdown(description, mdTheme, t => theme.fg(color, t));
|
|
362
|
+
const wrapped = wrapTextWithAnsi(colored, bodyWidth);
|
|
363
|
+
if (wrapped.length <= maxRows) return wrapped.map(row => indent + row);
|
|
364
|
+
const kept = wrapped.slice(0, maxRows);
|
|
365
|
+
kept[maxRows - 1] = truncateToWidth(wrapped.slice(maxRows - 1).join(" "), bodyWidth, Ellipsis.Unicode);
|
|
366
|
+
return kept.map(row => indent + row);
|
|
367
|
+
}
|
|
368
|
+
|
|
295
369
|
#renderedLineRowCount(line: string, renderWidth: number): number {
|
|
296
370
|
const normalized = replaceTabs(line);
|
|
297
371
|
if (this.#outlinedList) {
|
|
@@ -309,10 +383,11 @@ export class HookSelectorComponent extends Container {
|
|
|
309
383
|
renderWidth: number | undefined,
|
|
310
384
|
isSelected: boolean,
|
|
311
385
|
mdTheme: MarkdownTheme,
|
|
386
|
+
descRows: number | "full",
|
|
312
387
|
): number {
|
|
313
|
-
if (renderWidth === undefined) return option.description ? 2 : 1;
|
|
388
|
+
if (renderWidth === undefined) return option.description && descRows !== 0 ? 2 : 1;
|
|
314
389
|
let rows = 0;
|
|
315
|
-
for (const line of this.#renderOptionLines(option, isSelected, false, mdTheme)) {
|
|
390
|
+
for (const line of this.#renderOptionLines(option, isSelected, false, mdTheme, descRows, renderWidth)) {
|
|
316
391
|
rows += this.#renderedLineRowCount(line, renderWidth);
|
|
317
392
|
}
|
|
318
393
|
return rows;
|
|
@@ -322,7 +397,7 @@ export class HookSelectorComponent extends Container {
|
|
|
322
397
|
const themeForRows = mdTheme ?? getMarkdownTheme();
|
|
323
398
|
let rows = 0;
|
|
324
399
|
for (const option of options) {
|
|
325
|
-
rows += this.#optionRowCount(option, renderWidth, false, themeForRows);
|
|
400
|
+
rows += this.#optionRowCount(option, renderWidth, false, themeForRows, "full");
|
|
326
401
|
}
|
|
327
402
|
return rows;
|
|
328
403
|
}
|
|
@@ -331,19 +406,37 @@ export class HookSelectorComponent extends Container {
|
|
|
331
406
|
total: number,
|
|
332
407
|
renderWidth?: number,
|
|
333
408
|
mdTheme: MarkdownTheme = getMarkdownTheme(),
|
|
409
|
+
compact = false,
|
|
334
410
|
): { startIndex: number; endIndex: number } {
|
|
335
411
|
if (total === 0) return { startIndex: 0, endIndex: 0 };
|
|
336
412
|
|
|
413
|
+
// In compact mode every option contributes only its label rows; the
|
|
414
|
+
// highlighted option's description is layered on afterwards (see
|
|
415
|
+
// #updateList), so the window is sized to keep as many labels visible as
|
|
416
|
+
// possible rather than letting one long description swallow the budget.
|
|
417
|
+
const descMode: number | "full" = compact ? 0 : "full";
|
|
337
418
|
const rowBudget = Math.max(1, this.#maxVisible);
|
|
338
419
|
const selectedIndex = Math.max(0, Math.min(this.#selectedIndex, total - 1));
|
|
339
420
|
let startIndex = selectedIndex;
|
|
340
421
|
let endIndex = selectedIndex + 1;
|
|
341
|
-
let rows = this.#optionRowCount(
|
|
422
|
+
let rows = this.#optionRowCount(
|
|
423
|
+
this.#filteredOptions[selectedIndex]!.option,
|
|
424
|
+
renderWidth,
|
|
425
|
+
true,
|
|
426
|
+
mdTheme,
|
|
427
|
+
descMode,
|
|
428
|
+
);
|
|
342
429
|
let beforeRows = 0;
|
|
343
430
|
const targetBeforeRows = Math.max(0, Math.floor((rowBudget - rows) / 2));
|
|
344
431
|
|
|
345
432
|
while (startIndex > 0) {
|
|
346
|
-
const cost = this.#optionRowCount(
|
|
433
|
+
const cost = this.#optionRowCount(
|
|
434
|
+
this.#filteredOptions[startIndex - 1]!.option,
|
|
435
|
+
renderWidth,
|
|
436
|
+
false,
|
|
437
|
+
mdTheme,
|
|
438
|
+
descMode,
|
|
439
|
+
);
|
|
347
440
|
if (beforeRows + cost > targetBeforeRows || rows + cost > rowBudget) break;
|
|
348
441
|
startIndex--;
|
|
349
442
|
beforeRows += cost;
|
|
@@ -351,14 +444,26 @@ export class HookSelectorComponent extends Container {
|
|
|
351
444
|
}
|
|
352
445
|
|
|
353
446
|
while (endIndex < total) {
|
|
354
|
-
const cost = this.#optionRowCount(
|
|
447
|
+
const cost = this.#optionRowCount(
|
|
448
|
+
this.#filteredOptions[endIndex]!.option,
|
|
449
|
+
renderWidth,
|
|
450
|
+
false,
|
|
451
|
+
mdTheme,
|
|
452
|
+
descMode,
|
|
453
|
+
);
|
|
355
454
|
if (rows + cost > rowBudget) break;
|
|
356
455
|
endIndex++;
|
|
357
456
|
rows += cost;
|
|
358
457
|
}
|
|
359
458
|
|
|
360
459
|
while (startIndex > 0) {
|
|
361
|
-
const cost = this.#optionRowCount(
|
|
460
|
+
const cost = this.#optionRowCount(
|
|
461
|
+
this.#filteredOptions[startIndex - 1]!.option,
|
|
462
|
+
renderWidth,
|
|
463
|
+
false,
|
|
464
|
+
mdTheme,
|
|
465
|
+
descMode,
|
|
466
|
+
);
|
|
362
467
|
if (rows + cost > rowBudget) break;
|
|
363
468
|
startIndex--;
|
|
364
469
|
rows += cost;
|
|
@@ -371,13 +476,43 @@ export class HookSelectorComponent extends Container {
|
|
|
371
476
|
const lines: string[] = [];
|
|
372
477
|
const total = this.#filteredOptions.length;
|
|
373
478
|
const mdTheme = getMarkdownTheme();
|
|
374
|
-
|
|
479
|
+
// Compact mode kicks in exactly when the fully-expanded list (all
|
|
480
|
+
// descriptions) would overflow the row budget — the same condition that
|
|
481
|
+
// enables search. There we collapse every option to its label and show
|
|
482
|
+
// only the highlighted option's description, so the whole menu stays
|
|
483
|
+
// visible on short terminals instead of collapsing to a single entry.
|
|
484
|
+
const compact = this.#isSearchEnabled(renderWidth, mdTheme);
|
|
485
|
+
const { startIndex, endIndex } = this.#getVisibleOptionRange(total, renderWidth, mdTheme, compact);
|
|
486
|
+
|
|
487
|
+
let selectedDescRows = 0;
|
|
488
|
+
if (compact && renderWidth !== undefined) {
|
|
489
|
+
let labelRows = 0;
|
|
490
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
491
|
+
const filtered = this.#filteredOptions[i];
|
|
492
|
+
if (filtered === undefined) continue;
|
|
493
|
+
labelRows += this.#optionRowCount(filtered.option, renderWidth, i === this.#selectedIndex, mdTheme, 0);
|
|
494
|
+
}
|
|
495
|
+
// Reserve one row for the status line; give the remainder to the
|
|
496
|
+
// highlighted option's description.
|
|
497
|
+
selectedDescRows = Math.max(0, Math.max(1, this.#maxVisible) - labelRows - 1);
|
|
498
|
+
}
|
|
375
499
|
|
|
376
500
|
for (let i = startIndex; i < endIndex; i++) {
|
|
377
501
|
const filtered = this.#filteredOptions[i];
|
|
378
502
|
if (filtered === undefined) continue;
|
|
379
503
|
const isSelected = i === this.#selectedIndex;
|
|
380
|
-
|
|
504
|
+
const descMode: number | "full" = compact ? (isSelected ? selectedDescRows : 0) : "full";
|
|
505
|
+
lines.push(
|
|
506
|
+
...this.#renderOptionLines(
|
|
507
|
+
filtered.option,
|
|
508
|
+
isSelected,
|
|
509
|
+
this.#isDisabled(filtered.index),
|
|
510
|
+
mdTheme,
|
|
511
|
+
descMode,
|
|
512
|
+
renderWidth,
|
|
513
|
+
filtered.index,
|
|
514
|
+
),
|
|
515
|
+
);
|
|
381
516
|
}
|
|
382
517
|
|
|
383
518
|
if (total === 0) {
|