Skip to content

fix: portable paths in extra-manifest for cross-platform sync - #58

Merged
iHildy merged 5 commits into
iHildy:mainfrom
khangnghiem:fix/portable-extra-manifest-paths
Aug 31, 2026
Merged

fix: portable paths in extra-manifest for cross-platform sync#58
iHildy merged 5 commits into
iHildy:mainfrom
khangnghiem:fix/portable-extra-manifest-paths

Conversation

@khangnghiem

@khangnghiem khangnghiem commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Problem

extra-manifest.json stored absolute sourcePath values from the machine that pushed. A second machine with a different home or OpenCode config root could not match those paths against its local allowlist, so configured extra files were skipped.

This PR is intentionally separate from #72. PR #72 changes how relative extraConfigPaths and extraSecretPaths are interpreted in local configuration. This PR only makes manifest paths portable after the sync plan has resolved them.

Fix

  • Store paths inside the OpenCode config root as canonical /-separated relative paths.
  • Store config-root equality as . rather than an empty string.
  • Store paths elsewhere in the home as ~/....
  • Preserve external absolute paths for backward compatibility.
  • Recognize POSIX, Windows drive-letter, and UNC absolute paths regardless of the reader OS.
  • Compare Windows config and home roots case-insensitively.
  • Canonicalize manifest repoPath and directory item separators.
  • Accept legacy Windows separators while reading.
  • Ignore manifest repository paths that resolve outside the sync checkout.
  • Remove the unrelated package-lock.json.

Existing allowlist enforcement is unchanged. A manifest entry is still applied only when its resolved local destination exactly matches a configured extra path.

Verification

  • bun run check
  • bun test: 127 passed, 0 failed
  • bun run build
  • Focused path/apply tests: 54 passed, 0 failed
  • Windows to POSIX two-home exercise: themes/night.json resolved into the POSIX config root
  • POSIX to Windows two-home exercise: themes/day.json resolved into the Windows APPDATA OpenCode config root
  • Full isolated two-instance GitHub E2E passed: init, first push, link, second push, and pull all completed; the ephemeral private repository was deleted

The E2E emitted the existing duplicate-sandbox-skill warning and the known warning that the running machine-B config tree was not hot-reloaded even though its local sync checkout contained the second sentinel. Neither warning is caused by this change.

Merge order

Merge #72 first, then update this branch from main. A synthetic merge shows the production code combines automatically; only the two appended test files need a mechanical conflict resolution. Keeping that order preserves the separate issue scopes while validating portable manifests on top of #72's local path resolution.

Before this fix, extra-manifest.json stored absolute sourcePath values
from the pushing machine (e.g. /Users/khangnghiem/.config/opencode/tui.json).
On a different machine with a different home directory, the allowlist
comparison would fail and files would be skipped during pull.

Now:
- writeExtraPathManifest stores sourcePath relative to configRoot
  when the path is inside configRoot (e.g. 'tui.json')
- For paths inside homeDir but outside configRoot, stores with ~/
  prefix (e.g. '~/.ssh/id_rsa')
- For paths outside both, keeps absolute as fallback
- applyExtraPaths resolves manifest sourcePaths against the local
  configRoot/homeDir, making pull work across machines and platforms

This also fixes Windows compatibility where ~/ expands to USERPROFILE
but opencode configDir uses APPDATA — relative paths resolve correctly
against the local configRoot regardless of platform.

SyncPlan now includes configRoot so it's available during pull.
14 new tests cover toPortablePath/fromPortablePath and cross-platform
round-trips (macOS→Linux, macOS→Windows).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces portable paths for sync manifests by adding toPortablePath and fromPortablePath functions and incorporating configRoot into the SyncPlan. The review feedback identifies significant cross-platform issues, particularly on Windows, regarding path separator consistency and case sensitivity. It is recommended to use POSIX separators for all portable paths and utilize path.relative to ensure robust path resolution across different operating systems.

Comment thread src/sync/paths.ts Outdated
Comment thread src/sync/paths.test.ts Outdated
Comment thread src/sync/paths.test.ts Outdated
@iHildy
iHildy merged commit 96836af into iHildy:main Aug 31, 2026
3 checks passed
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