Compare commits

...
Author SHA1 Message Date
Aiden Cline c27aaee47b feat(core): fold unicode spaces in tool paths 2026-08-27 13:44:23 -05:00
2 changed files with 22 additions and 7 deletions
+12 -7
View File
@@ -58,16 +58,21 @@ export interface Interface {
readonly resolve: (input: ResolveInput) => Effect.Effect<Target, FSUtil.Error>
}
/** Lexical absolute path, expanding a leading `~` before resolving against `directory`. */
export const resolvePath = (directory: string, input: string, home = Global.Path.home) =>
path.resolve(
/** Unicode space separators that copy/paste as ordinary spaces in paths. */
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g
/** Lexical absolute path, folding Unicode spaces and expanding a leading `~`. */
export const resolvePath = (directory: string, input: string, home = Global.Path.home) => {
const normalized = input.replace(UNICODE_SPACES, " ")
return path.resolve(
directory,
input === "~"
normalized === "~"
? home
: input.startsWith("~/") || (process.platform === "win32" && input.startsWith("~\\"))
? path.join(home, input.slice(2))
: input,
: normalized.startsWith("~/") || (process.platform === "win32" && normalized.startsWith("~\\"))
? path.join(home, normalized.slice(2))
: normalized,
)
}
export class Service extends Context.Service<Service, Interface>()("@opencode/LocationMutation") {}
@@ -210,6 +210,16 @@ describe("LocationMutation", () => {
)
})
test("folds Unicode spaces in paths to ASCII spaces", () => {
expect(LocationMutation.resolvePath("/project", "file\u00A0name.txt")).toBe(path.resolve("/project", "file name.txt"))
expect(LocationMutation.resolvePath("/project", "Screenshot at 10.00.00\u202FAM.png")).toBe(
path.resolve("/project", "Screenshot at 10.00.00 AM.png"),
)
expect(LocationMutation.resolvePath("/project", "docs\u3000readme.md")).toBe(
path.resolve("/project", "docs readme.md"),
)
})
it.live("resolves a tilde path as an external home target", () =>
withTmp((directory) =>
Effect.gen(function* () {