pi-sync-cli 0.5.0__tar.gz → 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/AGENTS.md +63 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/DEVELOPMENT.md +47 -0
- pi_sync_cli-0.5.1/PKG-INFO +89 -0
- pi_sync_cli-0.5.1/README.md +72 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/pyproject.toml +1 -1
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/uv.lock +1 -1
- pi_sync_cli-0.5.0/PKG-INFO +0 -197
- pi_sync_cli-0.5.0/README.md +0 -180
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/.github/workflows/publish.yml +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/.gitignore +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/LICENSE +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/pyrightconfig.json +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/src/pi_sync/__init__.py +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/src/pi_sync/cli.py +0 -0
- {pi_sync_cli-0.5.0 → pi_sync_cli-0.5.1}/tests/test_cli.py +0 -0
|
@@ -60,3 +60,66 @@ uv run pi-sync --help
|
|
|
60
60
|
`.backup` is kept, but don't be cavalier about it.
|
|
61
61
|
- `~/.ssh/config` is protected: read it through code that extracts host aliases,
|
|
62
62
|
and don't dump its contents into output or a commit.
|
|
63
|
+
|
|
64
|
+
Kept out of the README: these describe *using* pi-sync rather than changing
|
|
65
|
+
it, and are collected here so the README stays a short front page.
|
|
66
|
+
|
|
67
|
+
## Hosts without pi
|
|
68
|
+
|
|
69
|
+
Each host is checked before syncing. If pi is missing, pi-sync offers to install
|
|
70
|
+
it — interactively, pi's installer takes over your terminal, and the sync
|
|
71
|
+
continues when it exits. `--install` does that unattended.
|
|
72
|
+
|
|
73
|
+
A host that still has no pi afterwards is skipped, and the run exits non-zero.
|
|
74
|
+
|
|
75
|
+
## Updating
|
|
76
|
+
|
|
77
|
+
- `pi-sync update` upgrades pi-sync itself, through whichever installer owns it
|
|
78
|
+
(`--check` reports without changing anything).
|
|
79
|
+
- `pi-sync --update-pi <hosts>` updates pi on the hosts before syncing.
|
|
80
|
+
|
|
81
|
+
## Uninstalling pi from a host
|
|
82
|
+
|
|
83
|
+
`pi-sync --uninstall <hosts>` removes pi and leaves your config in place. If it
|
|
84
|
+
fails, run `curl -fsSL https://pi.dev/install.sh | sh` on the host and choose
|
|
85
|
+
`u` instead.
|
|
86
|
+
|
|
87
|
+
## Shell completions
|
|
88
|
+
|
|
89
|
+
Host arguments complete from `~/.ssh/config`. zsh and fish also show where each
|
|
90
|
+
alias points:
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
$ pi-sync t<TAB>
|
|
94
|
+
tinfoil tinfoil@tinfoil.sayan.page
|
|
95
|
+
tinfoil-proxy notdebian@100.98.241.11
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# bash
|
|
100
|
+
_PI_SYNC_COMPLETE=bash_source pi-sync > ~/.pi-sync-complete.bash
|
|
101
|
+
echo 'source ~/.pi-sync-complete.bash' >> ~/.bashrc
|
|
102
|
+
|
|
103
|
+
# zsh
|
|
104
|
+
_PI_SYNC_COMPLETE=zsh_source pi-sync > ~/.pi-sync-complete.zsh
|
|
105
|
+
echo 'source ~/.pi-sync-complete.zsh' >> ~/.zshrc
|
|
106
|
+
|
|
107
|
+
# fish (config.fish)
|
|
108
|
+
_PI_SYNC_COMPLETE=fish_source pi-sync | source
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
PowerShell uses `powershell_source` the same way.
|
|
112
|
+
|
|
113
|
+
## Caveats
|
|
114
|
+
|
|
115
|
+
- `settings.json` is written by pi itself (`lastChangelogVersion` bumps, UI
|
|
116
|
+
toggles), so pushing it overwrites the host's local preferences — the previous
|
|
117
|
+
copy is kept as `settings.json.backup`. Sync it when you change `packages`.
|
|
118
|
+
- Extensions that keep runtime files in their own directory (logs, checkpoints)
|
|
119
|
+
get those files synced too, and whichever side pushes last wins. Exclude them
|
|
120
|
+
with `-x '*/logs/*'`.
|
|
121
|
+
- Extension versions are whatever each host has installed; pin them in
|
|
122
|
+
`settings.json` (`npm:pi-lens@1.2.3`) if you need hosts identical.
|
|
123
|
+
- `--auth` copies API keys in the clear. Prefer `OPENCODE_API_KEY` (and friends)
|
|
124
|
+
in the environment where you can.
|
|
125
|
+
- `--delete` disables backups for the mirrored directory.
|
|
@@ -25,6 +25,53 @@ Three design anchors worth understanding before editing:
|
|
|
25
25
|
An older install can coexist under the pre-rename name `pi-sync`, and a
|
|
26
26
|
hardcoded name would upgrade the wrong virtualenv — or nothing.
|
|
27
27
|
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
**One probe per host.** `probe_host` pipes a POSIX sh script through
|
|
31
|
+
`ssh host sh -s`, so reachability and pi's location cost a single round trip. It
|
|
32
|
+
checks `command -v pi` and then the usual install locations (`~/.local/bin`,
|
|
33
|
+
`~/.pi/bin`, `~/.pi/agent/bin`, linuxbrew, homebrew, `/usr/local/bin`) because a
|
|
34
|
+
non-interactive ssh session does not source the host's shell init — on a
|
|
35
|
+
linuxbrew host `command -v pi` alone finds nothing.
|
|
36
|
+
|
|
37
|
+
**Installing pi.** Interactively the terminal is handed to pi's own installer and
|
|
38
|
+
the sync resumes when it exits. Unattended (`--install` with no tty) the output is
|
|
39
|
+
captured and stdin is closed, so a prompt fails fast instead of hanging. The
|
|
40
|
+
installer's exit status is not trusted — its "do nothing" menu choice exits 0 —
|
|
41
|
+
so `install_pi` re-probes and reports honestly. A host that still lacks pi is
|
|
42
|
+
skipped, which makes the run exit non-zero. After a successful install,
|
|
43
|
+
`mkdir -p` creates the agent directory, because rsync will not create
|
|
44
|
+
intermediate directories itself.
|
|
45
|
+
|
|
46
|
+
**Uninstalling.** The official installer can only uninstall through its
|
|
47
|
+
interactive menu (its unattended mode always installs or reinstalls), so pi-sync
|
|
48
|
+
issues the npm command that menu would have: `npm uninstall -g --prefix <prefix>
|
|
49
|
+
@earendil-works/pi-coding-agent`, with the prefix derived from where pi actually
|
|
50
|
+
lives. It re-probes afterwards, since npm can exit 0 having removed nothing. Only
|
|
51
|
+
the CLI goes; the agent directory is never touched.
|
|
52
|
+
|
|
53
|
+
**Self-update.** `update` classifies the running environment and delegates:
|
|
54
|
+
|
|
55
|
+
| Detected | Action |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| pipx | `pipx upgrade <dist>` |
|
|
58
|
+
| uv tool | `uv tool upgrade <dist>` |
|
|
59
|
+
| editable checkout | prints `git -C <path> pull` |
|
|
60
|
+
| uvx ephemeral | nothing to do; suggests a durable install |
|
|
61
|
+
| otherwise | `python -m pip install --upgrade <dist>` |
|
|
62
|
+
|
|
63
|
+
It resolves the distribution from its own environment instead of hardcoding a
|
|
64
|
+
name, and refuses to downgrade when the local version is ahead of PyPI.
|
|
65
|
+
|
|
66
|
+
**Completions.** Read from `~/.ssh/config` at completion time, following
|
|
67
|
+
`Include` and skipping wildcard entries; `CompletionItem.help` carries
|
|
68
|
+
`user@hostname` for the shells that render it (bash cannot).
|
|
69
|
+
|
|
70
|
+
**rsync invocation.** `-az -i`, plus `--backup --suffix=.backup` and
|
|
71
|
+
`--exclude=*.backup` so replaced files are kept but backups never travel, and
|
|
72
|
+
`--delete-during` only for `extensions/` when `--delete` is given — which also
|
|
73
|
+
suppresses backups for that directory.
|
|
74
|
+
|
|
28
75
|
## Commands
|
|
29
76
|
|
|
30
77
|
```bash
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pi-sync-cli
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: Sync pi agent config and extensions between hosts over rsync
|
|
5
|
+
Project-URL: Repository, https://github.com/say4n/pi-sync
|
|
6
|
+
Project-URL: Issues, https://github.com/say4n/pi-sync/issues
|
|
7
|
+
Author: Sayan Goswami
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent-config,dotfiles,pi,rsync,sync
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: System :: Archiving :: Mirroring
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: click>=8.1
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# pi-sync
|
|
19
|
+
|
|
20
|
+
pi-sync keeps your pi agent config the same across hosts. It copies the
|
|
21
|
+
declarative parts of `~/.pi/agent` to another machine over rsync, and it reads
|
|
22
|
+
your ssh config, so the aliases in `~/.ssh/config` work as host names.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pi-sync tinfoil # copy config and extensions to tinfoil
|
|
26
|
+
pi-sync --config laptop # copy only models.json and settings.json
|
|
27
|
+
pi-sync --pull --all tinfoil # copy tinfoil's config back to this machine
|
|
28
|
+
pi-sync --dry-run --all a b # report what would change, without copying
|
|
29
|
+
pi-sync update # update pi-sync itself
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pipx install pi-sync-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The PyPI package is `pi-sync-cli`, and it installs the `pi-sync` command.
|
|
39
|
+
`uv tool install pi-sync-cli` works the same way.
|
|
40
|
+
|
|
41
|
+
To install from source, run:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pipx install git+ssh://git@github.com/say4n/pi-sync
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
pi-sync requires Python 3.10 or later.
|
|
48
|
+
|
|
49
|
+
## what syncs
|
|
50
|
+
|
|
51
|
+
pi-sync copies the declarative parts of the agent directory, and nothing else.
|
|
52
|
+
|
|
53
|
+
| group | what it copies |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `--config` | `models.json` and `settings.json` |
|
|
56
|
+
| `--extensions` | the `extensions/` directory |
|
|
57
|
+
| `--auth` | `auth.json`, which holds API keys. This group is opt-in, and pi-sync warns you before it copies secrets. |
|
|
58
|
+
|
|
59
|
+
`--all` copies `--config` and `--extensions`. It is the default when you pass no
|
|
60
|
+
group flag.
|
|
61
|
+
|
|
62
|
+
pi-sync leaves host-local state alone: `sessions/`, `npm/`, `models-store.json`,
|
|
63
|
+
`ayu/`, `bin/`, and `trust.json` stay where they are.
|
|
64
|
+
|
|
65
|
+
## flags
|
|
66
|
+
|
|
67
|
+
| flag | effect |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `--all`, `--config`, `--extensions`, `--auth` | set what pi-sync copies |
|
|
70
|
+
| `--pull` | copy from the host to this machine instead of the other way |
|
|
71
|
+
| `--delete` | make `extensions/` match the source exactly, including deletions |
|
|
72
|
+
| `--dry-run` | report changes without copying anything |
|
|
73
|
+
| `-x, --exclude PATTERN` | skip files that match the pattern. Repeat the flag to add more patterns. |
|
|
74
|
+
| `--install` | install pi on hosts that do not have it, without prompting |
|
|
75
|
+
| `--uninstall` | remove pi from the host instead of copying config. Your config stays. |
|
|
76
|
+
| `--update-pi` | update pi on each host before copying config |
|
|
77
|
+
| `--local-dir` | set the local agent directory. The default is `$PI_CODING_AGENT_DIR`, or `~/.pi/agent`. |
|
|
78
|
+
| `--remote-dir` | set the agent directory on the host. The default is `~/.pi/agent`. |
|
|
79
|
+
| `-v, --verbose` | print each rsync command and its output |
|
|
80
|
+
|
|
81
|
+
To copy to more than one host, pass more than one name: `pi-sync a b c`. The
|
|
82
|
+
command exits with a non-zero status when it cannot copy to a host. Each file
|
|
83
|
+
pi-sync overwrites on the destination is kept beside the new one as
|
|
84
|
+
`<name>.backup`.
|
|
85
|
+
|
|
86
|
+
## developing
|
|
87
|
+
|
|
88
|
+
For the layout, the tests, and the release process, see
|
|
89
|
+
[DEVELOPMENT.md](DEVELOPMENT.md).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# pi-sync
|
|
2
|
+
|
|
3
|
+
pi-sync keeps your pi agent config the same across hosts. It copies the
|
|
4
|
+
declarative parts of `~/.pi/agent` to another machine over rsync, and it reads
|
|
5
|
+
your ssh config, so the aliases in `~/.ssh/config` work as host names.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi-sync tinfoil # copy config and extensions to tinfoil
|
|
9
|
+
pi-sync --config laptop # copy only models.json and settings.json
|
|
10
|
+
pi-sync --pull --all tinfoil # copy tinfoil's config back to this machine
|
|
11
|
+
pi-sync --dry-run --all a b # report what would change, without copying
|
|
12
|
+
pi-sync update # update pi-sync itself
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pipx install pi-sync-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The PyPI package is `pi-sync-cli`, and it installs the `pi-sync` command.
|
|
22
|
+
`uv tool install pi-sync-cli` works the same way.
|
|
23
|
+
|
|
24
|
+
To install from source, run:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pipx install git+ssh://git@github.com/say4n/pi-sync
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
pi-sync requires Python 3.10 or later.
|
|
31
|
+
|
|
32
|
+
## what syncs
|
|
33
|
+
|
|
34
|
+
pi-sync copies the declarative parts of the agent directory, and nothing else.
|
|
35
|
+
|
|
36
|
+
| group | what it copies |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `--config` | `models.json` and `settings.json` |
|
|
39
|
+
| `--extensions` | the `extensions/` directory |
|
|
40
|
+
| `--auth` | `auth.json`, which holds API keys. This group is opt-in, and pi-sync warns you before it copies secrets. |
|
|
41
|
+
|
|
42
|
+
`--all` copies `--config` and `--extensions`. It is the default when you pass no
|
|
43
|
+
group flag.
|
|
44
|
+
|
|
45
|
+
pi-sync leaves host-local state alone: `sessions/`, `npm/`, `models-store.json`,
|
|
46
|
+
`ayu/`, `bin/`, and `trust.json` stay where they are.
|
|
47
|
+
|
|
48
|
+
## flags
|
|
49
|
+
|
|
50
|
+
| flag | effect |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `--all`, `--config`, `--extensions`, `--auth` | set what pi-sync copies |
|
|
53
|
+
| `--pull` | copy from the host to this machine instead of the other way |
|
|
54
|
+
| `--delete` | make `extensions/` match the source exactly, including deletions |
|
|
55
|
+
| `--dry-run` | report changes without copying anything |
|
|
56
|
+
| `-x, --exclude PATTERN` | skip files that match the pattern. Repeat the flag to add more patterns. |
|
|
57
|
+
| `--install` | install pi on hosts that do not have it, without prompting |
|
|
58
|
+
| `--uninstall` | remove pi from the host instead of copying config. Your config stays. |
|
|
59
|
+
| `--update-pi` | update pi on each host before copying config |
|
|
60
|
+
| `--local-dir` | set the local agent directory. The default is `$PI_CODING_AGENT_DIR`, or `~/.pi/agent`. |
|
|
61
|
+
| `--remote-dir` | set the agent directory on the host. The default is `~/.pi/agent`. |
|
|
62
|
+
| `-v, --verbose` | print each rsync command and its output |
|
|
63
|
+
|
|
64
|
+
To copy to more than one host, pass more than one name: `pi-sync a b c`. The
|
|
65
|
+
command exits with a non-zero status when it cannot copy to a host. Each file
|
|
66
|
+
pi-sync overwrites on the destination is kept beside the new one as
|
|
67
|
+
`<name>.backup`.
|
|
68
|
+
|
|
69
|
+
## developing
|
|
70
|
+
|
|
71
|
+
For the layout, the tests, and the release process, see
|
|
72
|
+
[DEVELOPMENT.md](DEVELOPMENT.md).
|
pi_sync_cli-0.5.0/PKG-INFO
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: pi-sync-cli
|
|
3
|
-
Version: 0.5.0
|
|
4
|
-
Summary: Sync pi agent config and extensions between hosts over rsync
|
|
5
|
-
Project-URL: Repository, https://github.com/say4n/pi-sync
|
|
6
|
-
Project-URL: Issues, https://github.com/say4n/pi-sync/issues
|
|
7
|
-
Author: Sayan Goswami
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Keywords: agent-config,dotfiles,pi,rsync,sync
|
|
11
|
-
Classifier: Environment :: Console
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Topic :: System :: Archiving :: Mirroring
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Requires-Dist: click>=8.1
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
|
|
18
|
-
# pi-sync
|
|
19
|
-
|
|
20
|
-
Sync pi agent config between hosts over rsync, using your existing ssh config
|
|
21
|
-
for routing (so `~/.ssh/config` aliases just work).
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
pi-sync tinfoil # push config + extensions
|
|
25
|
-
pi-sync --config laptop # only models.json and settings.json
|
|
26
|
-
pi-sync --pull --all tinfoil # fetch the host's config back
|
|
27
|
-
pi-sync --dry-run --all a b # preview against two hosts
|
|
28
|
-
pi-sync update # update pi-sync itself
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Install
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# the PyPI package is pi-sync-cli; it installs the `pi-sync` command
|
|
35
|
-
pipx install pi-sync-cli
|
|
36
|
-
pipx install git+ssh://git@github.com/say4n/pi-sync # from source (needs access)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Requires Python 3.10+. `uv tool install` works in place of `pipx install`.
|
|
40
|
-
|
|
41
|
-
## What syncs
|
|
42
|
-
|
|
43
|
-
Only the declarative parts of the agent dir:
|
|
44
|
-
|
|
45
|
-
| Group | Files |
|
|
46
|
-
| --- | --- |
|
|
47
|
-
| `--config` | `models.json`, `settings.json` |
|
|
48
|
-
| `--extensions` | `extensions/` |
|
|
49
|
-
| `--auth` | `auth.json` — secrets, opt-in, warns on push |
|
|
50
|
-
|
|
51
|
-
`--all` is `--config` + `--extensions` (also the default when no flag is given).
|
|
52
|
-
|
|
53
|
-
Host-local state is deliberately never touched: `sessions/`, `npm/`,
|
|
54
|
-
`models-store.json` (regenerated from the pi.dev catalog), `ayu/`, `bin/`,
|
|
55
|
-
`trust.json`.
|
|
56
|
-
|
|
57
|
-
## Flags
|
|
58
|
-
|
|
59
|
-
| Flag | Effect |
|
|
60
|
-
| --- | --- |
|
|
61
|
-
| `--all` / `--config` / `--extensions` / `--auth` | what to sync |
|
|
62
|
-
| `--pull` | host → local instead of local → host |
|
|
63
|
-
| `--delete` | mirror `extensions/` exactly (deletes extras on the destination) |
|
|
64
|
-
| `--dry-run` | report changes, copy nothing |
|
|
65
|
-
| `-x, --exclude PATTERN` | skip matching files (repeatable) |
|
|
66
|
-
| `--install` | install pi on hosts that lack it, without prompting |
|
|
67
|
-
| `--uninstall` | remove pi from the host instead of syncing (config is kept) |
|
|
68
|
-
| `--update-pi` | update pi on each host before syncing |
|
|
69
|
-
| `--local-dir` | default `$PI_CODING_AGENT_DIR` or `~/.pi/agent` |
|
|
70
|
-
| `--remote-dir` | default `~/.pi/agent` |
|
|
71
|
-
| `-v` / `--verbose` | print each rsync command and its output |
|
|
72
|
-
|
|
73
|
-
Multiple hosts are accepted: `pi-sync a b c`. Exits non-zero if any host is
|
|
74
|
-
unreachable or any transfer fails.
|
|
75
|
-
|
|
76
|
-
Anything pi-sync overwrites on the destination is kept beside it as
|
|
77
|
-
`<name>.backup`.
|
|
78
|
-
|
|
79
|
-
## Host preflight
|
|
80
|
-
|
|
81
|
-
Each host gets one ssh probe that reports reachability and pi's location in the
|
|
82
|
-
same round trip.
|
|
83
|
-
|
|
84
|
-
If pi is missing, pi-sync hands the terminal to pi's own installer
|
|
85
|
-
(`curl -fsSL https://pi.dev/install.sh | sh`), which keeps full control: its
|
|
86
|
-
prompts (its install/uninstall/do-nothing menu, a Node.js install, a sudo
|
|
87
|
-
password) work normally, and the sync continues once it exits. pi-sync does not
|
|
88
|
-
add a confirmation of its own, because the installer already asks. Without a
|
|
89
|
-
terminal it runs unattended under `--install`, stays quiet otherwise, and
|
|
90
|
-
`--dry-run` never installs anything.
|
|
91
|
-
|
|
92
|
-
The installer's exit status is not treated as proof: its "do nothing" choice
|
|
93
|
-
exits 0, so the host is re-probed afterwards and reported honestly.
|
|
94
|
-
|
|
95
|
-
**A host without pi is skipped** — copying into a host that has never run pi is
|
|
96
|
-
not useful and usually fails anyway, since there is no agent directory to copy
|
|
97
|
-
into. That covers an installer run that installed nothing, a failed install, and
|
|
98
|
-
a non-interactive run without `--install`; a skipped host makes the run exit
|
|
99
|
-
non-zero. After a successful install pi-sync creates the agent directory,
|
|
100
|
-
because rsync will not create intermediate directories on its own.
|
|
101
|
-
|
|
102
|
-
The probe checks `command -v pi` plus the usual install locations
|
|
103
|
-
(`~/.local/bin`, `~/.pi/bin`, `~/.pi/agent/bin`, linuxbrew, homebrew,
|
|
104
|
-
`/usr/local/bin`), because a non-interactive ssh session does not source the
|
|
105
|
-
host's shell init — on a linuxbrew host `command -v pi` alone misses it.
|
|
106
|
-
|
|
107
|
-
## Updating
|
|
108
|
-
|
|
109
|
-
`pi-sync update` upgrades this tool through whichever installer owns it —
|
|
110
|
-
`pipx upgrade`, `uv tool upgrade`, or `pip install --upgrade` — and reports the
|
|
111
|
-
version it moved from and to. `--check` reports without changing anything.
|
|
112
|
-
Running from a source checkout it tells you to `git pull` instead, and from an
|
|
113
|
-
ephemeral `uvx --from …` environment it explains that there is nothing to
|
|
114
|
-
upgrade.
|
|
115
|
-
|
|
116
|
-
`pi-sync --update-pi <hosts>` runs pi's own updater (`pi update --self`) on each
|
|
117
|
-
host before syncing, so the fleet does not drift:
|
|
118
|
-
|
|
119
|
-
```console
|
|
120
|
-
$ pi-sync --update-pi tinfoil
|
|
121
|
-
→ tinfoil
|
|
122
|
-
pi 0.85.1 → 0.86.0
|
|
123
|
-
models.json already in sync
|
|
124
|
-
settings.json already in sync
|
|
125
|
-
extensions already in sync
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
`update` is a reserved word — a host with that alias is still reachable as
|
|
129
|
-
`user@update`.
|
|
130
|
-
|
|
131
|
-
## Uninstalling
|
|
132
|
-
|
|
133
|
-
`--uninstall` removes pi from the host instead of syncing. It runs
|
|
134
|
-
`npm uninstall -g --prefix <prefix> @earendil-works/pi-coding-agent`, deriving the
|
|
135
|
-
prefix from where pi actually lives (as the official installer does), then
|
|
136
|
-
re-probes to confirm the binary is really gone — npm can exit 0 having removed
|
|
137
|
-
nothing. `~/.pi/agent` is deliberately left untouched, since that is your config
|
|
138
|
-
rather than the CLI.
|
|
139
|
-
|
|
140
|
-
This exists because the official installer can only uninstall through its
|
|
141
|
-
interactive menu: its unattended mode always installs or reinstalls. If the
|
|
142
|
-
uninstall fails, that is usually a managed install
|
|
143
|
-
(`PI_EXPERIMENTAL=1`, under `<agent dir>/install`) — run
|
|
144
|
-
`curl -fsSL https://pi.dev/install.sh | sh` on the host and choose `u`.
|
|
145
|
-
|
|
146
|
-
## Shell completions
|
|
147
|
-
|
|
148
|
-
Host arguments complete from `~/.ssh/config`, following `Include` directives and
|
|
149
|
-
skipping wildcard entries. zsh and fish also show where each alias points:
|
|
150
|
-
|
|
151
|
-
```console
|
|
152
|
-
$ pi-sync t<TAB>
|
|
153
|
-
tinfoil tinfoil@tinfoil.sayan.page
|
|
154
|
-
tinfoil-proxy notdebian@100.98.241.11
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
# bash
|
|
159
|
-
_PI_SYNC_COMPLETE=bash_source pi-sync > ~/.pi-sync-complete.bash
|
|
160
|
-
echo 'source ~/.pi-sync-complete.bash' >> ~/.bashrc
|
|
161
|
-
|
|
162
|
-
# zsh
|
|
163
|
-
_PI_SYNC_COMPLETE=zsh_source pi-sync > ~/.pi-sync-complete.zsh
|
|
164
|
-
echo 'source ~/.pi-sync-complete.zsh' >> ~/.zshrc
|
|
165
|
-
|
|
166
|
-
# fish (config.fish)
|
|
167
|
-
_PI_SYNC_COMPLETE=fish_source pi-sync | source
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Writing the script out (rather than `eval "$(_PI_SYNC_COMPLETE=bash_source pi-sync)"`
|
|
171
|
-
on every shell start) keeps shell startup fast, since the eval form runs the
|
|
172
|
-
binary each time. PowerShell works the same way via `powershell_source`.
|
|
173
|
-
|
|
174
|
-
Completions are read from the config at completion time, so new hosts appear
|
|
175
|
-
without regenerating anything.
|
|
176
|
-
|
|
177
|
-
## Caveats
|
|
178
|
-
|
|
179
|
-
- `settings.json` is machine-written by pi (`lastChangelogVersion` bumps, UI
|
|
180
|
-
toggles), so two hosts pushing it will overwrite each other's local
|
|
181
|
-
preferences. Sync it when you change `packages`, not reflexively — and note the
|
|
182
|
-
overwritten copy is kept as `settings.json.backup` on the receiving host.
|
|
183
|
-
- `*.backup` files are never synced, so those copies stay host-local and never
|
|
184
|
-
trampoline between hosts. `--delete` suppresses backups for the mirrored
|
|
185
|
-
directory, because mirroring means "match exactly".
|
|
186
|
-
- Extensions that write runtime files inside their own directory (logs,
|
|
187
|
-
checkpoints) get those files synced too, and each host's copy is overwritten by
|
|
188
|
-
whichever side pushed last — exclude them with `-x '*/logs/*'`.
|
|
189
|
-
- Extension versions are whatever each host has installed; pin them in
|
|
190
|
-
`settings.json` (`npm:pi-lens@1.2.3`) if you need hosts identical.
|
|
191
|
-
- `--auth` copies API keys in the clear. Prefer `OPENCODE_API_KEY` (and friends)
|
|
192
|
-
in the environment where you can.
|
|
193
|
-
- Remote paths go through the host's shell, so `~` expands there as usual.
|
|
194
|
-
|
|
195
|
-
## Developing
|
|
196
|
-
|
|
197
|
-
See [DEVELOPMENT.md](DEVELOPMENT.md) for the layout, tests and release process.
|
pi_sync_cli-0.5.0/README.md
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
# pi-sync
|
|
2
|
-
|
|
3
|
-
Sync pi agent config between hosts over rsync, using your existing ssh config
|
|
4
|
-
for routing (so `~/.ssh/config` aliases just work).
|
|
5
|
-
|
|
6
|
-
```bash
|
|
7
|
-
pi-sync tinfoil # push config + extensions
|
|
8
|
-
pi-sync --config laptop # only models.json and settings.json
|
|
9
|
-
pi-sync --pull --all tinfoil # fetch the host's config back
|
|
10
|
-
pi-sync --dry-run --all a b # preview against two hosts
|
|
11
|
-
pi-sync update # update pi-sync itself
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Install
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
# the PyPI package is pi-sync-cli; it installs the `pi-sync` command
|
|
18
|
-
pipx install pi-sync-cli
|
|
19
|
-
pipx install git+ssh://git@github.com/say4n/pi-sync # from source (needs access)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Requires Python 3.10+. `uv tool install` works in place of `pipx install`.
|
|
23
|
-
|
|
24
|
-
## What syncs
|
|
25
|
-
|
|
26
|
-
Only the declarative parts of the agent dir:
|
|
27
|
-
|
|
28
|
-
| Group | Files |
|
|
29
|
-
| --- | --- |
|
|
30
|
-
| `--config` | `models.json`, `settings.json` |
|
|
31
|
-
| `--extensions` | `extensions/` |
|
|
32
|
-
| `--auth` | `auth.json` — secrets, opt-in, warns on push |
|
|
33
|
-
|
|
34
|
-
`--all` is `--config` + `--extensions` (also the default when no flag is given).
|
|
35
|
-
|
|
36
|
-
Host-local state is deliberately never touched: `sessions/`, `npm/`,
|
|
37
|
-
`models-store.json` (regenerated from the pi.dev catalog), `ayu/`, `bin/`,
|
|
38
|
-
`trust.json`.
|
|
39
|
-
|
|
40
|
-
## Flags
|
|
41
|
-
|
|
42
|
-
| Flag | Effect |
|
|
43
|
-
| --- | --- |
|
|
44
|
-
| `--all` / `--config` / `--extensions` / `--auth` | what to sync |
|
|
45
|
-
| `--pull` | host → local instead of local → host |
|
|
46
|
-
| `--delete` | mirror `extensions/` exactly (deletes extras on the destination) |
|
|
47
|
-
| `--dry-run` | report changes, copy nothing |
|
|
48
|
-
| `-x, --exclude PATTERN` | skip matching files (repeatable) |
|
|
49
|
-
| `--install` | install pi on hosts that lack it, without prompting |
|
|
50
|
-
| `--uninstall` | remove pi from the host instead of syncing (config is kept) |
|
|
51
|
-
| `--update-pi` | update pi on each host before syncing |
|
|
52
|
-
| `--local-dir` | default `$PI_CODING_AGENT_DIR` or `~/.pi/agent` |
|
|
53
|
-
| `--remote-dir` | default `~/.pi/agent` |
|
|
54
|
-
| `-v` / `--verbose` | print each rsync command and its output |
|
|
55
|
-
|
|
56
|
-
Multiple hosts are accepted: `pi-sync a b c`. Exits non-zero if any host is
|
|
57
|
-
unreachable or any transfer fails.
|
|
58
|
-
|
|
59
|
-
Anything pi-sync overwrites on the destination is kept beside it as
|
|
60
|
-
`<name>.backup`.
|
|
61
|
-
|
|
62
|
-
## Host preflight
|
|
63
|
-
|
|
64
|
-
Each host gets one ssh probe that reports reachability and pi's location in the
|
|
65
|
-
same round trip.
|
|
66
|
-
|
|
67
|
-
If pi is missing, pi-sync hands the terminal to pi's own installer
|
|
68
|
-
(`curl -fsSL https://pi.dev/install.sh | sh`), which keeps full control: its
|
|
69
|
-
prompts (its install/uninstall/do-nothing menu, a Node.js install, a sudo
|
|
70
|
-
password) work normally, and the sync continues once it exits. pi-sync does not
|
|
71
|
-
add a confirmation of its own, because the installer already asks. Without a
|
|
72
|
-
terminal it runs unattended under `--install`, stays quiet otherwise, and
|
|
73
|
-
`--dry-run` never installs anything.
|
|
74
|
-
|
|
75
|
-
The installer's exit status is not treated as proof: its "do nothing" choice
|
|
76
|
-
exits 0, so the host is re-probed afterwards and reported honestly.
|
|
77
|
-
|
|
78
|
-
**A host without pi is skipped** — copying into a host that has never run pi is
|
|
79
|
-
not useful and usually fails anyway, since there is no agent directory to copy
|
|
80
|
-
into. That covers an installer run that installed nothing, a failed install, and
|
|
81
|
-
a non-interactive run without `--install`; a skipped host makes the run exit
|
|
82
|
-
non-zero. After a successful install pi-sync creates the agent directory,
|
|
83
|
-
because rsync will not create intermediate directories on its own.
|
|
84
|
-
|
|
85
|
-
The probe checks `command -v pi` plus the usual install locations
|
|
86
|
-
(`~/.local/bin`, `~/.pi/bin`, `~/.pi/agent/bin`, linuxbrew, homebrew,
|
|
87
|
-
`/usr/local/bin`), because a non-interactive ssh session does not source the
|
|
88
|
-
host's shell init — on a linuxbrew host `command -v pi` alone misses it.
|
|
89
|
-
|
|
90
|
-
## Updating
|
|
91
|
-
|
|
92
|
-
`pi-sync update` upgrades this tool through whichever installer owns it —
|
|
93
|
-
`pipx upgrade`, `uv tool upgrade`, or `pip install --upgrade` — and reports the
|
|
94
|
-
version it moved from and to. `--check` reports without changing anything.
|
|
95
|
-
Running from a source checkout it tells you to `git pull` instead, and from an
|
|
96
|
-
ephemeral `uvx --from …` environment it explains that there is nothing to
|
|
97
|
-
upgrade.
|
|
98
|
-
|
|
99
|
-
`pi-sync --update-pi <hosts>` runs pi's own updater (`pi update --self`) on each
|
|
100
|
-
host before syncing, so the fleet does not drift:
|
|
101
|
-
|
|
102
|
-
```console
|
|
103
|
-
$ pi-sync --update-pi tinfoil
|
|
104
|
-
→ tinfoil
|
|
105
|
-
pi 0.85.1 → 0.86.0
|
|
106
|
-
models.json already in sync
|
|
107
|
-
settings.json already in sync
|
|
108
|
-
extensions already in sync
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
`update` is a reserved word — a host with that alias is still reachable as
|
|
112
|
-
`user@update`.
|
|
113
|
-
|
|
114
|
-
## Uninstalling
|
|
115
|
-
|
|
116
|
-
`--uninstall` removes pi from the host instead of syncing. It runs
|
|
117
|
-
`npm uninstall -g --prefix <prefix> @earendil-works/pi-coding-agent`, deriving the
|
|
118
|
-
prefix from where pi actually lives (as the official installer does), then
|
|
119
|
-
re-probes to confirm the binary is really gone — npm can exit 0 having removed
|
|
120
|
-
nothing. `~/.pi/agent` is deliberately left untouched, since that is your config
|
|
121
|
-
rather than the CLI.
|
|
122
|
-
|
|
123
|
-
This exists because the official installer can only uninstall through its
|
|
124
|
-
interactive menu: its unattended mode always installs or reinstalls. If the
|
|
125
|
-
uninstall fails, that is usually a managed install
|
|
126
|
-
(`PI_EXPERIMENTAL=1`, under `<agent dir>/install`) — run
|
|
127
|
-
`curl -fsSL https://pi.dev/install.sh | sh` on the host and choose `u`.
|
|
128
|
-
|
|
129
|
-
## Shell completions
|
|
130
|
-
|
|
131
|
-
Host arguments complete from `~/.ssh/config`, following `Include` directives and
|
|
132
|
-
skipping wildcard entries. zsh and fish also show where each alias points:
|
|
133
|
-
|
|
134
|
-
```console
|
|
135
|
-
$ pi-sync t<TAB>
|
|
136
|
-
tinfoil tinfoil@tinfoil.sayan.page
|
|
137
|
-
tinfoil-proxy notdebian@100.98.241.11
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
# bash
|
|
142
|
-
_PI_SYNC_COMPLETE=bash_source pi-sync > ~/.pi-sync-complete.bash
|
|
143
|
-
echo 'source ~/.pi-sync-complete.bash' >> ~/.bashrc
|
|
144
|
-
|
|
145
|
-
# zsh
|
|
146
|
-
_PI_SYNC_COMPLETE=zsh_source pi-sync > ~/.pi-sync-complete.zsh
|
|
147
|
-
echo 'source ~/.pi-sync-complete.zsh' >> ~/.zshrc
|
|
148
|
-
|
|
149
|
-
# fish (config.fish)
|
|
150
|
-
_PI_SYNC_COMPLETE=fish_source pi-sync | source
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Writing the script out (rather than `eval "$(_PI_SYNC_COMPLETE=bash_source pi-sync)"`
|
|
154
|
-
on every shell start) keeps shell startup fast, since the eval form runs the
|
|
155
|
-
binary each time. PowerShell works the same way via `powershell_source`.
|
|
156
|
-
|
|
157
|
-
Completions are read from the config at completion time, so new hosts appear
|
|
158
|
-
without regenerating anything.
|
|
159
|
-
|
|
160
|
-
## Caveats
|
|
161
|
-
|
|
162
|
-
- `settings.json` is machine-written by pi (`lastChangelogVersion` bumps, UI
|
|
163
|
-
toggles), so two hosts pushing it will overwrite each other's local
|
|
164
|
-
preferences. Sync it when you change `packages`, not reflexively — and note the
|
|
165
|
-
overwritten copy is kept as `settings.json.backup` on the receiving host.
|
|
166
|
-
- `*.backup` files are never synced, so those copies stay host-local and never
|
|
167
|
-
trampoline between hosts. `--delete` suppresses backups for the mirrored
|
|
168
|
-
directory, because mirroring means "match exactly".
|
|
169
|
-
- Extensions that write runtime files inside their own directory (logs,
|
|
170
|
-
checkpoints) get those files synced too, and each host's copy is overwritten by
|
|
171
|
-
whichever side pushed last — exclude them with `-x '*/logs/*'`.
|
|
172
|
-
- Extension versions are whatever each host has installed; pin them in
|
|
173
|
-
`settings.json` (`npm:pi-lens@1.2.3`) if you need hosts identical.
|
|
174
|
-
- `--auth` copies API keys in the clear. Prefer `OPENCODE_API_KEY` (and friends)
|
|
175
|
-
in the environment where you can.
|
|
176
|
-
- Remote paths go through the host's shell, so `~` expands there as usual.
|
|
177
|
-
|
|
178
|
-
## Developing
|
|
179
|
-
|
|
180
|
-
See [DEVELOPMENT.md](DEVELOPMENT.md) for the layout, tests and release process.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|