fix(tool): strip leading colon before Windows path shapes
expandPath's leading-colon strip only fired before POSIX prefixes (`/`, `~/`, `./`, `../`), so Windows-mangled inputs like `:C:\repo\file` or `:.\src` slipped through and path.resolve treated them as relative children of cwd. The omp grep subcommand is the Windows grep path, so it hit the common Windows form of the same bug. Broaden the lookahead to admit `\` separators, `.\`/`..\` relatives, and drive-letter absolutes (`[A-Za-z]:`). Add expandPath regression tests for the Windows forms and the bare-token non-strip cases. Fixes #5624
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the `omp grep` CLI subcommand failing on paths with a stray leading colon (e.g. `:/abs/path`); it now routes the path argument through `expandPath` like `read`/`edit`/in-agent `grep` ([#5624](https://github.com/can1357/oh-my-pi/issues/5624)).
|
||||
- Fixed the `omp grep` CLI subcommand failing on paths with a stray leading colon (e.g. `:/abs/path`); it now routes the path argument through `expandPath` like `read`/`edit`/in-agent `grep`. Broadened `expandPath`'s leading-colon strip to also recover Windows-style shapes (`:C:\repo\file`, `:.\src`, `:..\rel`, `:\\server\share`) ([#5624](https://github.com/can1357/oh-my-pi/issues/5624)).
|
||||
|
||||
## [17.0.0] - 2026-07-15
|
||||
|
||||
|
||||
@@ -148,11 +148,14 @@ export function expandTilde(filePath: string, home?: string): string {
|
||||
|
||||
export function expandPath(filePath: string): string {
|
||||
// Some models intermittently prefix an otherwise-valid path with a stray
|
||||
// `:` (e.g. `:/abs/path`, `:../rel`). No real path starts with `:` and it
|
||||
// never begins a selector against an absolute/relative path, so strip it
|
||||
// before resolution — mirroring the `@`-prefix normalization above and the
|
||||
// implicit stripping `write` already tolerates (issue #5508).
|
||||
const deColoned = /^:(?=[/~]|\.\.?\/)/.test(filePath) ? filePath.slice(1) : filePath;
|
||||
// `:` (e.g. `:/abs/path`, `:../rel`, or the Windows forms `:C:\repo\file`
|
||||
// and `:.\src`). No real path starts with `:` and it never begins a
|
||||
// selector against an absolute/relative path, so strip it before
|
||||
// resolution — mirroring the `@`-prefix normalization above and the
|
||||
// implicit stripping `write` already tolerates (issues #5508, #5624). The
|
||||
// lookahead admits POSIX (`/`, `~`, `./`, `../`) and Windows (`\`, `.\`,
|
||||
// `..\`, drive-letter `C:`) path shapes.
|
||||
const deColoned = /^:(?=[/\\~]|\.\.?[/\\]|[A-Za-z]:)/.test(filePath) ? filePath.slice(1) : filePath;
|
||||
const normalized = stripWindowsExtendedLengthPathPrefix(
|
||||
stripFileUrl(normalizeUnicodeSpaces(normalizeAtPrefix(deColoned))),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config
|
||||
import { EditTool } from "@oh-my-pi/pi-coding-agent/edit";
|
||||
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
||||
import {
|
||||
expandPath,
|
||||
probeLiteralPathExists,
|
||||
resolveToCwd,
|
||||
splitPathAndSel,
|
||||
@@ -363,6 +364,23 @@ describe("leading-colon path recovery (issue #5508)", () => {
|
||||
expect(resolveToCwd(":name.txt", tmpDir)).toBe(path.join(tmpDir, ":name.txt"));
|
||||
});
|
||||
|
||||
it("strips a leading colon before Windows path shapes in expandPath (issue #5624)", () => {
|
||||
// Windows native paths mangled with a stray leading colon: drive-letter
|
||||
// absolutes and `\`/`.\`/`..\` relative forms. expandPath runs before any
|
||||
// path.resolve, so the strip is platform-independent.
|
||||
expect(expandPath(":C:\\repo\\file.ts")).toBe("C:\\repo\\file.ts");
|
||||
expect(expandPath(":.\\src")).toBe(".\\src");
|
||||
expect(expandPath(":..\\sibling")).toBe("..\\sibling");
|
||||
expect(expandPath(":\\\\server\\share")).toBe("\\\\server\\share");
|
||||
});
|
||||
|
||||
it("does not strip a colon before a bare drive letter without a path (expandPath)", () => {
|
||||
// `:selector` shapes still round-trip; the drive-letter branch requires
|
||||
// the `<letter>:` colon to follow, distinguishing `:C:\x` from `:cache`.
|
||||
expect(expandPath(":raw")).toBe(":raw");
|
||||
expect(expandPath(":cache")).toBe(":cache");
|
||||
});
|
||||
|
||||
it("read opens a file addressed with a leading colon", async () => {
|
||||
const abs = path.join(tmpDir, "colon-read.txt");
|
||||
await Bun.write(abs, "test line A\ntest line B\n");
|
||||
|
||||
Reference in New Issue
Block a user