Files
airship/packages
Nayan b60eabfc7c fix(core): give paths and line endings one identity across platforms
Four features key on a path — `--safe` containment, DiffCapture's before/after
map, the history store's per-repo directory, and the editor handler's
containment check — and each canonicalized differently, or not at all. They now
share ./paths.

`realpathSync` was never enough on Windows: it resolves links while preserving
whatever spelling the caller passed, and Windows filesystems are
case-insensitive, so `C:\Proj` and `c:\proj` compared unequal. Drive-letter
case alone triggers it — process.cwd() upper-cases it while `--cwd c:/proj`
does not. `realpathSync.native` canonicalizes case through
GetFinalPathNameByHandle. The failures were all quiet: `--safe` refusing edits
inside the project, DiffCapture attributing the user's own uncommitted work to
the agent and undoing it with the turn.

isPathInside also appended a separator to a root that already ended in one, so
a project at a filesystem root matched nothing at all. repoDir keeps a
read-only fallback to the pre-canonicalization directory, or existing history
would vanish on upgrade for anyone whose project is reached through a symlink.

Line endings get the same treatment in DiffCapture. With core.autocrlf=true the
working tree is CRLF while every agent's edit tool writes LF — and the HEAD
blob the Codex path reads back is LF too — so a one-line edit diffed as a
whole-file rewrite with garbage counts and review comments anchored to the
wrong lines. A leading BOM, which Visual Studio writes and edit tools drop, did
the same to the first line. Both are flattened for comparison and diffing only;
FileDiff.before/after keep the bytes on disk, because restoreFiles writes
`before` back verbatim and undo has to round-trip exactly.

Paths leaving the filesystem are now forward-slashed: a git pathspec (where
backslash is wildmatch's escape character), the JSON an MCP tool returns (where
each backslash arrives doubled), and the overlay's display labels.

The `--safe` command screen was POSIX-shell shaped throughout, so on Windows it
was a no-op while the launch banner still said it was on. Each added pattern
names the flags the real command takes rather than matching the verb loosely —
a bare /\bdel\s+\// fires on `sed -i 's/del /x/'`, and a false deny is not free.
2026-08-11 23:11:29 +05:30
..