@oh-my-pi/pi-coding-agent 16.1.23 → 16.2.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 +70 -0
- package/dist/cli.js +3817 -3735
- package/dist/types/advisor/__tests__/emission-guard.test.d.ts +1 -0
- package/dist/types/advisor/emission-guard.d.ts +73 -0
- package/dist/types/advisor/index.d.ts +1 -0
- package/dist/types/advisor/runtime.d.ts +7 -0
- package/dist/types/advisor/watchdog.d.ts +2 -0
- package/dist/types/cli/flag-tables.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +1 -1
- package/dist/types/collab/display-name.d.ts +3 -0
- package/dist/types/collab/host.d.ts +0 -2
- package/dist/types/commands/worktree.d.ts +0 -3
- package/dist/types/config/inline-tool-descriptors-mode.d.ts +13 -0
- package/dist/types/config/model-discovery.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +6 -2
- package/dist/types/config/model-resolver.d.ts +12 -0
- package/dist/types/config/models-config-schema.d.ts +29 -2
- package/dist/types/config/models-config.d.ts +22 -1
- package/dist/types/config/settings-schema.d.ts +91 -21
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/dap/config.d.ts +1 -1
- package/dist/types/edit/hashline/filesystem.d.ts +4 -2
- package/dist/types/edit/renderer.d.ts +4 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -17
- package/dist/types/extensibility/hooks/types.d.ts +10 -10
- package/dist/types/extensibility/plugins/marketplace/types.d.ts +1 -0
- package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +1 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/registry-helpers.d.ts +2 -0
- package/dist/types/internal-urls/router.d.ts +1 -1
- package/dist/types/internal-urls/ssh-protocol.d.ts +10 -0
- package/dist/types/internal-urls/types.d.ts +19 -2
- package/dist/types/irc/bus.d.ts +6 -0
- package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +7 -0
- package/dist/types/modes/components/move-overlay.d.ts +23 -0
- package/dist/types/modes/components/plugin-selector.d.ts +2 -1
- package/dist/types/modes/components/queue-mode-selector.d.ts +2 -1
- package/dist/types/modes/components/select-list-mouse-routing.d.ts +2 -0
- package/dist/types/modes/components/settings-defs.d.ts +4 -1
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/show-images-selector.d.ts +2 -1
- package/dist/types/modes/components/status-line/component.d.ts +2 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/theme-selector.d.ts +2 -1
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/controllers/command-controller.d.ts +10 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +10 -1
- package/dist/types/modes/internal-url-autocomplete.d.ts +1 -1
- package/dist/types/modes/running-subagent-badge.d.ts +6 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +9 -1
- package/dist/types/sdk.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +2 -1
- package/dist/types/session/session-manager.d.ts +13 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +1 -0
- package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +1 -0
- package/dist/types/ssh/connection-manager.d.ts +2 -0
- package/dist/types/ssh/file-transfer.d.ts +79 -0
- package/dist/types/ssh/utils.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +3 -0
- package/dist/types/task/executor.d.ts +16 -0
- package/dist/types/tiny/text.d.ts +1 -1
- package/dist/types/tools/builtin-names.d.ts +5 -1
- package/dist/types/tools/{find.d.ts → glob.d.ts} +15 -15
- package/dist/types/tools/{search.d.ts → grep.d.ts} +14 -14
- package/dist/types/tools/index.d.ts +3 -3
- package/dist/types/tools/path-utils.d.ts +29 -0
- package/dist/types/tools/read.d.ts +2 -2
- package/dist/types/tools/render-utils.d.ts +8 -0
- package/dist/types/tools/renderers.d.ts +11 -0
- package/dist/types/tools/ssh.d.ts +2 -0
- package/dist/types/tools/todo.d.ts +0 -16
- package/dist/types/tools/write.d.ts +2 -2
- package/dist/types/utils/active-repo-context.d.ts +8 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/utils/markit-cache.d.ts +23 -0
- package/dist/types/utils/markit.d.ts +5 -1
- package/dist/types/utils/prompt-path.d.ts +1 -0
- package/dist/types/web/search/providers/duckduckgo.d.ts +14 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +28 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +29 -0
- package/dist/types/web/search/providers/xai.d.ts +13 -0
- package/dist/types/web/search/types.d.ts +18 -2
- package/package.json +30 -15
- package/scripts/build-binary.ts +9 -9
- package/scripts/bundle-dist.ts +2 -2
- package/src/advisor/__tests__/advisor.test.ts +40 -4
- package/src/advisor/__tests__/emission-guard.test.ts +147 -0
- package/src/advisor/advise-tool.ts +1 -1
- package/src/advisor/emission-guard.ts +172 -0
- package/src/advisor/index.ts +1 -0
- package/src/advisor/runtime.ts +11 -0
- package/src/advisor/watchdog.ts +12 -1
- package/src/cli/args.ts +5 -2
- package/src/cli/auth-broker-cli.ts +17 -0
- package/src/cli/config-cli.ts +4 -0
- package/src/cli/flag-tables.ts +7 -4
- package/src/cli/gallery-cli.ts +14 -2
- package/src/cli/gallery-fixtures/edit.ts +60 -0
- package/src/cli/gallery-fixtures/fs.ts +17 -17
- package/src/cli/gallery-fixtures/search.ts +4 -4
- package/src/cli/usage-cli.ts +20 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/collab/display-name.ts +13 -0
- package/src/collab/guest.ts +5 -1
- package/src/collab/host.ts +2 -13
- package/src/commands/worktree.ts +6 -0
- package/src/config/inline-tool-descriptors-mode.ts +27 -0
- package/src/config/model-discovery.ts +77 -8
- package/src/config/model-registry.ts +89 -11
- package/src/config/model-resolver.ts +39 -1
- package/src/config/models-config-schema.ts +41 -5
- package/src/config/models-config.ts +4 -1
- package/src/config/settings-schema.ts +85 -27
- package/src/config/settings.ts +172 -1
- package/src/cursor.ts +1 -1
- package/src/dap/config.ts +152 -8
- package/src/dap/session.ts +1 -1
- package/src/discovery/helpers.ts +3 -1
- package/src/edit/hashline/diff.ts +14 -3
- package/src/edit/hashline/execute.ts +42 -6
- package/src/edit/hashline/filesystem.ts +38 -2
- package/src/edit/index.ts +1 -0
- package/src/edit/modes/patch.ts +11 -1
- package/src/edit/renderer.ts +140 -13
- package/src/eval/__tests__/agent-bridge.test.ts +101 -0
- package/src/eval/agent-bridge.ts +26 -3
- package/src/eval/js/tool-bridge.ts +2 -2
- package/src/export/html/index.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/export/html/tool-views.generated.js +20 -20
- package/src/extensibility/extensions/types.ts +22 -22
- package/src/extensibility/hooks/types.ts +11 -11
- package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +8 -3
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +25 -10
- package/src/extensibility/plugins/marketplace/manager.ts +22 -0
- package/src/extensibility/plugins/marketplace/types.ts +1 -0
- package/src/internal-urls/__tests__/ssh-protocol.test.ts +331 -0
- package/src/internal-urls/docs-index.generated.txt +2 -2
- package/src/internal-urls/docs-index.ts +2 -3
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/registry-helpers.ts +19 -4
- package/src/internal-urls/router.ts +5 -3
- package/src/internal-urls/ssh-protocol.ts +367 -0
- package/src/internal-urls/types.ts +19 -2
- package/src/irc/bus.ts +11 -3
- package/src/mcp/tool-bridge.ts +32 -2
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +2 -2
- package/src/modes/components/__tests__/move-overlay.test.ts +166 -0
- package/src/modes/components/agent-hub.ts +3 -0
- package/src/modes/components/agent-transcript-viewer.ts +9 -7
- package/src/modes/components/custom-editor.ts +90 -5
- package/src/modes/components/move-overlay.ts +282 -0
- package/src/modes/components/plan-review-overlay.ts +35 -35
- package/src/modes/components/plugin-selector.ts +6 -1
- package/src/modes/components/queue-mode-selector.ts +6 -1
- package/src/modes/components/select-list-mouse-routing.ts +35 -0
- package/src/modes/components/session-selector.ts +11 -10
- package/src/modes/components/settings-defs.ts +14 -1
- package/src/modes/components/settings-selector.ts +196 -29
- package/src/modes/components/show-images-selector.ts +6 -1
- package/src/modes/components/status-line/component.ts +108 -28
- package/src/modes/components/status-line/segments.ts +5 -1
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/theme-selector.ts +6 -1
- package/src/modes/components/thinking-selector.ts +6 -1
- package/src/modes/components/tool-execution.ts +25 -9
- package/src/modes/components/tree-selector.ts +5 -5
- package/src/modes/controllers/command-controller.ts +140 -47
- package/src/modes/controllers/event-controller.ts +59 -3
- package/src/modes/controllers/input-controller.ts +68 -2
- package/src/modes/controllers/selector-controller.ts +5 -2
- package/src/modes/controllers/streaming-reveal.ts +17 -0
- package/src/modes/controllers/tool-args-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +116 -50
- package/src/modes/internal-url-autocomplete.ts +17 -2
- package/src/modes/prompt-action-autocomplete.ts +3 -1
- package/src/modes/running-subagent-badge.ts +13 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +2 -13
- package/src/modes/setup-wizard/scenes/providers.ts +2 -1
- package/src/modes/setup-wizard/scenes/theme.ts +6 -12
- package/src/modes/setup-wizard/scenes/web-search.ts +8 -13
- package/src/modes/setup-wizard/wizard-overlay.ts +6 -5
- package/src/modes/theme/theme.ts +9 -1
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/interactive-context-helpers.ts +1 -1
- package/src/priority.json +15 -0
- package/src/prompts/advisor/active-repo-watchdog.md +6 -0
- package/src/prompts/advisor/system.md +21 -7
- package/src/prompts/agents/designer.md +1 -1
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/librarian.md +2 -2
- package/src/prompts/agents/plan.md +2 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +2 -2
- package/src/prompts/system/active-repo-context.md +4 -0
- package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
- package/src/prompts/system/plan-mode-active.md +3 -3
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/system-prompt.md +6 -6
- package/src/prompts/tools/bash.md +2 -2
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/{find.md → glob.md} +1 -1
- package/src/prompts/tools/{search.md → grep.md} +3 -3
- package/src/prompts/tools/read.md +4 -2
- package/src/sdk.ts +55 -25
- package/src/session/agent-session.ts +508 -132
- package/src/session/session-history-format.ts +2 -2
- package/src/session/session-manager.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +138 -20
- package/src/slash-commands/helpers/usage-report.ts +23 -2
- package/src/ssh/__tests__/connection-manager-args.test.ts +69 -0
- package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +68 -0
- package/src/ssh/connection-manager.ts +12 -15
- package/src/ssh/file-transfer.ts +209 -0
- package/src/ssh/utils.ts +24 -0
- package/src/system-prompt.ts +56 -28
- package/src/task/executor.ts +96 -36
- package/src/task/index.ts +3 -3
- package/src/task/render.ts +14 -13
- package/src/task/worktree.ts +38 -1
- package/src/tiny/text.ts +49 -4
- package/src/tiny/worker.ts +3 -3
- package/src/tools/bash.ts +2 -2
- package/src/tools/builtin-names.ts +26 -2
- package/src/tools/{find.ts → glob.ts} +48 -42
- package/src/tools/{search.ts → grep.ts} +311 -129
- package/src/tools/index.ts +13 -14
- package/src/tools/irc.ts +6 -2
- package/src/tools/path-utils.ts +64 -1
- package/src/tools/read.ts +35 -6
- package/src/tools/render-utils.ts +14 -0
- package/src/tools/renderers.ts +15 -4
- package/src/tools/ssh.ts +17 -2
- package/src/tools/todo.ts +4 -26
- package/src/tools/write.ts +25 -9
- package/src/utils/active-repo-context.ts +143 -0
- package/src/utils/image-resize.ts +88 -7
- package/src/utils/lang-from-path.ts +3 -3
- package/src/utils/markit-cache.ts +166 -0
- package/src/utils/markit.ts +86 -18
- package/src/utils/prompt-path.ts +3 -0
- package/src/utils/title-generator.ts +1 -1
- package/src/web/search/provider.ts +54 -34
- package/src/web/search/providers/duckduckgo.ts +140 -0
- package/src/web/search/providers/firecrawl.ts +144 -0
- package/src/web/search/providers/tinyfish.ts +159 -0
- package/src/web/search/providers/xai.ts +292 -0
- package/src/web/search/providers/zai.ts +142 -56
- package/src/web/search/types.ts +6 -2
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
Markdown,
|
|
24
24
|
type MarkdownTheme,
|
|
25
25
|
matchesKey,
|
|
26
|
-
|
|
26
|
+
routeSgrMouseInput,
|
|
27
27
|
ScrollView,
|
|
28
28
|
truncateToWidth,
|
|
29
29
|
visibleWidth,
|
|
@@ -333,42 +333,42 @@ export class PlanReviewOverlay implements Component {
|
|
|
333
333
|
* the body.
|
|
334
334
|
*/
|
|
335
335
|
#handleMouse(data: string): boolean {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
336
|
+
return routeSgrMouseInput(data, event => {
|
|
337
|
+
if (event.wheel !== null) {
|
|
338
|
+
// Scroll wheel: three rows per notch.
|
|
339
|
+
this.#scrollView.scroll(event.wheel * 3);
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
if (event.release) return true;
|
|
343
|
+
if (event.motion) {
|
|
344
|
+
// Motion (hover or drag): light up the option row under the pointer so a
|
|
345
|
+
// mouse user gets the same affordance the keyboard cursor gives. Any
|
|
346
|
+
// non-option row clears the highlight.
|
|
347
|
+
this.#setHoveredOption(this.#optionClickRows.get(event.row));
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
if (!event.leftClick) return true;
|
|
351
|
+
const optionIndex = this.#optionClickRows.get(event.row);
|
|
352
|
+
if (optionIndex !== undefined) {
|
|
353
|
+
if (!this.#disabled.has(optionIndex)) {
|
|
354
|
+
this.#focus = "actions";
|
|
355
|
+
this.#selectedIndex = optionIndex;
|
|
356
|
+
this.#confirmSelection();
|
|
357
|
+
}
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
const tocPos = this.#tocClickRows.get(event.row);
|
|
361
|
+
if (tocPos !== undefined && event.col < this.#sidebarClickMaxCol) {
|
|
362
|
+
this.#focus = "toc";
|
|
363
|
+
this.#tocCursor = tocPos;
|
|
364
|
+
this.#scrubBodyToToc();
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
if (this.#bodyClickRows.has(event.row)) {
|
|
368
|
+
this.#setFocus("body");
|
|
358
369
|
}
|
|
359
370
|
return true;
|
|
360
|
-
}
|
|
361
|
-
const tocPos = this.#tocClickRows.get(event.row);
|
|
362
|
-
if (tocPos !== undefined && event.col < this.#sidebarClickMaxCol) {
|
|
363
|
-
this.#focus = "toc";
|
|
364
|
-
this.#tocCursor = tocPos;
|
|
365
|
-
this.#scrubBodyToToc();
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
if (this.#bodyClickRows.has(event.row)) {
|
|
369
|
-
this.#setFocus("body");
|
|
370
|
-
}
|
|
371
|
-
return true;
|
|
371
|
+
});
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
/** Set the hovered option from a hit-tested row, ignoring disabled rows and
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Shows available plugins from all configured marketplaces in a SelectList.
|
|
5
5
|
* Selecting a plugin triggers installation. Esc cancels.
|
|
6
6
|
*/
|
|
7
|
-
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import { Container, type SelectItem, SelectList, type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
8
8
|
import { getSelectListTheme } from "../theme/theme";
|
|
9
9
|
import { DynamicBorder } from "./dynamic-border";
|
|
10
|
+
import { routeSelectListMouseWithTopBorder } from "./select-list-mouse-routing";
|
|
10
11
|
|
|
11
12
|
export interface PluginSelectorCallbacks {
|
|
12
13
|
onSelect: (pluginName: string, marketplace: string, scope?: "user" | "project") => void;
|
|
@@ -82,6 +83,10 @@ export class PluginSelectorComponent extends Container {
|
|
|
82
83
|
getSelectList(): SelectList {
|
|
83
84
|
return this.#selectList;
|
|
84
85
|
}
|
|
86
|
+
|
|
87
|
+
routeMouse(event: SgrMouseEvent, line: number, col: number): void {
|
|
88
|
+
routeSelectListMouseWithTopBorder(this.#selectList, event, line, col);
|
|
89
|
+
}
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
function splitPluginId(id: string): [string, string, "user" | "project" | undefined] | [null, null, null] {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
1
|
+
import { Container, type SelectItem, SelectList, type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import { getSelectListTheme } from "../../modes/theme/theme";
|
|
3
3
|
import { DynamicBorder } from "./dynamic-border";
|
|
4
|
+
import { routeSelectListMouseWithTopBorder } from "./select-list-mouse-routing";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Component that renders a queue mode selector with borders
|
|
@@ -53,4 +54,8 @@ export class QueueModeSelectorComponent extends Container {
|
|
|
53
54
|
getSelectList(): SelectList {
|
|
54
55
|
return this.#selectList;
|
|
55
56
|
}
|
|
57
|
+
|
|
58
|
+
routeMouse(event: SgrMouseEvent, line: number, col: number): void {
|
|
59
|
+
routeSelectListMouseWithTopBorder(this.#selectList, event, line, col);
|
|
60
|
+
}
|
|
56
61
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SelectList, SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
2
|
+
|
|
3
|
+
interface RoutableSelectList {
|
|
4
|
+
routeMouse?: (event: SgrMouseEvent, line: number, col: number) => void;
|
|
5
|
+
handleWheel(delta: -1 | 1): void;
|
|
6
|
+
hitTest(line: number): number | undefined;
|
|
7
|
+
setHoverIndex(index: number | null): void;
|
|
8
|
+
clickItem(index: number): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function routeSelectListMouseWithTopBorder(
|
|
12
|
+
selectList: SelectList,
|
|
13
|
+
event: SgrMouseEvent,
|
|
14
|
+
line: number,
|
|
15
|
+
col: number,
|
|
16
|
+
): void {
|
|
17
|
+
const localLine = line - 1;
|
|
18
|
+
const target = selectList as RoutableSelectList;
|
|
19
|
+
if (typeof target.routeMouse === "function") {
|
|
20
|
+
target.routeMouse(event, localLine, col);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (event.wheel !== null) {
|
|
24
|
+
target.handleWheel(event.wheel);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const index = target.hitTest(localLine);
|
|
28
|
+
if (event.motion) {
|
|
29
|
+
target.setHoverIndex(index ?? null);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (event.leftClick && index !== undefined) {
|
|
33
|
+
target.clickItem(index);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
Input,
|
|
6
6
|
matchesKey,
|
|
7
7
|
padding,
|
|
8
|
-
parseSgrMouse,
|
|
9
8
|
replaceTabs,
|
|
9
|
+
routeSgrMouseInput,
|
|
10
10
|
ScrollView,
|
|
11
11
|
Spacer,
|
|
12
12
|
Text,
|
|
@@ -726,15 +726,16 @@ export class SessionSelectorComponent extends Container {
|
|
|
726
726
|
*/
|
|
727
727
|
#handleMouse(data: string): void {
|
|
728
728
|
if (this.#confirmationDialog) return;
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
729
|
+
routeSgrMouseInput(data, event => {
|
|
730
|
+
if (event.wheel !== null) {
|
|
731
|
+
this.#sessionList.handleWheel(event.wheel);
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
if (!event.leftClick || event.row >= this.#footerStart) return true;
|
|
735
|
+
const index = this.#sessionList.hitTestSession(event.row - this.#listLineOffset);
|
|
736
|
+
if (index !== undefined) this.#sessionList.selectAndConfirm(index);
|
|
737
|
+
return true;
|
|
738
|
+
});
|
|
738
739
|
}
|
|
739
740
|
|
|
740
741
|
getSessionList(): SessionList {
|
|
@@ -68,7 +68,16 @@ export interface TextInputSettingDef extends BaseSettingDef {
|
|
|
68
68
|
type: "text";
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export
|
|
71
|
+
export interface ProviderLimitsSettingDef extends BaseSettingDef {
|
|
72
|
+
type: "providerLimits";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type SettingDef =
|
|
76
|
+
| BooleanSettingDef
|
|
77
|
+
| EnumSettingDef
|
|
78
|
+
| SubmenuSettingDef
|
|
79
|
+
| TextInputSettingDef
|
|
80
|
+
| ProviderLimitsSettingDef;
|
|
72
81
|
|
|
73
82
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
74
83
|
// Condition Functions
|
|
@@ -170,6 +179,10 @@ function pathToSettingDef(path: SettingPath): SettingDef | null {
|
|
|
170
179
|
return { ...base, type: "text" };
|
|
171
180
|
}
|
|
172
181
|
|
|
182
|
+
if (schemaType === "record") {
|
|
183
|
+
return path === "providers.maxInFlightRequests" ? { ...base, type: "providerLimits" } : null;
|
|
184
|
+
}
|
|
185
|
+
|
|
173
186
|
return null;
|
|
174
187
|
}
|
|
175
188
|
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
type ImageBudget,
|
|
11
11
|
Input,
|
|
12
12
|
matchesKey,
|
|
13
|
-
|
|
13
|
+
replaceTabs,
|
|
14
|
+
routeSelectListMouse,
|
|
15
|
+
routeSgrMouseInput,
|
|
14
16
|
type SelectItem,
|
|
15
17
|
SelectList,
|
|
16
18
|
type SettingItem,
|
|
@@ -24,7 +26,14 @@ import {
|
|
|
24
26
|
visibleWidth,
|
|
25
27
|
} from "@oh-my-pi/pi-tui";
|
|
26
28
|
import type { ShapeTarget } from "@oh-my-pi/snapcompact";
|
|
27
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
getDefault,
|
|
31
|
+
getType,
|
|
32
|
+
normalizeProviderMaxInFlightRequests,
|
|
33
|
+
type SettingPath,
|
|
34
|
+
settings,
|
|
35
|
+
validateProviderMaxInFlightRequests,
|
|
36
|
+
} from "../../config/settings";
|
|
28
37
|
import type {
|
|
29
38
|
SettingTab,
|
|
30
39
|
StatusLinePreset,
|
|
@@ -50,6 +59,7 @@ import { getPreset } from "./status-line/presets";
|
|
|
50
59
|
*/
|
|
51
60
|
class TextInputSubmenu extends Container {
|
|
52
61
|
#input: Input;
|
|
62
|
+
#error: Text;
|
|
53
63
|
|
|
54
64
|
constructor(
|
|
55
65
|
label: string,
|
|
@@ -71,11 +81,18 @@ class TextInputSubmenu extends Container {
|
|
|
71
81
|
if (currentValue) {
|
|
72
82
|
this.#input.setValue(currentValue);
|
|
73
83
|
}
|
|
84
|
+
this.#error = new Text("", 0, 0);
|
|
74
85
|
this.#input.onSubmit = value => {
|
|
75
|
-
|
|
86
|
+
try {
|
|
87
|
+
this.onSubmit(value); // empty string clears the setting
|
|
88
|
+
} catch (error) {
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
this.#error.setText(theme.fg("error", truncateToWidth(replaceTabs(message).replace(/[\r\n]+/g, " "), 100)));
|
|
91
|
+
}
|
|
76
92
|
};
|
|
77
93
|
this.addChild(this.#input);
|
|
78
94
|
this.addChild(new Spacer(1));
|
|
95
|
+
this.addChild(this.#error);
|
|
79
96
|
this.addChild(new Text(theme.fg("dim", " Enter to save · Esc to cancel · Clear field to unset"), 0, 0));
|
|
80
97
|
}
|
|
81
98
|
|
|
@@ -89,7 +106,6 @@ class SelectSubmenu extends Container {
|
|
|
89
106
|
#previewText: Text | null = null;
|
|
90
107
|
#previewUpdateRequestId: number = 0;
|
|
91
108
|
#selectListLineOffset = 0;
|
|
92
|
-
#selectListLineCount = 0;
|
|
93
109
|
|
|
94
110
|
constructor(
|
|
95
111
|
title: string,
|
|
@@ -187,7 +203,6 @@ class SelectSubmenu extends Container {
|
|
|
187
203
|
const childLines = child.render(Math.max(1, width));
|
|
188
204
|
if (child === this.#selectList) {
|
|
189
205
|
this.#selectListLineOffset = lines.length;
|
|
190
|
-
this.#selectListLineCount = childLines.length;
|
|
191
206
|
}
|
|
192
207
|
lines.push(...childLines);
|
|
193
208
|
}
|
|
@@ -196,20 +211,7 @@ class SelectSubmenu extends Container {
|
|
|
196
211
|
|
|
197
212
|
/** Mouse routed from the host: wheel steps, hover lights, click confirms. */
|
|
198
213
|
routeMouse(event: SgrMouseEvent, line: number, _col: number): void {
|
|
199
|
-
|
|
200
|
-
this.#selectList.handleWheel(event.wheel);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
const listLine = line - this.#selectListLineOffset;
|
|
204
|
-
const within = listLine >= 0 && listLine < this.#selectListLineCount;
|
|
205
|
-
const index = within ? this.#selectList.hitTest(listLine) : undefined;
|
|
206
|
-
if (event.motion) {
|
|
207
|
-
this.#selectList.setHoverIndex(index ?? null);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
if (event.leftClick && index !== undefined) {
|
|
211
|
-
this.#selectList.clickItem(index);
|
|
212
|
-
}
|
|
214
|
+
routeSelectListMouse(this.#selectList, event, line - this.#selectListLineOffset);
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
handleInput(data: string): void {
|
|
@@ -217,6 +219,113 @@ class SelectSubmenu extends Container {
|
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
class ProviderLimitsSubmenu extends Container {
|
|
223
|
+
#selectList: SelectList | undefined;
|
|
224
|
+
|
|
225
|
+
constructor(
|
|
226
|
+
private readonly providers: readonly string[],
|
|
227
|
+
private readonly onChange: (value: Record<string, number>) => void,
|
|
228
|
+
private readonly onCancel: () => void,
|
|
229
|
+
private readonly requestRender?: () => void,
|
|
230
|
+
) {
|
|
231
|
+
super();
|
|
232
|
+
this.#showProviderList();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
#providerIds(): string[] {
|
|
236
|
+
const limits = normalizeProviderMaxInFlightRequests(settings.get("providers.maxInFlightRequests"));
|
|
237
|
+
return [...new Set([...this.providers, ...Object.keys(limits)])].sort((a, b) => a.localeCompare(b));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
#showProviderList(): void {
|
|
241
|
+
this.clear();
|
|
242
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Max In-Flight Requests")), 0, 0));
|
|
243
|
+
this.addChild(new Spacer(1));
|
|
244
|
+
this.addChild(
|
|
245
|
+
new Text(
|
|
246
|
+
theme.fg(
|
|
247
|
+
"muted",
|
|
248
|
+
"Select a provider, enter a positive number to cap concurrent LLM requests, or clear it for unlimited.",
|
|
249
|
+
),
|
|
250
|
+
0,
|
|
251
|
+
0,
|
|
252
|
+
),
|
|
253
|
+
);
|
|
254
|
+
this.addChild(new Spacer(1));
|
|
255
|
+
|
|
256
|
+
const limits = normalizeProviderMaxInFlightRequests(settings.get("providers.maxInFlightRequests"));
|
|
257
|
+
const providerItems = this.#providerIds().map((provider): SelectItem => {
|
|
258
|
+
const limit = limits[provider];
|
|
259
|
+
return {
|
|
260
|
+
value: provider,
|
|
261
|
+
label: provider,
|
|
262
|
+
description: limit === undefined ? "Unlimited" : `Limit: ${limit}`,
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
const clearItem: SelectItem[] =
|
|
266
|
+
Object.keys(limits).length === 0
|
|
267
|
+
? []
|
|
268
|
+
: [{ value: "__clear_all", label: "Clear all limits", description: "Make every provider unlimited" }];
|
|
269
|
+
const items = [...providerItems, ...clearItem];
|
|
270
|
+
this.#selectList = new SelectList(items, Math.min(Math.max(items.length, 1), 12), getSelectListTheme());
|
|
271
|
+
this.#selectList.onSelect = item => {
|
|
272
|
+
if (item.value === "__clear_all") {
|
|
273
|
+
settings.set("providers.maxInFlightRequests", {});
|
|
274
|
+
this.onChange({});
|
|
275
|
+
this.#showProviderList();
|
|
276
|
+
this.requestRender?.();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
this.#showProviderEditor(item.value);
|
|
280
|
+
};
|
|
281
|
+
this.#selectList.onCancel = this.onCancel;
|
|
282
|
+
this.addChild(this.#selectList);
|
|
283
|
+
this.addChild(new Spacer(1));
|
|
284
|
+
this.addChild(new Text(theme.fg("dim", " Enter to edit provider · Esc to go back"), 0, 0));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
#showProviderEditor(provider: string): void {
|
|
288
|
+
const limits = normalizeProviderMaxInFlightRequests(settings.get("providers.maxInFlightRequests"));
|
|
289
|
+
this.clear();
|
|
290
|
+
this.#selectList = undefined;
|
|
291
|
+
this.addChild(
|
|
292
|
+
new TextInputSubmenu(
|
|
293
|
+
`Max In-Flight Requests: ${provider}`,
|
|
294
|
+
"Enter a positive number. Decimals round down. Clear the field to make this provider unlimited.",
|
|
295
|
+
limits[provider]?.toString() ?? "",
|
|
296
|
+
value => {
|
|
297
|
+
const next = { ...limits };
|
|
298
|
+
const trimmed = value.trim();
|
|
299
|
+
if (trimmed === "") {
|
|
300
|
+
delete next[provider];
|
|
301
|
+
} else {
|
|
302
|
+
const limit = Number(trimmed);
|
|
303
|
+
if (!Number.isFinite(limit) || limit <= 0) throw new Error("Limit must be a positive number.");
|
|
304
|
+
next[provider] = Math.max(1, Math.floor(limit));
|
|
305
|
+
}
|
|
306
|
+
const normalized = validateProviderMaxInFlightRequests(next);
|
|
307
|
+
settings.set("providers.maxInFlightRequests", normalized);
|
|
308
|
+
this.onChange(normalized);
|
|
309
|
+
this.#showProviderList();
|
|
310
|
+
this.requestRender?.();
|
|
311
|
+
},
|
|
312
|
+
() => {
|
|
313
|
+
this.#showProviderList();
|
|
314
|
+
this.requestRender?.();
|
|
315
|
+
},
|
|
316
|
+
),
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
handleInput(data: string): void {
|
|
321
|
+
if (this.#selectList) {
|
|
322
|
+
this.#selectList.handleInput(data);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
this.children[0]?.handleInput?.(data);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
220
329
|
let cachedSidebarWidth: number | undefined;
|
|
221
330
|
/**
|
|
222
331
|
* Split-sidebar width derived from every group name in the schema (not just
|
|
@@ -258,6 +367,8 @@ export interface SettingsRuntimeContext {
|
|
|
258
367
|
thinkingLevel: ThinkingLevel | undefined;
|
|
259
368
|
/** Available themes */
|
|
260
369
|
availableThemes: string[];
|
|
370
|
+
/** Provider/source ids shown in /model. */
|
|
371
|
+
providers: string[];
|
|
261
372
|
/** Working directory for plugins tab */
|
|
262
373
|
cwd: string;
|
|
263
374
|
/** Active model (api + id); resolves what the snapcompact `auto` shape maps to. */
|
|
@@ -458,12 +569,14 @@ export class SettingsSelectorComponent implements Component {
|
|
|
458
569
|
* activates it (toggle / open submenu).
|
|
459
570
|
*/
|
|
460
571
|
#handleMouse(data: string): boolean {
|
|
461
|
-
|
|
462
|
-
|
|
572
|
+
return routeSgrMouseInput(data, event => this.#routeMouseEvent(event));
|
|
573
|
+
}
|
|
463
574
|
|
|
575
|
+
#routeMouseEvent(event: SgrMouseEvent): boolean {
|
|
464
576
|
const list = this.#searchList ?? this.#currentList;
|
|
465
|
-
// row() insets content by
|
|
466
|
-
const
|
|
577
|
+
// row() insets content by the border column plus a space.
|
|
578
|
+
const contentColInset = 2;
|
|
579
|
+
const innerCol = event.col - contentColInset;
|
|
467
580
|
const contentLine = event.row - this.#contentRowStart;
|
|
468
581
|
|
|
469
582
|
// An open submenu owns the pointer: wheel, hover, and clicks route into
|
|
@@ -723,10 +836,20 @@ export class SettingsSelectorComponent implements Component {
|
|
|
723
836
|
id: def.path,
|
|
724
837
|
label: def.label,
|
|
725
838
|
description: def.description,
|
|
726
|
-
currentValue:
|
|
839
|
+
currentValue: this.#formatTextInputValue(def.path, currentValue),
|
|
727
840
|
submenu: (cv, done) => this.#createTextInput(def, cv, done),
|
|
728
841
|
changed,
|
|
729
842
|
};
|
|
843
|
+
|
|
844
|
+
case "providerLimits":
|
|
845
|
+
return {
|
|
846
|
+
id: def.path,
|
|
847
|
+
label: def.label,
|
|
848
|
+
description: def.description,
|
|
849
|
+
currentValue: this.#formatProviderLimitsValue(currentValue),
|
|
850
|
+
submenu: (_cv, done) => this.#createProviderLimitsInput(done),
|
|
851
|
+
changed,
|
|
852
|
+
};
|
|
730
853
|
}
|
|
731
854
|
}
|
|
732
855
|
|
|
@@ -856,7 +979,7 @@ export class SettingsSelectorComponent implements Component {
|
|
|
856
979
|
*/
|
|
857
980
|
#createTextInput(
|
|
858
981
|
def: SettingDef & { type: "text" },
|
|
859
|
-
|
|
982
|
+
_currentValue: string,
|
|
860
983
|
done: (value?: string) => void,
|
|
861
984
|
): Container {
|
|
862
985
|
this.#textInputActive = true;
|
|
@@ -867,28 +990,72 @@ export class SettingsSelectorComponent implements Component {
|
|
|
867
990
|
return new TextInputSubmenu(
|
|
868
991
|
def.label,
|
|
869
992
|
def.description,
|
|
870
|
-
|
|
993
|
+
this.#formatTextInputEditValue(def.path, settings.get(def.path)),
|
|
871
994
|
value => {
|
|
872
995
|
// Empty string clears the setting; undefined-typed string settings
|
|
873
996
|
// store "" which the browser.ts expandPath ignores (no-op fallback).
|
|
874
997
|
this.#setSettingValue(def.path, value);
|
|
875
|
-
this.callbacks.onChange(def.path,
|
|
876
|
-
wrappedDone(
|
|
998
|
+
this.callbacks.onChange(def.path, settings.get(def.path));
|
|
999
|
+
wrappedDone(this.#formatTextInputValue(def.path, settings.get(def.path)));
|
|
877
1000
|
},
|
|
878
1001
|
() => wrappedDone(),
|
|
879
1002
|
);
|
|
880
1003
|
}
|
|
881
1004
|
|
|
1005
|
+
#createProviderLimitsInput(done: (value?: string) => void): Container {
|
|
1006
|
+
return new ProviderLimitsSubmenu(
|
|
1007
|
+
this.context.providers,
|
|
1008
|
+
value => {
|
|
1009
|
+
this.callbacks.onChange("providers.maxInFlightRequests", value);
|
|
1010
|
+
done(this.#formatProviderLimitsValue(value));
|
|
1011
|
+
},
|
|
1012
|
+
() => done(),
|
|
1013
|
+
this.context.requestRender,
|
|
1014
|
+
);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
#formatProviderLimitsValue(value: unknown): string {
|
|
1018
|
+
const limits = normalizeProviderMaxInFlightRequests(value);
|
|
1019
|
+
const entries = Object.entries(limits).sort(([a], [b]) => a.localeCompare(b));
|
|
1020
|
+
if (entries.length === 0) return "Unlimited";
|
|
1021
|
+
return entries.map(([provider, limit]) => `${provider}: ${limit}`).join(", ");
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
#formatTextInputValue(path: SettingPath, value: unknown): string {
|
|
1025
|
+
if (path === "providers.maxInFlightRequests") return this.#formatProviderLimitsValue(value);
|
|
1026
|
+
return this.#formatTextInputEditValue(path, value);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
#formatTextInputEditValue(_path: SettingPath, value: unknown): string {
|
|
1030
|
+
if (value === undefined || value === null) return "";
|
|
1031
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1032
|
+
return String(value);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
882
1035
|
/**
|
|
883
1036
|
* Set a setting value, handling type conversion.
|
|
884
1037
|
*/
|
|
885
1038
|
#setSettingValue(path: SettingPath, value: string): void {
|
|
886
|
-
// Handle number conversions
|
|
887
1039
|
const currentValue = settings.get(path);
|
|
1040
|
+
const schemaType = getType(path);
|
|
888
1041
|
if (path === "compaction.thresholdPercent" && value === "default") {
|
|
889
1042
|
settings.set(path, -1 as never);
|
|
890
1043
|
} else if (path === "compaction.thresholdTokens" && value === "default") {
|
|
891
1044
|
settings.set(path, -1 as never);
|
|
1045
|
+
} else if (schemaType === "record") {
|
|
1046
|
+
let parsed: unknown;
|
|
1047
|
+
try {
|
|
1048
|
+
parsed = JSON.parse(value || "{}");
|
|
1049
|
+
} catch {
|
|
1050
|
+
throw new Error(`Invalid record JSON for ${path}`);
|
|
1051
|
+
}
|
|
1052
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1053
|
+
throw new Error(`Invalid record JSON for ${path}`);
|
|
1054
|
+
}
|
|
1055
|
+
if (path === "providers.maxInFlightRequests") {
|
|
1056
|
+
parsed = validateProviderMaxInFlightRequests(parsed);
|
|
1057
|
+
}
|
|
1058
|
+
settings.set(path, parsed as never);
|
|
892
1059
|
} else if (typeof currentValue === "number") {
|
|
893
1060
|
settings.set(path, Number(value) as never);
|
|
894
1061
|
} else if (typeof currentValue === "boolean") {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Container, type SelectItem, SelectList } from "@oh-my-pi/pi-tui";
|
|
1
|
+
import { Container, type SelectItem, SelectList, type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import { getSelectListTheme } from "../../modes/theme/theme";
|
|
3
3
|
import { DynamicBorder } from "./dynamic-border";
|
|
4
|
+
import { routeSelectListMouseWithTopBorder } from "./select-list-mouse-routing";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Component that renders a show images selector with borders
|
|
@@ -42,4 +43,8 @@ export class ShowImagesSelectorComponent extends Container {
|
|
|
42
43
|
getSelectList(): SelectList {
|
|
43
44
|
return this.#selectList;
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
routeMouse(event: SgrMouseEvent, line: number, col: number): void {
|
|
48
|
+
routeSelectListMouseWithTopBorder(this.#selectList, event, line, col);
|
|
49
|
+
}
|
|
45
50
|
}
|