jachy-pi-git-sync

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

pi-git-sync

Sync Pi configuration across machines via a GitHub private repository.

npm

📖 中文文档


How It Works

pi-git-sync keeps your Pi configuration in a private Git repository and syncs it across all your machines. It uses a three-way comparison model based on a sync baseline to detect local changes, remote changes, and conflicts.

Key features:

  • Glob-based include/exclude whitelist — no manual per-file mappings needed
  • settings.json shared as a whole file — simple and predictable
  • Three-way diff with sync baseline — accurate detection of creates, deletes, and bilateral conflicts
  • Full push chain: capture → commit → fetch → rebase → push → apply
  • push --continue for resolving rebase conflicts mid-push
  • Config repo is a standalone Git repo, not a Pi Package
  • All synced content lives under a single sync/ directory

Usage

Prerequisites

  • Pi installed
  • Git + SSH configured (for GitHub)

1. Create an Empty Private Repo on GitHub

Create an empty private repo (any name you like). Do NOT check "Initialize with README".

2. Install pi-git-sync

pi install npm:@jachy/pi-git-sync

3. One-Click Init

In Pi, provide your repo URL. pi-git-sync will clone, scaffold the config structure, commit and push automatically.

/pisync init git@github.com:<your-username>/<your-repo>.git

Generated repo structure:

<your-repo>/
├── .gitignore
├── pi-sync.json              # Sync configuration
└── sync/                     # All synced content lives here
    ├── settings.json          # Shared settings (whole file)
    ├── AGENTS.md              # (optional)
    ├── SYSTEM.md              # (optional)
    ├── APPEND_SYSTEM.md       # (optional)
    ├── keybindings.json       # (optional)
    ├── extensions/            # Custom extensions
    ├── skills/                # Skills
    ├── prompts/               # Prompt templates
    └── themes/                # Themes

4. Capture Current Config

On first use, import your current local config into the repo:

/pisync capture

Then commit + push:

/pisync push

The push command combines capture → commit → fetch → rebase → push → apply in one step, with a confirmation prompt after showing you the diff.


Commands

Command Description
/pisync Interactive TUI menu
/pisync init [url] Initialize or clone a config repo (--force to rebuild)
/pisync status Show detailed sync status (three-way comparison + git info)
/pisync diff Show pending changes between agent and repo
/pisync pull Pull remote changes and apply to agent
/pisync push Capture, commit, and push local changes
/pisync push --continue Continue push after resolving rebase conflicts
/pisync capture Import local config changes into repo (no commit/push)
/pisync doctor Run diagnostic checks
/pisync rollback Rollback to last backup

What Gets Synced

Content Method
Extensions Copied from sync/extensions/ into agent directory
Skills Copied from sync/skills/ into agent directory
Prompts Copied from sync/prompts/ into agent directory
Themes Copied from sync/themes/ into agent directory
settings.json Whole-file copy (no key-level merge)
AGENTS.md, SYSTEM.md, APPEND_SYSTEM.md Copied into agent directory
keybindings.json Copied into agent directory
Third-party Packages Declared in sync/settings.jsonpackages[], auto-installed on apply (local-only packages are never auto-removed)

What Never Gets Synced

Hard deny list (built-in, not configurable):

auth.json, sessions/**, trust.json, models-store.json, npm/**, git/**, node_modules/**, .pi-sync/**, **/.env, **/*.pem, **/id_rsa, **/id_ed25519

Also: hidden files (except .gitignore) and symlinks are skipped.


Config Reference (pi-sync.json)

{
  "schemaVersion": 2,
  "branch": "main",
  "root": "sync",
  "include": [
    "settings.json",
    "AGENTS.md",
    "SYSTEM.md",
    "APPEND_SYSTEM.md",
    "keybindings.json",
    "extensions/**",
    "skills/**",
    "prompts/**",
    "themes/**"
  ],
  "exclude": [
    "**/.DS_Store",
    "**/*.tmp",
    "**/*.log"
  ],
  "delete": "tracked",
  "security": {
    "scanSecretsBeforePush": true
  }
}

Fields

