@oh-my-pi/pi-tui 18.3.2 → 18.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/types/app-keybindings.d.ts +2 -17
- package/dist/types/autocomplete.d.ts +18 -3
- package/dist/types/chrome/keybinding-hints.d.ts +16 -10
- package/dist/types/components/editor.d.ts +11 -0
- package/dist/types/key-hint-format.d.ts +29 -0
- package/dist/types/keys.d.ts +2 -1
- package/dist/types/overlays/agent-hub.d.ts +1 -1
- package/dist/types/overlays/agent-transcript-viewer.d.ts +1 -1
- package/dist/types/overlays/model-picker.d.ts +1 -3
- package/dist/types/prompt/composer-hints.d.ts +42 -0
- package/dist/types/prompt/composer.d.ts +2 -1
- package/dist/types/prompt/custom-editor.d.ts +8 -2
- package/dist/types/prompt/macos-spelling.d.ts +7 -16
- package/dist/types/prompt/prompt-action-autocomplete.d.ts +4 -1
- package/dist/types/prompt/prose-gate.d.ts +24 -0
- package/dist/types/prompt/word-completion.d.ts +46 -0
- package/dist/types/render/render-utils.d.ts +1 -1
- package/dist/types/theme/active-symbols.d.ts +12 -0
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme-class.d.ts +0 -1
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/mcp.d.ts +3 -1
- package/dist/types/tools/task-yield-assembly.d.ts +10 -2
- package/dist/types/tools/task.d.ts +4 -0
- package/package.json +11 -10
- package/src/app-keybindings.ts +11 -104
- package/src/apps/autoresearch-dashboard.ts +10 -3
- package/src/apps/debug/log-viewer.ts +3 -2
- package/src/apps/debug/raw-sse.ts +2 -1
- package/src/apps/git/git-tui.ts +9 -5
- package/src/apps/live-visualizer.ts +2 -1
- package/src/apps/ps-top.ts +13 -4
- package/src/autocomplete.ts +42 -7
- package/src/chat/compaction-summary-message.ts +2 -1
- package/src/chat/execution-shared.ts +4 -2
- package/src/chat/tool-execution.ts +3 -1
- package/src/chat/ttsr-notification.ts +4 -3
- package/src/chat/user-message.ts +2 -2
- package/src/chrome/keybinding-hints.ts +38 -13
- package/src/components/editor.ts +180 -58
- package/src/components/settings-list.ts +10 -3
- package/src/components/tab-bar.ts +2 -1
- package/src/debug-server.ts +4 -1
- package/src/hotkeys-markdown.ts +14 -17
- package/src/key-hint-format.ts +122 -0
- package/src/keys.ts +2 -1
- package/src/overlays/advisor-config.ts +28 -6
- package/src/overlays/agent-hub.ts +8 -5
- package/src/overlays/agent-transcript-viewer.ts +6 -4
- package/src/overlays/agents-hub.ts +22 -8
- package/src/overlays/annotation-overlay.ts +31 -17
- package/src/overlays/ask-dialog.ts +14 -19
- package/src/overlays/bordered-loader.ts +2 -1
- package/src/overlays/btw-history-panel.ts +15 -12
- package/src/overlays/btw-panel.ts +12 -7
- package/src/overlays/cleanse-panel.ts +9 -6
- package/src/overlays/codex-reset-fireworks.ts +5 -3
- package/src/overlays/copy-selector.ts +13 -5
- package/src/overlays/extensions/extension-dashboard.ts +6 -1
- package/src/overlays/history-search.ts +3 -2
- package/src/overlays/hook-editor.ts +7 -2
- package/src/overlays/hook-input.ts +2 -1
- package/src/overlays/hook-selector.ts +5 -1
- package/src/overlays/login-dialog.ts +17 -4
- package/src/overlays/logout-account-selector.ts +10 -1
- package/src/overlays/mcp-add-wizard.ts +32 -20
- package/src/overlays/model-hub.ts +55 -28
- package/src/overlays/model-picker.ts +27 -12
- package/src/overlays/move-overlay.ts +5 -1
- package/src/overlays/omfg-panel.ts +8 -5
- package/src/overlays/pause-screen.ts +7 -3
- package/src/overlays/plan-review-overlay.ts +40 -14
- package/src/overlays/plan-save-overlay.ts +3 -1
- package/src/overlays/plugin-settings.ts +15 -8
- package/src/overlays/reset-usage-selector.ts +10 -3
- package/src/overlays/rewind-selector.ts +11 -5
- package/src/overlays/session-info-overlay.ts +4 -3
- package/src/overlays/session-selector.ts +12 -2
- package/src/overlays/settings-selector.ts +18 -11
- package/src/overlays/tree-selector.ts +27 -4
- package/src/overlays/usage-dashboard.ts +8 -2
- package/src/prompt/composer-cache.ts +2 -1
- package/src/prompt/composer-hints.ts +75 -0
- package/src/prompt/composer.ts +3 -2
- package/src/prompt/custom-editor.ts +22 -4
- package/src/prompt/macos-spelling.ts +17 -158
- package/src/prompt/prompt-action-autocomplete.ts +9 -2
- package/src/prompt/prose-gate.ts +87 -0
- package/src/prompt/tips.txt +6 -6
- package/src/prompt/welcome.ts +35 -2
- package/src/prompt/word-completion.ts +205 -0
- package/src/render/render-utils.ts +4 -4
- package/src/setup/scenes/composer.ts +5 -1
- package/src/setup/scenes/model.ts +3 -1
- package/src/setup/scenes/providers.ts +4 -1
- package/src/setup/scenes/sign-in.ts +4 -2
- package/src/setup/scenes/splash.ts +9 -4
- package/src/setup/scenes/theme.ts +18 -5
- package/src/setup/wizard-overlay.ts +5 -4
- package/src/theme/active-symbols.ts +20 -0
- package/src/theme/glyph-bundle.json +28 -1
- package/src/theme/symbols.ts +88 -6
- package/src/theme/theme-class.ts +0 -1
- package/src/theme/theme.ts +2 -0
- package/src/tools/bash-interactive.ts +2 -1
- package/src/tools/eval.ts +3 -3
- package/src/tools/mcp.ts +3 -1
- package/src/tools/task-yield-assembly.ts +34 -8
- package/src/tools/task.ts +14 -5
- package/dist/types/overlays/tiny-title-download-progress.d.ts +0 -21
- package/src/overlays/tiny-title-download-progress.ts +0 -102
|
@@ -5,6 +5,7 @@ import { replaceTabs } from "../render/render-utils";
|
|
|
5
5
|
import { theme } from "../theme/theme";
|
|
6
6
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
7
7
|
import { StreamingPanelContent, type StreamingPanelPresentation } from "../chrome/streaming-panel";
|
|
8
|
+
import { interruptKey } from "../chrome/keybinding-hints";
|
|
8
9
|
import type {
|
|
9
10
|
CleanseBoardModel,
|
|
10
11
|
CleanseCheckerDescriptor,
|
|
@@ -149,19 +150,21 @@ export class CleansePanelComponent extends OverlayPanel {
|
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
#footerLine(): string {
|
|
153
|
+
// The main editor routes `app.interrupt` (Escape by default) to the panel.
|
|
154
|
+
const esc = interruptKey();
|
|
152
155
|
switch (this.#outcome) {
|
|
153
156
|
case undefined:
|
|
154
|
-
return theme.fg("muted",
|
|
157
|
+
return theme.fg("muted", `${esc} cancel /cleanse`);
|
|
155
158
|
case "clean":
|
|
156
|
-
return theme.fg("success", `${theme.status.success} Clean ·
|
|
159
|
+
return theme.fg("success", `${theme.status.success} Clean · ${esc} dismiss`);
|
|
157
160
|
case "unresolved":
|
|
158
|
-
return theme.fg("warning", `${theme.status.warning} Diagnostics remain ·
|
|
161
|
+
return theme.fg("warning", `${theme.status.warning} Diagnostics remain · ${esc} dismiss`);
|
|
159
162
|
case "unsupported":
|
|
160
|
-
return theme.fg("warning", `${theme.status.warning} No runnable checker ·
|
|
163
|
+
return theme.fg("warning", `${theme.status.warning} No runnable checker · ${esc} dismiss`);
|
|
161
164
|
case "cancelled":
|
|
162
|
-
return theme.fg("warning", `${theme.status.warning} Cancelled ·
|
|
165
|
+
return theme.fg("warning", `${theme.status.warning} Cancelled · ${esc} dismiss`);
|
|
163
166
|
case "error":
|
|
164
|
-
return theme.fg("error", `${theme.status.error} Error ·
|
|
167
|
+
return theme.fg("error", `${theme.status.error} Error · ${esc} dismiss`);
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
visibleWidth,
|
|
9
9
|
} from "../index";
|
|
10
10
|
import { type ThemeColor, theme } from "../theme/theme";
|
|
11
|
+
import { formatKeyHint } from "../app-keybindings";
|
|
11
12
|
|
|
12
13
|
const FRAME_INTERVAL_MS = 85;
|
|
13
14
|
const FRAME_COUNT = 34;
|
|
@@ -176,12 +177,13 @@ function drawBanner(
|
|
|
176
177
|
const innerWidth = panelWidth - 2;
|
|
177
178
|
const titleText =
|
|
178
179
|
event.kind === "unscheduled-weekly-reset" ? " O P E N A I R E S E T " : " S A V E D R E S E T ";
|
|
180
|
+
const esc = formatKeyHint("escape");
|
|
179
181
|
const subtitleText =
|
|
180
182
|
event.kind === "unscheduled-weekly-reset"
|
|
181
|
-
?
|
|
183
|
+
? `Weekly usage cleared early · ${esc} to return`
|
|
182
184
|
: event.added === 1
|
|
183
|
-
? `New reset banked · ${event.available} available ·
|
|
184
|
-
: `${event.added} resets banked · ${event.available} available ·
|
|
185
|
+
? `New reset banked · ${event.available} available · ${esc} to return`
|
|
186
|
+
: `${event.added} resets banked · ${event.available} available · ${esc} to return`;
|
|
185
187
|
const title = truncateToWidth(titleText, innerWidth, "");
|
|
186
188
|
const subtitle = truncateToWidth(subtitleText, innerWidth, "");
|
|
187
189
|
const titleOffset = Math.floor((innerWidth - visibleWidth(title)) / 2);
|
|
@@ -24,7 +24,9 @@ import {
|
|
|
24
24
|
userTurnDraft,
|
|
25
25
|
} from "../chat/transcript-entry";
|
|
26
26
|
import type { SessionMessageEntryLike as SessionMessageEntry } from "../chat/transcript-entry";
|
|
27
|
-
import { replaceTabs } from "../render/render-utils";
|
|
27
|
+
import { expandKeyHint, replaceTabs } from "../render/render-utils";
|
|
28
|
+
import { formatKeyHint } from "../app-keybindings";
|
|
29
|
+
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
28
30
|
import { highlightCode, type ThemeColor, theme } from "../theme/theme";
|
|
29
31
|
import { commandFromToolCall, extractBlocks, extractLinks } from "./copy-targets";
|
|
30
32
|
import { matchesAppToolsExpand, matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../keybinding-matchers";
|
|
@@ -374,17 +376,23 @@ export class CopySelectorComponent implements Component {
|
|
|
374
376
|
prepared,
|
|
375
377
|
style: {
|
|
376
378
|
color: OUTLINE_COLOR,
|
|
377
|
-
caption:
|
|
379
|
+
caption:
|
|
380
|
+
blocks.length > 0
|
|
381
|
+
? `${blocks.length} block${blocks.length === 1 ? "" : "s"} ${formatKeyHint("right")}`
|
|
382
|
+
: undefined,
|
|
378
383
|
},
|
|
379
384
|
}).column;
|
|
380
385
|
}
|
|
381
386
|
|
|
382
387
|
const selectedBlock = this.#blocks?.[this.#blockSelected];
|
|
383
|
-
const openHint = selectedBlock?.href && this.deps.onOpen ? "
|
|
388
|
+
const openHint = selectedBlock?.href && this.deps.onOpen ? ` ${formatKeyHint("o")} open` : "";
|
|
384
389
|
const action = this.deps.actionLabel ?? "copy";
|
|
390
|
+
const upDown = editorKeys("tui.select.up", "tui.select.down");
|
|
391
|
+
const enter = formatKeyHint("enter");
|
|
392
|
+
const cancel = editorKey("tui.select.cancel");
|
|
385
393
|
const hint = this.#blocks
|
|
386
|
-
? `${this.#blockSelected + 1}/${this.#blocks.length}
|
|
387
|
-
: `${this.#targets.length > 0 ? `${this.#selected + 1}/${this.#targets.length} ` : ""}
|
|
394
|
+
? `${this.#blockSelected + 1}/${this.#blocks.length} ${upDown} block ${formatKeyHint("left")}/${cancel} back ${enter} ${action}${openHint} click ${theme.cmd.copy}/${theme.cmd.share}`
|
|
395
|
+
: `${this.#targets.length > 0 ? `${this.#selected + 1}/${this.#targets.length} ` : ""}${upDown} step ${blocks.length > 0 ? `${formatKeyHint("right")} blocks ` : ""}${enter} ${action} ${this.#truncated ? `${formatKeyHint("a")} earlier turns ` : ""}${expandKeyHint()} expand ${cancel} close`;
|
|
388
396
|
const anchorId = target
|
|
389
397
|
? this.#blocks
|
|
390
398
|
? `copy:${target.turnId}:block:${this.#blockSelected}`
|
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
matchesSelectPageUp,
|
|
31
31
|
} from "../../keybinding-matchers";
|
|
32
32
|
import { expandKeyHint } from "../../render/render-utils";
|
|
33
|
+
import { formatKeyHint, formatKeyHints } from "../../app-keybindings";
|
|
34
|
+
import { editorKeys, interruptKey } from "../../chrome/keybinding-hints";
|
|
33
35
|
import { bottomBorder, divider, PanelRows, row, topBorder } from "../../chrome/overlay-box";
|
|
34
36
|
import { ExtensionList } from "./extension-list";
|
|
35
37
|
import { InspectorPanel, type ToolRuntimeSource } from "./inspector-panel";
|
|
@@ -73,7 +75,10 @@ export interface ExtensionDashboardOptions {
|
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function extFooter(): string {
|
|
76
|
-
|
|
78
|
+
const upDown = editorKeys("tui.select.up", "tui.select.down");
|
|
79
|
+
const pages = editorKeys("tui.select.pageUp", "tui.select.pageDown");
|
|
80
|
+
const close = interruptKey();
|
|
81
|
+
return ` ${upDown}: navigate · ${formatKeyHint("space")}: toggle · ${formatKeyHints(["left", "right"])}: provider · ${pages}: inspector · ${expandKeyHint()}: expand · ${close}: close`;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
/**
|
|
@@ -28,7 +28,7 @@ export interface HistorySource {
|
|
|
28
28
|
search(query: string, limit: number): HistorySearchEntry[];
|
|
29
29
|
getRecent(limit: number): HistorySearchEntry[];
|
|
30
30
|
}
|
|
31
|
-
import { rawKeyHint } from "../chrome/keybinding-hints";
|
|
31
|
+
import { editorKeys, keyHint, rawKeyHint } from "../chrome/keybinding-hints";
|
|
32
32
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
33
33
|
import { contentRowWidth, renderScrollableList } from "../chrome/selector-helpers";
|
|
34
34
|
import { MenuSelection } from "../components/menu-selection";
|
|
@@ -195,7 +195,8 @@ export class HistorySearchComponent extends OverlayPanel {
|
|
|
195
195
|
this.#resultsList = new HistoryResultsList(this.#menu);
|
|
196
196
|
|
|
197
197
|
const dot = theme.fg("dim", theme.sep.dot);
|
|
198
|
-
const
|
|
198
|
+
const navigate = theme.fg("dim", editorKeys("tui.select.up", "tui.select.down")) + theme.fg("muted", " navigate");
|
|
199
|
+
const hint = [navigate, rawKeyHint("enter", "select"), keyHint("tui.select.cancel", "cancel")].join(dot);
|
|
199
200
|
|
|
200
201
|
this.addChild(new Spacer(1));
|
|
201
202
|
this.addChild(this.#searchInput);
|
|
@@ -14,6 +14,8 @@ import { matchesAppExternalEditor, matchesAppFollowUp, matchesAppInterrupt } fro
|
|
|
14
14
|
import { formTheme } from "../chrome/form-theme";
|
|
15
15
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
16
16
|
import { FormField } from "../components/form";
|
|
17
|
+
import { formatKeyHint, formatKeyHints } from "../app-keybindings";
|
|
18
|
+
import { boundKeys, editorKey, interruptKey } from "../chrome/keybinding-hints";
|
|
17
19
|
|
|
18
20
|
export interface HookEditorOptions {
|
|
19
21
|
/** Edit text with the host's configured external editor. */
|
|
@@ -81,9 +83,12 @@ export class HookEditorComponent extends OverlayPanel implements Focusable {
|
|
|
81
83
|
this.#editor.setText(prefill);
|
|
82
84
|
}
|
|
83
85
|
// Hint
|
|
86
|
+
const followUpKeys = boundKeys("app.message.followUp", ["ctrl+q", "ctrl+enter"]);
|
|
87
|
+
const [primaryFollowUpKey = "ctrl+q"] = followUpKeys;
|
|
88
|
+
const externalEditorKey = editorKey("app.editor.external") || formatKeyHint("ctrl+g");
|
|
84
89
|
const hint = this.#promptStyle
|
|
85
|
-
? "enter or
|
|
86
|
-
:
|
|
90
|
+
? `${formatKeyHint("enter")} or ${formatKeyHint(primaryFollowUpKey)} submit ${formatKeyHint("escape")} cancel ${externalEditorKey} external editor`
|
|
91
|
+
: `${formatKeyHints(followUpKeys)} submit ${interruptKey()} cancel ${externalEditorKey} external editor`;
|
|
87
92
|
this.#field = new FormField(this.#editor, {
|
|
88
93
|
theme: formTheme,
|
|
89
94
|
details:
|
|
@@ -7,6 +7,7 @@ import { CountdownTimer } from "../chrome/countdown-timer";
|
|
|
7
7
|
import { formTheme } from "../chrome/form-theme";
|
|
8
8
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
9
9
|
import { Form, TextFormField } from "../components/form";
|
|
10
|
+
import { editorKey, interruptKey } from "../chrome/keybinding-hints";
|
|
10
11
|
|
|
11
12
|
export interface HookInputOptions {
|
|
12
13
|
tui?: TUI;
|
|
@@ -49,7 +50,7 @@ export class HookInputComponent extends OverlayPanel {
|
|
|
49
50
|
|
|
50
51
|
this.#field = new TextFormField({
|
|
51
52
|
theme: formTheme,
|
|
52
|
-
hint: "
|
|
53
|
+
hint: `${editorKey("tui.input.submit")} submit ${interruptKey()} cancel`,
|
|
53
54
|
empty: "submit",
|
|
54
55
|
onSubmit: value => this.#onSubmitCallback(value),
|
|
55
56
|
onCancel: () => this.#onCancelCallback(),
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
matchesSelectUp,
|
|
27
27
|
} from "../keybinding-matchers";
|
|
28
28
|
import { CountdownTimer } from "../chrome/countdown-timer";
|
|
29
|
+
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
30
|
+
import { formatKeyHint } from "../app-keybindings";
|
|
29
31
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
30
32
|
import { renderSegmentTrack } from "../chrome/segment-track";
|
|
31
33
|
import { MenuSelection, getMenuWindow } from "../components/menu-selection";
|
|
@@ -264,7 +266,9 @@ export class HookSelectorComponent extends OverlayPanel {
|
|
|
264
266
|
this.addChild(this.#listContainer);
|
|
265
267
|
}
|
|
266
268
|
this.addChild(new Spacer(1));
|
|
267
|
-
const controlsHint =
|
|
269
|
+
const controlsHint =
|
|
270
|
+
opts?.helpText ??
|
|
271
|
+
`${editorKeys("tui.select.up", "tui.select.down")} navigate ${formatKeyHint("enter")} select ${editorKey("tui.select.cancel")} cancel`;
|
|
268
272
|
this.addChild(new Text(theme.fg("dim", controlsHint), 0, 0));
|
|
269
273
|
this.addChild(new Spacer(1));
|
|
270
274
|
|
|
@@ -6,6 +6,8 @@ import { urlHyperlinkAlways, WidthAwareText } from "../render/index";
|
|
|
6
6
|
import { formTheme } from "../chrome/form-theme";
|
|
7
7
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
8
8
|
import { TextFormField } from "../components/form";
|
|
9
|
+
import { formatKeyHint, keyHintPlatform } from "../app-keybindings";
|
|
10
|
+
import { editorKey } from "../chrome/keybinding-hints";
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Login dialog component - replaces editor during OAuth login flow
|
|
@@ -98,7 +100,7 @@ export class LoginDialogComponent extends OverlayPanel {
|
|
|
98
100
|
),
|
|
99
101
|
);
|
|
100
102
|
|
|
101
|
-
const clickHint =
|
|
103
|
+
const clickHint = `${formatKeyHint(keyHintPlatform() === "darwin" ? "super" : "ctrl")}+click to open`;
|
|
102
104
|
const hyperlink = `\x1b]8;;${url}\x07${clickHint}\x1b]8;;\x07`;
|
|
103
105
|
this.#contentContainer.addChild(new Text(theme.fg("dim", hyperlink), 0, 0));
|
|
104
106
|
|
|
@@ -132,7 +134,9 @@ export class LoginDialogComponent extends OverlayPanel {
|
|
|
132
134
|
this.#contentContainer.addChild(new Spacer(1));
|
|
133
135
|
this.#contentContainer.addChild(new Text(theme.fg("dim", prompt), 0, 0));
|
|
134
136
|
this.#contentContainer.addChild(this.#input);
|
|
135
|
-
this.#contentContainer.addChild(
|
|
137
|
+
this.#contentContainer.addChild(
|
|
138
|
+
new Text(theme.fg("dim", `(${editorKey("tui.select.cancel")} to cancel)`), 0, 0),
|
|
139
|
+
);
|
|
136
140
|
}
|
|
137
141
|
this.#tui.requestRender();
|
|
138
142
|
|
|
@@ -175,7 +179,16 @@ export class LoginDialogComponent extends OverlayPanel {
|
|
|
175
179
|
this.#contentContainer.addChild(new Text(theme.fg("dim", `e.g., ${prompt.placeholder}`), 0, 0));
|
|
176
180
|
}
|
|
177
181
|
this.#contentContainer.addChild(this.#input);
|
|
178
|
-
this.#contentContainer.addChild(
|
|
182
|
+
this.#contentContainer.addChild(
|
|
183
|
+
new Text(
|
|
184
|
+
theme.fg(
|
|
185
|
+
"dim",
|
|
186
|
+
`(${editorKey("tui.select.cancel")} to cancel, ${editorKey("tui.input.submit")} to submit)`,
|
|
187
|
+
),
|
|
188
|
+
0,
|
|
189
|
+
0,
|
|
190
|
+
),
|
|
191
|
+
);
|
|
179
192
|
|
|
180
193
|
this.#tui.requestRender();
|
|
181
194
|
|
|
@@ -200,7 +213,7 @@ export class LoginDialogComponent extends OverlayPanel {
|
|
|
200
213
|
showWaiting(message: string): void {
|
|
201
214
|
this.#contentContainer.addChild(new Spacer(1));
|
|
202
215
|
this.#contentContainer.addChild(new Text(theme.fg("dim", message), 0, 0));
|
|
203
|
-
this.#contentContainer.addChild(new Text(theme.fg("dim", "
|
|
216
|
+
this.#contentContainer.addChild(new Text(theme.fg("dim", `(${editorKey("tui.select.cancel")} to cancel)`), 0, 0));
|
|
204
217
|
this.#tui.requestRender();
|
|
205
218
|
}
|
|
206
219
|
|
|
@@ -4,6 +4,8 @@ import { matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../keyb
|
|
|
4
4
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
5
5
|
import { MenuSelection } from "../components/menu-selection";
|
|
6
6
|
import { centeredViewportRange } from "../components/scroll-viewport";
|
|
7
|
+
import { formatKeyHint } from "../app-keybindings";
|
|
8
|
+
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
7
9
|
|
|
8
10
|
const LOGOUT_SELECTOR_MAX_VISIBLE = 10;
|
|
9
11
|
|
|
@@ -84,7 +86,14 @@ export class LogoutAccountSelectorComponent extends OverlayPanel {
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
this.#listContainer.addChild(
|
|
87
|
-
new TruncatedText(
|
|
89
|
+
new TruncatedText(
|
|
90
|
+
theme.fg(
|
|
91
|
+
"muted",
|
|
92
|
+
`${editorKeys("tui.select.up", "tui.select.down")} select · ${formatKeyHint("enter")} log out account · ${editorKey("tui.select.cancel")} cancel`,
|
|
93
|
+
),
|
|
94
|
+
0,
|
|
95
|
+
0,
|
|
96
|
+
),
|
|
88
97
|
);
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -9,6 +9,8 @@ import { getMCPConfigPath, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
|
9
9
|
import { shortenPath } from "../render/render-utils";
|
|
10
10
|
import { getSelectListTheme, theme } from "../theme/theme";
|
|
11
11
|
import { matchesAppInterrupt, matchesSelectDown, matchesSelectUp } from "../keybinding-matchers";
|
|
12
|
+
import { formatKeyHint } from "../app-keybindings";
|
|
13
|
+
import { editorKey, editorKeys, interruptKey } from "../chrome/keybinding-hints";
|
|
12
14
|
import { OverlayPanel } from "../chrome/overlay-box";
|
|
13
15
|
import { TextFormField, type FormFieldTheme } from "../components/form";
|
|
14
16
|
import { SelectList } from "../components/select-list";
|
|
@@ -163,6 +165,16 @@ function sanitize(text: string): string {
|
|
|
163
165
|
return truncateToWidth(replaceTabs(text), MAX_DISPLAY_WIDTH);
|
|
164
166
|
}
|
|
165
167
|
|
|
168
|
+
/** Footer for text steps; the field submits on `tui.input.submit` and cancels on `tui.select.cancel`. */
|
|
169
|
+
function inputHint(escapeAction: string): string {
|
|
170
|
+
return `[${editorKey("tui.input.submit")} to continue, ${editorKey("tui.select.cancel")} to ${escapeAction}]`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Footer for choice steps; the wizard routes navigation, Enter, and Escape itself. */
|
|
174
|
+
function choiceHint(escapeAction: string): string {
|
|
175
|
+
return `[${editorKeys("tui.select.up", "tui.select.down")} to navigate, ${formatKeyHint("enter")} to select, ${interruptKey()} to ${escapeAction}]`;
|
|
176
|
+
}
|
|
177
|
+
|
|
166
178
|
const mcpFormTheme: FormFieldTheme = {
|
|
167
179
|
label: text => text,
|
|
168
180
|
description: text => theme.fg("muted", text),
|
|
@@ -451,7 +463,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
451
463
|
heading: "Step 1: Server Name",
|
|
452
464
|
prompt: "Enter a unique name for this server:",
|
|
453
465
|
initial: this.#state.name,
|
|
454
|
-
hint:
|
|
466
|
+
hint: `[Only letters, numbers, dash, underscore, dot, colon]\n${inputHint("cancel")}`,
|
|
455
467
|
optional: false,
|
|
456
468
|
error: this.#validationError,
|
|
457
469
|
});
|
|
@@ -466,7 +478,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
466
478
|
{ label: "http (HTTP server)" },
|
|
467
479
|
{ label: "sse (Server-Sent Events)" },
|
|
468
480
|
],
|
|
469
|
-
hint: "
|
|
481
|
+
hint: choiceHint("cancel"),
|
|
470
482
|
});
|
|
471
483
|
}
|
|
472
484
|
|
|
@@ -475,7 +487,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
475
487
|
heading: "Step 3: Command",
|
|
476
488
|
prompt: "Enter the command to run:",
|
|
477
489
|
initial: this.#state.command,
|
|
478
|
-
hint: "
|
|
490
|
+
hint: inputHint("go back"),
|
|
479
491
|
optional: false,
|
|
480
492
|
});
|
|
481
493
|
}
|
|
@@ -485,7 +497,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
485
497
|
heading: "Step 4: Arguments (Optional)",
|
|
486
498
|
prompt: "Enter command arguments (space-separated):",
|
|
487
499
|
initial: this.#state.args,
|
|
488
|
-
hint:
|
|
500
|
+
hint: `[Press ${editorKey("tui.input.submit")} to skip or continue]`,
|
|
489
501
|
optional: true,
|
|
490
502
|
});
|
|
491
503
|
}
|
|
@@ -495,7 +507,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
495
507
|
heading: "Step 3: Server URL",
|
|
496
508
|
prompt: "Enter the server URL:",
|
|
497
509
|
initial: this.#state.url,
|
|
498
|
-
hint:
|
|
510
|
+
hint: `[Must start with http:// or https://]\n${inputHint("go back")}`,
|
|
499
511
|
optional: false,
|
|
500
512
|
error: this.#validationError,
|
|
501
513
|
});
|
|
@@ -505,7 +517,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
505
517
|
this.#choiceStep({
|
|
506
518
|
heading: "Step: How to provide the key?",
|
|
507
519
|
choices: [{ label: "Environment variable" }, { label: "HTTP header" }],
|
|
508
|
-
hint: "
|
|
520
|
+
hint: choiceHint("go back"),
|
|
509
521
|
});
|
|
510
522
|
}
|
|
511
523
|
|
|
@@ -514,7 +526,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
514
526
|
heading: "Step: Environment Variable Name",
|
|
515
527
|
prompt: "Enter the environment variable name:",
|
|
516
528
|
initial: this.#state.envVarName,
|
|
517
|
-
hint: "
|
|
529
|
+
hint: inputHint("go back"),
|
|
518
530
|
optional: false,
|
|
519
531
|
});
|
|
520
532
|
}
|
|
@@ -524,7 +536,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
524
536
|
heading: "Step: HTTP Header Name",
|
|
525
537
|
prompt: "Enter the HTTP header name:",
|
|
526
538
|
initial: this.#state.headerName,
|
|
527
|
-
hint: "
|
|
539
|
+
hint: inputHint("go back"),
|
|
528
540
|
optional: false,
|
|
529
541
|
});
|
|
530
542
|
}
|
|
@@ -536,7 +548,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
536
548
|
this.#choiceStep({
|
|
537
549
|
heading: "Step: Configuration Scope",
|
|
538
550
|
choices: [{ label: `User level (${userPathLabel})` }, { label: `Project level (${projectPathLabel})` }],
|
|
539
|
-
hint: "
|
|
551
|
+
hint: choiceHint("go back"),
|
|
540
552
|
});
|
|
541
553
|
}
|
|
542
554
|
|
|
@@ -576,7 +588,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
576
588
|
heading: "Review Configuration",
|
|
577
589
|
intro: summary,
|
|
578
590
|
choices: [{ label: "Yes" }, { label: "No" }],
|
|
579
|
-
hint: "
|
|
591
|
+
hint: choiceHint("go back"),
|
|
580
592
|
kind: "confirm",
|
|
581
593
|
});
|
|
582
594
|
}
|
|
@@ -931,7 +943,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
931
943
|
{ label: "OAuth flow (web-based)", description: "(opens browser)" },
|
|
932
944
|
{ label: "Manual API key/token", description: "(paste or use shell command)" },
|
|
933
945
|
],
|
|
934
|
-
hint: "
|
|
946
|
+
hint: choiceHint("go back"),
|
|
935
947
|
});
|
|
936
948
|
}
|
|
937
949
|
|
|
@@ -941,7 +953,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
941
953
|
prompt: "Enter the OAuth authorization endpoint:",
|
|
942
954
|
initial: this.#state.oauthAuthUrl,
|
|
943
955
|
details: ["e.g., https://auth.example.com/oauth/authorize"],
|
|
944
|
-
hint: "
|
|
956
|
+
hint: inputHint("go back"),
|
|
945
957
|
optional: false,
|
|
946
958
|
});
|
|
947
959
|
}
|
|
@@ -952,7 +964,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
952
964
|
prompt: "Enter the OAuth token endpoint:",
|
|
953
965
|
initial: this.#state.oauthTokenUrl,
|
|
954
966
|
details: ["e.g., https://auth.example.com/oauth/token"],
|
|
955
|
-
hint: "
|
|
967
|
+
hint: inputHint("go back"),
|
|
956
968
|
optional: false,
|
|
957
969
|
});
|
|
958
970
|
}
|
|
@@ -962,7 +974,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
962
974
|
heading: "OAuth: Client ID",
|
|
963
975
|
prompt: "Enter your OAuth client ID:",
|
|
964
976
|
initial: this.#state.oauthClientId,
|
|
965
|
-
hint: "
|
|
977
|
+
hint: inputHint("go back"),
|
|
966
978
|
optional: false,
|
|
967
979
|
});
|
|
968
980
|
}
|
|
@@ -973,7 +985,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
973
985
|
prompt: "Enter your OAuth client secret:",
|
|
974
986
|
initial: this.#state.oauthClientSecret,
|
|
975
987
|
details: ["(Leave empty for PKCE-only flows)"],
|
|
976
|
-
hint: "
|
|
988
|
+
hint: inputHint("go back"),
|
|
977
989
|
optional: true,
|
|
978
990
|
});
|
|
979
991
|
}
|
|
@@ -984,7 +996,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
984
996
|
prompt: "Enter OAuth scopes (space-separated):",
|
|
985
997
|
initial: this.#state.oauthScopes,
|
|
986
998
|
details: ["e.g., read write"],
|
|
987
|
-
hint: "
|
|
999
|
+
hint: inputHint("go back"),
|
|
988
1000
|
optional: true,
|
|
989
1001
|
});
|
|
990
1002
|
}
|
|
@@ -1002,7 +1014,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
1002
1014
|
headingTone: this.#oauthErrorHeading?.tone ?? "error",
|
|
1003
1015
|
intro,
|
|
1004
1016
|
choices: [{ label: "Retry OAuth authentication" }, { label: "Edit OAuth settings" }],
|
|
1005
|
-
hint: "
|
|
1017
|
+
hint: choiceHint("go back"),
|
|
1006
1018
|
});
|
|
1007
1019
|
}
|
|
1008
1020
|
|
|
@@ -1012,7 +1024,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
1012
1024
|
prompt: "Enter your API key or token:",
|
|
1013
1025
|
initial: this.#state.apiKey,
|
|
1014
1026
|
details: ["(Supports !command for password manager)"],
|
|
1015
|
-
hint: "
|
|
1027
|
+
hint: inputHint("go back"),
|
|
1016
1028
|
optional: false,
|
|
1017
1029
|
});
|
|
1018
1030
|
}
|
|
@@ -1210,7 +1222,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
1210
1222
|
"OAuth configuration incomplete",
|
|
1211
1223
|
"error",
|
|
1212
1224
|
incompleteBody,
|
|
1213
|
-
new Text(theme.fg("muted",
|
|
1225
|
+
new Text(theme.fg("muted", `[Press ${interruptKey()} to go back]`), 0, 0),
|
|
1214
1226
|
);
|
|
1215
1227
|
this.#requestRender();
|
|
1216
1228
|
return;
|
|
@@ -1226,7 +1238,7 @@ export class MCPAddWizard extends OverlayPanel {
|
|
|
1226
1238
|
"OAuth Authentication",
|
|
1227
1239
|
"accent",
|
|
1228
1240
|
authBody,
|
|
1229
|
-
new Text(theme.fg("muted",
|
|
1241
|
+
new Text(theme.fg("muted", `(Press ${interruptKey()} to cancel)`), 0, 0),
|
|
1230
1242
|
);
|
|
1231
1243
|
this.#requestRender();
|
|
1232
1244
|
|