@narumitw/pi-sync 0.57.10 → 0.57.12
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/CHANGELOG.md +14 -0
- package/README.md +32 -22
- package/dist/chunks/{agent-candidate-EYB35AGL.ts → agent-candidate-U2NU3GUX.ts} +11 -11
- package/dist/chunks/{agent-plan-KO43GTOR.ts → agent-plan-3YXDIJXO.ts} +25 -22
- package/dist/chunks/agent-plan-3YXDIJXO.ts.map +7 -0
- package/dist/chunks/{agent-refusal-retry-C2HQROTP.ts → agent-refusal-retry-476YGNU5.ts} +10 -10
- package/dist/chunks/{agent-runner-WMSCKSCB.ts → agent-runner-FCRV2Z75.ts} +11 -10
- package/dist/chunks/agent-runner-FCRV2Z75.ts.map +7 -0
- package/dist/chunks/{agent-store-UT52DS7B.ts → agent-store-7GINKTS7.ts} +8 -8
- package/dist/chunks/{agent-store-UT52DS7B.ts.map → agent-store-7GINKTS7.ts.map} +2 -2
- package/dist/chunks/{agent-sync-VM3TXWA3.ts → agent-sync-P6AWQXGK.ts} +6 -6
- package/dist/chunks/{chunk-JXWTEJS5.ts → chunk-45COPAK7.ts} +10 -3
- package/dist/chunks/chunk-45COPAK7.ts.map +7 -0
- package/dist/chunks/{chunk-DOJRPBQU.ts → chunk-5TSCBBPP.ts} +4 -4
- package/dist/chunks/{chunk-CDQGSZL3.ts → chunk-6LD5KX55.ts} +6 -6
- package/dist/chunks/{chunk-MDUORMCK.ts → chunk-6O3EDBRL.ts} +2 -2
- package/dist/chunks/{chunk-AAPAHANE.ts → chunk-7A35ZAVO.ts} +320 -219
- package/dist/chunks/chunk-7A35ZAVO.ts.map +7 -0
- package/dist/chunks/{chunk-STVQQ5KG.ts → chunk-7ZIYU5QS.ts} +6 -6
- package/dist/chunks/{chunk-AO6EDUA6.ts → chunk-AKMV47YC.ts} +3 -3
- package/dist/chunks/{chunk-66GAUVDL.ts → chunk-BEST45H2.ts} +6 -6
- package/dist/chunks/{chunk-DO55XUNU.ts → chunk-CBLTWXAU.ts} +15 -5
- package/dist/chunks/chunk-CBLTWXAU.ts.map +7 -0
- package/dist/chunks/{chunk-IMMMZUFC.ts → chunk-CQD2TJHE.ts} +7 -7
- package/dist/chunks/{chunk-IMMMZUFC.ts.map → chunk-CQD2TJHE.ts.map} +2 -2
- package/dist/chunks/{chunk-73MDIVYJ.ts → chunk-DN4IA7MR.ts} +6 -6
- package/dist/chunks/{chunk-PHANBTVM.ts → chunk-ESKOPQVB.ts} +4 -4
- package/dist/chunks/{chunk-YZ5BQNRZ.ts → chunk-FHE2DCA2.ts} +2 -2
- package/dist/chunks/{chunk-YZ5BQNRZ.ts.map → chunk-FHE2DCA2.ts.map} +2 -2
- package/dist/chunks/{chunk-MRIPZGPR.ts → chunk-FLHCOJCD.ts} +3 -3
- package/dist/chunks/{chunk-5WJQ6XOW.ts → chunk-GNYGNHFF.ts} +2 -2
- package/dist/chunks/{chunk-DFJGTVPX.ts → chunk-KYTT7KV4.ts} +2 -2
- package/dist/chunks/{chunk-UGSSZWQ6.ts → chunk-MKSMJPVA.ts} +2 -2
- package/dist/chunks/{chunk-2VSN3MFX.ts → chunk-MMQIEDZ6.ts} +33 -27
- package/dist/chunks/chunk-MMQIEDZ6.ts.map +7 -0
- package/dist/chunks/{chunk-RAMHGOX2.ts → chunk-OJARL2TG.ts} +4 -4
- package/dist/chunks/{chunk-BJXSCGQK.ts → chunk-OKPPZA4D.ts} +148 -89
- package/dist/chunks/chunk-OKPPZA4D.ts.map +7 -0
- package/dist/chunks/{chunk-RX3WGWVL.ts → chunk-OVBAW7KV.ts} +177 -130
- package/dist/chunks/chunk-OVBAW7KV.ts.map +7 -0
- package/dist/chunks/{chunk-U77DWNRH.ts → chunk-Q23JJW7E.ts} +3 -3
- package/dist/chunks/{chunk-NLWS55B6.ts → chunk-QPC5HT3A.ts} +2 -2
- package/dist/chunks/{chunk-NLWS55B6.ts.map → chunk-QPC5HT3A.ts.map} +1 -1
- package/dist/chunks/{chunk-4RLATUP4.ts → chunk-S5OCYVPS.ts} +7 -7
- package/dist/chunks/{chunk-4RLATUP4.ts.map → chunk-S5OCYVPS.ts.map} +2 -2
- package/dist/chunks/{chunk-QWV3XKNJ.ts → chunk-TIMWN2RH.ts} +5 -5
- package/dist/chunks/{chunk-Z5O2TLNF.ts → chunk-TZC7GDJE.ts} +7 -7
- package/dist/chunks/{chunk-UCD7TQDT.ts → chunk-U6GXGY5G.ts} +5 -5
- package/dist/chunks/{chunk-PWA3YN5Z.ts → chunk-XEODG2PE.ts} +3 -3
- package/dist/chunks/{chunk-TO2GMX3K.ts → chunk-XJHQPB3E.ts} +2 -2
- package/dist/chunks/{chunk-JY2RVOUL.ts → chunk-Y4UVXOLQ.ts} +5 -5
- package/dist/chunks/{chunk-ODF2M4RF.ts → chunk-ZC3IHFNM.ts} +8 -8
- package/dist/chunks/{chunk-ODF2M4RF.ts.map → chunk-ZC3IHFNM.ts.map} +2 -2
- package/dist/chunks/{chunk-M5IV3KL2.ts → chunk-ZDDBZH72.ts} +3 -3
- package/dist/chunks/{command-handler-FO6F2APH.ts → command-handler-VKLZBRLO.ts} +26 -21
- package/dist/chunks/command-handler-VKLZBRLO.ts.map +7 -0
- package/dist/chunks/{config-B37W7FXW.ts → config-HYG7G5EM.ts} +6 -4
- package/dist/chunks/{conflict-artifacts-6XGSSU5S.ts → conflict-artifacts-J6WSDCWP.ts} +12 -12
- package/dist/chunks/{conflict-review-BQSHSJB3.ts → conflict-review-GXA6Y7KY.ts} +23 -23
- package/dist/chunks/{continuous-record-4DQ2EAZS.ts → continuous-record-EPHGR2DU.ts} +6 -6
- package/dist/chunks/{continuous-sync-ZT3UEQLK.ts → continuous-sync-TTOSJCQU.ts} +18 -18
- package/dist/chunks/{file-selection-FBLKM25V.ts → file-selection-IELTXSGZ.ts} +6 -7
- package/dist/chunks/{file-selection-FBLKM25V.ts.map → file-selection-IELTXSGZ.ts.map} +1 -1
- package/dist/chunks/{git-backend-7PCWECRN.ts → git-backend-KHD36W27.ts} +6 -7
- package/dist/chunks/{git-backend-7PCWECRN.ts.map → git-backend-KHD36W27.ts.map} +1 -1
- package/dist/chunks/{local-fields-B6JWLPAE.ts → local-fields-JEKAPZKD.ts} +6 -7
- package/dist/chunks/manager-result-dispatcher-6W52NM7F.ts +32 -0
- package/dist/chunks/{manager-ui-DGRTG76I.ts → manager-ui-INVMAFEN.ts} +245 -224
- package/dist/chunks/manager-ui-INVMAFEN.ts.map +7 -0
- package/dist/chunks/{merge-baseline-store-HL3VLMAM.ts → merge-baseline-store-65GKUMXI.ts} +6 -6
- package/dist/chunks/{remote-selection-ui-OHMIQ32X.ts → remote-selection-ui-TD4C4W3J.ts} +16 -12
- package/dist/chunks/{s3-backend-CJXBEWWU.ts → s3-backend-L24UZ6IK.ts} +12 -10
- package/dist/chunks/s3-backend-L24UZ6IK.ts.map +7 -0
- package/dist/chunks/{setup-switch-66GWMBNH.ts → setup-switch-KLGESLQX.ts} +6 -6
- package/dist/chunks/{setup-wizard-OHZXJVQZ.ts → setup-wizard-ZQAK35BP.ts} +7 -7
- package/dist/chunks/{snapshot-VRHNAUUH.ts → snapshot-RGNDYT6A.ts} +5 -6
- package/dist/chunks/{snapshot-transaction-EUGA4VX6.ts → snapshot-transaction-26BQO36S.ts} +8 -8
- package/dist/chunks/{sync-inspection-4WFQEJOE.ts → sync-inspection-MOMLGUTD.ts} +11 -11
- package/dist/chunks/{sync-operations-X4AOXMBT.ts → sync-operations-TMGQHBF5.ts} +26 -26
- package/dist/chunks/{sync-operations-X4AOXMBT.ts.map → sync-operations-TMGQHBF5.ts.map} +2 -2
- package/dist/chunks/{sync-state-SWLSMK4G.ts → sync-state-7L4NT7W2.ts} +7 -8
- package/dist/chunks/{webdav-backend-2Q5ZEBST.ts → webdav-backend-3ZCACILP.ts} +7 -8
- package/dist/chunks/{webdav-backend-2Q5ZEBST.ts.map → webdav-backend-3ZCACILP.ts.map} +1 -1
- package/dist/index.ts +20 -20
- package/docs/agent-continuous-hardening.md +5 -5
- package/docs/agent-mode-verification.md +3 -3
- package/docs/agent-quality-verification.md +3 -3
- package/docs/continuous-sync-verification.md +2 -2
- package/docs/settings.md +9 -5
- package/docs/tui-contract.md +20 -3
- package/package.json +3 -3
- package/skills/configure-pi-sync/SKILL.md +3 -1
- package/skills/configure-pi-sync/references/configuration.md +56 -38
- package/src/backends/s3/s3-client.ts +8 -1
- package/src/commands/command-execution.ts +11 -6
- package/src/commands/command.ts +1 -1
- package/src/paths.ts +6 -1
- package/src/settings/config-file.ts +205 -118
- package/src/settings/config.ts +1 -1
- package/src/settings/settings-management.ts +15 -1
- package/src/settings/settings-store.ts +0 -14
- package/src/settings/settings-types.ts +1 -1
- package/src/snapshot/session-paths.ts +15 -2
- package/src/snapshot/snapshot-mutation-queues.ts +142 -0
- package/src/snapshot/snapshot-transaction.ts +122 -125
- package/src/sync/agent-candidate.ts +3 -3
- package/src/sync/agent-plan.ts +11 -8
- package/src/sync/agent-runner.ts +10 -9
- package/src/sync/agent-store.ts +1 -1
- package/src/sync/agent-sync.ts +2 -2
- package/src/sync/continuous-record.ts +1 -1
- package/src/sync/merge-apply.ts +6 -0
- package/src/sync/merged-sync.ts +4 -4
- package/src/sync/sync-mutations.ts +1 -1
- package/src/ui/agent-mode-setting.ts +6 -6
- package/src/ui/cancellable-operation.ts +36 -13
- package/src/ui/manager-state.ts +4 -2
- package/src/ui/manager-ui.ts +76 -24
- package/src/ui/remote-selection-ui.ts +131 -82
- package/src/ui/settings-ui.ts +21 -56
- package/src/ui/setup/setup-switcher.ts +2 -2
- package/src/ui/sync-setups-ui.ts +2 -2
- package/dist/chunks/agent-plan-KO43GTOR.ts.map +0 -7
- package/dist/chunks/agent-runner-WMSCKSCB.ts.map +0 -7
- package/dist/chunks/chunk-2VSN3MFX.ts.map +0 -7
- package/dist/chunks/chunk-AAPAHANE.ts.map +0 -7
- package/dist/chunks/chunk-BJXSCGQK.ts.map +0 -7
- package/dist/chunks/chunk-DO55XUNU.ts.map +0 -7
- package/dist/chunks/chunk-JXWTEJS5.ts.map +0 -7
- package/dist/chunks/chunk-RX3WGWVL.ts.map +0 -7
- package/dist/chunks/command-handler-FO6F2APH.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-NODX3KKH.ts +0 -28
- package/dist/chunks/manager-ui-DGRTG76I.ts.map +0 -7
- package/dist/chunks/s3-backend-CJXBEWWU.ts.map +0 -7
- /package/dist/chunks/{agent-candidate-EYB35AGL.ts.map → agent-candidate-U2NU3GUX.ts.map} +0 -0
- /package/dist/chunks/{agent-refusal-retry-C2HQROTP.ts.map → agent-refusal-retry-476YGNU5.ts.map} +0 -0
- /package/dist/chunks/{agent-sync-VM3TXWA3.ts.map → agent-sync-P6AWQXGK.ts.map} +0 -0
- /package/dist/chunks/{chunk-DOJRPBQU.ts.map → chunk-5TSCBBPP.ts.map} +0 -0
- /package/dist/chunks/{chunk-CDQGSZL3.ts.map → chunk-6LD5KX55.ts.map} +0 -0
- /package/dist/chunks/{chunk-MDUORMCK.ts.map → chunk-6O3EDBRL.ts.map} +0 -0
- /package/dist/chunks/{chunk-STVQQ5KG.ts.map → chunk-7ZIYU5QS.ts.map} +0 -0
- /package/dist/chunks/{chunk-AO6EDUA6.ts.map → chunk-AKMV47YC.ts.map} +0 -0
- /package/dist/chunks/{chunk-66GAUVDL.ts.map → chunk-BEST45H2.ts.map} +0 -0
- /package/dist/chunks/{chunk-73MDIVYJ.ts.map → chunk-DN4IA7MR.ts.map} +0 -0
- /package/dist/chunks/{chunk-PHANBTVM.ts.map → chunk-ESKOPQVB.ts.map} +0 -0
- /package/dist/chunks/{chunk-MRIPZGPR.ts.map → chunk-FLHCOJCD.ts.map} +0 -0
- /package/dist/chunks/{chunk-5WJQ6XOW.ts.map → chunk-GNYGNHFF.ts.map} +0 -0
- /package/dist/chunks/{chunk-DFJGTVPX.ts.map → chunk-KYTT7KV4.ts.map} +0 -0
- /package/dist/chunks/{chunk-UGSSZWQ6.ts.map → chunk-MKSMJPVA.ts.map} +0 -0
- /package/dist/chunks/{chunk-RAMHGOX2.ts.map → chunk-OJARL2TG.ts.map} +0 -0
- /package/dist/chunks/{chunk-U77DWNRH.ts.map → chunk-Q23JJW7E.ts.map} +0 -0
- /package/dist/chunks/{chunk-QWV3XKNJ.ts.map → chunk-TIMWN2RH.ts.map} +0 -0
- /package/dist/chunks/{chunk-Z5O2TLNF.ts.map → chunk-TZC7GDJE.ts.map} +0 -0
- /package/dist/chunks/{chunk-UCD7TQDT.ts.map → chunk-U6GXGY5G.ts.map} +0 -0
- /package/dist/chunks/{chunk-PWA3YN5Z.ts.map → chunk-XEODG2PE.ts.map} +0 -0
- /package/dist/chunks/{chunk-TO2GMX3K.ts.map → chunk-XJHQPB3E.ts.map} +0 -0
- /package/dist/chunks/{chunk-JY2RVOUL.ts.map → chunk-Y4UVXOLQ.ts.map} +0 -0
- /package/dist/chunks/{chunk-M5IV3KL2.ts.map → chunk-ZDDBZH72.ts.map} +0 -0
- /package/dist/chunks/{config-B37W7FXW.ts.map → config-HYG7G5EM.ts.map} +0 -0
- /package/dist/chunks/{conflict-artifacts-6XGSSU5S.ts.map → conflict-artifacts-J6WSDCWP.ts.map} +0 -0
- /package/dist/chunks/{conflict-review-BQSHSJB3.ts.map → conflict-review-GXA6Y7KY.ts.map} +0 -0
- /package/dist/chunks/{continuous-record-4DQ2EAZS.ts.map → continuous-record-EPHGR2DU.ts.map} +0 -0
- /package/dist/chunks/{continuous-sync-ZT3UEQLK.ts.map → continuous-sync-TTOSJCQU.ts.map} +0 -0
- /package/dist/chunks/{local-fields-B6JWLPAE.ts.map → local-fields-JEKAPZKD.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-NODX3KKH.ts.map → manager-result-dispatcher-6W52NM7F.ts.map} +0 -0
- /package/dist/chunks/{merge-baseline-store-HL3VLMAM.ts.map → merge-baseline-store-65GKUMXI.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-OHMIQ32X.ts.map → remote-selection-ui-TD4C4W3J.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-66GWMBNH.ts.map → setup-switch-KLGESLQX.ts.map} +0 -0
- /package/dist/chunks/{setup-wizard-OHZXJVQZ.ts.map → setup-wizard-ZQAK35BP.ts.map} +0 -0
- /package/dist/chunks/{snapshot-VRHNAUUH.ts.map → snapshot-RGNDYT6A.ts.map} +0 -0
- /package/dist/chunks/{snapshot-transaction-EUGA4VX6.ts.map → snapshot-transaction-26BQO36S.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-4WFQEJOE.ts.map → sync-inspection-MOMLGUTD.ts.map} +0 -0
- /package/dist/chunks/{sync-state-SWLSMK4G.ts.map → sync-state-7L4NT7W2.ts.map} +0 -0
|
@@ -7,8 +7,8 @@ The configuration skill provides guidance only; the user performs settings chang
|
|
|
7
7
|
- [Required backend shapes](#required-backend-shapes)
|
|
8
8
|
- [Status display](#status-display)
|
|
9
9
|
- [Secret scanning](#secret-scanning)
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
10
|
+
- [Autonomous sync](#autonomous-sync)
|
|
11
|
+
- [Continuous sync](#continuous-sync)
|
|
12
12
|
- [Included content](#included-content)
|
|
13
13
|
- [Unsupported old settings and recovery](#unsupported-old-settings-and-recovery)
|
|
14
14
|
|
|
@@ -26,11 +26,16 @@ Missing settings load as unconfigured without creating an agent directory, file,
|
|
|
26
26
|
An explicit setup creates the file atomically.
|
|
27
27
|
On POSIX, pi-sync creates and replaces it with mode `0600`.
|
|
28
28
|
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.
|
|
29
|
+
Within one process, settings reads wait for earlier writes, including writes that have not acquired the lock yet.
|
|
30
|
+
Replacement writes and flushes a private temporary file before renaming it over the canonical file; the active file is not moved away first.
|
|
29
31
|
Credentials stay in this canonical private file and are never shown in menus, reviews, status, notifications, errors, logs, or completion metadata.
|
|
30
32
|
|
|
31
33
|
A private `pi-sync.local.json` containing a valid version 3 document is copied byte-for-byte to `pi-sync.json`.
|
|
32
34
|
The old file remains as a recovery copy.
|
|
33
35
|
If both paths exist, `pi-sync.json` wins and the legacy file remains untouched.
|
|
36
|
+
If an older interrupted replacement left `pi-sync.json` missing and a hidden `.pi-sync.json.*.schema-migration-source` or `.pi-sync.json.*.migration-retired` file remains, settings access stops instead of loading the legacy copy.
|
|
37
|
+
Close every Pi process, preserve all recovery files, and review the retained settings before restoring the correct document to `pi-sync.json` with private permissions.
|
|
38
|
+
Do not delete recovery evidence or accept defaults to bypass this check.
|
|
34
39
|
|
|
35
40
|
### Settings ownership and required fields
|
|
36
41
|
|
|
@@ -50,14 +55,20 @@ Global settings apply to all setups on this device; they are not remote policy.
|
|
|
50
55
|
| Content/partial policy | `sync.mergeContent`, `sync.partialSync` | Enabling either requires version 5. |
|
|
51
56
|
|
|
52
57
|
Do not downgrade version 4 or 5 merely because an option is turned off.
|
|
53
|
-
The four automatic controls have separate effects:
|
|
58
|
+
The four automatic controls have separate effects:
|
|
59
|
+
|
|
60
|
+
- **Automatic sync** (`sync.automatic`) enables startup observation and selected-content shutdown pushes when sessions are included.
|
|
61
|
+
- **Startup transfer** (`sync.automaticTransfer`) enables one eligible startup transfer.
|
|
62
|
+
- **Autonomous sync** (`sync.agentMode`, unchanged) authorizes eligible startup and **Sync now** transfers without another transfer confirmation, plus model assistance and disclosure for supported conflicts.
|
|
63
|
+
- **Continuous sync** (`sync.continuous`) adds recurring work only with Autonomous sync enabled.
|
|
64
|
+
|
|
54
65
|
None of these controls is enabled by invoking the configuration skill.
|
|
55
66
|
|
|
56
67
|
### Editing in the manager
|
|
57
68
|
|
|
58
|
-
Open `/sync` → **Settings**
|
|
59
|
-
|
|
60
|
-
**Included paths** and **Compare included paths** are adjacent
|
|
69
|
+
Open `/sync` → **Settings** to go directly to **Pi Sync Settings**.
|
|
70
|
+
The screen has one searchable flat list with all 16 rows in their existing order and no category navigation or headings.
|
|
71
|
+
**Included paths** and **Compare included paths** are adjacent; the latter compares path policies, not file contents.
|
|
61
72
|
**Storage location** edits the current setup's coordinates, while **Manage sync setups** and **Manage storage connections** retain the catalog and affected-setup reviews.
|
|
62
73
|
Returning from catalog management refreshes the rows; switching or removing the owning setup closes its old Settings screen.
|
|
63
74
|
|
|
@@ -65,7 +76,7 @@ Descriptions identify the owner: this setup, all setups on this device, or share
|
|
|
65
76
|
Simple choices report Saving and the durable Saved or failed/rejected result, preserve the selected row and search during refresh, and restore their previous value if saving fails.
|
|
66
77
|
Escape closes the screen without undoing successful saves.
|
|
67
78
|
Complex values retain their input/review flows.
|
|
68
|
-
This navigation change does not alter schema, defaults, automatic-sync behavior, or
|
|
79
|
+
This navigation change does not alter schema, defaults, automatic-sync behavior, or explicit opt-ins.
|
|
69
80
|
|
|
70
81
|
The manager separates current state from transfer, inspection, and management actions.
|
|
71
82
|
**Check remote status** and **View differences** invoke the existing read/check routes only when selected.
|
|
@@ -174,7 +185,7 @@ This check does not contact the server or discover setups configured only on oth
|
|
|
174
185
|
Every setup requires `sync.include` and explicit `sync.automatic`.
|
|
175
186
|
Setup asks for automatic sync with Off first; existing values are not rewritten.
|
|
176
187
|
When enabled, the current setup receives one background startup check in TUI/RPC, including reload/new/resume/fork.
|
|
177
|
-
|
|
188
|
+
Automatic sync alone does not perform startup transfers or open dialogs; review changes through `/sync`.
|
|
178
189
|
Print/JSON skip startup checks.
|
|
179
190
|
Checks compare local hashes and remote metadata against the last sync baseline, so revision changes and missing baselines require review rather than proving a file conflict.
|
|
180
191
|
|
|
@@ -214,14 +225,14 @@ It accepts:
|
|
|
214
225
|
### Status display
|
|
215
226
|
|
|
216
227
|
The global `showStatus` setting accepts a boolean and defaults to `true` when omitted from an existing version 3 document.
|
|
217
|
-
Set it through **/sync → Settings →
|
|
228
|
+
Set it through **/sync → Settings → Show sync status**; changes are saved and applied immediately for every setup.
|
|
218
229
|
When `false`, pi-sync clears and suppresses status text for background checks, manual and automatic transfers, and review attention.
|
|
219
230
|
TUI review widgets and TUI/RPC notifications remain available, and lifecycle cleanup still clears any stale status owned by pi-sync.
|
|
220
231
|
|
|
221
232
|
### Debug startup timings
|
|
222
233
|
|
|
223
234
|
The top-level user setting `debug` accepts only `true` or `false` and defaults to `false`.
|
|
224
|
-
Edit `<getAgentDir()>/pi-sync.json` (normally `~/.pi/agent/pi-sync.json`) or use **/sync → Settings →
|
|
235
|
+
Edit `<getAgentDir()>/pi-sync.json` (normally `~/.pi/agent/pi-sync.json`) or use **/sync → Settings → Debug startup timings**.
|
|
225
236
|
UI changes save immediately through the existing ordered, atomic settings writer; both manual and UI changes take effect on the next session start, including `/reload`, new, resume, and fork.
|
|
226
237
|
There is no project or environment override.
|
|
227
238
|
|
|
@@ -250,7 +261,7 @@ Set `debug` to `false` or remove it, then start a new session to disable reports
|
|
|
250
261
|
### Secret scanning
|
|
251
262
|
|
|
252
263
|
The global `skipSecretScan` setting accepts a boolean and defaults to `false`, including when omitted from an existing version 3 document.
|
|
253
|
-
Set it through **/sync → Settings →
|
|
264
|
+
Set it through **/sync → Settings → Skip secret scan**; changes are saved immediately and apply to subsequent pushes for every sync setup, including automatic pushes.
|
|
254
265
|
When `true`, pushes skip the local secret scan; other safety checks and confirmations remain unchanged.
|
|
255
266
|
Enable it only after reviewing the destination and selected content because files containing secrets can be uploaded.
|
|
256
267
|
`/sync doctor` still scans and reports possible secrets regardless of this setting.
|
|
@@ -290,8 +301,10 @@ RPC remains a read-only summary with the manual `sync.include` path.
|
|
|
290
301
|
|
|
291
302
|
Every new snapshot stores the normalized included-content selection separately from the files that happened to exist.
|
|
292
303
|
This preserves selected-but-missing paths without syncing `pi-sync.json`, storage credentials, automatic-sync preferences, or setup names.
|
|
293
|
-
**Settings →
|
|
294
|
-
Adoption revalidates the remote head, immutable snapshot, reviewed
|
|
304
|
+
**Settings → Compare included paths** opens the same review-first flow as a manager operation when local and remote lists differ.
|
|
305
|
+
Adoption revalidates the remote head, immutable snapshot, and complete reviewed setup configuration, including the shared connection and credentials, before one atomic settings update.
|
|
306
|
+
Cancelling the network check leaves the content list unchanged.
|
|
307
|
+
A settings save that has started its atomic replacement can still finish; later cancellation does not undo it.
|
|
295
308
|
The saved state changes only `sync.include`, preserves unknown settings fields, and never pulls files or writes sync state.
|
|
296
309
|
Its explicit Continue action starts a fresh **Sync now** route, while **Done** leaves the reviewed settings change saved without implying a file operation.
|
|
297
310
|
Keeping this device's list opens the reviewed force-push path and explicitly replaces the remote policy while preserving eligible unmanaged remote files.
|
|
@@ -310,7 +323,7 @@ Pull protects the currently open session file; restart Pi or resume a pulled ses
|
|
|
310
323
|
### Automatic startup transfer
|
|
311
324
|
|
|
312
325
|
`sync.automaticTransfer` is optional and accepts only a boolean; absent means `false`.
|
|
313
|
-
Set it through **/sync → Settings →
|
|
326
|
+
Set it through **/sync → Settings → Startup transfer**.
|
|
314
327
|
It is separate from `sync.automatic`: the legacy setting retains observation and selected-content shutdown behavior.
|
|
315
328
|
|
|
316
329
|
When explicitly enabled, one startup transfer waits for an idle boundary in TUI/RPC.
|
|
@@ -338,27 +351,30 @@ Turning **Startup transfer** off does not revert transfers or remove backups/jou
|
|
|
338
351
|
For interrupted operations, follow [merge recovery](https://github.com/narumiruna/pi-extensions/blob/main/packages/pi-sync/docs/merge-implementation-audit.md).
|
|
339
352
|
Unknown fields remain preserved and malformed/invalid files block saves, just as for the existing policy.
|
|
340
353
|
|
|
341
|
-
|
|
354
|
+
<a id="experimental-agent-mode"></a>
|
|
342
355
|
|
|
343
|
-
|
|
344
|
-
|
|
356
|
+
### Autonomous sync
|
|
357
|
+
|
|
358
|
+
Autonomous sync uses the unchanged `sync.agentMode` key, an optional per-setup boolean, default `false`, in settings versions 3, 4, and 5.
|
|
359
|
+
Open **Settings → Autonomous sync** and review the setup, destination, selected paths, transfer authorization, model disclosure, costs, and autonomous writes before enabling.
|
|
345
360
|
RPC users can explicitly set the same field in the private settings file.
|
|
346
361
|
Setting it to `true` is authorization, not just a display preference.
|
|
347
362
|
|
|
348
|
-
|
|
349
|
-
It can publish
|
|
363
|
+
Autonomous sync authorizes one eligible merged sync at the next session startup and the same flow from **Sync now** or `/sync sync`, without another transfer confirmation.
|
|
364
|
+
It can publish, replace, or delete selected local and remote content.
|
|
365
|
+
The selected Pi model resolves supported text and settings conflicts; eligible conflict content is sent to its provider and may incur costs.
|
|
350
366
|
It is independent of `sync.automatic` and `sync.automaticTransfer`; neither existing preference is changed.
|
|
351
|
-
Disabling Startup transfer alone does not disable
|
|
367
|
+
Disabling Startup transfer alone does not disable Autonomous sync.
|
|
352
368
|
Saving never starts a transfer from Settings.
|
|
353
369
|
The atomic write cannot be cancelled after its final cancellation check.
|
|
354
370
|
A completed save remains in effect after cancellation or session replacement; reopen Settings to read the saved value.
|
|
355
371
|
TUI/RPC are supported; print/JSON and shutdown do not start a resolver.
|
|
356
|
-
|
|
372
|
+
Autonomous sync alone adds no polling or daemon.
|
|
357
373
|
Separately enabled Continuous sync provides recurring work while Pi remains open.
|
|
358
374
|
|
|
359
375
|
An accepted baseline, matching included-content/local-field policies, and conditional or lease-protected publication remain required.
|
|
360
376
|
First-source selection, policy migrations, explicit push/pull, and rollback keep their existing reviewed flows.
|
|
361
|
-
`--yes` does not enable
|
|
377
|
+
`--yes` does not enable Autonomous sync or authorize model disclosure.
|
|
362
378
|
Completed transfers never reload resources automatically.
|
|
363
379
|
|
|
364
380
|
The resolver uses the initiating session's selected model through Pi's public provider/authentication registry.
|
|
@@ -371,14 +387,14 @@ Parent model prompts and tools are not changed.
|
|
|
371
387
|
This is configuration isolation, not an OS sandbox or proof of semantic correctness.
|
|
372
388
|
|
|
373
389
|
Eligible text is global `AGENTS.md` and `.md`/`.txt` files under `prompts/` or `skills/`.
|
|
374
|
-
Global `settings.json` uses the existing strict JSON, numeric, coupled-field, unknown-field, and machine-local-field policies.
|
|
390
|
+
Global `settings.json` uses the existing strict JSON, numeric, coupled-field, unknown-field, and machine-local-field policies. With Autonomous sync enabled, `packages` merges by source identity and selects the higher explicit SemVer version for each npm package present on both sides, even when one side has not changed from the verified ancestor. No registry lookup occurs. Equal SemVer precedence does not select a winner: one-sided source edits are preserved, and divergent edits require atomic selection. Package filters must match. An existing local or remote array keeps its JSON spelling when it matches the merged result. Accepted settings files keep their bytes unless a package override is required; that override changes only the `packages` value. The ordered npm identity list can change on one side, or identically on both sides; conflicting order or membership changes retain atomic selection. This preserves insertion positions and resource precedence. Non-npm entries must remain unchanged across all three versions for per-package merging. Changed Git refs and local path aliases retain atomic selection instead of being combined as separate sources. Delete/upgrade conflicts, duplicate identities, incompatible filters, version ranges and tags also retain the existing atomic selection rules when deterministic merging is not possible. Other arrays and nested objects remain atomic.
|
|
375
391
|
Code/scripts, keybindings, binaries, unknown formats, session histories, deletion/modification conflicts, path collisions, and session-root transitions are not model-resolved.
|
|
376
392
|
Existing deterministic merges still follow their own explicit settings.
|
|
377
393
|
Unsupported or refused groups remain unresolved; only an explicitly enabled `partialSync` policy permits progress around them.
|
|
378
394
|
Preserving versions does not mean a conflict is resolved.
|
|
379
395
|
|
|
380
396
|
A verified accepted ancestor is required.
|
|
381
|
-
Enabling
|
|
397
|
+
Enabling Autonomous sync cannot recover historical ancestor bytes that were never retained.
|
|
382
398
|
If the original accepted bytes are still available on both sides, a conflict-free sync can seed the text ancestors for future runs; otherwise use the existing reviewed recovery flow rather than inventing a base from current edits.
|
|
383
399
|
|
|
384
400
|
Bounds are 8 KiB per input file, 16 conflict paths/units, 24 KiB of serialized model evidence, 16 KiB of candidate output, 8,192 maximum output tokens (or the selected model's smaller positive output limit), and one provider request per candidate attempt. A separately confirmed refusal retry can request the same candidate evidence again.
|
|
@@ -391,7 +407,7 @@ These limits are not an exact currency spending cap; in-flight disclosure or cha
|
|
|
391
407
|
|
|
392
408
|
The existing possible-secret scanner always checks model evidence, even when `skipSecretScan` permits uploads without scanning.
|
|
393
409
|
It is a heuristic, not a guarantee that all secrets are detected.
|
|
394
|
-
Do not enable
|
|
410
|
+
Do not enable Autonomous sync for content you cannot disclose to the selected provider.
|
|
395
411
|
Provider errors and model reasoning are not copied into status or persistent records.
|
|
396
412
|
|
|
397
413
|
Pi sessions sharing one agent directory use one local resolver claim.
|
|
@@ -410,7 +426,7 @@ They can contain merged text; retain them as private data.
|
|
|
410
426
|
Different candidates are retained without automatic retention pruning.
|
|
411
427
|
Ordinary **Sync now** and `/sync sync` reuse a valid cached refusal without another provider request.
|
|
412
428
|
The manager's **Retry refused model result…** action separately reviews the setup, destination, conflict paths, selected model, disclosure and cost before one fresh request for that exact refusal.
|
|
413
|
-
It requires foreground TUI/RPC,
|
|
429
|
+
It requires foreground TUI/RPC, Autonomous sync, an accepted baseline and no pending journal; use ordinary Sync now or reviewed recovery first when those prerequisites are absent.
|
|
414
430
|
Changed evidence, settings, model, session or cached bytes invalidate the review without disclosure.
|
|
415
431
|
A repeated refusal, invalid response or failed pre-publication replacement retains the original result.
|
|
416
432
|
A complete validated result replaces the active candidate only after the original refusal is archived privately in the same directory.
|
|
@@ -425,23 +441,25 @@ Pi-sync's cross-process operation lock excludes other pi-sync transfers, not arb
|
|
|
425
441
|
Pi file mutation queues coordinate participating writers only within one process.
|
|
426
442
|
Checks near rename reduce stale writes but do not provide an atomic compare-and-swap against another Pi process or editor.
|
|
427
443
|
Session JSONL is not rewritten by the model; other active session writers remain subject to the existing protection limitations.
|
|
428
|
-
Do not use
|
|
444
|
+
Do not use Autonomous sync as a guarantee of lossless live editing.
|
|
429
445
|
|
|
430
|
-
Turn
|
|
446
|
+
Turn Autonomous sync Off to prevent subsequent requests and invalidate pending authorization.
|
|
431
447
|
Keep backups, snapshots, conflicts and pending journals; disabling does not undo completed work or erase history.
|
|
432
448
|
Unknown publication outcomes use the existing journal reconciliation and never authorize blind republishing.
|
|
433
449
|
Pending journals can be reconciled on a read/check/write/verify backend because recovery does not publish.
|
|
434
|
-
New autonomous transfers still require conditional or lease-protected publication; turn
|
|
450
|
+
New autonomous transfers still require conditional or lease-protected publication; turn Autonomous sync Off before a reviewed manual transfer on a weaker backend.
|
|
435
451
|
If recovery is blocked, retain evidence and use the existing reviewed recovery routes.
|
|
436
452
|
Finish/reconcile pending merge journals before a downgrade.
|
|
437
453
|
No Pi core changes or other extension are required.
|
|
438
454
|
|
|
439
|
-
|
|
455
|
+
<a id="experimental-continuous-sync"></a>
|
|
456
|
+
|
|
457
|
+
### Continuous sync
|
|
440
458
|
|
|
441
459
|
`sync.continuous` is an optional per-setup boolean, default `false`, in settings versions 3, 4 and 5.
|
|
442
|
-
Open **Settings →
|
|
460
|
+
Open **Settings → Continuous sync** after enabling Autonomous sync.
|
|
443
461
|
RPC users can set the field explicitly in the private settings file.
|
|
444
|
-
Existing
|
|
462
|
+
Existing Autonomous sync consent does not enable recurring requests.
|
|
445
463
|
|
|
446
464
|
The separate review names the setup, storage connection, destination, included paths, recurring costs and automatic writes.
|
|
447
465
|
An elected idle session uses its selected Pi model; a different session can use a different provider/model.
|
|
@@ -453,8 +471,8 @@ Reopen Settings to read the saved value.
|
|
|
453
471
|
|
|
454
472
|
Monitoring starts at an eligible TUI/RPC session startup, after awaited local transaction recovery, or after a foreground `/sync` command or manager closes.
|
|
455
473
|
It replaces the duplicate one-shot startup transfer, not the legacy shutdown policy.
|
|
456
|
-
Turning Continuous sync off stops its work without disabling
|
|
457
|
-
Turning
|
|
474
|
+
Turning Continuous sync off stops its work without disabling Autonomous sync.
|
|
475
|
+
Turning Autonomous sync off also stops monitoring; a saved Continuous sync On value remains ineffective until Autonomous sync is enabled again.
|
|
458
476
|
|
|
459
477
|
A control-file change during monitoring is detected by a watcher or the five-second local control check.
|
|
460
478
|
If monitoring is already off, external enablement requires the next session start or a foreground `/sync` command.
|
|
@@ -553,14 +571,14 @@ Preserve journals, backups and unresolved versions when proof is unavailable.
|
|
|
553
571
|
|
|
554
572
|
Turn Continuous sync off and drain its owner before downgrade.
|
|
555
573
|
Reconcile pending transfers with the current release.
|
|
556
|
-
Existing
|
|
574
|
+
Existing Autonomous sync and shutdown preferences remain separately effective.
|
|
557
575
|
Private scheduler records are separate from baseline/journal formats and remain retained; no automatic filesystem rollback or state migration is performed.
|
|
558
576
|
|
|
559
577
|
For implementation evidence and test scope, see [Continuous sync verification](https://github.com/narumiruna/pi-extensions/blob/main/packages/pi-sync/docs/continuous-sync-verification.md).
|
|
560
578
|
|
|
561
579
|
### Settings field merge and machine-local fields
|
|
562
580
|
|
|
563
|
-
`sync.mergeSettings` is
|
|
581
|
+
`sync.mergeSettings` is an explicit opt-in, defaults to `false`, and is available through **Settings → Merge settings fields** for the current setup.
|
|
564
582
|
With a verified accepted ancestor, global `settings.json` root fields merge conservatively: absent differs from null, arrays/nested objects are atomic, and provider/model and other coupled fields form one unit.
|
|
565
583
|
Unknown fields are preserved.
|
|
566
584
|
Pi accepts plain UTF-8 JSON with an optional BOM, not JSONC; duplicate/prototype-sensitive keys, invalid encodings, migration-dependent syntax, and over-bound inputs require directional review.
|
|
@@ -609,8 +627,8 @@ Never reinterpret portable snapshots with an old binary.
|
|
|
609
627
|
|
|
610
628
|
### Content merge and partial progress
|
|
611
629
|
|
|
612
|
-
`sync.mergeContent` and `sync.partialSync` are independent
|
|
613
|
-
The owning **
|
|
630
|
+
`sync.mergeContent` and `sync.partialSync` are independent opt-in booleans, both default `false`.
|
|
631
|
+
The owning **Settings → Content merge / partial progress** setting offers Off, Merge only, Merge + partial, and Partial only and confirms an explicit settings-version-5 upgrade.
|
|
614
632
|
Manual configuration must also declare version 5.
|
|
615
633
|
Settings version 5 retains the portable-policy behavior of version 4; moving from a legacy setup can require the existing separately confirmed directional policy migration.
|
|
616
634
|
Disabling options retains the schema and recovery evidence.
|
|
@@ -193,7 +193,12 @@ export class S3Client {
|
|
|
193
193
|
extraHeaders: Record<string, string> = {},
|
|
194
194
|
) {
|
|
195
195
|
const url = new URL(this.endpoint.toString());
|
|
196
|
-
|
|
196
|
+
// Preserve escaped endpoint bytes without decoding or double-encoding them.
|
|
197
|
+
// SigV4 requires uppercase escape hex, including existing endpoint escapes.
|
|
198
|
+
const endpointPath = url.pathname
|
|
199
|
+
.replace(/%(?![0-9A-Fa-f]{2})|[^A-Za-z0-9._~/%-]/gu, encodeKey)
|
|
200
|
+
.replace(/%[0-9A-Fa-f]{2}/gu, (escaped) => escaped.toUpperCase());
|
|
201
|
+
url.pathname = posixJoin(endpointPath, encodeKey(this.config.destination.bucket), encodeKey(key));
|
|
197
202
|
const send = async (sessionToken: string | undefined) => {
|
|
198
203
|
const transportSignal = this.transportSignal();
|
|
199
204
|
const headers = await signedHeaders({
|
|
@@ -213,6 +218,8 @@ export class S3Client {
|
|
|
213
218
|
method,
|
|
214
219
|
headers,
|
|
215
220
|
body: body ? new Uint8Array(body) : undefined,
|
|
221
|
+
// Never forward signed headers or snapshot bodies to an unreviewed URL.
|
|
222
|
+
redirect: "error",
|
|
216
223
|
signal: transportSignal,
|
|
217
224
|
});
|
|
218
225
|
} catch (error) {
|
|
@@ -231,8 +231,12 @@ async function migrateStateDirectory(ctx: ExtensionCommandContext, options: Comm
|
|
|
231
231
|
|
|
232
232
|
async function initConfig(ctx: ExtensionCommandContext, signal?: AbortSignal) {
|
|
233
233
|
const configPath = localConfigPath();
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
const existing = await readLocalConfigObject();
|
|
235
|
+
throwIfAborted(signal);
|
|
236
|
+
if (existing) {
|
|
237
|
+
const activePath = await activeLocalConfigPath();
|
|
238
|
+
throwIfAborted(signal);
|
|
239
|
+
ctx.ui.notify(`Config already exists: ${activePath}`, "info");
|
|
236
240
|
return;
|
|
237
241
|
}
|
|
238
242
|
|
|
@@ -242,7 +246,8 @@ async function initConfig(ctx: ExtensionCommandContext, signal?: AbortSignal) {
|
|
|
242
246
|
await showSetupWizard(ctx, signal);
|
|
243
247
|
return;
|
|
244
248
|
}
|
|
245
|
-
await createLocalConfigDocument(localConfigTemplate());
|
|
249
|
+
await createLocalConfigDocument(localConfigTemplate(), signal);
|
|
250
|
+
throwIfAborted(signal);
|
|
246
251
|
ctx.ui.notify(`Created ${configPath}. Add a storage connection and sync setup before syncing.`, "info");
|
|
247
252
|
}
|
|
248
253
|
|
|
@@ -261,11 +266,11 @@ async function showConfig(ctx: ExtensionCommandContext, options: CommandOptions)
|
|
|
261
266
|
...storageLines,
|
|
262
267
|
`storage path: ${config.storagePath}`,
|
|
263
268
|
`automatic sync: ${automaticSyncSummary(config.automatic)}`,
|
|
264
|
-
`settings field merge: ${config.mergeSettings ? "On
|
|
269
|
+
`settings field merge: ${config.mergeSettings ? "On" : "Off"}`,
|
|
265
270
|
`machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(", ") || "none"}`,
|
|
266
271
|
`startup transfer: ${startupTransferSummary(config)}`,
|
|
267
|
-
`
|
|
268
|
-
`continuous sync: ${config.continuous ? (config.agentMode ? "On
|
|
272
|
+
`autonomous sync: ${config.agentMode ? "On" : "Off"}`,
|
|
273
|
+
`continuous sync: ${config.continuous ? (config.agentMode ? "On" : "paused; Autonomous sync is Off") : "Off"}`,
|
|
269
274
|
`included content: ${config.include.join(", ") || "none"}`,
|
|
270
275
|
`sessions: ${config.include.includes("sessions") ? "included" : "not included"}`,
|
|
271
276
|
`settings file: ${localConfigPath()}`,
|
package/src/commands/command.ts
CHANGED
|
@@ -236,7 +236,7 @@ export function usage() {
|
|
|
236
236
|
`Automatic sync: ${AUTOMATIC_SYNC_DESCRIPTION}`,
|
|
237
237
|
`Startup transfer: ${STARTUP_TRANSFER_DESCRIPTION}`,
|
|
238
238
|
"Automatic transfer at startup is a separate opt-in: one conflict-free established-baseline transfer at idle in TUI/RPC, with conditional/lease publication and no resource reload.",
|
|
239
|
-
"
|
|
239
|
+
"Continuous sync is a separate default-Off opt-in in Settings. It requires Autonomous sync, monitors while Pi is open, and can incur recurring network/model costs. Safety blocks and durable automatic request limits remain.",
|
|
240
240
|
"Settings: use /sync init or edit storage connections and sync setups in ~/.pi/agent/pi-sync.json (or the configured Pi agent directory). Version 1 and version 2 settings are unsupported and are never rewritten.",
|
|
241
241
|
].join("\n");
|
|
242
242
|
}
|
package/src/paths.ts
CHANGED
|
@@ -45,7 +45,12 @@ export function assertWithinRoot(root: string, target: string, label = target) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export function encodeKey(key: string) {
|
|
48
|
-
|
|
48
|
+
// SigV4 permits only RFC 3986 unreserved characters and key separators.
|
|
49
|
+
return key
|
|
50
|
+
.split("/")
|
|
51
|
+
.map(encodeURIComponent)
|
|
52
|
+
.join("/")
|
|
53
|
+
.replace(/[!'()*]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
export function posixJoin(...parts: string[]) {
|