Field Type Default Description
schemaVersion 2 Config schema version (currently 2)
branch string "main" Git branch to sync
root string "sync" Root directory inside the repo for synced content
include string[] Glob whitelist (relative to root). Supports *, **, ?
exclude string[] [] Glob patterns to exclude (lower priority than built-in hard deny)
delete "tracked" | "none" "tracked" "tracked": delete agent files when removed from repo. "none": never delete
security.scanSecretsBeforePush boolean true Scan staged files for secrets (API keys, tokens, private keys) before pushing

Sync Model

Three-Way Comparison

Every sync operation compares three states:

B = Baseline (last synced commit hash)  — stored in .pi-sync/state.json
L = Local   (current agent files)
R = Remote  (current repo sync/ files)

This gives accurate detection of:

Scenario Classification Action
Only you changed a file local_only Captured on push
Only remote changed a file remote_only Applied on pull
Both changed the same file differently both_modified Blocked — resolve manually
You created a new file local_created Captured on push
Remote created a new file remote_created Applied on pull
You deleted a tracked file local_deleted Captured on push
Remote deleted a tracked file remote_deleted Applied on pull (if delete: "tracked")
Both made the same change converged Baseline updated, no conflict

Push Flow

capture (agent → repo working tree)
  → commit
  → fetch origin
  → rebase onto origin/main
  → push
  → apply (new HEAD → agent)

If a rebase conflict occurs, the push pauses. Resolve conflicts with standard Git tools, then:

/pisync push --continue

Pull Flow

fetch origin
  → check for local un-captured changes (block if any)
  → fast-forward only (block if diverged)
  → apply (new HEAD → agent)

Safety

  • Pull uses fast-forward only; stops on divergence
  • Bilateral conflict detection — never silently overwrites both sides
  • Automatic secret scanning before push (API keys, tokens, private keys)
  • Atomic config writes (temp file → rename)
  • Automatic backup before every apply, with rollback support
  • Concurrency lock prevents multiple Pi instances from syncing simultaneously
  • Built-in hard deny list prevents syncing credentials (not user-overridable)
  • Settings.json portability validation — warns about absolute paths and machine-specific content

Development

Local Debugging

Symlink into Pi extensions directory:

ln -s $(pwd) ~/.pi/agent/extensions/pi-git-sync

Then /reload in Pi to pick up changes.

Or load temporarily via -e (does not write to settings.json):

pi -e ./index.ts

Run Tests

npm install
npm test           # single run
npm run test:watch # watch mode
npm run typecheck  # type check

Project Structure

pi-git-sync/
├── index.ts              # Extension entry point
├── package.json
├── tsconfig.json
├── scripts/
│   └── bootstrap.sh      # Bootstrap script for new machines
├── src/
│   ├── commands.ts        # /pisync command routing + push/pull/init flows
│   ├── config.ts          # pi-sync.json loading & validation
│   ├── git.ts             # Git operations (status, fetch, pull, push, rebase)
│   ├── inventory.ts       # Three-way file comparison (baseline vs local vs remote)
│   ├── materialize.ts     # Apply repo files to agent (atomic writes, validation)
│   ├── capture.ts         # Import agent changes into repo working tree
│   ├── backup.ts          # Backup & rollback
│   ├── lock.ts            # Concurrency lock (pid-based with staleness detection)
│   ├── security.ts        # Built-in hard deny list & secret scanning
│   ├── doctor.ts          # Environment diagnostics (git, ssh, portability)
│   ├── validate.ts        # File content validation (JSON, conflict markers, portability)
│   ├── state.ts           # Sync state persistence (baseline)
│   ├── packages.ts        # Package reconciliation (settings.json packages[])
│   ├── settings.ts        # Utility functions (deepMerge, deepEqual — legacy)
│   ├── glob.ts            # Custom minimatch glob + hard deny + path filtering
│   └── ui.ts              # Output formatting
└── test/
    ├── config.test.ts
    ├── git.test.ts
    ├── lock.test.ts
    ├── materialize.test.ts
    ├── minimatch.test.ts
    ├── packages.test.ts
    ├── security.test.ts
    └── settings.test.ts

Publishing

npm run pub        # patch version
npm run pub:minor  # minor version
npm run pub:major  # major version

Type checking and tests run automatically before publish. A git tag is created after publish.


License

MIT