npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rnx-kit/fork-sync

v0.4.0

Published

EXPERIMENTAL - USE WITH CAUTION - Sync forked/vendored dependencies with upstream using AI-powered Git 3-way merge

Downloads

181

Readme

@rnx-kit/fork-sync

Build npm version

THIS TOOL IS EXPERIMENTAL — USE WITH CAUTION

Sync forked/vendored dependencies with upstream using Git's native 3-way merge. Preserves local modifications while incorporating upstream changes.

Two CLI Tools

  • fork-sync — Main sync tool. Clones upstream, creates a work branch with your local changes, merges the target upstream commit, and copies the result back.
  • ai-merge — AI-assisted Git mergetool. Parses conflict markers into hunks, sends each to an AI (Claude or Copilot) for resolution, validates confidence, and applies or skips.

Installation

npm install -g @rnx-kit/fork-sync

Usage

fork-sync

# Sync to latest upstream commit on the tracked branch
fork-sync --dep <name>

# Sync to a specific commit or tag
fork-sync --dep <name> --commit <sha>
fork-sync --dep <name> --tag v24.2.0

# Switch to a new upstream branch
fork-sync --dep <name> --branch v25.x

# Show sync status
fork-sync --dep <name> --status

# Continue after manual conflict resolution
fork-sync --dep <name> --continue

# Abort an in-progress sync
fork-sync --dep <name> --abort

# Run AI merge on all conflicted files (default)
fork-sync --dep <name> --mergetool ai

# Use git's built-in mergetool instead
fork-sync --dep <name> --mergetool git

# Clean cached upstream clone
fork-sync --dep <name> --clean --no-sync

ai-merge

Designed to integrate with Git's mergetool system:

ai-merge --base $BASE --local $LOCAL --remote $REMOTE --merged $MERGED

Configuration

sync-manifest.json

The manifest file defines which dependencies to sync and how AI merge should behave. Place it in the repository root (or specify with --manifest). fork-sync searches from the current directory upward until it finds the file or hits a .git boundary.

{
  "version": 1,
  "aiMerge": {
    "provider": "claude",
    "model": "haiku",
    "minConfidence": "MEDIUM"
  },
  "dependencies": [
    {
      "name": "hermes",
      "localPath": "."
    },
    {
      "name": "icu-small",
      "localPath": "external/icu-small"
    }
  ]
}

| Field | Description | | -------------------------- | ---------------------------------------------------------------------------------- | | version | Must be 1 | | aiMerge.provider | AI provider: "claude" or "copilot" | | aiMerge.model | Model name (optional, provider-specific) | | aiMerge.minConfidence | Minimum confidence to apply a hunk: "HIGH", "MEDIUM" (default), or "LOW" | | dependencies[].name | Unique name for the dependency (used in --dep flag) | | dependencies[].localPath | Path to the vendored copy, relative to the manifest. Use "." for full-repo forks |

sync-config.json

Each dependency needs a sync-config.json in its local directory (e.g., external/icu-small/sync-config.json). This file tells fork-sync where to fetch upstream code from and tracks the last synced commit. It is auto-updated after each successful sync.

{
  "repo": "https://github.com/nodejs/node",
  "branch": "main",
  "commit": "abc1234def5678...",
  "subDir": "deps/icu-small",
  "tag": "",
  "lastSync": "2025-06-15T10:30:00.000Z"
}

| Field | Description | | ---------- | -------------------------------------------------------------------------- | | repo | Full HTTPS URL of the upstream repository | | branch | Upstream branch to track | | commit | Last synced upstream commit hash (empty string for first sync) | | subDir | Subfolder within the upstream repo to sync (optional, omit for whole repo) | | tag | Tag name if synced to a tag (empty string otherwise) | | lastSync | ISO timestamp of last sync (empty string if never synced) |

Subfolder sync with subDir

When a dependency lives inside a larger upstream repository, set subDir to sync only that subfolder. For example, to vendor deps/icu-small/ from the Node.js repository into external/icu-small/:

{
  "repo": "https://github.com/nodejs/node",
  "branch": "main",
  "commit": "1bd7f62d139...",
  "subDir": "deps/icu-small"
}

When subDir is set:

  • Sparse checkout is configured automatically so only the subfolder is materialized on disk, avoiding the cost of checking out the entire upstream repo.
  • Path mapping strips the subDir prefix from upstream paths and the localPath prefix from local paths, producing a common relative path for file comparison and copying.
  • Git merge operates on the full commit graph and works correctly — only the subfolder has local modifications, so conflicts only arise there.

When subDir is omitted or empty, the entire upstream repo is synced (default behavior).

.syncignore

Place a .syncignore file in the dependency's local directory (e.g., external/icu-small/.syncignore) to exclude files and folders from sync. Uses standard .gitignore syntax.

# Exclude local-only build files
/CMakeLists.txt
/hermes_icu_glue.cpp

# Exclude local-only metadata
/sync-config.json
/.syncignore

Excluded files are not copied from upstream and are not deleted locally.

Anchored vs unanchored patterns

Patterns follow .gitignore rules. A leading / anchors the pattern to the directory where the .syncignore file is located:

| Pattern | Matches | Does not match | | ----------------- | ----------------------------- | -------------------- | | /CMakeLists.txt | CMakeLists.txt at the root | sub/CMakeLists.txt | | CMakeLists.txt | CMakeLists.txt at any depth | — | | /test/ | test/ directory at the root | sub/test/ |

Selective inclusion with negation (!)

To exclude most content and re-include specific parts, use negation patterns. Important: gitignore cannot re-include children of an excluded parent directory. Exclude the children, not the parent:

# WRONG — negation won't work because parent is excluded:
/test/
!/test/intl402/

# CORRECT — exclude children individually, then negate one:
/test/*/
!/test/intl402/

This is useful for large repos where you only need a subset. For example, to sync only test/intl402/ and harness/ from a test suite:

# Exclude repo infrastructure
/.github/
/docs/
/tools/
/package.json

# Exclude all test suites, re-include only intl402
/test/*/
!/test/intl402/

sync-instructions.md

Place sync-instructions.md files in any directory within the dependency to give the AI merge tool additional context about how conflicts should be resolved. These are collected from the repository root down to the directory of the file being merged (general to specific), and included in the AI prompt.

For example, with this directory structure:

deps/nodejs/
  sync-instructions.md          # General instructions for the whole dependency
  src/
    sync-instructions.md        # More specific instructions for src/
    node_api.cc                 # When merging this file, both files above apply

When resolving conflicts in src/node_api.cc, both instruction files are included — root-level first, then the more specific src/ one. Use these files to describe local conventions, intentional divergences from upstream, or domain-specific merge guidance.

Requirements

  • Node.js ^20.16.0 or >=22.4.0
  • Git
  • For AI merge: Claude CLI (claude) or GitHub Copilot CLI (copilot)