@narumitw/pi-sync 0.57.11 → 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 +8 -0
- package/README.md +27 -21
- package/dist/chunks/{agent-candidate-OCDPRI5G.ts → agent-candidate-U2NU3GUX.ts} +2 -2
- package/dist/chunks/{agent-plan-P5B5RGZ7.ts → agent-plan-3YXDIJXO.ts} +13 -10
- package/dist/chunks/agent-plan-3YXDIJXO.ts.map +7 -0
- 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-RJSMNOYP.ts → agent-store-7GINKTS7.ts} +2 -2
- package/dist/chunks/{agent-store-RJSMNOYP.ts.map → agent-store-7GINKTS7.ts.map} +2 -2
- package/dist/chunks/{agent-sync-EUK2CPSS.ts → agent-sync-P6AWQXGK.ts} +2 -2
- package/dist/chunks/{chunk-67INJPKR.ts → chunk-CQD2TJHE.ts} +4 -4
- package/dist/chunks/{chunk-67INJPKR.ts.map → chunk-CQD2TJHE.ts.map} +2 -2
- package/dist/chunks/{chunk-7OLLPPLU.ts → chunk-MMQIEDZ6.ts} +6 -6
- package/dist/chunks/{chunk-7OLLPPLU.ts.map → chunk-MMQIEDZ6.ts.map} +2 -2
- 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-DRTC4PKM.ts → chunk-S5OCYVPS.ts} +2 -2
- package/dist/chunks/{chunk-DRTC4PKM.ts.map → chunk-S5OCYVPS.ts.map} +2 -2
- package/dist/chunks/{chunk-3IYAPMST.ts → chunk-U6GXGY5G.ts} +2 -2
- package/dist/chunks/{chunk-CPT2BN6N.ts → chunk-XEODG2PE.ts} +2 -2
- package/dist/chunks/{chunk-F7E3VFXU.ts → chunk-ZC3IHFNM.ts} +6 -6
- package/dist/chunks/{chunk-F7E3VFXU.ts.map → chunk-ZC3IHFNM.ts.map} +2 -2
- package/dist/chunks/{command-handler-F2E7A5T5.ts → command-handler-VKLZBRLO.ts} +9 -9
- package/dist/chunks/{command-handler-F2E7A5T5.ts.map → command-handler-VKLZBRLO.ts.map} +2 -2
- package/dist/chunks/{conflict-review-2QMO2K6Q.ts → conflict-review-GXA6Y7KY.ts} +2 -2
- package/dist/chunks/{continuous-record-AH7JGYKM.ts → continuous-record-EPHGR2DU.ts} +2 -2
- package/dist/chunks/{continuous-sync-VRMXCA5X.ts → continuous-sync-TTOSJCQU.ts} +3 -3
- package/dist/chunks/{manager-ui-LM7DSJ2Y.ts → manager-ui-INVMAFEN.ts} +146 -176
- package/dist/chunks/manager-ui-INVMAFEN.ts.map +7 -0
- package/dist/chunks/{setup-switch-PIPXYPCW.ts → setup-switch-KLGESLQX.ts} +3 -3
- package/dist/chunks/{setup-wizard-RR5U3SUB.ts → setup-wizard-ZQAK35BP.ts} +3 -3
- package/dist/chunks/{sync-operations-CV3TULLD.ts → sync-operations-TMGQHBF5.ts} +4 -4
- package/dist/chunks/{sync-operations-CV3TULLD.ts.map → sync-operations-TMGQHBF5.ts.map} +2 -2
- package/dist/index.ts +6 -6
- 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 +48 -37
- package/src/commands/command-execution.ts +3 -3
- package/src/commands/command.ts +1 -1
- package/src/settings/settings-types.ts +1 -1
- 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/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/manager-state.ts +1 -1
- package/src/ui/settings-ui.ts +19 -55
- package/src/ui/setup/setup-switcher.ts +2 -2
- package/src/ui/sync-setups-ui.ts +2 -2
- package/dist/chunks/agent-plan-P5B5RGZ7.ts.map +0 -7
- package/dist/chunks/agent-runner-WMSCKSCB.ts.map +0 -7
- package/dist/chunks/manager-ui-LM7DSJ2Y.ts.map +0 -7
- /package/dist/chunks/{agent-candidate-OCDPRI5G.ts.map → agent-candidate-U2NU3GUX.ts.map} +0 -0
- /package/dist/chunks/{agent-sync-EUK2CPSS.ts.map → agent-sync-P6AWQXGK.ts.map} +0 -0
- /package/dist/chunks/{chunk-3IYAPMST.ts.map → chunk-U6GXGY5G.ts.map} +0 -0
- /package/dist/chunks/{chunk-CPT2BN6N.ts.map → chunk-XEODG2PE.ts.map} +0 -0
- /package/dist/chunks/{conflict-review-2QMO2K6Q.ts.map → conflict-review-GXA6Y7KY.ts.map} +0 -0
- /package/dist/chunks/{continuous-record-AH7JGYKM.ts.map → continuous-record-EPHGR2DU.ts.map} +0 -0
- /package/dist/chunks/{continuous-sync-VRMXCA5X.ts.map → continuous-sync-TTOSJCQU.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-PIPXYPCW.ts.map → setup-switch-KLGESLQX.ts.map} +0 -0
- /package/dist/chunks/{setup-wizard-RR5U3SUB.ts.map → setup-wizard-ZQAK35BP.ts.map} +0 -0
|
@@ -15,7 +15,7 @@ This skill provides guidance only, even when the request asks you to apply a cha
|
|
|
15
15
|
Read the relevant headings in the [settings reference](references/configuration.md), not the user's private settings file.
|
|
16
16
|
Use **Settings ownership and required fields**, **Complete version 3 example**, and **Required backend shapes** for schema, backend, and destination questions.
|
|
17
17
|
Use **Included content** for path selection and session privacy.
|
|
18
|
-
Use **Required backend shapes**, **Automatic startup transfer**, **
|
|
18
|
+
Use **Required backend shapes**, **Automatic startup transfer**, **Autonomous sync**, and **Continuous sync** to distinguish automatic controls.
|
|
19
19
|
Use **Settings field merge and machine-local fields** and **Content merge and partial progress** for versions 4 and 5.
|
|
20
20
|
Use **Diagnostics** and **Unsupported old settings and recovery** for diagnostic side effects and recovery boundaries.
|
|
21
21
|
If the reference does not establish an answer, state the missing evidence instead of inventing a field, default, migration, or compatibility guarantee.
|
|
@@ -34,6 +34,8 @@ These are instruction limits, not an OS sandbox or a guarantee that the agent ca
|
|
|
34
34
|
|
|
35
35
|
For a question, give the supported setting name, scope, accepted value, default when applicable, and material effect from the reference.
|
|
36
36
|
Do not equate `sync.automatic`, `sync.automaticTransfer`, `sync.agentMode`, and `sync.continuous`.
|
|
37
|
+
Map Autonomous sync to the unchanged `sync.agentMode` key.
|
|
38
|
+
Explain its authorization for eligible startup and Sync now transfers without another transfer confirmation before its model assistance for supported conflicts.
|
|
37
39
|
|
|
38
40
|
For setup or a requested edit, explain that this skill cannot apply it and identify the corresponding `/sync` manager action for the user.
|
|
39
41
|
Ask at most one question at a time when the backend, destination, or included content is not sufficiently clear.
|
|
@@ -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
|
|
|
@@ -55,14 +55,20 @@ Global settings apply to all setups on this device; they are not remote policy.
|
|
|
55
55
|
| Content/partial policy | `sync.mergeContent`, `sync.partialSync` | Enabling either requires version 5. |
|
|
56
56
|
|
|
57
57
|
Do not downgrade version 4 or 5 merely because an option is turned off.
|
|
58
|
-
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
|
+
|
|
59
65
|
None of these controls is enabled by invoking the configuration skill.
|
|
60
66
|
|
|
61
67
|
### Editing in the manager
|
|
62
68
|
|
|
63
|
-
Open `/sync` → **Settings**
|
|
64
|
-
|
|
65
|
-
**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.
|
|
66
72
|
**Storage location** edits the current setup's coordinates, while **Manage sync setups** and **Manage storage connections** retain the catalog and affected-setup reviews.
|
|
67
73
|
Returning from catalog management refreshes the rows; switching or removing the owning setup closes its old Settings screen.
|
|
68
74
|
|
|
@@ -70,7 +76,7 @@ Descriptions identify the owner: this setup, all setups on this device, or share
|
|
|
70
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.
|
|
71
77
|
Escape closes the screen without undoing successful saves.
|
|
72
78
|
Complex values retain their input/review flows.
|
|
73
|
-
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.
|
|
74
80
|
|
|
75
81
|
The manager separates current state from transfer, inspection, and management actions.
|
|
76
82
|
**Check remote status** and **View differences** invoke the existing read/check routes only when selected.
|
|
@@ -179,7 +185,7 @@ This check does not contact the server or discover setups configured only on oth
|
|
|
179
185
|
Every setup requires `sync.include` and explicit `sync.automatic`.
|
|
180
186
|
Setup asks for automatic sync with Off first; existing values are not rewritten.
|
|
181
187
|
When enabled, the current setup receives one background startup check in TUI/RPC, including reload/new/resume/fork.
|
|
182
|
-
|
|
188
|
+
Automatic sync alone does not perform startup transfers or open dialogs; review changes through `/sync`.
|
|
183
189
|
Print/JSON skip startup checks.
|
|
184
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.
|
|
185
191
|
|
|
@@ -219,14 +225,14 @@ It accepts:
|
|
|
219
225
|
### Status display
|
|
220
226
|
|
|
221
227
|
The global `showStatus` setting accepts a boolean and defaults to `true` when omitted from an existing version 3 document.
|
|
222
|
-
Set it through **/sync → Settings →
|
|
228
|
+
Set it through **/sync → Settings → Show sync status**; changes are saved and applied immediately for every setup.
|
|
223
229
|
When `false`, pi-sync clears and suppresses status text for background checks, manual and automatic transfers, and review attention.
|
|
224
230
|
TUI review widgets and TUI/RPC notifications remain available, and lifecycle cleanup still clears any stale status owned by pi-sync.
|
|
225
231
|
|
|
226
232
|
### Debug startup timings
|
|
227
233
|
|
|
228
234
|
The top-level user setting `debug` accepts only `true` or `false` and defaults to `false`.
|
|
229
|
-
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**.
|
|
230
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.
|
|
231
237
|
There is no project or environment override.
|
|
232
238
|
|
|
@@ -255,7 +261,7 @@ Set `debug` to `false` or remove it, then start a new session to disable reports
|
|
|
255
261
|
### Secret scanning
|
|
256
262
|
|
|
257
263
|
The global `skipSecretScan` setting accepts a boolean and defaults to `false`, including when omitted from an existing version 3 document.
|
|
258
|
-
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.
|
|
259
265
|
When `true`, pushes skip the local secret scan; other safety checks and confirmations remain unchanged.
|
|
260
266
|
Enable it only after reviewing the destination and selected content because files containing secrets can be uploaded.
|
|
261
267
|
`/sync doctor` still scans and reports possible secrets regardless of this setting.
|
|
@@ -295,7 +301,7 @@ RPC remains a read-only summary with the manual `sync.include` path.
|
|
|
295
301
|
|
|
296
302
|
Every new snapshot stores the normalized included-content selection separately from the files that happened to exist.
|
|
297
303
|
This preserves selected-but-missing paths without syncing `pi-sync.json`, storage credentials, automatic-sync preferences, or setup names.
|
|
298
|
-
**Settings →
|
|
304
|
+
**Settings → Compare included paths** opens the same review-first flow as a manager operation when local and remote lists differ.
|
|
299
305
|
Adoption revalidates the remote head, immutable snapshot, and complete reviewed setup configuration, including the shared connection and credentials, before one atomic settings update.
|
|
300
306
|
Cancelling the network check leaves the content list unchanged.
|
|
301
307
|
A settings save that has started its atomic replacement can still finish; later cancellation does not undo it.
|
|
@@ -317,7 +323,7 @@ Pull protects the currently open session file; restart Pi or resume a pulled ses
|
|
|
317
323
|
### Automatic startup transfer
|
|
318
324
|
|
|
319
325
|
`sync.automaticTransfer` is optional and accepts only a boolean; absent means `false`.
|
|
320
|
-
Set it through **/sync → Settings →
|
|
326
|
+
Set it through **/sync → Settings → Startup transfer**.
|
|
321
327
|
It is separate from `sync.automatic`: the legacy setting retains observation and selected-content shutdown behavior.
|
|
322
328
|
|
|
323
329
|
When explicitly enabled, one startup transfer waits for an idle boundary in TUI/RPC.
|
|
@@ -345,27 +351,30 @@ Turning **Startup transfer** off does not revert transfers or remove backups/jou
|
|
|
345
351
|
For interrupted operations, follow [merge recovery](https://github.com/narumiruna/pi-extensions/blob/main/packages/pi-sync/docs/merge-implementation-audit.md).
|
|
346
352
|
Unknown fields remain preserved and malformed/invalid files block saves, just as for the existing policy.
|
|
347
353
|
|
|
348
|
-
|
|
354
|
+
<a id="experimental-agent-mode"></a>
|
|
349
355
|
|
|
350
|
-
|
|
351
|
-
|
|
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.
|
|
352
360
|
RPC users can explicitly set the same field in the private settings file.
|
|
353
361
|
Setting it to `true` is authorization, not just a display preference.
|
|
354
362
|
|
|
355
|
-
|
|
356
|
-
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.
|
|
357
366
|
It is independent of `sync.automatic` and `sync.automaticTransfer`; neither existing preference is changed.
|
|
358
|
-
Disabling Startup transfer alone does not disable
|
|
367
|
+
Disabling Startup transfer alone does not disable Autonomous sync.
|
|
359
368
|
Saving never starts a transfer from Settings.
|
|
360
369
|
The atomic write cannot be cancelled after its final cancellation check.
|
|
361
370
|
A completed save remains in effect after cancellation or session replacement; reopen Settings to read the saved value.
|
|
362
371
|
TUI/RPC are supported; print/JSON and shutdown do not start a resolver.
|
|
363
|
-
|
|
372
|
+
Autonomous sync alone adds no polling or daemon.
|
|
364
373
|
Separately enabled Continuous sync provides recurring work while Pi remains open.
|
|
365
374
|
|
|
366
375
|
An accepted baseline, matching included-content/local-field policies, and conditional or lease-protected publication remain required.
|
|
367
376
|
First-source selection, policy migrations, explicit push/pull, and rollback keep their existing reviewed flows.
|
|
368
|
-
`--yes` does not enable
|
|
377
|
+
`--yes` does not enable Autonomous sync or authorize model disclosure.
|
|
369
378
|
Completed transfers never reload resources automatically.
|
|
370
379
|
|
|
371
380
|
The resolver uses the initiating session's selected model through Pi's public provider/authentication registry.
|
|
@@ -378,14 +387,14 @@ Parent model prompts and tools are not changed.
|
|
|
378
387
|
This is configuration isolation, not an OS sandbox or proof of semantic correctness.
|
|
379
388
|
|
|
380
389
|
Eligible text is global `AGENTS.md` and `.md`/`.txt` files under `prompts/` or `skills/`.
|
|
381
|
-
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.
|
|
382
391
|
Code/scripts, keybindings, binaries, unknown formats, session histories, deletion/modification conflicts, path collisions, and session-root transitions are not model-resolved.
|
|
383
392
|
Existing deterministic merges still follow their own explicit settings.
|
|
384
393
|
Unsupported or refused groups remain unresolved; only an explicitly enabled `partialSync` policy permits progress around them.
|
|
385
394
|
Preserving versions does not mean a conflict is resolved.
|
|
386
395
|
|
|
387
396
|
A verified accepted ancestor is required.
|
|
388
|
-
Enabling
|
|
397
|
+
Enabling Autonomous sync cannot recover historical ancestor bytes that were never retained.
|
|
389
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.
|
|
390
399
|
|
|
391
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.
|
|
@@ -398,7 +407,7 @@ These limits are not an exact currency spending cap; in-flight disclosure or cha
|
|
|
398
407
|
|
|
399
408
|
The existing possible-secret scanner always checks model evidence, even when `skipSecretScan` permits uploads without scanning.
|
|
400
409
|
It is a heuristic, not a guarantee that all secrets are detected.
|
|
401
|
-
Do not enable
|
|
410
|
+
Do not enable Autonomous sync for content you cannot disclose to the selected provider.
|
|
402
411
|
Provider errors and model reasoning are not copied into status or persistent records.
|
|
403
412
|
|
|
404
413
|
Pi sessions sharing one agent directory use one local resolver claim.
|
|
@@ -417,7 +426,7 @@ They can contain merged text; retain them as private data.
|
|
|
417
426
|
Different candidates are retained without automatic retention pruning.
|
|
418
427
|
Ordinary **Sync now** and `/sync sync` reuse a valid cached refusal without another provider request.
|
|
419
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.
|
|
420
|
-
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.
|
|
421
430
|
Changed evidence, settings, model, session or cached bytes invalidate the review without disclosure.
|
|
422
431
|
A repeated refusal, invalid response or failed pre-publication replacement retains the original result.
|
|
423
432
|
A complete validated result replaces the active candidate only after the original refusal is archived privately in the same directory.
|
|
@@ -432,23 +441,25 @@ Pi-sync's cross-process operation lock excludes other pi-sync transfers, not arb
|
|
|
432
441
|
Pi file mutation queues coordinate participating writers only within one process.
|
|
433
442
|
Checks near rename reduce stale writes but do not provide an atomic compare-and-swap against another Pi process or editor.
|
|
434
443
|
Session JSONL is not rewritten by the model; other active session writers remain subject to the existing protection limitations.
|
|
435
|
-
Do not use
|
|
444
|
+
Do not use Autonomous sync as a guarantee of lossless live editing.
|
|
436
445
|
|
|
437
|
-
Turn
|
|
446
|
+
Turn Autonomous sync Off to prevent subsequent requests and invalidate pending authorization.
|
|
438
447
|
Keep backups, snapshots, conflicts and pending journals; disabling does not undo completed work or erase history.
|
|
439
448
|
Unknown publication outcomes use the existing journal reconciliation and never authorize blind republishing.
|
|
440
449
|
Pending journals can be reconciled on a read/check/write/verify backend because recovery does not publish.
|
|
441
|
-
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.
|
|
442
451
|
If recovery is blocked, retain evidence and use the existing reviewed recovery routes.
|
|
443
452
|
Finish/reconcile pending merge journals before a downgrade.
|
|
444
453
|
No Pi core changes or other extension are required.
|
|
445
454
|
|
|
446
|
-
|
|
455
|
+
<a id="experimental-continuous-sync"></a>
|
|
456
|
+
|
|
457
|
+
### Continuous sync
|
|
447
458
|
|
|
448
459
|
`sync.continuous` is an optional per-setup boolean, default `false`, in settings versions 3, 4 and 5.
|
|
449
|
-
Open **Settings →
|
|
460
|
+
Open **Settings → Continuous sync** after enabling Autonomous sync.
|
|
450
461
|
RPC users can set the field explicitly in the private settings file.
|
|
451
|
-
Existing
|
|
462
|
+
Existing Autonomous sync consent does not enable recurring requests.
|
|
452
463
|
|
|
453
464
|
The separate review names the setup, storage connection, destination, included paths, recurring costs and automatic writes.
|
|
454
465
|
An elected idle session uses its selected Pi model; a different session can use a different provider/model.
|
|
@@ -460,8 +471,8 @@ Reopen Settings to read the saved value.
|
|
|
460
471
|
|
|
461
472
|
Monitoring starts at an eligible TUI/RPC session startup, after awaited local transaction recovery, or after a foreground `/sync` command or manager closes.
|
|
462
473
|
It replaces the duplicate one-shot startup transfer, not the legacy shutdown policy.
|
|
463
|
-
Turning Continuous sync off stops its work without disabling
|
|
464
|
-
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.
|
|
465
476
|
|
|
466
477
|
A control-file change during monitoring is detected by a watcher or the five-second local control check.
|
|
467
478
|
If monitoring is already off, external enablement requires the next session start or a foreground `/sync` command.
|
|
@@ -560,14 +571,14 @@ Preserve journals, backups and unresolved versions when proof is unavailable.
|
|
|
560
571
|
|
|
561
572
|
Turn Continuous sync off and drain its owner before downgrade.
|
|
562
573
|
Reconcile pending transfers with the current release.
|
|
563
|
-
Existing
|
|
574
|
+
Existing Autonomous sync and shutdown preferences remain separately effective.
|
|
564
575
|
Private scheduler records are separate from baseline/journal formats and remain retained; no automatic filesystem rollback or state migration is performed.
|
|
565
576
|
|
|
566
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).
|
|
567
578
|
|
|
568
579
|
### Settings field merge and machine-local fields
|
|
569
580
|
|
|
570
|
-
`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.
|
|
571
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.
|
|
572
583
|
Unknown fields are preserved.
|
|
573
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.
|
|
@@ -616,8 +627,8 @@ Never reinterpret portable snapshots with an old binary.
|
|
|
616
627
|
|
|
617
628
|
### Content merge and partial progress
|
|
618
629
|
|
|
619
|
-
`sync.mergeContent` and `sync.partialSync` are independent
|
|
620
|
-
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.
|
|
621
632
|
Manual configuration must also declare version 5.
|
|
622
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.
|
|
623
634
|
Disabling options retains the schema and recovery evidence.
|
|
@@ -266,11 +266,11 @@ async function showConfig(ctx: ExtensionCommandContext, options: CommandOptions)
|
|
|
266
266
|
...storageLines,
|
|
267
267
|
`storage path: ${config.storagePath}`,
|
|
268
268
|
`automatic sync: ${automaticSyncSummary(config.automatic)}`,
|
|
269
|
-
`settings field merge: ${config.mergeSettings ? "On
|
|
269
|
+
`settings field merge: ${config.mergeSettings ? "On" : "Off"}`,
|
|
270
270
|
`machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(", ") || "none"}`,
|
|
271
271
|
`startup transfer: ${startupTransferSummary(config)}`,
|
|
272
|
-
`
|
|
273
|
-
`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"}`,
|
|
274
274
|
`included content: ${config.include.join(", ") || "none"}`,
|
|
275
275
|
`sessions: ${config.include.includes("sessions") ? "included" : "not included"}`,
|
|
276
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
|
}
|
|
@@ -81,7 +81,7 @@ export interface SyncPolicySettings {
|
|
|
81
81
|
automatic: boolean;
|
|
82
82
|
/** Explicit opt-in, separate from the legacy observe/shutdown policy. */
|
|
83
83
|
automaticTransfer?: boolean;
|
|
84
|
-
/**
|
|
84
|
+
/** Autonomous merged-sync authorization. */
|
|
85
85
|
agentMode?: boolean;
|
|
86
86
|
/** Separate explicit authorization for recurring background work. */
|
|
87
87
|
continuous?: boolean;
|
|
@@ -93,7 +93,7 @@ export function buildAgentEvidence(
|
|
|
93
93
|
const evidence: AgentEvidence = { units: [], files: [], unsupported: [] };
|
|
94
94
|
if (plan.kind !== "planned") return evidence;
|
|
95
95
|
if (plan.conflicts.length > AGENT_MAX_UNITS)
|
|
96
|
-
throw new Error("
|
|
96
|
+
throw new Error("Autonomous sync paused: too many conflict paths for bounded analysis.");
|
|
97
97
|
for (const conflict of plan.conflicts) {
|
|
98
98
|
try {
|
|
99
99
|
if (conflict.reason !== "both-changed") throw new Error("unsupported conflict");
|
|
@@ -159,7 +159,7 @@ export function buildAgentEvidence(
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
if (evidence.units.length > AGENT_MAX_UNITS || Buffer.byteLength(JSON.stringify(evidence.units)) > AGENT_INPUT_BYTES)
|
|
162
|
-
throw new Error("
|
|
162
|
+
throw new Error("Autonomous sync paused: conflict evidence exceeds its input bound.");
|
|
163
163
|
// Scan only the actual disclosure image; skipSecretScan never authorizes model disclosure.
|
|
164
164
|
if (
|
|
165
165
|
scanSnapshot({
|
|
@@ -169,7 +169,7 @@ export function buildAgentEvidence(
|
|
|
169
169
|
),
|
|
170
170
|
}).length
|
|
171
171
|
)
|
|
172
|
-
throw new Error("
|
|
172
|
+
throw new Error("Autonomous sync paused: possible secrets in model evidence; nothing was disclosed.");
|
|
173
173
|
return evidence;
|
|
174
174
|
}
|
|
175
175
|
|
package/src/sync/agent-plan.ts
CHANGED
|
@@ -34,24 +34,27 @@ export async function resolveAgentPlan(
|
|
|
34
34
|
return plan;
|
|
35
35
|
}
|
|
36
36
|
if (!ctx.hasUI || (ctx.mode !== "tui" && ctx.mode !== "rpc"))
|
|
37
|
-
throw new Error("
|
|
37
|
+
throw new Error("Autonomous sync paused: TUI/RPC is required.");
|
|
38
38
|
const ancestors = (await readMergeAncestors(config, state)) ?? [];
|
|
39
39
|
await validate();
|
|
40
40
|
let evidence: ReturnType<typeof buildAgentEvidence>;
|
|
41
41
|
try {
|
|
42
42
|
evidence = buildAgentEvidence(plan, local, remote, ancestors);
|
|
43
43
|
} catch {
|
|
44
|
-
throw new ContinuousError("unsafe", "
|
|
44
|
+
throw new ContinuousError("unsafe", "Autonomous sync paused: unsafe or unsupported conflict evidence.");
|
|
45
45
|
}
|
|
46
46
|
if (!config.partialSync && evidence.unsupported.length)
|
|
47
|
-
throw new ContinuousError(
|
|
47
|
+
throw new ContinuousError(
|
|
48
|
+
"unsafe",
|
|
49
|
+
"Autonomous sync paused: unsupported conflicts prevent an all-or-nothing transfer.",
|
|
50
|
+
);
|
|
48
51
|
if (!evidence.files.length) {
|
|
49
52
|
if (options.agentRetryRefusal)
|
|
50
53
|
throw new ContinuousError("unsafe", "No eligible cached refusal for the current evidence. Use Sync now.");
|
|
51
54
|
if (config.partialSync) return plan;
|
|
52
55
|
throw new ContinuousError(
|
|
53
56
|
"unsafe",
|
|
54
|
-
"
|
|
57
|
+
"Autonomous sync paused: unsupported conflict or missing verified ancestor; evidence is unchanged.",
|
|
55
58
|
);
|
|
56
59
|
}
|
|
57
60
|
if (!evidence.units.length) {
|
|
@@ -59,7 +62,7 @@ export async function resolveAgentPlan(
|
|
|
59
62
|
throw new ContinuousError("unsafe", "No eligible cached refusal for the current evidence. Use Sync now.");
|
|
60
63
|
return applyAgentCandidate(plan, evidence, { version: 1, results: [] });
|
|
61
64
|
}
|
|
62
|
-
if (!ctx.model) throw new ContinuousError("model", "
|
|
65
|
+
if (!ctx.model) throw new ContinuousError("model", "Autonomous sync paused: select an available model first.");
|
|
63
66
|
const model = digest(ctx.model);
|
|
64
67
|
const key = digest([
|
|
65
68
|
1,
|
|
@@ -75,7 +78,7 @@ export async function resolveAgentPlan(
|
|
|
75
78
|
try {
|
|
76
79
|
return applyAgentCandidate(plan, evidence, options.agentAcceptance.candidate);
|
|
77
80
|
} catch {
|
|
78
|
-
throw new ContinuousError("unsafe", "
|
|
81
|
+
throw new ContinuousError("unsafe", "Autonomous sync paused: candidate refused or unsupported conflict remains.");
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
const validateEvidence = async (signal = options.signal) => {
|
|
@@ -85,7 +88,7 @@ export async function resolveAgentPlan(
|
|
|
85
88
|
signal?.throwIfAborted();
|
|
86
89
|
};
|
|
87
90
|
await check();
|
|
88
|
-
if (digest(ctx.model) !== model) throw new Error("
|
|
91
|
+
if (digest(ctx.model) !== model) throw new Error("Autonomous sync paused: selected model changed.");
|
|
89
92
|
const current = await createSnapshot(config.snapshotIdentity, { ...snapshotOptions, signal });
|
|
90
93
|
await check();
|
|
91
94
|
const currentState = await readStateForConfig(config);
|
|
@@ -98,7 +101,7 @@ export async function resolveAgentPlan(
|
|
|
98
101
|
!currentHead ||
|
|
99
102
|
!backend.sameRevision(head.revision, currentHead.revision)
|
|
100
103
|
)
|
|
101
|
-
throw new ContinuousError("stale", "
|
|
104
|
+
throw new ContinuousError("stale", "Autonomous sync paused: conflict evidence changed; retry a fresh sync.");
|
|
102
105
|
};
|
|
103
106
|
throw new AgentResolutionRequired(key, evidence, validateEvidence);
|
|
104
107
|
}
|
package/src/sync/agent-runner.ts
CHANGED
|
@@ -39,9 +39,9 @@ export async function runAgentResolver(
|
|
|
39
39
|
beforeRequest?: (signal: AbortSignal) => Promise<void>,
|
|
40
40
|
): Promise<string> {
|
|
41
41
|
const model = ctx.model;
|
|
42
|
-
if (!model) throw new ContinuousError("model", "
|
|
42
|
+
if (!model) throw new ContinuousError("model", "Autonomous sync paused: select an available model first.");
|
|
43
43
|
if (!Number.isSafeInteger(model.maxTokens) || model.maxTokens < 0)
|
|
44
|
-
throw new Error("
|
|
44
|
+
throw new Error("Autonomous sync paused: selected model has an invalid output limit.");
|
|
45
45
|
// Pi uses zero for unknown limits, including virtual models. Its registry caps routed requests.
|
|
46
46
|
const maxTokens = model.maxTokens > 0 ? Math.min(AGENT_MAX_TOKENS, model.maxTokens) : AGENT_MAX_TOKENS;
|
|
47
47
|
const controller = new AbortController();
|
|
@@ -74,7 +74,7 @@ export async function runAgentResolver(
|
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
76
|
const childModel = runtime.getModel(provider, "resolver");
|
|
77
|
-
if (!childModel) throw new Error("
|
|
77
|
+
if (!childModel) throw new Error("Autonomous sync paused: resolver model unavailable.");
|
|
78
78
|
({ session } = await createAgentSession({
|
|
79
79
|
cwd: ctx.cwd,
|
|
80
80
|
model: childModel,
|
|
@@ -104,7 +104,7 @@ export async function runAgentResolver(
|
|
|
104
104
|
});
|
|
105
105
|
child.agent.streamFunction = async (_model, context, options) => {
|
|
106
106
|
ownedSignal.throwIfAborted();
|
|
107
|
-
if (++calls > 1) throw new Error("
|
|
107
|
+
if (++calls > 1) throw new Error("Autonomous sync paused: one provider request per candidate is permitted.");
|
|
108
108
|
await validate(ownedSignal);
|
|
109
109
|
ownedSignal.throwIfAborted();
|
|
110
110
|
if (beforeRequest) {
|
|
@@ -146,15 +146,16 @@ export async function runAgentResolver(
|
|
|
146
146
|
last.stopReason !== "stop" ||
|
|
147
147
|
last.content.some((block) => block.type !== "text" && block.type !== "thinking")
|
|
148
148
|
)
|
|
149
|
-
throw new Error("
|
|
149
|
+
throw new Error("Autonomous sync paused: incomplete, failed or tool-bearing model output.");
|
|
150
150
|
const output = last.content
|
|
151
151
|
.filter((block) => block.type === "text")
|
|
152
152
|
.map((block) => block.text)
|
|
153
153
|
.join("");
|
|
154
|
-
if (Buffer.byteLength(output) > AGENT_OUTPUT_BYTES)
|
|
154
|
+
if (Buffer.byteLength(output) > AGENT_OUTPUT_BYTES)
|
|
155
|
+
throw new Error("Autonomous sync paused: output bound exceeded.");
|
|
155
156
|
if (ctx.hasUI)
|
|
156
157
|
ctx.ui.notify(
|
|
157
|
-
`Pi Sync
|
|
158
|
+
`Pi Sync resolver candidate: ${last.usage.totalTokens} tokens. Semantic correctness is not guaranteed.`,
|
|
158
159
|
"info",
|
|
159
160
|
);
|
|
160
161
|
return output;
|
|
@@ -169,13 +170,13 @@ export async function runAgentResolver(
|
|
|
169
170
|
if (failure.retry)
|
|
170
171
|
throw new ContinuousError(
|
|
171
172
|
failure.kind,
|
|
172
|
-
"
|
|
173
|
+
"Autonomous sync paused: transient resolver transport failure.",
|
|
173
174
|
failure.delay,
|
|
174
175
|
);
|
|
175
176
|
// Provider errors can quote submitted content or auth; never surface their payload.
|
|
176
177
|
throw new ContinuousError(
|
|
177
178
|
"model",
|
|
178
|
-
"
|
|
179
|
+
"Autonomous sync paused: resolver failed or returned unusable output. Check model access and retry later.",
|
|
179
180
|
);
|
|
180
181
|
} finally {
|
|
181
182
|
clearTimeout(timer);
|
package/src/sync/agent-store.ts
CHANGED
|
@@ -92,7 +92,7 @@ export async function withAgentClaim<T>(fn: (assertOwner: () => Promise<void>) =
|
|
|
92
92
|
await withClaimGuard(async () => {
|
|
93
93
|
const existing = await readClaim();
|
|
94
94
|
if (existing && alive(existing.pid))
|
|
95
|
-
throw new ContinuousError("contention", "
|
|
95
|
+
throw new ContinuousError("contention", "Autonomous sync deferred: another local resolver is running.");
|
|
96
96
|
// A durability failure can occur after rename: cleanup must own partial initialization too.
|
|
97
97
|
armed = true;
|
|
98
98
|
await writeJson(paths().claim, claim);
|
package/src/sync/agent-sync.ts
CHANGED
|
@@ -89,7 +89,7 @@ export async function withAgentSyncLock<T>(
|
|
|
89
89
|
try {
|
|
90
90
|
candidate = parseAgentCandidate(raw, request.evidence);
|
|
91
91
|
} catch {
|
|
92
|
-
throw new ContinuousError("model", "
|
|
92
|
+
throw new ContinuousError("model", "Autonomous sync paused: invalid resolver output; evidence retained.");
|
|
93
93
|
}
|
|
94
94
|
if (retry && candidate.results.some((row) => "refuse" in row))
|
|
95
95
|
throw new ContinuousError("model", "The model refused again. The previous refusal was retained.");
|
|
@@ -132,7 +132,7 @@ export async function withAgentSyncLock<T>(
|
|
|
132
132
|
request = error;
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
throw new ContinuousError("stale", "
|
|
135
|
+
throw new ContinuousError("stale", "Autonomous sync paused: content changed repeatedly; retry later.");
|
|
136
136
|
} finally {
|
|
137
137
|
options.signal?.removeEventListener("abort", onAbort);
|
|
138
138
|
if (!options.signal?.aborted) clearStatus();
|
|
@@ -210,7 +210,7 @@ function hasReservationCapacity(record: ContinuousRecord, now: number): boolean
|
|
|
210
210
|
/** Read-only status: no directory creation, lease, mutation, request reservation or provider call. */
|
|
211
211
|
export async function continuousStatusLines(config: AnySyncConfig, clock: () => number = Date.now): Promise<string[]> {
|
|
212
212
|
if (!config.continuous) return ["Continuous sync: Off"];
|
|
213
|
-
if (!config.agentMode) return ["Continuous sync: paused; enable
|
|
213
|
+
if (!config.agentMode) return ["Continuous sync: paused; enable Autonomous sync first"];
|
|
214
214
|
try {
|
|
215
215
|
const binding = await continuousBinding(config);
|
|
216
216
|
const document = await readContinuousPrivateDocument(`${binding}.json`);
|
package/src/sync/merged-sync.ts
CHANGED
|
@@ -102,7 +102,7 @@ export async function mergeSync(
|
|
|
102
102
|
options.agentRetryRefusal &&
|
|
103
103
|
(!config.agentMode || options.auto || options.background || !ctx.hasUI || !["tui", "rpc"].includes(ctx.mode))
|
|
104
104
|
)
|
|
105
|
-
throw new Error("Refused-candidate retry requires foreground
|
|
105
|
+
throw new Error("Refused-candidate retry requires foreground Autonomous sync in TUI or RPC.");
|
|
106
106
|
};
|
|
107
107
|
const config = await loadConfig(options.setup);
|
|
108
108
|
validateOwner(config);
|
|
@@ -131,7 +131,7 @@ export async function mergeSync(
|
|
|
131
131
|
throw new Error("Session storage root changed during transfer; evidence retained for review.");
|
|
132
132
|
}
|
|
133
133
|
if (config.agentMode && JSON.stringify(ctx.model) !== modelToken)
|
|
134
|
-
throw new Error("
|
|
134
|
+
throw new Error("Autonomous sync paused: selected model changed during transfer.");
|
|
135
135
|
if (options.auto && (!startupTransferEnabled(latest) || !ctx.isIdle()))
|
|
136
136
|
throw new Error("Automatic transfer is no longer authorized at this idle boundary.");
|
|
137
137
|
});
|
|
@@ -171,7 +171,7 @@ export async function mergeSync(
|
|
|
171
171
|
// Recovery above never publishes. This gate applies only to new autonomous transfers.
|
|
172
172
|
if ((options.auto || config.agentMode) && backend.capability === "read-check-write-verify") {
|
|
173
173
|
throw new Error(
|
|
174
|
-
"Automatic transfer requires conditional publication or a lease; this backend supports only read/check/write/verify. Disable
|
|
174
|
+
"Automatic transfer requires conditional publication or a lease; this backend supports only read/check/write/verify. Disable Autonomous sync and use manual sync.",
|
|
175
175
|
);
|
|
176
176
|
}
|
|
177
177
|
const textBudget = { remaining: TEXT_MERGE_WORK_LIMIT };
|
|
@@ -353,7 +353,7 @@ export async function mergeSync(
|
|
|
353
353
|
if (plan.kind !== "planned" || (plan.conflicts.length && !config.partialSync))
|
|
354
354
|
throw new ContinuousError(
|
|
355
355
|
"unsafe",
|
|
356
|
-
"
|
|
356
|
+
"Autonomous sync paused: unsupported or refused conflict groups remain; no transfer was performed.",
|
|
357
357
|
);
|
|
358
358
|
}
|
|
359
359
|
if (
|
|
@@ -433,7 +433,7 @@ export async function syncBoth(
|
|
|
433
433
|
options.background?.validate(config);
|
|
434
434
|
if (options.agentRetryRefusal) {
|
|
435
435
|
if (!config.agentMode || options.auto || options.background || !ctx.hasUI)
|
|
436
|
-
throw new Error("Enable
|
|
436
|
+
throw new Error("Enable Autonomous sync and use the foreground manager to retry a cached refusal.");
|
|
437
437
|
const state = await readStateForConfig(config);
|
|
438
438
|
validateMutation();
|
|
439
439
|
const pending = await readMergeJournal(config);
|
|
@@ -6,10 +6,10 @@ import { confirmMergeReview } from "./merge-review.js";
|
|
|
6
6
|
import { safeTerminalText } from "./terminal-text.js";
|
|
7
7
|
|
|
8
8
|
export const AGENT_MODE_DESCRIPTION =
|
|
9
|
-
"This setup
|
|
9
|
+
"This setup: sync eligible changes at session startup and on Sync now without transfer confirmation. Use the selected Pi model to resolve supported text and settings conflicts. Eligible conflict content may be sent to its provider and incur costs. Selected local and remote content can be replaced or deleted. Unresolved conflicts pause unless partial sync permits independent progress. Continuous sync is a separate opt-in. No automatic reload.";
|
|
10
10
|
|
|
11
11
|
export const CONTINUOUS_DESCRIPTION =
|
|
12
|
-
"This setup
|
|
12
|
+
"This setup: recurring sync while Pi is open. Requires Autonomous sync. Watches selected files, checks the remote every 60–66 seconds, and retries temporary failures. Local changes and retries can cause extra requests between polls. May disclose conflict text and incur model/storage costs. No automatic reload.";
|
|
13
13
|
|
|
14
14
|
export function saveContinuousMode(
|
|
15
15
|
ctx: ExtensionCommandContext,
|
|
@@ -33,8 +33,8 @@ export async function saveAgentMode(
|
|
|
33
33
|
const setup = settings.syncSetups[setupName];
|
|
34
34
|
if (!setup || settings.activeSyncSetup !== setupName) throw new Error("Current sync setup changed; reopen Settings.");
|
|
35
35
|
const continuous = preference === "continuous";
|
|
36
|
-
const label = continuous ? "Continuous sync" : "
|
|
37
|
-
if (enabled && continuous && !setup.sync.agentMode) throw new Error("Enable
|
|
36
|
+
const label = continuous ? "Continuous sync" : "Autonomous sync";
|
|
37
|
+
if (enabled && continuous && !setup.sync.agentMode) throw new Error("Enable Autonomous sync before Continuous sync.");
|
|
38
38
|
if (Boolean(setup.sync[preference]) === enabled) return true;
|
|
39
39
|
if (enabled) {
|
|
40
40
|
const summary = [
|
|
@@ -59,7 +59,7 @@ export async function saveAgentMode(
|
|
|
59
59
|
if (
|
|
60
60
|
!(await confirmMergeReview(
|
|
61
61
|
ctx,
|
|
62
|
-
`Enable
|
|
62
|
+
`Enable ${label}?`,
|
|
63
63
|
summary,
|
|
64
64
|
signal,
|
|
65
65
|
() => !signal?.aborted,
|
|
@@ -80,7 +80,7 @@ export async function saveAgentMode(
|
|
|
80
80
|
settings.storageConnections[setup.storage.connection],
|
|
81
81
|
)
|
|
82
82
|
)
|
|
83
|
-
throw new Error("Sync setup or connection changed during
|
|
83
|
+
throw new Error("Sync setup or connection changed during Autonomous sync review; reopen Settings.");
|
|
84
84
|
return {
|
|
85
85
|
...current,
|
|
86
86
|
syncSetups: { ...current.syncSetups, [setupName]: { ...setup, sync: { ...setup.sync, [preference]: enabled } } },
|
package/src/ui/manager-state.ts
CHANGED
|
@@ -165,7 +165,7 @@ export async function describeManagerState(
|
|
|
165
165
|
`Included: ${selection.builtIns.length} built-in group${selection.builtIns.length === 1 ? "" : "s"} · ${selection.custom.length} extra path${selection.custom.length === 1 ? "" : "s"} · Sessions ${selection.sessions ? "on" : "off"}`,
|
|
166
166
|
`Automatic sync: ${automaticSyncSummary(config.automatic)}`,
|
|
167
167
|
`Startup transfer: ${startupTransferSummary(config)}`,
|
|
168
|
-
`
|
|
168
|
+
`Autonomous sync: ${config.agentMode ? "On (autonomous merged sync)" : "Off"}`,
|
|
169
169
|
...(config.continuous ? await (await import("../sync/continuous-record.js")).continuousStatusLines(config) : []),
|
|
170
170
|
`Last applied: ${lastAppliedSnapshot}`,
|
|
171
171
|
...(noSyncedContent
|