Skip to content

feat(sync): resolve symlinked path prefixes to their real target - #74

Open
marioparaschiv wants to merge 6 commits into
tawanorg:mainfrom
marioparaschiv:feat/resolve-symlink-paths
Open

marioparaschiv wants to merge 6 commits into
tawanorg:mainfrom
marioparaschiv:feat/resolve-symlink-paths

Conversation

@marioparaschiv

@marioparaschiv marioparaschiv commented Jul 31, 2026 •

Copy link
Copy Markdown

Depends on #73 (merge that first).

Resolves symlinked path prefixes (HOME and path_map entries) to their real target, so sessions recorded through a symlink resume under the path claude --resume looks them up by.

Example: ~/Developer symlinked to ~/Documents/Projects. Sessions stored under Developer now resolve to Documents/Projects on pull.

Can be toggled off with resolve_symlinks: false in the config.

known_marketplaces.json and installed_plugins.json record absolute
install locations, but content translation only covered history.jsonl
and projects/, so a pull left them pointing at the pushing device and
Claude Code rejected the marketplace.

Both go through the path mapper now, decoded as JSON rather than
replaced as raw bytes: a Windows path is escaped in the file, so byte
replacement would eat an escape and leave the document invalid.
…ResolveFile

Fold the parallel JSON path API (NormalizeJSONContent/ResolveJSONContent,
IsPortableJSONPath, mapJSONStrings) into NormalizeFile/ResolveFile, which
pick JSON-aware vs byte translation internally. Call sites drop the two-way
branch and the ordering dependency between the two path predicates.

Also scope SplitConflictPath's marker match to the final path segment so a
parent directory containing ".conflict." no longer triggers a false match
or a wrong original path.
The JSON round-trip re-encoded with default settings, which HTML-escaped
&, < and > (mangling marketplace repo URLs) and widened integers via
float64 decoding. Decode with UseNumber and encode with SetEscapeHTML(false)
so only translated path prefixes change.
ResolveContent spliced local paths into session content with raw byte
replacement, producing invalid JSON escapes and mixed separators on
Windows (e.g. C:\Users\bob/foo). Route .jsonl (per line) and .json
content through JSON-aware translation so inserted paths stay escaped and
follow the local separator convention.
Claude Code records a session's cwd under the path the user cd'd through,
but `claude --resume` looks it up under the resolved real path. When a
mapped prefix (HOME or a path_map entry) is a symlink, sessions recorded
through it never matched on resume.

Resolve symlinks when building each mapping so the token maps to the real
path, and keep the unresolved spelling as an alias so paths recorded
through the symlink still normalize to the same token. A prefix absent on
a device is left unchanged so mapping never breaks.
Canonicalizing symlinked prefixes is not always wanted. Add a
resolve_symlinks config flag (default enabled) and thread it through
NewPathMapper so a device can keep the literal symlink path with
resolve_symlinks: false.
Copilot AI review requested due to automatic review settings July 31, 2026 07:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants