@oh-my-pi/pi-tui 18.4.2 → 18.4.3

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/types/chat/thinking-display.d.ts +2 -0
  3. package/dist/types/components/editor.d.ts +5 -0
  4. package/dist/types/loop-watchdog.d.ts +9 -0
  5. package/dist/types/overlays/model-picker.d.ts +2 -1
  6. package/dist/types/setup/scenes/sign-in.d.ts +9 -9
  7. package/dist/types/setup/scenes/types.d.ts +0 -26
  8. package/dist/types/stdin-buffer.d.ts +10 -7
  9. package/dist/types/terminal.d.ts +9 -0
  10. package/dist/types/tools/web-search-types.d.ts +90 -0
  11. package/dist/types/tools/web-search.d.ts +1 -168
  12. package/package.json +9 -9
  13. package/src/chat/assistant-message.ts +192 -40
  14. package/src/chat/thinking-display.ts +73 -11
  15. package/src/chrome/transcript-container.ts +102 -17
  16. package/src/components/editor.ts +23 -9
  17. package/src/components/markdown.ts +110 -56
  18. package/src/loop-watchdog.ts +38 -10
  19. package/src/overlays/model-picker.ts +9 -6
  20. package/src/overlays/settings-selector.ts +2 -10
  21. package/src/setup/scenes/sign-in.ts +17 -12
  22. package/src/setup/scenes/types.ts +0 -27
  23. package/src/setup/wizard.ts +1 -1
  24. package/src/status-line/component.ts +16 -2
  25. package/src/stdin-buffer.ts +27 -21
  26. package/src/terminal.ts +23 -9
  27. package/src/theme/mermaid-cache.ts +10 -1
  28. package/src/theme/tui-adapters.ts +14 -1
  29. package/src/tools/bash.ts +53 -13
  30. package/src/tools/edit.ts +110 -29
  31. package/src/tools/streaming-output.ts +79 -16
  32. package/src/tools/web-search-types.ts +99 -0
  33. package/src/tools/web-search.ts +1 -172
  34. package/src/tui.ts +1 -1
  35. package/dist/types/setup/scenes/providers.d.ts +0 -3
  36. package/dist/types/setup/scenes/web-search.d.ts +0 -22
  37. package/src/setup/scenes/providers.ts +0 -110
  38. package/src/setup/scenes/web-search.ts +0 -165
