@oh-my-pi/pi-tui 18.3.4 → 18.4.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
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.4.0] - 2026-09-28
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Prevented interrupted wait operations from appearing in the transcript when a queued completion or message is received.
|
|
10
|
+
|
|
11
|
+
## [18.3.5] - 2026-09-27
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added an "OpenAI API" option to the setup wizard's web-search step; the existing ChatGPT-OAuth option is now labeled "OpenAI Codex" ([#13467](https://github.com/can1357/oh-my-pi/pull/13467) by [@anatoli-tsinovoy](https://github.com/anatoli-tsinovoy)).
|
|
16
|
+
|
|
5
17
|
## [18.3.3] - 2026-09-27
|
|
6
18
|
|
|
7
19
|
### Added
|
|
@@ -60,8 +60,12 @@ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
|
|
|
60
60
|
readonly description: "Claude's native web_search tool (uses Anthropic OAuth or ANTHROPIC_API_KEY)";
|
|
61
61
|
}, {
|
|
62
62
|
readonly value: "codex";
|
|
63
|
-
readonly label: "OpenAI";
|
|
63
|
+
readonly label: "OpenAI Codex";
|
|
64
64
|
readonly description: "OpenAI's native web_search (uses ChatGPT OAuth via /login openai-codex)";
|
|
65
|
+
}, {
|
|
66
|
+
readonly value: "openai";
|
|
67
|
+
readonly label: "OpenAI API";
|
|
68
|
+
readonly description: "OpenAI hosted web_search via OPENAI_API_KEY or OpenAI API-key registry credentials; billed by API usage";
|
|
65
69
|
}, {
|
|
66
70
|
readonly value: "xai";
|
|
67
71
|
readonly label: "xAI";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "18.
|
|
4
|
+
"version": "18.4.0",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"gen:glyphs": "bun scripts/gen-glyphs.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@oh-my-pi/omptype": "18.
|
|
45
|
-
"@oh-my-pi/pi-agent-core": "18.
|
|
46
|
-
"@oh-my-pi/pi-ai": "18.
|
|
47
|
-
"@oh-my-pi/pi-catalog": "18.
|
|
48
|
-
"@oh-my-pi/pi-natives": "18.
|
|
49
|
-
"@oh-my-pi/pi-utils": "18.
|
|
50
|
-
"@oh-my-pi/pi-wire": "18.
|
|
51
|
-
"@oh-my-pi/snapcompact": "18.
|
|
44
|
+
"@oh-my-pi/omptype": "18.4.0",
|
|
45
|
+
"@oh-my-pi/pi-agent-core": "18.4.0",
|
|
46
|
+
"@oh-my-pi/pi-ai": "18.4.0",
|
|
47
|
+
"@oh-my-pi/pi-catalog": "18.4.0",
|
|
48
|
+
"@oh-my-pi/pi-natives": "18.4.0",
|
|
49
|
+
"@oh-my-pi/pi-utils": "18.4.0",
|
|
50
|
+
"@oh-my-pi/pi-wire": "18.4.0",
|
|
51
|
+
"@oh-my-pi/snapcompact": "18.4.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -840,7 +840,9 @@ export class ToolExecutionComponent extends Container {
|
|
|
840
840
|
}
|
|
841
841
|
|
|
842
842
|
override render(width: number): readonly string[] {
|
|
843
|
-
if (!this.#toolActivityVisible || this.#allocation === 0)
|
|
843
|
+
if (!this.#toolActivityVisible || this.#allocation === 0 || (this.#toolName === "wait" && this.#isBenignSkip())) {
|
|
844
|
+
return [];
|
|
845
|
+
}
|
|
844
846
|
let lines = super.render(width);
|
|
845
847
|
if (this.#allocation < 3) {
|
|
846
848
|
// A squeezed allocation degrades only blocks that genuinely overflow it.
|
|
@@ -929,6 +931,12 @@ export class ToolExecutionComponent extends Container {
|
|
|
929
931
|
this.#renderState.executionStarted = this.#executionStarted;
|
|
930
932
|
this.#renderState.spinnerFrame = this.#spinnerFrame;
|
|
931
933
|
|
|
934
|
+
// Interrupted waits carry only model-facing retry guidance, not user-facing output.
|
|
935
|
+
if (this.#toolName === "wait" && this.#isBenignSkip()) {
|
|
936
|
+
this.#contentBox.clear();
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
|
|
932
940
|
// Non-self-framing tools (custom/extension renderers and the generic
|
|
933
941
|
// fallback) get a padded, state-tinted block — built-ins that draw their
|
|
934
942
|
// own frame opt out below via the framed-component mark. A benign skip
|
|
@@ -9,6 +9,7 @@ import * as os from "node:os";
|
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
11
11
|
import type { Ellipsis } from "@oh-my-pi/pi-natives";
|
|
12
|
+
import { expandWindowsLongPath, getWindowsShortPath } from "@oh-my-pi/pi-natives/path";
|
|
12
13
|
import { pluralize, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
13
14
|
import { formatKeyHint, type KeyId } from "../app-keybindings";
|
|
14
15
|
import { getKeybindings } from "../keybindings";
|
|
@@ -876,22 +877,45 @@ function defaultHomeDir(): string {
|
|
|
876
877
|
return cachedHomeDir;
|
|
877
878
|
}
|
|
878
879
|
|
|
879
|
-
|
|
880
|
-
|
|
880
|
+
interface HomePattern {
|
|
881
|
+
leading: RegExp;
|
|
882
|
+
embedded: RegExp;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const homePatternCache = new Map<string, HomePattern>();
|
|
886
|
+
function homePatternFor(homeDir: string, windowsStyle: boolean): HomePattern {
|
|
881
887
|
const key = `${windowsStyle ? 1 : 0} ${homeDir}`;
|
|
882
888
|
let pattern = homePatternCache.get(key);
|
|
883
889
|
if (pattern === undefined) {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
890
|
+
// A trailing separator (`C:\Users\me\`, `/home/me/`) must still match `<home>/child`;
|
|
891
|
+
// roots such as `/` and `C:\` keep theirs.
|
|
892
|
+
const home = homeDir.replace(/(?<=[^\\/:])[\\/]+$/, "");
|
|
893
|
+
let escapedHome = RegExp.escape(home);
|
|
894
|
+
if (windowsStyle) {
|
|
895
|
+
// Query only home, once per cached pattern: descendants need not exist,
|
|
896
|
+
// and rendering must neither resolve junctions nor probe output paths.
|
|
897
|
+
const parts = home.replaceAll("/", "\\").split("\\");
|
|
898
|
+
const longHome = expandWindowsLongPath(home);
|
|
899
|
+
const aliases = [longHome, getWindowsShortPath(longHome)]
|
|
900
|
+
.map(alias => alias.replaceAll("/", "\\").split("\\"))
|
|
901
|
+
.filter(alias => alias.length === parts.length);
|
|
902
|
+
escapedHome = parts
|
|
903
|
+
.map((part, index) => {
|
|
904
|
+
// Each component may independently use its long or short spelling.
|
|
905
|
+
const names = [...new Set([part, ...aliases.map(alias => alias[index]!)])].map(name =>
|
|
906
|
+
RegExp.escape(name),
|
|
907
|
+
);
|
|
908
|
+
return names.length === 1 ? names[0]! : `(?:${names.join("|")})`;
|
|
909
|
+
})
|
|
910
|
+
.join("[\\\\/]");
|
|
911
|
+
}
|
|
912
|
+
pattern = {
|
|
913
|
+
leading: new RegExp(`^${escapedHome}(?=$|[\\\\/])`, windowsStyle ? "i" : ""),
|
|
914
|
+
embedded: new RegExp(
|
|
915
|
+
`[a-zA-Z][a-zA-Z0-9+.-]*://[^\\s"'<>]+|(^|[\\s"'\\x60([{=,:])(${escapedHome})(?=$|[\\\\/\\s"'\\x60)\\]},;:])`,
|
|
916
|
+
windowsStyle ? "gi" : "g",
|
|
917
|
+
),
|
|
918
|
+
};
|
|
895
919
|
if (homePatternCache.size >= 16) homePatternCache.clear();
|
|
896
920
|
homePatternCache.set(key, pattern);
|
|
897
921
|
}
|
|
@@ -904,15 +928,12 @@ export function shortenPath(filePath: unknown, homeDir?: string): string {
|
|
|
904
928
|
return "";
|
|
905
929
|
}
|
|
906
930
|
const home = homeDir ?? defaultHomeDir();
|
|
931
|
+
if (!home) return filePath;
|
|
907
932
|
const windowsStyle = /^[A-Za-z]:[\\/]/.test(home) || home.startsWith("\\\\");
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
const suffix = filePath.slice(home.length);
|
|
913
|
-
if (suffix === "" || suffix.startsWith(path.posix.sep) || suffix.startsWith(path.win32.sep)) {
|
|
914
|
-
return `~${suffix.replaceAll(path.win32.sep, path.posix.sep)}`;
|
|
915
|
-
}
|
|
933
|
+
const match = homePatternFor(home, windowsStyle).leading.exec(filePath);
|
|
934
|
+
if (match) {
|
|
935
|
+
const suffix = filePath.slice(match[0].length);
|
|
936
|
+
return `~${suffix.replaceAll(path.win32.sep, path.posix.sep)}`;
|
|
916
937
|
}
|
|
917
938
|
return filePath;
|
|
918
939
|
}
|
|
@@ -924,7 +945,7 @@ export function shortenEmbeddedPaths(text: string, homeDir?: string, preserveSep
|
|
|
924
945
|
const windowsStyle = /^[A-Za-z]:[\\/]/.test(resolvedHome) || resolvedHome.startsWith("\\\\");
|
|
925
946
|
const homePattern = homePatternFor(resolvedHome, windowsStyle);
|
|
926
947
|
const textWithShortenedHome = text.replace(
|
|
927
|
-
homePattern,
|
|
948
|
+
homePattern.embedded,
|
|
928
949
|
(match, boundary: string | undefined, candidate: string | undefined) =>
|
|
929
950
|
candidate === undefined ? match : `${boundary}~`,
|
|
930
951
|
);
|
package/src/tools/web-search.ts
CHANGED
|
@@ -281,9 +281,15 @@ export const SEARCH_PROVIDER_OPTIONS = [
|
|
|
281
281
|
},
|
|
282
282
|
{
|
|
283
283
|
value: "codex",
|
|
284
|
-
label: "OpenAI",
|
|
284
|
+
label: "OpenAI Codex",
|
|
285
285
|
description: "OpenAI's native web_search (uses ChatGPT OAuth via /login openai-codex)",
|
|
286
286
|
},
|
|
287
|
+
{
|
|
288
|
+
value: "openai",
|
|
289
|
+
label: "OpenAI API",
|
|
290
|
+
description:
|
|
291
|
+
"OpenAI hosted web_search via OPENAI_API_KEY or OpenAI API-key registry credentials; billed by API usage",
|
|
292
|
+
},
|
|
287
293
|
{
|
|
288
294
|
value: "xai",
|
|
289
295
|
label: "xAI",
|