@narumitw/pi-sync 0.49.14 → 0.50.0
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.
- package/README.md +134 -241
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
- package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
- package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
- package/dist/chunks/chunk-6UHKGALE.ts +134 -0
- package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
- package/dist/chunks/{chunk-RGJ6SOYR.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-3NDD5QPM.ts → chunk-AXXS2BPA.ts} +9 -9
- package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
- package/dist/chunks/{chunk-APZVBSM6.ts → chunk-C7XY5NF5.ts} +214 -365
- package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
- package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
- package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
- package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
- package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
- package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
- package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
- package/dist/chunks/{chunk-LJDSHNS3.ts → chunk-GWMHAQG4.ts} +4 -4
- package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
- package/dist/chunks/{chunk-FR6CVXAL.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
- package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
- package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts +51 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
- package/dist/chunks/chunk-L7TBO32M.ts +25 -0
- package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
- package/dist/chunks/{chunk-4F3W4CSC.ts → chunk-LCRI3ABW.ts} +22 -8
- package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
- package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
- package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
- package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
- package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
- package/dist/chunks/{chunk-EWX3TPLQ.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
- package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
- package/dist/chunks/chunk-OUHGBFYF.ts.map +7 -0
- package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
- package/dist/chunks/{chunk-BHJUISB4.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
- package/dist/chunks/chunk-THMF4BVL.ts +18 -0
- package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
- package/dist/chunks/{chunk-LONPFFNP.ts → chunk-X5OM6GXT.ts} +9 -7
- package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
- package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
- package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
- package/dist/chunks/{chunk-5WJNWFTG.ts → chunk-YKJHPTGO.ts} +23 -55
- package/dist/chunks/chunk-YKJHPTGO.ts.map +7 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
- package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
- package/dist/chunks/{file-selection-4UABOP44.ts → file-selection-FTTKAOYX.ts} +10 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
- package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-OQW46G2X.ts} +42 -17
- package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
- package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
- package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
- package/dist/chunks/{s3-backend-3QZGO2EF.ts → s3-backend-3P33LQHU.ts} +96 -18
- package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
- package/dist/chunks/{setup-switch-X3W3FALZ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
- package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
- package/dist/chunks/{snapshot-WBSV4MQG.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
- package/dist/chunks/{sync-operations-MPAFVVHA.ts → sync-operations-ONJ27QRL.ts} +381 -299
- package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
- package/dist/chunks/{sync-state-36H7ULG2.ts → sync-state-Q2FTXTW6.ts} +6 -6
- package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
- package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
- package/dist/index.ts +477 -342
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +211 -0
- package/package.json +6 -8
- package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
- package/src/backends/backend-identity.ts +40 -0
- package/src/backends/backend-types.ts +81 -0
- package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
- package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
- package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
- package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
- package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
- package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
- package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
- package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
- package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
- package/src/commands/command-execution.ts +330 -0
- package/src/commands/command-handler.ts +201 -0
- package/src/commands/command-types.ts +18 -0
- package/src/{command.ts → commands/command.ts} +2 -1
- package/src/commands/setup-completions.ts +6 -0
- package/src/settings/config.ts +238 -0
- package/src/{settings-management.ts → settings/settings-management.ts} +40 -14
- package/src/settings/settings-store.ts +109 -0
- package/src/settings/settings-types.ts +128 -0
- package/src/settings/settings-validation.ts +443 -0
- package/src/snapshot/session-paths.ts +84 -0
- package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
- package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
- package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
- package/src/snapshot/snapshot-types.ts +38 -0
- package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
- package/src/state/json-file.ts +20 -0
- package/src/{lock.ts → state/lock.ts} +3 -2
- package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
- package/src/state/state-types.ts +20 -0
- package/src/state/sync-state-store.ts +62 -0
- package/src/sync/automatic-sync.ts +103 -0
- package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
- package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
- package/src/sync/signals.ts +10 -0
- package/src/sync/startup-check.ts +128 -0
- package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
- package/src/sync/sync-error-guidance.ts +53 -0
- package/src/sync/sync-inspection.ts +51 -0
- package/src/sync/sync-loaders.ts +54 -0
- package/src/{sync-operations.ts → sync/sync-mutations.ts} +41 -330
- package/src/sync/sync-operations.ts +12 -0
- package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
- package/src/sync/sync-queries.ts +235 -0
- package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
- package/src/sync-extension.ts +64 -708
- package/src/sync.ts +8 -8
- package/src/types.ts +47 -284
- package/src/ui/automatic-sync-summary.ts +6 -0
- package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
- package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
- package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
- package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
- package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
- package/src/ui/manager-ui.ts +386 -0
- package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
- package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
- package/src/{settings-ui.ts → ui/settings-ui.ts} +42 -11
- package/src/ui/setup/git-ui.ts +293 -0
- package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
- package/src/ui/setup/s3-ui.ts +217 -0
- package/src/ui/setup/setup-actions.ts +127 -0
- package/src/ui/setup/setup-location-ui.ts +167 -0
- package/src/ui/setup/setup-name-ui.ts +34 -0
- package/src/ui/setup/setup-prompts.ts +92 -0
- package/src/ui/setup/setup-review.ts +70 -0
- package/src/ui/setup/setup-switcher.ts +181 -0
- package/src/ui/setup/setup-wizard.ts +39 -0
- package/src/ui/setup/text-input.ts +78 -0
- package/src/ui/setup/webdav-ui.ts +330 -0
- package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
- package/src/{sync-attention.ts → ui/sync-attention.ts} +75 -6
- package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
- package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
- package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
- package/src/ui/terminal-text.ts +4 -0
- package/dist/chunks/chunk-3NDD5QPM.ts.map +0 -7
- package/dist/chunks/chunk-4F3W4CSC.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5WJNWFTG.ts.map +0 -7
- package/dist/chunks/chunk-APZVBSM6.ts.map +0 -7
- package/dist/chunks/chunk-BHJUISB4.ts.map +0 -7
- package/dist/chunks/chunk-EWX3TPLQ.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-FR6CVXAL.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-JNOOSPEW.ts +0 -82
- package/dist/chunks/chunk-JNOOSPEW.ts.map +0 -7
- package/dist/chunks/chunk-LJDSHNS3.ts.map +0 -7
- package/dist/chunks/chunk-LONPFFNP.ts.map +0 -7
- package/dist/chunks/chunk-RGJ6SOYR.ts.map +0 -7
- package/dist/chunks/chunk-W64NEHXT.ts +0 -167
- package/dist/chunks/chunk-W64NEHXT.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-4UABOP44.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-RNRQA3PW.ts +0 -18
- package/dist/chunks/manager-ui-QO2P4V3Z.ts +0 -2757
- package/dist/chunks/manager-ui-QO2P4V3Z.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-LHSAGKGA.ts +0 -17
- package/dist/chunks/s3-backend-3QZGO2EF.ts.map +0 -7
- package/dist/chunks/sync-operations-MPAFVVHA.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -910
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-RNRQA3PW.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-X3W3FALZ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-WBSV4MQG.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-36H7ULG2.ts.map → sync-inspection-FEP4L5TR.ts.map} +0 -0
- /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
- /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
- /package/src/{config-file.ts → settings/config-file.ts} +0 -0
- /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
- /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
- /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
- /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
- /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
- /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,19 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-sync) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
Sync selected Pi settings and content across machines through Git, WebDAV, Cloudflare R2, or another S3-compatible store.
|
|
6
|
-
|
|
7
|
-
Reusable storage connections hold credentials, while named sync setups define the exact remote path, included content, and automatic-sync behavior.
|
|
5
|
+
Pi Sync synchronizes selected Pi settings and content across machines through Git, WebDAV, Cloudflare R2, or another S3-compatible store.
|
|
6
|
+
Reusable storage connections hold credentials, while named sync setups define exactly what to sync, where to store it, and whether to sync automatically.
|
|
8
7
|
|
|
9
8
|
## ✨ Features
|
|
10
9
|
|
|
11
|
-
- Manages Git, WebDAV, Cloudflare R2, and general S3-compatible
|
|
12
|
-
- Separates reusable storage connections from named
|
|
13
|
-
-
|
|
10
|
+
- Manages Git, WebDAV, Cloudflare R2, and general S3-compatible storage through `/sync`.
|
|
11
|
+
- Separates reusable storage connections from named setups with exact reviewed remote paths.
|
|
12
|
+
- Uses one ordered list for Pi roots, safe agent-relative paths, and privacy-sensitive sessions.
|
|
14
13
|
- Protects changes with immutable snapshots, secret scanning, locks, conflict checks, pull backups, transactional apply, and recovery journals.
|
|
15
|
-
- Keeps snapshot selection portable and
|
|
14
|
+
- Keeps snapshot selection portable and free of credentials.
|
|
16
15
|
- Writes settings atomically, preserves unknown fields, rejects stale edits, and fails closed on unsafe configuration.
|
|
17
|
-
- Loads a generated split runtime
|
|
16
|
+
- Loads a generated split runtime with lazy UI and backend chunks.
|
|
18
17
|
|
|
19
18
|
## 📦 Install
|
|
20
19
|
|
|
@@ -35,56 +34,78 @@ npm --workspace @narumitw/pi-sync run build
|
|
|
35
34
|
pi -e ./packages/pi-sync
|
|
36
35
|
```
|
|
37
36
|
|
|
38
|
-
The package declares `dist/index.ts`, so
|
|
37
|
+
The package declares `dist/index.ts`, so an unbuilt checkout must run the build before Pi loads the package directory.
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
Extensions run with Pi's permissions, so install only packages from sources you trust.
|
|
41
40
|
|
|
42
41
|
## 🚀 Quick start
|
|
43
42
|
|
|
44
|
-
Run `/sync
|
|
43
|
+
Run `/sync` and choose **Set up sync**.
|
|
44
|
+
Name the setup once; its first storage connection uses the same name.
|
|
45
|
+
Input prompts show examples or an explicit default that you can accept by submitting an empty value; cancelling never accepts a default.
|
|
46
|
+
Remote URLs, endpoints, usernames, and credentials require your own values, not the displayed examples.
|
|
47
|
+
All new setups default to storage path `./`: the Git repository root, the WebDAV collection URL, or the selected R2/S3 bucket root.
|
|
48
|
+
Git also suggests branch `main`.
|
|
49
|
+
Use different folders or prefixes for independent setups sharing a WebDAV collection or bucket; existing settings and paths are unchanged.
|
|
50
|
+
If another configured setup already uses the chosen location, setup asks for a different path before the content selection and review; Git requires a different branch, even when the directory differs.
|
|
51
|
+
Every new setup asks for included content and automatic sync; automatic sync is off unless you enable it. Recommended includes nine Pi roots; Minimal includes `settings.json` and `AGENTS.md`. Sessions stay off unless explicitly included with a privacy acknowledgement.
|
|
52
|
+
Before saving, scroll through the exact destination, every included path, automatic-sync choice, and hidden-credential summary. R2/S3 always asks for an existing bucket; an example bucket name is not a default.
|
|
53
|
+
|
|
54
|
+
Invalid fields ask for a correction without restarting setup. A temporary local save failure keeps the review for another Save; changed settings require reopening and reviewing the current values. Saving only changes local settings, not remote data. A connection saved through **Add a new storage connection…** remains saved if you later cancel the setup.
|
|
55
|
+
|
|
45
56
|
Buckets and remote repositories must already exist.
|
|
46
57
|
Git uses existing non-interactive SSH or credential-helper configuration and never stores Git credentials.
|
|
58
|
+
It owns the entire selected branch: use an empty repository or a new branch if `main` already contains unrelated content.
|
|
59
|
+
At `./`, Git stores `manifest.json` and `files/` at the repository root; it does not modify your local working tree.
|
|
60
|
+
WebDAV and R2/S3 store `latest.json`, `history.json`, and `snapshots/` directly under their selected root, not under a literal `./` prefix.
|
|
47
61
|
|
|
48
62
|
## 🧭 Manager, conflicts, and recovery
|
|
49
63
|
|
|
50
|
-
The manager shows local state without contacting remote storage:
|
|
64
|
+
The `/sync` manager shows local state without contacting remote storage:
|
|
51
65
|
|
|
52
66
|
```text
|
|
53
67
|
Current sync setup: home
|
|
54
68
|
Storage: Cloudflare R2 · r2 · personal-pi
|
|
55
69
|
Included: 5 built-in groups · 0 extra files · Sessions off
|
|
56
|
-
Automatic sync: On
|
|
70
|
+
Automatic sync: On (startup check; shutdown pushes selected content if sessions included)
|
|
57
71
|
Remote status: Not checked
|
|
58
72
|
```
|
|
59
73
|
|
|
60
74
|
Primary actions include **Sync now**, **Switch sync setup**, **Status & changes**, **Settings**, and **More…**.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
|
|
76
|
+
After Pi Sync detects an included-content mismatch, the manager shows **Sync status: Review needed** and puts **Review synced content (recommended)** first.
|
|
77
|
+
**Sync now** remains unavailable until you review the mismatch.
|
|
78
|
+
Opening the manager does not make another remote request.
|
|
79
|
+
Under **More…**, **Storage connections** holds reusable server addresses and sign-in details; **Sync setups** holds content, destination, and automatic-sync choices. **Edit storage location…** changes only bucket, branch, or path, not the connection or included content. Use **Settings** for the current setup's content and automatic sync; make another setup current before changing those settings.
|
|
80
|
+
|
|
81
|
+
**More… → Check setup** (also `/sync doctor`) reports configuration and backend-specific access checks. S3/R2 performs a read-only request: success does not prove write access or snapshot validity, and an ambiguous 404 does not prove a bucket is missing. Check the indicated credentials, address, bucket, or path before retrying. Git checks remote reads and the local cache, not write access. WebDAV uses an isolated write/cleanup probe and repairs the active snapshot's history entry if missing. The existing **History & recovery** route remains available.
|
|
82
|
+
|
|
83
|
+
On secondary menus, **Back** and Escape return to the previous screen. In setup inputs and save reviews, cancellation (including Ctrl+C) discards the current unsaved draft and returns to its owning menu. Session replacement or shutdown closes the owning flow.
|
|
84
|
+
Specialized operation and masked-credential prompts show the effective cancellation bindings and keep Ctrl+C as a hard-cancel input when Back is remapped.
|
|
85
|
+
Destructive, credential-bearing, and externally visible operations show exact previews and confirmations.
|
|
67
86
|
|
|
68
87
|
### Restore sync access
|
|
69
88
|
|
|
70
|
-
|
|
71
|
-
When
|
|
89
|
+
While an operation is running, the manager shows its command and process ID, disables sync and settings changes, and puts **Refresh operation status** first.
|
|
90
|
+
When an active guard still protects lock metadata, the manager asks you to wait because another Pi Sync process may be starting or finishing.
|
|
72
91
|
It never offers lock removal while an owner or guard may still be active.
|
|
73
92
|
|
|
74
|
-
|
|
75
|
-
Unreadable metadata receives a stronger warning because
|
|
76
|
-
Close every other Pi session that may still be syncing, review the local-lock-only confirmation,
|
|
77
|
-
|
|
93
|
+
If a stopped operation leaves its local lock behind, the manager shows **Sync paused** and puts **Restore sync access… (recommended)** first.
|
|
94
|
+
Unreadable metadata receives a stronger warning because Pi Sync cannot verify its owner.
|
|
95
|
+
Close every other Pi session that may still be syncing, review the local-lock-only confirmation, and choose **Remove local lock and continue**.
|
|
96
|
+
Before removal, the guarded recovery path rechecks metadata and ownership.
|
|
97
|
+
|
|
98
|
+
Successful recovery changes no settings, local files, sync state, or remote data and returns to the normal manager.
|
|
78
99
|
Cancellation leaves the lock unchanged.
|
|
79
|
-
If ownership changes or a guard is still expiring,
|
|
80
|
-
|
|
100
|
+
If ownership changes or a guard is still expiring, Pi Sync refuses removal and keeps refresh or retry available.
|
|
101
|
+
After the same no-other-sync verification, `/sync unlock --stale` provides a deterministic fallback.
|
|
81
102
|
|
|
82
103
|
### Resolve conflicts in the manager
|
|
83
104
|
|
|
84
|
-
When **Sync now**, **Pull from remote…**, or **Push to remote…**
|
|
85
|
-
The flow names the current
|
|
105
|
+
When **Sync now**, **Pull from remote…**, or **Push to remote…** requires a direction choice, the manager opens **Resolve sync conflict**.
|
|
106
|
+
The flow names the current setup and explains whether local content, remote content, or the included-content policy changed.
|
|
86
107
|
|
|
87
|
-
An explicit remote content-list mismatch
|
|
108
|
+
An explicit remote content-list mismatch opens **Synced content differs** in the same manager flow.
|
|
88
109
|
Nothing changes until you choose an action.
|
|
89
110
|
Choose **Review all paths (recommended)** first to compare exact remote-only paths, device-only paths, and both ordered lists.
|
|
90
111
|
If membership matches but order differs, the review says that only ordering differs.
|
|
@@ -96,13 +117,12 @@ Then choose one action:
|
|
|
96
117
|
- **Keep this device's content list and update remote…** opens the existing `push --force` preparation and exact confirmation without `--yes`.
|
|
97
118
|
Cancelling preparation or confirmation returns to the content-list choice without changing remote data.
|
|
98
119
|
- **Cancel** returns to the manager without changing settings, files, remote data, or sync state.
|
|
99
|
-
- **Later** appears when automatic startup sync detected the mismatch and returns immediately to the Pi editor without changing anything.
|
|
100
120
|
|
|
101
121
|
Choose **Review differences (recommended)** in an ordinary file-direction conflict to inspect the exact affected paths without changing local files, remote data, or sync state.
|
|
102
122
|
Then choose one reviewed direction:
|
|
103
123
|
|
|
104
124
|
- **Keep local content and replace remote…** uses the existing forced-push path.
|
|
105
|
-
It
|
|
125
|
+
It applies the [secret-scan setting](./docs/settings.md#secret-scanning), shows the exact remote publication effect, re-reads a changed remote head, and asks again if the reviewed plan changed.
|
|
106
126
|
- **Use remote content and replace local…** uses the existing forced-pull path.
|
|
107
127
|
It shows exact local writes and deletions, protects the live session, and creates a local backup before applying.
|
|
108
128
|
- First sync uses **Use local as initial source…** and **Use remote as initial source…** labels.
|
|
@@ -111,77 +131,51 @@ Then choose one reviewed direction:
|
|
|
111
131
|
Cancelling a preparation or confirmation returns to conflict resolution with no side effects.
|
|
112
132
|
Back returns to the sync manager, and Ctrl+C closes the complete flow.
|
|
113
133
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
It clears after verified resolution, invalidation, session replacement, or shutdown.
|
|
134
|
+
Startup checks never open a dialog. Detected changes leave a compact hint above the editor; open `/sync` when ready. An included-content mismatch puts **Review synced content (recommended)** in the manager, where a fresh review verifies the remote snapshot before offering changes.
|
|
135
|
+
Check results are advisory observations against the last sync baseline, not proof of a file conflict or current equality. Opening the manager uses local information and shows when the check completed; it does not contact remote storage. Transfer actions recheck current content.
|
|
136
|
+
Attention stays in memory and is invalidated by relevant settings/state changes or a foreground transfer's commit boundary, and cleared on session replacement or shutdown. Cancelling a review or a failure before commit preserves a still-valid hint.
|
|
118
137
|
|
|
119
138
|
Interactive TUI `/sync sync`, `/sync pull`, and `/sync push` routes without `--yes` open the same review flow when they detect the mismatch.
|
|
120
139
|
Explicit `--yes` routes remain non-interactive and report exact remote-only, device-only, or order-only guidance while leaving visible attention for later review.
|
|
121
140
|
Shutdown automatic sync never opens a dialog because Pi is exiting.
|
|
122
|
-
RPC startup
|
|
141
|
+
RPC startup check results use nonblocking notifications; included-content review remains read-only.
|
|
142
|
+
Print and JSON modes do not support `/sync` because UI output is not observable there.
|
|
123
143
|
|
|
124
144
|
## ⚙️ Settings
|
|
125
145
|
|
|
126
|
-
|
|
146
|
+
Run `/sync` → **Set up sync** to create the canonical private user file at `<getAgentDir()>/pi-sync.json` (normally `~/.pi/agent/pi-sync.json`).
|
|
147
|
+
Use **Settings** to manage an existing setup.
|
|
148
|
+
Missing settings stay unconfigured without creating files or locks.
|
|
127
149
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
150
|
+
### Background startup checks
|
|
151
|
+
|
|
152
|
+
With **Automatic sync** enabled, session startup schedules a background check instead of waiting for a transfer. Pi remains usable while Git, WebDAV, R2, or S3 checks local hashes and remote metadata. Unchanged results are quiet; changes or failures provide `/sync` guidance without opening a dialog. Use **Sync now** to start a reviewed transfer, or `/sync status` to retry a check. Foreground `/sync` cancels and drains the background check before starting.
|
|
153
|
+
|
|
154
|
+
Checks run once per session start, including `/reload`, new, resumed, and forked sessions, in TUI and RPC only. Print/JSON skip startup checks. There is no polling or automatic check retry loop. The overall deadline is 30 seconds, followed by underlying cleanup where needed; Git process termination and temporary-ref cleanup can take additional time. Git checks can still fetch objects and update the extension's private bare cache, but never push, apply managed files, update the sync baseline, or reload Pi.
|
|
131
155
|
|
|
132
|
-
|
|
133
|
-
Missing settings load as unconfigured without creating an agent directory, file, temporary, or lock.
|
|
134
|
-
An explicit setup creates the file atomically.
|
|
135
|
-
On POSIX, pi-sync creates and replaces it with mode `0600`.
|
|
136
|
-
Pi-sync processes coordinate settings access through `pi-sync.json.mutation-lock`; lock-unaware editors are outside that serialization boundary and should not save the file while a pi-sync settings operation is running.
|
|
137
|
-
Credentials stay in this canonical private file and are never shown in menus, reviews, status, notifications, errors, logs, or completion metadata.
|
|
156
|
+
**Compatibility change:** the existing `sync.automatic` boolean and Off default are unchanged, but On no longer performs startup push/pull. Startup is not guaranteed to use the latest remote content. Local transaction recovery remains an awaited safety barrier and can restore interrupted file changes before use; existing legacy settings-file initialization is also retained.
|
|
138
157
|
|
|
139
|
-
|
|
140
|
-
If both paths exist, `pi-sync.json` wins and the other path remains untouched.
|
|
158
|
+
Shutdown behavior is unchanged: when **Automatic sync** is On and sessions are included, pi-sync can automatically push the selected content, not only session files. This also applies to headless modes; shutdown never opens a dialog, and `/reload` skips this push. Turning the setting Off disables both future startup checks and automatic shutdown pushes.
|
|
141
159
|
|
|
142
|
-
|
|
160
|
+
**Settings → Skip secret scan (all setups)** defaults to **Off**; enable it only after reviewing the destination and selected content because it disables push scanning for every setup.
|
|
161
|
+
See [Secret scanning](./docs/settings.md#secret-scanning) for the setting and diagnostic behavior.
|
|
162
|
+
|
|
163
|
+
A minimal Git setup uses an existing private remote and keeps automatic sync off:
|
|
143
164
|
|
|
144
165
|
```json
|
|
145
166
|
{
|
|
146
167
|
"version": 3,
|
|
147
168
|
"activeSyncSetup": "home",
|
|
148
169
|
"onSwitch": "ask-before-pull",
|
|
170
|
+
"skipSecretScan": false,
|
|
149
171
|
"storageConnections": {
|
|
150
|
-
"r2": {
|
|
151
|
-
"type": "s3",
|
|
152
|
-
"endpoint": "https://example.r2.cloudflarestorage.com",
|
|
153
|
-
"region": "auto",
|
|
154
|
-
"credentials": {
|
|
155
|
-
"accessKeyId": "<access-key-id>",
|
|
156
|
-
"secretAccessKey": "<secret-access-key>"
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
172
|
"github": {
|
|
160
173
|
"type": "git",
|
|
161
174
|
"remote": "git@github.com:owner/private-pi-sync.git"
|
|
162
|
-
},
|
|
163
|
-
"nextcloud": {
|
|
164
|
-
"type": "webdav",
|
|
165
|
-
"url": "https://cloud.example.com/remote.php/dav/files/user",
|
|
166
|
-
"credentials": {
|
|
167
|
-
"username": "user",
|
|
168
|
-
"password": "<app-password>"
|
|
169
|
-
}
|
|
170
175
|
}
|
|
171
176
|
},
|
|
172
177
|
"syncSetups": {
|
|
173
178
|
"home": {
|
|
174
|
-
"storage": {
|
|
175
|
-
"connection": "r2",
|
|
176
|
-
"bucket": "personal-pi",
|
|
177
|
-
"path": "pi-sync/home"
|
|
178
|
-
},
|
|
179
|
-
"sync": {
|
|
180
|
-
"include": ["settings.json", "AGENTS.md", "skills", "prompts", "themes"],
|
|
181
|
-
"automatic": true
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
"git-backup": {
|
|
185
179
|
"storage": {
|
|
186
180
|
"connection": "github",
|
|
187
181
|
"branch": "pi-sync/home",
|
|
@@ -191,136 +185,53 @@ If both paths exist, `pi-sync.json` wins and the other path remains untouched.
|
|
|
191
185
|
"include": ["settings.json", "AGENTS.md"],
|
|
192
186
|
"automatic": false
|
|
193
187
|
}
|
|
194
|
-
},
|
|
195
|
-
"webdav-backup": {
|
|
196
|
-
"storage": {
|
|
197
|
-
"connection": "nextcloud",
|
|
198
|
-
"path": "pi-sync/home"
|
|
199
|
-
},
|
|
200
|
-
"sync": {
|
|
201
|
-
"include": ["settings.json", "sessions"],
|
|
202
|
-
"automatic": false
|
|
203
|
-
}
|
|
204
188
|
}
|
|
205
189
|
}
|
|
206
190
|
}
|
|
207
191
|
```
|
|
208
192
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
### Required backend shapes
|
|
213
|
-
|
|
214
|
-
- **S3/R2 connection:** `type`, `endpoint`, `region`, and `credentials.accessKeyId` / `credentials.secretAccessKey`.
|
|
215
|
-
- **S3/R2 setup storage:** `connection`, `bucket`, and complete relative `path`; `branch` is rejected.
|
|
216
|
-
- **Git connection:** `type` and a credential-free SSH or HTTPS `remote`.
|
|
217
|
-
- **Git setup storage:** `connection`, `branch`, and complete repository `path`; `bucket` is rejected.
|
|
218
|
-
- **WebDAV connection:** `type`, HTTPS `url`, and `credentials.username` / `credentials.password`.
|
|
219
|
-
- **WebDAV setup storage:** `connection` and complete relative `path`; `bucket` and `branch` are rejected.
|
|
220
|
-
|
|
221
|
-
Every setup requires `sync.include` and explicit `sync.automatic`.
|
|
222
|
-
`activeSyncSetup` must reference an own-property setup when any setups exist and must be absent when the setup catalog is empty.
|
|
223
|
-
A referenced connection cannot be removed.
|
|
224
|
-
The current setup must be switched before removal.
|
|
225
|
-
Two setups cannot resolve to the same normalized backend location.
|
|
226
|
-
|
|
227
|
-
`onSwitch` accepts:
|
|
228
|
-
|
|
229
|
-
- `ask-before-pull` — switch, then ask in TUI whether to start a reviewed pull;
|
|
230
|
-
- `pull-after-switch` — require observable UI and start the normal reviewed pull;
|
|
231
|
-
- `switch-only` — switch without reading or applying remote content.
|
|
232
|
-
|
|
233
|
-
### Included content
|
|
234
|
-
|
|
235
|
-
`sync.include` is ordered and duplicate-free.
|
|
236
|
-
Supported Pi roots are:
|
|
237
|
-
|
|
238
|
-
```text
|
|
239
|
-
settings.json, keybindings.json, models.json, AGENTS.md, APPEND_SYSTEM.md,
|
|
240
|
-
skills, prompts, themes, extensions, sessions
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Safe agent-relative custom files or directories may also be included.
|
|
244
|
-
Absolute paths, `..`, backslashes, controls, denied secret/settings paths, duplicate case variants, and ambiguous nested paths under reserved roots are rejected.
|
|
245
|
-
|
|
246
|
-
An empty array is valid.
|
|
247
|
-
It means no useful transfer is selected: **Sync now** reports the condition and does not claim that the setup is up to date.
|
|
248
|
-
Unselected content remains unmanaged locally and is preserved when republishing existing remote snapshots.
|
|
249
|
-
|
|
250
|
-
The Included Content editor is a standard bounded multi-select backed by one in-memory draft.
|
|
251
|
-
Toggles never write settings.
|
|
252
|
-
**Add custom path…** accepts a safe agent-relative file or directory even when it does not exist locally yet, allowing a new environment to select content that exists only in the remote snapshot.
|
|
253
|
-
Leaving the editor opens an exact Include/Exclude review with **Save changes**, **Discard changes**, and **Continue editing**; only reviewed Save publishes, while Continue preserves the draft and Discard/cancellation preserves the settings bytes.
|
|
254
|
-
RPC remains a read-only summary with the manual `sync.include` path.
|
|
255
|
-
|
|
256
|
-
Every new snapshot stores the normalized included-content selection separately from the files that happened to exist.
|
|
257
|
-
This preserves selected-but-missing paths without syncing `pi-sync.json`, storage credentials, automatic-sync preferences, or setup names.
|
|
258
|
-
**Settings → Compare synced content** opens the same review-first flow as a manager operation when local and remote lists differ.
|
|
259
|
-
Adoption revalidates the remote head, immutable snapshot, reviewed storage coordinates, and local include list before one atomic settings update.
|
|
260
|
-
The saved state changes only `sync.include`, preserves unknown settings fields, and never pulls files or writes sync state.
|
|
261
|
-
Its explicit Continue action starts a fresh **Sync now** route, while **Done** leaves the reviewed settings change saved without implying a file operation.
|
|
262
|
-
Keeping this device's list opens the reviewed force-push path and explicitly replaces the remote policy while preserving eligible unmanaged remote files.
|
|
263
|
-
|
|
264
|
-
Automatic sync and pull, including forced pull, pause on an explicit remote-policy difference rather than silently expanding local scope.
|
|
265
|
-
Status reports matches and exact local-only/remote-only paths.
|
|
266
|
-
Old snapshots remain readable.
|
|
267
|
-
Because they have no authoritative selection, pi-sync offers only a clearly labeled read-only partial discovery from safe remote file roots; selected-but-missing and preserved-unmanaged intent cannot be reconstructed.
|
|
268
|
-
Use **Add custom path…** for any needed path.
|
|
269
|
-
|
|
270
|
-
Adding `sessions` requires a privacy acknowledgement in interactive flows.
|
|
271
|
-
Session JSONL can contain prompts, tool output, file paths, images, and secrets.
|
|
272
|
-
Automatic apply protects the currently open session file; restart Pi or resume a pulled session to use newly synchronized conversations.
|
|
273
|
-
|
|
274
|
-
### Unsupported old settings and recovery
|
|
275
|
-
|
|
276
|
-
Version 1, version 2, and non-empty unversioned documents are intentionally unsupported by this breaking schema reset. pi-sync does **not** migrate, partially interpret, downgrade, or overwrite them.
|
|
277
|
-
Automatic sync pauses and reports an actionable version 3 error without displaying secrets.
|
|
278
|
-
|
|
279
|
-
Recovery:
|
|
280
|
-
|
|
281
|
-
1. retain the old file byte-for-byte;
|
|
282
|
-
2. move it aside manually;
|
|
283
|
-
3. create a new version 3 document or run the setup manager;
|
|
284
|
-
4. run `/sync doctor`, inspect the exact storage path, and review the first pull or push;
|
|
285
|
-
5. restore the retained file and a compatible older package only if rolling back.
|
|
286
|
-
|
|
193
|
+
Setup saves are atomic and private (`0600` on POSIX), preserve unknown fields, and coordinate across pi-sync processes.
|
|
194
|
+
Do not save from a lock-unaware editor during a pi-sync settings operation.
|
|
287
195
|
Malformed, invalid, unsupported, symlinked, or concurrently changed documents remain untouched.
|
|
288
|
-
|
|
196
|
+
Version 1, version 2, and non-empty unversioned settings require manual recovery rather than automatic migration.
|
|
289
197
|
|
|
290
|
-
|
|
198
|
+
Adding `sessions` can upload prompts, tool output, paths, images, and secrets; interactive flows require a privacy acknowledgement.
|
|
199
|
+
Startup checks report included-content differences without changing anything. Transfers retain their existing included-content policy checks instead of silently expanding local scope.
|
|
291
200
|
|
|
292
|
-
|
|
201
|
+
Read the [settings reference](./docs/settings.md) for complete S3/R2, Git, and WebDAV examples, backend fields, included-content rules, legacy paths, and recovery steps.
|
|
293
202
|
|
|
294
|
-
|
|
295
|
-
/sync help
|
|
296
|
-
/sync use <setup>
|
|
297
|
-
/sync init
|
|
298
|
-
/sync config [--setup <name>]
|
|
299
|
-
/sync files [--setup <name>]
|
|
300
|
-
/sync status [--setup <name>]
|
|
301
|
-
/sync diff [--setup <name>]
|
|
302
|
-
/sync doctor [--setup <name>]
|
|
303
|
-
/sync push [--setup <name>]
|
|
304
|
-
/sync pull [--setup <name>]
|
|
305
|
-
/sync sync [--setup <name>]
|
|
306
|
-
/sync history [--setup <name>]
|
|
307
|
-
/sync rollback <snapshot-id> [--setup <name>]
|
|
308
|
-
/sync migrate-state [--yes]
|
|
309
|
-
/sync unlock --stale
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
- `--setup <name>` addresses a setup without switching it.
|
|
313
|
-
- `--yes` / `-y` skips a direct route's confirmation.
|
|
314
|
-
- `--force` accepts a reviewed content conflict but never disables backend concurrency protection.
|
|
315
|
-
- `--stale` requests guarded stale-lock recovery.
|
|
316
|
-
|
|
317
|
-
The former version 2 setup-addressing flag is rejected.
|
|
318
|
-
Unknown flags, unknown commands, trailing values, and missing setup/snapshot values are rejected.
|
|
319
|
-
Completion includes known setup names and preserves preceding command tokens.
|
|
203
|
+
## 💬 Commands
|
|
320
204
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
205
|
+
| Command | Purpose |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| `/sync` | Set up storage, manage synced content, and review sync operations or recovery. |
|
|
208
|
+
| `/sync help` | Show command usage. |
|
|
209
|
+
| `/sync use <setup>` | Switch the active local sync setup, following its switch policy. |
|
|
210
|
+
| `/sync init` | Create a local configuration template. |
|
|
211
|
+
| `/sync config` | Show resolved configuration. |
|
|
212
|
+
| `/sync files` | List included local files. |
|
|
213
|
+
| `/sync status` | Compare local and remote snapshot state. |
|
|
214
|
+
| `/sync diff` | Show local and remote differences. |
|
|
215
|
+
| `/sync doctor` | Check configuration, connectivity, and backend safety. |
|
|
216
|
+
| `/sync push` | Publish local content to remote storage. |
|
|
217
|
+
| `/sync pull` | Back up local content, then apply the remote snapshot. |
|
|
218
|
+
| `/sync sync` | Choose a safe sync direction or require conflict review. |
|
|
219
|
+
| `/sync history` | Browse remote snapshots and review a rollback. |
|
|
220
|
+
| `/sync rollback <snapshot-id>` | Back up local content, apply a historical snapshot, and republish it remotely. |
|
|
221
|
+
| `/sync migrate-state` | Migrate the legacy local state directory. |
|
|
222
|
+
| `/sync unlock --stale` | Recover an abandoned local lock after guarded ownership checks. |
|
|
223
|
+
|
|
224
|
+
All routes support TUI and RPC; RPC settings and included-content screens are read-only.
|
|
225
|
+
Print and JSON modes reject `/sync`.
|
|
226
|
+
Unknown commands or flags, trailing values, and missing setup/snapshot values are rejected, including the former version 2 setup-addressing flag.
|
|
227
|
+
|
|
228
|
+
- `--setup <name>` targets a setup without switching it on `config`, `files`, `status`, `diff`, `doctor`, `push`, `pull`, `sync`, `history`, and `rollback`.
|
|
229
|
+
- `--yes` (alias: `-y`) skips confirmation on `push`, `pull`, `sync`, `rollback`, and `migrate-state`; use only after reviewing the affected content.
|
|
230
|
+
- `--force` lets `push` or `pull` accept content conflicts without disabling backend concurrency protection. It is also accepted by `sync`, which still requires a direction choice for divergent content, and by `rollback`, where it has no additional effect.
|
|
231
|
+
- `--stale` is accepted only by `unlock` and is required to remove a stale lock.
|
|
232
|
+
|
|
233
|
+
Push and rollback publish data externally; pull and rollback can replace or delete local managed files.
|
|
234
|
+
Review [Settings](#-settings) for included-content privacy and [Manager, conflicts, and recovery](#-manager-conflicts-and-recovery) before forcing a direction, skipping confirmation, or removing a lock.
|
|
324
235
|
|
|
325
236
|
## 🔄 Backend and recovery model
|
|
326
237
|
|
|
@@ -337,7 +248,7 @@ The private bare cache under `<agent-dir>/pi-sync/git/` is rebuildable.
|
|
|
337
248
|
|
|
338
249
|
WebDAV requires HTTPS except loopback tests.
|
|
339
250
|
URL credentials, query strings, fragments, unsafe redirects, weak/missing ETags, and ignored conditional headers fail closed.
|
|
340
|
-
`/sync doctor` verifies collection and conditional-write behavior with an isolated probe.
|
|
251
|
+
`/sync doctor` verifies collection and conditional-write behavior with an isolated probe, then repairs a missing active-snapshot history entry.
|
|
341
252
|
|
|
342
253
|
S3/R2 stages immutable bundles, rechecks the visible head before publication, and verifies afterward.
|
|
343
254
|
Unlike Git/WebDAV, generic S3 does not provide an atomic compare-and-swap for `latest.json`; status review remains important for simultaneous writers.
|
|
@@ -357,7 +268,7 @@ Preserve both roots before manual recovery; with every Pi process closed and no
|
|
|
357
268
|
## 🔒 Security and privacy
|
|
358
269
|
|
|
359
270
|
- Canonical, legacy, temporary, and recovery settings paths are denied from snapshots; both `pi-sync/` and `.pisync/` state roots are permanently denied.
|
|
360
|
-
- Push scans managed local content for common secret patterns.
|
|
271
|
+
- Push scans managed local content for common secret patterns unless the user explicitly enables **Skip secret scan**; `/sync doctor` always retains the diagnostic scan.
|
|
361
272
|
- Remote snapshot references, checksums, paths, manifests, response sizes, and publication revisions are validated.
|
|
362
273
|
- Symlink parents, path escapes, duplicate paths, and unsafe file/directory replacement fail before local mutation.
|
|
363
274
|
- Live locks block mutation; stale recovery rechecks process and guard ownership.
|
|
@@ -365,59 +276,41 @@ Preserve both roots before manual recovery; with every Pi process closed and no
|
|
|
365
276
|
Publication/apply commit boundaries finish with bounded signals and report ambiguous outcomes explicitly.
|
|
366
277
|
- Terminal-bound names, paths, metadata, and errors are control-character sanitized.
|
|
367
278
|
|
|
368
|
-
## ♿
|
|
279
|
+
## ♿ Terminal accessibility
|
|
369
280
|
|
|
370
|
-
Pi exposes terminal components rather than a semantic
|
|
371
|
-
Release
|
|
372
|
-
Critical meaning appears in text such as `(current)`, `Review needed`, `
|
|
373
|
-
|
|
281
|
+
Pi exposes terminal components rather than a semantic or ARIA tree.
|
|
282
|
+
Release checks cover textual state, keyboard operation, Escape and Back behavior, control escaping, and narrow rendering.
|
|
283
|
+
Critical meaning appears in text such as `(current)`, `Review needed`, `No startup transfer`, `Warning`, `Invalid`, `Saved`, `Cancelled`, and `Applied`.
|
|
284
|
+
Color is supplementary, and the attention widget is informational rather than interactive.
|
|
374
285
|
|
|
375
286
|
## 🗂️ Package layout
|
|
376
287
|
|
|
377
288
|
```text
|
|
378
289
|
packages/pi-sync/
|
|
379
|
-
├── dist/ # Generated split TypeScript runtime loaded through Pi's Jiti loader
|
|
380
|
-
├── scripts/
|
|
381
|
-
│ └── build-runtime.mjs # Deterministic bundler and eager-boundary validator
|
|
382
290
|
├── src/
|
|
383
|
-
│ ├── index.ts
|
|
384
|
-
│ ├── sync-extension.ts
|
|
385
|
-
│ ├──
|
|
386
|
-
│ ├──
|
|
387
|
-
│ ├──
|
|
388
|
-
│ ├──
|
|
389
|
-
│ ├──
|
|
390
|
-
│ ├──
|
|
391
|
-
│
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
│ ├── sync-attention.ts
|
|
397
|
-
│ ├── storage-connections-ui.ts
|
|
398
|
-
│ ├── sync-setups-ui.ts
|
|
399
|
-
│ ├── file-selection.ts
|
|
400
|
-
│ ├── remote-selection-ui.ts
|
|
401
|
-
│ ├── remote-snapshot.ts
|
|
402
|
-
│ ├── sync-operations.ts
|
|
403
|
-
│ ├── sync-backend.ts
|
|
404
|
-
│ ├── backend-factory.ts # lazy selected-backend loader
|
|
405
|
-
│ ├── s3-backend.ts
|
|
406
|
-
│ ├── webdav-backend.ts
|
|
407
|
-
│ ├── git-backend.ts
|
|
408
|
-
│ ├── snapshot-paths.ts # Eager recovery-safe session path helpers
|
|
409
|
-
│ ├── snapshot.ts # Loaded only for snapshot operations/session push
|
|
410
|
-
│ └── *.ts
|
|
411
|
-
├── test/
|
|
412
|
-
├── README.md
|
|
413
|
-
├── LICENSE
|
|
414
|
-
└── package.json
|
|
291
|
+
│ ├── index.ts # Thin Pi entrypoint
|
|
292
|
+
│ ├── sync-extension.ts # Registration and session lifecycle ownership
|
|
293
|
+
│ ├── commands/ # Parsing, execution, and attention dispatch
|
|
294
|
+
│ ├── settings/ # Schema, validation, resolution, and persistence
|
|
295
|
+
│ ├── sync/ # Queries, mutations, policy, and lazy loaders
|
|
296
|
+
│ ├── snapshot/ # Collection, session paths, apply, and recovery
|
|
297
|
+
│ ├── backends/ # Contract and Git, S3, and WebDAV transports
|
|
298
|
+
│ ├── state/ # Sync-state persistence, locks, and migration
|
|
299
|
+
│ └── ui/ # Manager, settings, reviews, and setup flows
|
|
300
|
+
├── dist/ # Generated Jiti runtime
|
|
301
|
+
├── scripts/build-runtime.mjs # Runtime builder
|
|
302
|
+
├── docs/ # Published reference documentation
|
|
303
|
+
└── test/ # Behavior and lifecycle coverage
|
|
415
304
|
```
|
|
416
305
|
|
|
306
|
+
The generated runtime is built from `src/index.ts` and does not import back into `src`.
|
|
307
|
+
Internal modules use direct imports from their owners; `src/sync.ts` and `src/types.ts` retain compatibility exports.
|
|
308
|
+
Backend transports do not depend on UI, and first-use operation and setup implementations remain lazy.
|
|
309
|
+
|
|
417
310
|
## 🔎 Keywords
|
|
418
311
|
|
|
419
312
|
Pi extension, Pi coding agent, settings sync, Git, WebDAV, Nextcloud, Cloudflare R2, S3-compatible storage, storage connections, sync setups, snapshot sync, dotfiles sync.
|
|
420
313
|
|
|
421
314
|
## 📄 License
|
|
422
315
|
|
|
423
|
-
MIT
|
|
316
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
|
|
4
|
+
// src/sync/sync-errors.ts
|
|
5
|
+
var SetupPullRequiresUiError = class extends Error {
|
|
6
|
+
};
|
|
7
|
+
var SyncDecisionRequiredError = class extends Error {
|
|
8
|
+
decision;
|
|
9
|
+
constructor(decision) {
|
|
10
|
+
super(decision.directMessage);
|
|
11
|
+
this.name = "SyncDecisionRequiredError";
|
|
12
|
+
this.decision = decision;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function isSyncDecisionRequiredError(error) {
|
|
16
|
+
return error instanceof SyncDecisionRequiredError;
|
|
17
|
+
}
|
|
18
|
+
function errorMessage(error) {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
return message.replace(/[\u0000-\u001f\u007f-\u009f]/gu, "?");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
SetupPullRequiresUiError,
|
|
25
|
+
SyncDecisionRequiredError,
|
|
26
|
+
isSyncDecisionRequiredError,
|
|
27
|
+
errorMessage
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=chunk-2B2ELUF5.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/sync-errors.ts"],
|
|
4
|
+
"sourcesContent": ["import type { SyncDecision } from \"./sync-decision.js\";\n\nexport class SetupPullRequiresUiError extends Error {}\n\nexport class SyncDecisionRequiredError extends Error {\n\treadonly decision: SyncDecision;\n\n\tconstructor(decision: SyncDecision) {\n\t\tsuper(decision.directMessage);\n\t\tthis.name = \"SyncDecisionRequiredError\";\n\t\tthis.decision = decision;\n\t}\n}\n\nexport function isSyncDecisionRequiredError(error: unknown): error is SyncDecisionRequiredError {\n\treturn error instanceof SyncDecisionRequiredError;\n}\n\nexport function errorMessage(error: unknown) {\n\tconst message = error instanceof Error ? error.message : String(error);\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.\n\treturn message.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \"?\");\n}\n"],
|
|
5
|
+
"mappings": ";;;;AAEO,IAAM,2BAAN,cAAuC,MAAM;AAAC;AAE9C,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC3C;AAAA,EAET,YAAY,UAAwB;AACnC,UAAM,SAAS,aAAa;AAC5B,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EACjB;AACD;AAEO,SAAS,4BAA4B,OAAoD;AAC/F,SAAO,iBAAiB;AACzB;AAEO,SAAS,aAAa,OAAgB;AAC5C,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAErE,SAAO,QAAQ,QAAQ,kCAAkC,GAAG;AAC7D;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|