@@ -1,165 +0,0 @@
1
- import { type SgrMouseEvent } from "../../mouse";
2
- import { type SelectItem, SelectList } from "../../components/select-list";
3
- import { Spacer } from "../../components/spacer";
4
- import { Text } from "../../components/text";
5
- import { WizardStep } from "../../components/wizard-step";
6
- import { Container } from "../../tui";
7
- import { truncateToWidth } from "../../utils";
8
- import { SEARCH_PROVIDER_OPTIONS, type SearchProviderId } from "../../tools/web-search";
9
- import { getSelectListTheme, theme } from "../../theme/theme";
10
- import type { SetupSceneHost, SetupTab } from "./types";
11
-
12
- const MAX_VISIBLE = 8;
13
-
14
- /** Reuse the shared provider options as the single source of truth for labels/descriptions. */
15
- const WEB_SEARCH_ITEMS: readonly SelectItem[] = SEARCH_PROVIDER_OPTIONS.map(option => ({
16
- value: option.value,
17
- label: option.label,
18
- description: option.description,
19
- }));
20
-
21
- type Availability = "checking" | boolean;
22
-
23
- /**
24
- * "Web search" panel: picks the provider the web_search tool should prefer and
25
- * reports whether the highlighted provider is ready to use given current
26
- * credentials (env keys or OAuth sign-ins from the Sign in tab) or an
27
- * unauthenticated fallback.
28
- */
29
- export class WebSearchTab implements SetupTab {
30
- readonly id = "web-search";
31
- readonly label = "Web search";
32
- readonly modal = false;
33
-
34
- #list: SelectList;
35
- #availability = new Map<SearchProviderId, Availability>();
36
- #status: string[] = [];
37
- #disposed = false;
38
- #step: WizardStep | undefined;
39
-
40
- readonly #host: SetupSceneHost;
41
-
42
- constructor(host: SetupSceneHost) {
43
- this.#host = host;
44
- this.#list = new SelectList(WEB_SEARCH_ITEMS, MAX_VISIBLE, getSelectListTheme());
45
- const order = host.ctx.webSearchOrder;
46
- const current = Array.isArray(order) && typeof order[0] === "string" ? order[0] : "auto";
47
- const index = WEB_SEARCH_ITEMS.findIndex(item => item.value === current);
48
- if (index >= 0) this.#list.setSelectedIndex(index);
49
- this.#list.onSelectionChange = item => this.#onHighlight(item.value);
50
- this.#list.onSelect = item => this.#apply(item.value);
51
- this.#list.onCancel = () => host.finish("skipped");
52
- }
53
-
54
- onActivate(): void {
55
- // Auth may have changed in the Sign in tab; re-check from scratch.
56
- this.#availability.clear();
57
- this.#status = [];
58
- const selected = this.#list.getSelectedItem();
59
- if (selected) this.#onHighlight(selected.value);
60
- this.#host.requestRender();
61
- }
62
-
63
- handleInput(data: string): void {
64
- if (this.#step) this.#step.handleInput(data);
65
- else this.#list.handleInput(data);
66
- }
67
-
68
- /** Wheel moves the highlight; hover lights the row under the pointer; click confirms it. */
69
- routeMouse(event: SgrMouseEvent, line: number, col: number): void {
70
- this.#step?.routeMouse(event, line, col);
71
- }
72
-
73
- invalidate(): void {
74
- if (this.#step) this.#step.invalidate();
75
- else this.#list.invalidate();
76
- }
77
-
78
- dispose(): void {
79
- this.#disposed = true;
80
- }
81
-
82
- render(width: number, maxLines?: number): readonly string[] {
83
- const intro = new Text(theme.fg("muted", "Choose the provider the web_search tool should prefer."), 0, 0);
84
- const status = new Container();
85
- const selected = this.#list.getSelectedItem();
86
- if (selected) {
87
- for (const line of this.#readinessLines(selected.value)) {
88
- status.addChild(new Text(truncateToWidth(line, width), 0, 0));
89
- }
90
- }
91
- if (selected && this.#status.length > 0) status.addChild(new Spacer(1));
92
- for (const line of this.#status) {
93
- status.addChild(new Text(truncateToWidth(line, width), 0, 0));
94
- }
95
- if (!this.#step) {
96
- this.#step = new WizardStep({
97
- kind: "choice",
98
- intro,
99
- content: this.#list,
100
- status,
101
- minContentLines: 1,
102
- fitContent: budget => {
103
- // Above: hint + blank. Below: the list's own search-status row plus
104
- // blank + readiness line. Shrinking keeps the selection centered.
105
- const visible = budget === undefined ? MAX_VISIBLE : budget - 1;
106
- this.#list.setMaxVisible(Math.max(1, Math.min(MAX_VISIBLE, visible)));
107
- },
108
- });
109
- } else {
110
- this.#step.setIntro(intro);
111
- this.#step.setStatus(status);
112
- }
113
- this.#step.setMaxHeight(maxLines);
114
- return this.#step.render(width);
115
- }
116
-
117
- #onHighlight(value: string): void {
118
- this.#status = [];
119
- if (value !== "auto") this.#checkAvailability(value as SearchProviderId);
120
- this.#host.requestRender();
121
- }
122
-
123
- #checkAvailability(id: SearchProviderId): void {
124
- if (this.#availability.has(id)) return;
125
- this.#availability.set(id, "checking");
126
- void (async () => {
127
- let ready = false;
128
- try {
129
- ready = await this.#host.ctx.isSearchProviderAvailable(id);
130
- } catch {
131
- ready = false;
132
- }
133
- if (this.#disposed) return;
134
- this.#availability.set(id, ready);
135
- this.#host.requestRender();
136
- })();
137
- }
138
-
139
- #apply(value: string): void {
140
- const option = SEARCH_PROVIDER_OPTIONS.find(option => option.value === value);
141
- if (!option) return;
142
- // The wizard picks one favorite; persist it as the head of the priority
143
- // list with the remaining providers in their built-in order (auto = reset).
144
- this.#host.ctx.saveSearchProvider(option.value);
145
- const label = WEB_SEARCH_ITEMS.find(item => item.value === value)?.label ?? value;
146
- this.#status = [theme.fg("success", `${theme.status.success} Web search set to ${label}`)];
147
- if (value !== "auto" && this.#availability.get(value as SearchProviderId) === false) {
148
- this.#status.push(theme.fg("dim", "Not configured yet — add its API key or sign in to enable it."));
149
- }
150
- this.#host.requestRender();
151
- }
152
-
153
- #readinessLines(value: string): string[] {
154
- if (value === "auto") {
155
- return [theme.fg("dim", "Automatically uses the first configured provider.")];
156
- }
157
- const state = this.#availability.get(value as SearchProviderId);
158
- if (state === undefined || state === "checking") {
159
- return [theme.fg("dim", "Checking availability…")];
160
- }
161
- return state
162
- ? [theme.fg("success", `${theme.status.success} Ready to use`)]
163
- : [theme.fg("warning", `${theme.status.pending} Needs credentials`)];
164
- }
165
- }