@narumitw/pi-sync 0.54.2 → 0.56.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.
Files changed (194) hide show
  1. package/README.md +40 -15
  2. package/dist/chunks/agent-candidate-3JN6DJKT.ts +26 -0
  3. package/dist/chunks/agent-plan-QCUJWBP4.ts +99 -0
  4. package/dist/chunks/agent-plan-QCUJWBP4.ts.map +7 -0
  5. package/dist/chunks/agent-runner-E2JU2VZ6.ts +182 -0
  6. package/dist/chunks/agent-runner-E2JU2VZ6.ts.map +7 -0
  7. package/dist/chunks/agent-store-A3F6IYWZ.ts +152 -0
  8. package/dist/chunks/agent-store-A3F6IYWZ.ts.map +7 -0
  9. package/dist/chunks/chunk-5Q5SSKNG.ts +128 -0
  10. package/dist/chunks/chunk-5Q5SSKNG.ts.map +7 -0
  11. package/dist/chunks/chunk-5XZOC7FD.ts +215 -0
  12. package/dist/chunks/chunk-5XZOC7FD.ts.map +7 -0
  13. package/dist/chunks/{chunk-IJ6VV6FN.ts → chunk-AAEEHR7H.ts} +31 -87
  14. package/dist/chunks/chunk-AAEEHR7H.ts.map +7 -0
  15. package/dist/chunks/{chunk-CHSIAC4N.ts → chunk-B4QZBDBT.ts} +2 -2
  16. package/dist/chunks/{chunk-CL7BZRRQ.ts → chunk-CRKTAPSL.ts} +8 -8
  17. package/dist/chunks/chunk-DT7M4VQS.ts +69 -0
  18. package/dist/chunks/chunk-DT7M4VQS.ts.map +7 -0
  19. package/dist/chunks/chunk-ED3TYIVW.ts +229 -0
  20. package/dist/chunks/chunk-ED3TYIVW.ts.map +7 -0
  21. package/dist/chunks/{chunk-VHXBCEVF.ts → chunk-EUMINX7L.ts} +6 -6
  22. package/dist/chunks/chunk-FQOSHGJ7.ts +215 -0
  23. package/dist/chunks/chunk-FQOSHGJ7.ts.map +7 -0
  24. package/dist/chunks/chunk-GNH73BJ5.ts +153 -0
  25. package/dist/chunks/chunk-GNH73BJ5.ts.map +7 -0
  26. package/dist/chunks/{chunk-UQ3ALBIB.ts → chunk-GP5DU62N.ts} +8 -9
  27. package/dist/chunks/chunk-GP5DU62N.ts.map +7 -0
  28. package/dist/chunks/{chunk-5RZPINUQ.ts → chunk-GSNPASKB.ts} +2 -2
  29. package/dist/chunks/{chunk-QE7NZZWT.ts → chunk-IWZH5KYS.ts} +23 -7
  30. package/dist/chunks/chunk-IWZH5KYS.ts.map +7 -0
  31. package/dist/chunks/{chunk-5ZWQ33XL.ts → chunk-JJTARUSO.ts} +15 -14
  32. package/dist/chunks/chunk-JJTARUSO.ts.map +7 -0
  33. package/dist/chunks/{chunk-2DI6PDZV.ts → chunk-NLWS55B6.ts} +15 -2
  34. package/dist/chunks/chunk-NLWS55B6.ts.map +7 -0
  35. package/dist/chunks/{chunk-SDZCTCYQ.ts → chunk-OEWQVWLC.ts} +4 -4
  36. package/dist/chunks/{chunk-MYPSMJHJ.ts → chunk-OTZRCKYP.ts} +380 -510
  37. package/dist/chunks/chunk-OTZRCKYP.ts.map +7 -0
  38. package/dist/chunks/{chunk-WFKUKVCP.ts → chunk-OWBAZA6J.ts} +24 -12
  39. package/dist/chunks/chunk-OWBAZA6J.ts.map +7 -0
  40. package/dist/chunks/chunk-PRUEIIK7.ts +24 -0
  41. package/dist/chunks/chunk-PRUEIIK7.ts.map +7 -0
  42. package/dist/chunks/chunk-QGK445K7.ts +21 -0
  43. package/dist/chunks/chunk-QGK445K7.ts.map +7 -0
  44. package/dist/chunks/{chunk-3B4Z2SKV.ts → chunk-QO333NM4.ts} +49 -21
  45. package/dist/chunks/chunk-QO333NM4.ts.map +7 -0
  46. package/dist/chunks/{chunk-4SBTAVFL.ts → chunk-QSHMOL3I.ts} +22 -24
  47. package/dist/chunks/chunk-QSHMOL3I.ts.map +7 -0
  48. package/dist/chunks/chunk-S2FMH5FT.ts +97 -0
  49. package/dist/chunks/chunk-S2FMH5FT.ts.map +7 -0
  50. package/dist/chunks/{chunk-BVVP33U5.ts → chunk-SWRVXVFD.ts} +12 -9
  51. package/dist/chunks/chunk-SWRVXVFD.ts.map +7 -0
  52. package/dist/chunks/{chunk-ZX2Q6THB.ts → chunk-UBV24CG4.ts} +4 -5
  53. package/dist/chunks/chunk-UBV24CG4.ts.map +7 -0
  54. package/dist/chunks/chunk-UOHR7LRO.ts +70 -0
  55. package/dist/chunks/chunk-UOHR7LRO.ts.map +7 -0
  56. package/dist/chunks/{chunk-4QVPTIZB.ts → chunk-UPNVIUBN.ts} +3 -3
  57. package/dist/chunks/chunk-UZPMDLTL.ts +54 -0
  58. package/dist/chunks/chunk-UZPMDLTL.ts.map +7 -0
  59. package/dist/chunks/chunk-VJN7KU4J.ts +350 -0
  60. package/dist/chunks/chunk-VJN7KU4J.ts.map +7 -0
  61. package/dist/chunks/chunk-YHT4YTYG.ts +31 -0
  62. package/dist/chunks/chunk-YHT4YTYG.ts.map +7 -0
  63. package/dist/chunks/{chunk-V6VZ5TLG.ts → chunk-YK52VDXG.ts} +6 -5
  64. package/dist/chunks/chunk-YK52VDXG.ts.map +7 -0
  65. package/dist/chunks/config-KGIYTTXQ.ts +37 -0
  66. package/dist/chunks/{conflict-artifacts-BB2FZMIE.ts → conflict-artifacts-FXFIIBCB.ts} +8 -7
  67. package/dist/chunks/{conflict-review-4PLVLMRO.ts → conflict-review-6WIEQLXW.ts} +31 -24
  68. package/dist/chunks/{conflict-review-4PLVLMRO.ts.map → conflict-review-6WIEQLXW.ts.map} +1 -1
  69. package/dist/chunks/continuous-record-LFRVXQBD.ts +30 -0
  70. package/dist/chunks/continuous-sync-AWAAOXK2.ts +545 -0
  71. package/dist/chunks/continuous-sync-AWAAOXK2.ts.map +7 -0
  72. package/dist/chunks/{file-selection-WZX7HAY2.ts → file-selection-3JJYOVNR.ts} +5 -5
  73. package/dist/chunks/{git-backend-FD7AVSK6.ts → git-backend-KYDZ673X.ts} +28 -32
  74. package/dist/chunks/git-backend-KYDZ673X.ts.map +7 -0
  75. package/dist/chunks/{manager-result-dispatcher-6MQKFCWB.ts → manager-result-dispatcher-AGBBVDDS.ts} +10 -9
  76. package/dist/chunks/{manager-ui-IURS4WXY.ts → manager-ui-KRAW3NE2.ts} +464 -164
  77. package/dist/chunks/manager-ui-KRAW3NE2.ts.map +7 -0
  78. package/dist/chunks/{merge-baseline-store-EVQAAML6.ts → merge-baseline-store-RFCAH7KL.ts} +7 -5
  79. package/dist/chunks/{remote-selection-ui-6LJJ4IMQ.ts → remote-selection-ui-5725JDNC.ts} +9 -8
  80. package/dist/chunks/remote-selection-ui-5725JDNC.ts.map +7 -0
  81. package/dist/chunks/{s3-backend-AQGV6LFT.ts → s3-backend-Y7WSCLJI.ts} +38 -38
  82. package/dist/chunks/s3-backend-Y7WSCLJI.ts.map +7 -0
  83. package/dist/chunks/{setup-switch-KTUWL6DE.ts → setup-switch-E7PHKI6J.ts} +7 -6
  84. package/dist/chunks/setup-switch-E7PHKI6J.ts.map +7 -0
  85. package/dist/chunks/{setup-wizard-GSDPDFC4.ts → setup-wizard-65DROCIJ.ts} +14 -13
  86. package/dist/chunks/setup-wizard-65DROCIJ.ts.map +7 -0
  87. package/dist/chunks/{sync-inspection-K45QVLHB.ts → sync-inspection-XFJOAMJD.ts} +9 -8
  88. package/dist/chunks/sync-inspection-XFJOAMJD.ts.map +7 -0
  89. package/dist/chunks/{sync-operations-47OUX76C.ts → sync-operations-HDUDT5PD.ts} +188 -73
  90. package/dist/chunks/sync-operations-HDUDT5PD.ts.map +7 -0
  91. package/dist/chunks/{webdav-backend-TBILVEQK.ts → webdav-backend-6K26F6LT.ts} +39 -48
  92. package/dist/chunks/webdav-backend-6K26F6LT.ts.map +7 -0
  93. package/dist/index.ts +246 -131
  94. package/dist/index.ts.map +3 -3
  95. package/docs/agent-mode-verification.md +99 -0
  96. package/docs/continuous-sync-verification.md +87 -0
  97. package/docs/settings.md +131 -11
  98. package/docs/tui-contract.md +61 -0
  99. package/package.json +3 -2
  100. package/src/backends/git/git-backend.ts +1 -4
  101. package/src/backends/git/git-runner.ts +1 -5
  102. package/src/backends/s3/s3-backend.ts +3 -25
  103. package/src/backends/s3/s3-client.ts +14 -2
  104. package/src/backends/snapshot-pointer.ts +27 -0
  105. package/src/backends/webdav/webdav-backend.ts +3 -29
  106. package/src/backends/webdav/webdav-client.ts +11 -7
  107. package/src/commands/command-execution.ts +7 -3
  108. package/src/commands/command-handler.ts +15 -3
  109. package/src/commands/command-types.ts +10 -0
  110. package/src/commands/command.ts +4 -1
  111. package/src/settings/config.ts +20 -10
  112. package/src/settings/settings-store.ts +1 -34
  113. package/src/settings/settings-types.ts +10 -0
  114. package/src/settings/settings-validation.ts +4 -1
  115. package/src/snapshot/snapshot-codec.ts +1 -5
  116. package/src/state/lock.ts +13 -10
  117. package/src/state/merge-baseline-store.ts +19 -1
  118. package/src/state/state-directory.ts +8 -1
  119. package/src/sync/agent-candidate.ts +251 -0
  120. package/src/sync/agent-plan.ts +87 -0
  121. package/src/sync/agent-policy.ts +13 -0
  122. package/src/sync/agent-request.ts +17 -0
  123. package/src/sync/agent-runner.ts +188 -0
  124. package/src/sync/agent-store.ts +151 -0
  125. package/src/sync/agent-sync.ts +91 -0
  126. package/src/sync/apply-review.ts +63 -0
  127. package/src/sync/automatic-sync.ts +46 -33
  128. package/src/sync/continuous-errors.ts +85 -0
  129. package/src/sync/continuous-lease.ts +221 -0
  130. package/src/sync/continuous-record.ts +179 -0
  131. package/src/sync/continuous-storage.ts +55 -0
  132. package/src/sync/continuous-sync.ts +516 -0
  133. package/src/sync/continuous-watch.ts +59 -0
  134. package/src/sync/merged-sync.ts +268 -112
  135. package/src/sync/remote-snapshot.ts +2 -3
  136. package/src/sync/settings-merge.ts +19 -3
  137. package/src/sync/setup-switch.ts +1 -5
  138. package/src/sync/startup-check.ts +51 -29
  139. package/src/sync/startup-timings.ts +90 -0
  140. package/src/sync/sync-inspection.ts +16 -5
  141. package/src/sync/sync-mutations.ts +55 -28
  142. package/src/sync/sync-queries.ts +19 -3
  143. package/src/sync/text-merge.ts +3 -3
  144. package/src/sync-extension.ts +75 -19
  145. package/src/ui/agent-mode-setting.ts +91 -0
  146. package/src/ui/manager-state.ts +12 -6
  147. package/src/ui/manager-ui.ts +57 -7
  148. package/src/ui/merge-review.ts +3 -3
  149. package/src/ui/merged-sync-summary.ts +2 -18
  150. package/src/ui/remote-selection-ui.ts +5 -5
  151. package/src/ui/settings-frame.ts +55 -0
  152. package/src/ui/settings-ui.ts +223 -43
  153. package/src/ui/setup/s3-credentials-ui.ts +1 -5
  154. package/src/ui/setup/setup-name-ui.ts +2 -5
  155. package/src/ui/setup/setup-prompts.ts +4 -3
  156. package/src/ui/setup/setup-switcher.ts +2 -0
  157. package/src/ui/sync-behavior.ts +15 -0
  158. package/src/ui/sync-format.ts +69 -38
  159. package/src/ui/sync-setups-ui.ts +3 -5
  160. package/src/ui/transfer-changes.ts +33 -0
  161. package/src/ui/transfer-review.ts +27 -0
  162. package/dist/chunks/chunk-2DI6PDZV.ts.map +0 -7
  163. package/dist/chunks/chunk-3B4Z2SKV.ts.map +0 -7
  164. package/dist/chunks/chunk-4SBTAVFL.ts.map +0 -7
  165. package/dist/chunks/chunk-5ZWQ33XL.ts.map +0 -7
  166. package/dist/chunks/chunk-BVVP33U5.ts.map +0 -7
  167. package/dist/chunks/chunk-IJ6VV6FN.ts.map +0 -7
  168. package/dist/chunks/chunk-MYPSMJHJ.ts.map +0 -7
  169. package/dist/chunks/chunk-ORQRHEEO.ts +0 -362
  170. package/dist/chunks/chunk-ORQRHEEO.ts.map +0 -7
  171. package/dist/chunks/chunk-QE7NZZWT.ts.map +0 -7
  172. package/dist/chunks/chunk-UQ3ALBIB.ts.map +0 -7
  173. package/dist/chunks/chunk-V6VZ5TLG.ts.map +0 -7
  174. package/dist/chunks/chunk-WFKUKVCP.ts.map +0 -7
  175. package/dist/chunks/chunk-ZX2Q6THB.ts.map +0 -7
  176. package/dist/chunks/git-backend-FD7AVSK6.ts.map +0 -7
  177. package/dist/chunks/manager-ui-IURS4WXY.ts.map +0 -7
  178. package/dist/chunks/s3-backend-AQGV6LFT.ts.map +0 -7
  179. package/dist/chunks/setup-wizard-GSDPDFC4.ts.map +0 -7
  180. package/dist/chunks/sync-operations-47OUX76C.ts.map +0 -7
  181. package/dist/chunks/webdav-backend-TBILVEQK.ts.map +0 -7
  182. /package/dist/chunks/{conflict-artifacts-BB2FZMIE.ts.map → agent-candidate-3JN6DJKT.ts.map} +0 -0
  183. /package/dist/chunks/{chunk-CHSIAC4N.ts.map → chunk-B4QZBDBT.ts.map} +0 -0
  184. /package/dist/chunks/{chunk-CL7BZRRQ.ts.map → chunk-CRKTAPSL.ts.map} +0 -0
  185. /package/dist/chunks/{chunk-VHXBCEVF.ts.map → chunk-EUMINX7L.ts.map} +0 -0
  186. /package/dist/chunks/{chunk-5RZPINUQ.ts.map → chunk-GSNPASKB.ts.map} +0 -0
  187. /package/dist/chunks/{chunk-SDZCTCYQ.ts.map → chunk-OEWQVWLC.ts.map} +0 -0
  188. /package/dist/chunks/{chunk-4QVPTIZB.ts.map → chunk-UPNVIUBN.ts.map} +0 -0
  189. /package/dist/chunks/{manager-result-dispatcher-6MQKFCWB.ts.map → config-KGIYTTXQ.ts.map} +0 -0
  190. /package/dist/chunks/{merge-baseline-store-EVQAAML6.ts.map → conflict-artifacts-FXFIIBCB.ts.map} +0 -0
  191. /package/dist/chunks/{remote-selection-ui-6LJJ4IMQ.ts.map → continuous-record-LFRVXQBD.ts.map} +0 -0
  192. /package/dist/chunks/{file-selection-WZX7HAY2.ts.map → file-selection-3JJYOVNR.ts.map} +0 -0
  193. /package/dist/chunks/{setup-switch-KTUWL6DE.ts.map → manager-result-dispatcher-AGBBVDDS.ts.map} +0 -0
  194. /package/dist/chunks/{sync-inspection-K45QVLHB.ts.map → merge-baseline-store-RFCAH7KL.ts.map} +0 -0
package/dist/index.ts CHANGED
@@ -1,22 +1,19 @@
1
1
  // @generated by scripts/build-runtime.mjs; do not edit.
2
2
  // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
3
  import {
4
- createSyncAttentionController,
5
- observationMatchesConfig,
6
- syncAttentionMatchesConfig
7
- } from "./chunks/chunk-5RZPINUQ.ts";
4
+ withAgentSyncLock
5
+ } from "./chunks/chunk-S2FMH5FT.ts";
8
6
  import {
9
7
  recoverSnapshotTransactionsOnStartup
10
- } from "./chunks/chunk-CL7BZRRQ.ts";
8
+ } from "./chunks/chunk-CRKTAPSL.ts";
11
9
  import {
12
- captureMutationOwner,
13
- unlock,
14
- withLock
15
- } from "./chunks/chunk-IJ6VV6FN.ts";
10
+ createSyncAttentionController,
11
+ observationMatchesConfig,
12
+ syncAttentionMatchesConfig
13
+ } from "./chunks/chunk-GSNPASKB.ts";
16
14
  import {
17
- combineSignals,
18
- throwIfAborted
19
- } from "./chunks/chunk-PWMWOJP4.ts";
15
+ captureMutationOwner
16
+ } from "./chunks/chunk-UOHR7LRO.ts";
20
17
  import {
21
18
  automaticSyncSummary
22
19
  } from "./chunks/chunk-ECYCNZOE.ts";
@@ -30,23 +27,26 @@ import {
30
27
  resolveSyncCommand,
31
28
  setSyncSetupCompletions,
32
29
  splitArgs,
30
+ startupTransferSummary,
33
31
  usage,
34
32
  validateCommandOptions
35
- } from "./chunks/chunk-2DI6PDZV.ts";
33
+ } from "./chunks/chunk-NLWS55B6.ts";
36
34
  import {
37
35
  safeTerminalText
38
36
  } from "./chunks/chunk-AMJRUXFT.ts";
39
- import "./chunks/chunk-76NB4R7U.ts";
40
37
  import {
41
- ensureStateDir,
42
- readStateForConfig,
43
- syncStateFingerprint
44
- } from "./chunks/chunk-4QVPTIZB.ts";
38
+ createStartupTimings
39
+ } from "./chunks/chunk-UZPMDLTL.ts";
40
+ import "./chunks/chunk-UBV24CG4.ts";
45
41
  import {
46
- migrateLegacyStateDirectory,
47
- stateDirectoryMigrationNotice,
48
- withStateDirectoryAccess
49
- } from "./chunks/chunk-BVVP33U5.ts";
42
+ syncErrorGuidance
43
+ } from "./chunks/chunk-G4RUXRWZ.ts";
44
+ import {
45
+ SetupPullRequiresUiError,
46
+ errorMessage,
47
+ isSyncDecisionRequiredError
48
+ } from "./chunks/chunk-7D5SF7P3.ts";
49
+ import "./chunks/chunk-QGK445K7.ts";
50
50
  import {
51
51
  activeLocalConfigPath,
52
52
  consumeLocalConfigMigrationNotice,
@@ -60,26 +60,41 @@ import {
60
60
  sessionTokenWarnings,
61
61
  syncCheckConfigFingerprint,
62
62
  syncSessionsWarnings
63
- } from "./chunks/chunk-3B4Z2SKV.ts";
64
- import "./chunks/chunk-2JZFHNLM.ts";
65
- import "./chunks/chunk-T2SJD3N7.ts";
66
- import "./chunks/chunk-ZX2Q6THB.ts";
63
+ } from "./chunks/chunk-QO333NM4.ts";
64
+ import "./chunks/chunk-A6HU4ERM.ts";
67
65
  import {
68
- syncErrorGuidance
69
- } from "./chunks/chunk-G4RUXRWZ.ts";
66
+ unlock,
67
+ withLock
68
+ } from "./chunks/chunk-AAEEHR7H.ts";
70
69
  import {
71
- SetupPullRequiresUiError,
72
- errorMessage,
73
- isSyncDecisionRequiredError
74
- } from "./chunks/chunk-7D5SF7P3.ts";
75
- import "./chunks/chunk-A6HU4ERM.ts";
70
+ combineSignals,
71
+ throwIfAborted
72
+ } from "./chunks/chunk-PWMWOJP4.ts";
73
+ import "./chunks/chunk-DT7M4VQS.ts";
74
+ import "./chunks/chunk-YDVQYUHE.ts";
76
75
  import {
77
76
  RemoteSelectionMismatchError,
78
77
  formatRemoteSelectionMismatch,
79
78
  sessionDirFromContext,
80
79
  snapshotOptionsForContext
81
80
  } from "./chunks/chunk-QOFMXPM5.ts";
81
+ import "./chunks/chunk-76NB4R7U.ts";
82
82
  import "./chunks/chunk-ZW5ZLGBI.ts";
83
+ import {
84
+ startupTransferEnabled
85
+ } from "./chunks/chunk-PRUEIIK7.ts";
86
+ import {
87
+ ensureStateDir,
88
+ readStateForConfig,
89
+ syncStateFingerprint
90
+ } from "./chunks/chunk-UPNVIUBN.ts";
91
+ import {
92
+ migrateLegacyStateDirectory,
93
+ stateDirectoryMigrationNotice,
94
+ withStateDirectoryAccess
95
+ } from "./chunks/chunk-SWRVXVFD.ts";
96
+ import "./chunks/chunk-2JZFHNLM.ts";
97
+ import "./chunks/chunk-T2SJD3N7.ts";
83
98
  import "./chunks/chunk-HUZ5CR4W.ts";
84
99
 
85
100
  // src/ui/operation-dialogs.ts
@@ -129,7 +144,7 @@ async function executeRecoveryCommand(rawArgs, ctx, signal, loaders, onCommit, s
129
144
  const outcome = await withLock("pull", () => operations.pull(ctx, options));
130
145
  return { kind: "completed", ...outcome ? { outcome } : {} };
131
146
  }
132
- await withLock("sync", () => operations.syncBoth(ctx, options));
147
+ await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));
133
148
  return { kind: "completed" };
134
149
  } catch (error) {
135
150
  if (signal?.aborted) return { kind: "failed" };
@@ -182,7 +197,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
182
197
  await showConfig(ctx, options);
183
198
  return { kind: "completed" };
184
199
  case "files": {
185
- const { showFileSelection } = await import("./chunks/file-selection-WZX7HAY2.ts");
200
+ const { showFileSelection } = await import("./chunks/file-selection-3JJYOVNR.ts");
186
201
  throwIfAborted(options.signal);
187
202
  await showFileSelection(ctx, options.setup, options.signal);
188
203
  return { kind: "completed" };
@@ -200,7 +215,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
200
215
  return { kind: "completed" };
201
216
  }
202
217
  case "conflicts": {
203
- const { showConflicts } = await import("./chunks/conflict-review-4PLVLMRO.ts");
218
+ const { showConflicts } = await import("./chunks/conflict-review-6WIEQLXW.ts");
204
219
  throwIfAborted(options.signal);
205
220
  await withLock("sync", () => showConflicts(ctx, options));
206
221
  return { kind: "completed" };
@@ -226,7 +241,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
226
241
  case "sync": {
227
242
  const operations = await loaders.operations();
228
243
  throwIfAborted(options.signal);
229
- await withLock("sync", () => operations.syncBoth(ctx, options));
244
+ await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));
230
245
  return { kind: "completed" };
231
246
  }
232
247
  case "history": {
@@ -297,7 +312,7 @@ async function initConfig(ctx, signal) {
297
312
  return;
298
313
  }
299
314
  if (ctx.mode === "tui") {
300
- const { showSetupWizard } = await import("./chunks/setup-wizard-GSDPDFC4.ts");
315
+ const { showSetupWizard } = await import("./chunks/setup-wizard-65DROCIJ.ts");
301
316
  throwIfAborted(signal);
302
317
  await showSetupWizard(ctx, signal);
303
318
  return;
@@ -322,7 +337,9 @@ async function showConfig(ctx, options) {
322
337
  `automatic sync: ${automaticSyncSummary(config.automatic)}`,
323
338
  `settings field merge: ${config.mergeSettings ? "On (experimental)" : "Off"}`,
324
339
  `machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(", ") || "none"}`,
325
- `automatic transfer at startup: ${config.automaticTransfer ? "On \u2014 selected-file upload/replace/delete; no reload" : "Off"}`,
340
+ `startup transfer: ${startupTransferSummary(config)}`,
341
+ `agent mode: ${config.agentMode ? "On (experimental)" : "Off"}`,
342
+ `continuous sync: ${config.continuous ? config.agentMode ? "On (experimental)" : "paused; Agent mode is Off" : "Off"}`,
326
343
  `included content: ${config.include.join(", ") || "none"}`,
327
344
  `sessions: ${config.include.includes("sessions") ? "included" : "not included"}`,
328
345
  `settings file: ${localConfigPath()}`,
@@ -387,21 +404,32 @@ function displayWebDavUrl(value, username) {
387
404
  }
388
405
 
389
406
  // src/commands/command-handler.ts
390
- async function handleCommand(rawArgs, ctx, sessionSignal, loaders, attention) {
407
+ async function handleCommand(rawArgs, ctx, sessionSignal, loaders, attention, onExplicitSync) {
391
408
  await reconcileObservation(attention, sessionSignal);
392
409
  if (sessionSignal.aborted) return;
393
- const run = (route, signal, onCommit, target, onDialog) => executeCommand(
394
- route,
395
- ctx,
396
- combineSignals(sessionSignal, signal),
397
- loaders,
398
- observationCommitCallback(attention, sessionSignal, onCommit),
399
- target,
400
- onDialog
401
- );
410
+ const run = (route, signal, onCommit, target, onDialog) => {
411
+ const [command, ...args] = splitArgs(route);
412
+ if (command === "sync") {
413
+ try {
414
+ const options = parseOptions(args);
415
+ validateCommandOptions("sync", options);
416
+ onExplicitSync?.(target ?? options.setup);
417
+ } catch {
418
+ }
419
+ }
420
+ return executeCommand(
421
+ route,
422
+ ctx,
423
+ combineSignals(sessionSignal, signal),
424
+ loaders,
425
+ observationCommitCallback(attention, sessionSignal, onCommit),
426
+ target,
427
+ onDialog
428
+ );
429
+ };
402
430
  if (!rawArgs.trim()) {
403
431
  try {
404
- const { showSyncManager } = await import("./chunks/manager-ui-IURS4WXY.ts");
432
+ const { showSyncManager } = await import("./chunks/manager-ui-KRAW3NE2.ts");
405
433
  if (sessionSignal.aborted) return;
406
434
  await showSyncManager(ctx, run, sessionSignal, {
407
435
  getAttention: () => attention.current(),
@@ -501,7 +529,7 @@ function directSelectionOrigin(rawArgs) {
501
529
  async function resolveSelectionAttention(ctx, attention, signal, loaders, options = {}) {
502
530
  const current = attention.current();
503
531
  if (!current || signal.aborted) return;
504
- const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-6MQKFCWB.ts");
532
+ const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-AGBBVDDS.ts");
505
533
  if (signal.aborted || attention.current() !== current) return;
506
534
  await dispatchManagerResult(
507
535
  ctx,
@@ -545,42 +573,54 @@ var AUTO_SYNC_OPTIONS = {
545
573
  args: []
546
574
  };
547
575
  async function startSession(ctx, signal) {
548
- throwIfAborted(signal);
549
- const stateNotice = stateDirectoryMigrationNotice();
550
- if (stateNotice && ctx.hasUI) ctx.ui.notify(stateNotice, "warning");
551
- const validateMutation = captureMutationOwner(ctx, signal);
552
- const currentFile = ctx.sessionManager.getSessionFile?.();
553
- await recoverSnapshotTransactionsOnStartup({
554
- signal,
555
- sessionDir: sessionDirFromContext(ctx),
556
- protectedTargets: currentFile ? [currentFile] : [],
557
- validateMutation
558
- });
559
- throwIfAborted(signal);
576
+ const timings = createStartupTimings();
577
+ let debug = false;
578
+ let outcome = "stopped";
560
579
  try {
561
- const settings = await readLocalConfigObject();
562
580
  throwIfAborted(signal);
563
- const names = settings ? Object.keys(settings.syncSetups).sort((left, right) => left.localeCompare(right)) : [];
564
- setSyncSetupCompletions(names);
565
- configureSyncStatus(ctx, settings?.showStatus ?? true);
566
- } catch {
567
- if (signal.aborted) return;
568
- setSyncSetupCompletions([]);
569
- }
570
- const migrationNotice = consumeLocalConfigMigrationNotice();
571
- if (migrationNotice && ctx.hasUI) ctx.ui.notify(migrationNotice, "warning");
572
- throwIfAborted(signal);
573
- if (!ctx.hasUI) return;
574
- try {
575
- const config = await loadConfig();
581
+ const stateNotice = stateDirectoryMigrationNotice();
582
+ if (stateNotice && ctx.hasUI) ctx.ui.notify(stateNotice, "warning");
583
+ const validateMutation = captureMutationOwner(ctx, signal);
584
+ const currentFile = ctx.sessionManager.getSessionFile?.();
585
+ await timings.measure(
586
+ "transaction recovery",
587
+ () => recoverSnapshotTransactionsOnStartup({
588
+ signal,
589
+ sessionDir: sessionDirFromContext(ctx),
590
+ protectedTargets: currentFile ? [currentFile] : [],
591
+ validateMutation
592
+ })
593
+ );
576
594
  throwIfAborted(signal);
577
- configureSyncStatus(ctx, config.showStatus);
578
- return config.automatic || config.automaticTransfer ? config : void 0;
579
- } catch (error) {
595
+ try {
596
+ const settings = await timings.measure("settings read", () => readLocalConfigObject());
597
+ throwIfAborted(signal);
598
+ debug = settings?.debug ?? false;
599
+ const names = settings ? Object.keys(settings.syncSetups).sort((left, right) => left.localeCompare(right)) : [];
600
+ setSyncSetupCompletions(names);
601
+ configureSyncStatus(ctx, settings?.showStatus ?? true);
602
+ } catch {
603
+ if (signal.aborted) return;
604
+ setSyncSetupCompletions([]);
605
+ }
606
+ const migrationNotice = consumeLocalConfigMigrationNotice();
607
+ if (migrationNotice && ctx.hasUI) ctx.ui.notify(migrationNotice, "warning");
580
608
  throwIfAborted(signal);
581
- if (!isMissingConfigError(error)) {
582
- ctx.ui.notify(`pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}`, "warning");
609
+ if (!ctx.hasUI) return;
610
+ try {
611
+ const config = await timings.measure("config resolution", () => loadConfig());
612
+ throwIfAborted(signal);
613
+ configureSyncStatus(ctx, config.showStatus);
614
+ outcome = "completed";
615
+ return config.automatic || startupTransferEnabled(config) ? config : void 0;
616
+ } catch (error) {
617
+ throwIfAborted(signal);
618
+ if (!isMissingConfigError(error)) {
619
+ ctx.ui.notify(`pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}`, "warning");
620
+ }
583
621
  }
622
+ } finally {
623
+ timings.publish(ctx, debug, signal, "local initialization", outcome);
584
624
  }
585
625
  }
586
626
  async function autoPushSessions(ctx, signal, loaders) {
@@ -638,18 +678,19 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
638
678
  },
639
679
  start(ctx, sessionSignal, initialConfig) {
640
680
  if (!ctx.hasUI || sessionSignal.aborted) return;
641
- if (initialConfig?.automaticTransfer && !ctx.isIdle()) {
681
+ if (initialConfig && startupTransferEnabled(initialConfig) && !ctx.isIdle()) {
642
682
  pending = { ctx, signal: sessionSignal, config: initialConfig };
643
683
  return;
644
684
  }
645
685
  if (active) throw new Error("Previous startup check has not been drained.");
686
+ const timings = createStartupTimings();
646
687
  const controller = new AbortController();
647
688
  const signal = combineSignals(sessionSignal, controller.signal);
648
689
  const task = {
649
690
  controller,
650
691
  owner: ctx.sessionManager,
651
692
  promise: Promise.resolve(),
652
- transfer: Boolean(initialConfig?.automaticTransfer)
693
+ transfer: Boolean(initialConfig && startupTransferEnabled(initialConfig))
653
694
  };
654
695
  active = task;
655
696
  const isCurrent = () => !sessionSignal.aborted && active === task && task.owner === ctx.sessionManager;
@@ -659,29 +700,33 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
659
700
  );
660
701
  let config;
661
702
  let checking = false;
703
+ let stopped = false;
662
704
  task.promise = Promise.resolve().then(async () => {
663
705
  try {
664
706
  throwIfAborted(signal);
665
707
  config = initialConfig ?? await loadConfigForCheck();
666
- task.transfer = Boolean(config.automaticTransfer);
708
+ task.transfer = startupTransferEnabled(config);
667
709
  throwIfAborted(signal);
668
- if (!config.automatic && !config.automaticTransfer) return;
710
+ if (!config.automatic && !startupTransferEnabled(config)) return;
669
711
  const captured = config;
670
712
  const identity = syncCheckConfigFingerprint(captured);
671
713
  checking = true;
672
714
  setSyncStatus(ctx, "sync ...");
673
- const { inspectSync } = await loaders.inspection();
715
+ const { inspectSync } = await timings.measure("inspection import", () => loaders.inspection());
674
716
  throwIfAborted(signal);
675
717
  const currentConfig = await loadConfigForCheck();
676
718
  throwIfAborted(signal);
677
719
  if (syncCheckConfigFingerprint(currentConfig) !== identity) return;
678
- const inspection = await withStateDirectoryAccess(() => {
679
- throwIfAborted(signal);
680
- return withLock("startup-check", () => {
720
+ const inspection = await timings.measure(
721
+ "inspection and guards",
722
+ () => withStateDirectoryAccess(() => {
681
723
  throwIfAborted(signal);
682
- return inspectSync(captured, snapshotOptionsForContext(ctx, captured), signal);
683
- });
684
- });
724
+ return withLock("startup-check", () => {
725
+ throwIfAborted(signal);
726
+ return inspectSync(captured, snapshotOptionsForContext(ctx, captured), signal, void 0, timings);
727
+ });
728
+ })
729
+ );
685
730
  throwIfAborted(signal);
686
731
  const latest = await loadConfigForCheck();
687
732
  throwIfAborted(signal);
@@ -694,30 +739,35 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
694
739
  configIdentity: identity,
695
740
  checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
696
741
  inspection,
697
- automaticTransfer: captured.automaticTransfer
742
+ automaticTransfer: startupTransferEnabled(captured)
698
743
  });
699
- if (captured.automaticTransfer && !inspection.firstSync && inspection.head && inspection.selectionState?.kind === "same") {
700
- const operations = await loaders.operations();
744
+ if (startupTransferEnabled(captured) && !inspection.firstSync && inspection.head && inspection.selectionState?.kind === "same") {
745
+ const operations = await timings.measure("operations import", () => loaders.operations());
701
746
  throwIfAborted(signal);
702
747
  if (!isCurrent()) return;
703
748
  if (!ctx.isIdle()) {
704
749
  pending = { ctx, signal: sessionSignal, config: captured };
705
750
  return;
706
751
  }
707
- await withStateDirectoryAccess(
708
- () => withLock(
709
- "startup-transfer",
710
- () => operations.syncBoth(ctx, {
711
- args: [],
712
- yes: true,
713
- force: false,
714
- stale: false,
715
- silent: true,
716
- reload: false,
717
- auto: true,
718
- signal,
719
- onCommit: () => attention.clearObservation()
720
- })
752
+ await timings.measure(
753
+ "automatic transfer",
754
+ () => withStateDirectoryAccess(
755
+ () => withAgentSyncLock(
756
+ ctx,
757
+ {
758
+ args: [],
759
+ yes: true,
760
+ force: false,
761
+ stale: false,
762
+ silent: true,
763
+ reload: false,
764
+ auto: true,
765
+ signal,
766
+ startupTimings: timings,
767
+ onCommit: () => attention.clearObservation()
768
+ },
769
+ (options) => operations.syncBoth(ctx, options)
770
+ )
721
771
  )
722
772
  );
723
773
  throwIfAborted(signal);
@@ -730,10 +780,11 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
730
780
  configIdentity: identity,
731
781
  checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
732
782
  inspection,
733
- automaticTransfer: captured.automaticTransfer
783
+ automaticTransfer: startupTransferEnabled(captured)
734
784
  });
735
785
  if (ctx.mode === "rpc") attention.notifyObservation(ctx);
736
786
  } catch (error) {
787
+ stopped = true;
737
788
  if (!isCurrent() || sessionSignal.aborted || isMissingConfigError(error)) return;
738
789
  if (signal.aborted && controller.signal.reason?.name !== "TimeoutError") return;
739
790
  if (config) {
@@ -742,7 +793,7 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
742
793
  if (!latest || syncCheckConfigFingerprint(latest) !== syncCheckConfigFingerprint(config)) return;
743
794
  }
744
795
  ctx.ui.notify(
745
- config?.automaticTransfer ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.` : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,
796
+ config && startupTransferEnabled(config) ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.` : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,
746
797
  "warning"
747
798
  );
748
799
  } finally {
@@ -759,6 +810,15 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
759
810
  }
760
811
  } else setSyncStatus(ctx, void 0);
761
812
  }
813
+ if (isCurrent()) {
814
+ timings.publish(
815
+ ctx,
816
+ config?.debug ?? false,
817
+ sessionSignal,
818
+ "background startup",
819
+ signal.aborted || stopped ? "stopped" : "completed"
820
+ );
821
+ }
762
822
  if (active === task) active = void 0;
763
823
  }
764
824
  }).catch(() => {
@@ -780,11 +840,11 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
780
840
  // src/sync/sync-loaders.ts
781
841
  function createSyncLoaders(dependencies) {
782
842
  const loaders = {
783
- inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import("./chunks/sync-inspection-K45QVLHB.ts"))),
784
- setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-KTUWL6DE.ts"))),
843
+ inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import("./chunks/sync-inspection-XFJOAMJD.ts"))),
844
+ setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-E7PHKI6J.ts"))),
785
845
  snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import("./chunks/snapshot-THS5EY2L.ts"))),
786
846
  syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./chunks/sync-state-CFL4RRRB.ts"))),
787
- operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-47OUX76C.ts")))
847
+ operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-HDUDT5PD.ts")))
788
848
  };
789
849
  return loaders;
790
850
  }
@@ -809,6 +869,30 @@ function sync(pi, dependencies = {}) {
809
869
  let sessionAbort = new AbortController();
810
870
  let shutdownAbort;
811
871
  let initialization = Promise.resolve(void 0);
872
+ let continuous;
873
+ let owner;
874
+ let continuousPossible = false;
875
+ const foreground = /* @__PURE__ */ new Map();
876
+ async function resumeContinuous(ctx, signal, retry) {
877
+ const isCurrent = () => !signal.aborted && !foreground.has(ctx.sessionManager) && owner === ctx.sessionManager;
878
+ if (!isCurrent() || !ctx.hasUI) return;
879
+ try {
880
+ const { loadConfigForCheck: loadConfigForCheck2 } = await import("./chunks/config-KGIYTTXQ.ts");
881
+ if (!isCurrent()) return;
882
+ const config = await loadConfigForCheck2();
883
+ if (!isCurrent()) return;
884
+ continuousPossible = Boolean(config.continuous && config.agentMode);
885
+ if (!continuousPossible) {
886
+ await continuous?.stop(ctx.sessionManager);
887
+ return;
888
+ }
889
+ const { createContinuousSync } = await import("./chunks/continuous-sync-AWAAOXK2.ts");
890
+ if (!isCurrent()) return;
891
+ continuous ??= createContinuousSync(loaders);
892
+ continuous.start(ctx, signal, Boolean(retry && (retry.setup === void 0 || retry.setup === config.setupName)));
893
+ } catch {
894
+ }
895
+ }
812
896
  pi.registerCommand("sync", {
813
897
  description: "Sync Pi settings through Git, WebDAV, R2, or S3-compatible storage",
814
898
  getArgumentCompletions: completeSyncArguments,
@@ -817,21 +901,37 @@ function sync(pi, dependencies = {}) {
817
901
  throw new Error("/sync requires TUI or RPC mode so results and safety prompts are observable.");
818
902
  }
819
903
  const signal = sessionAbort.signal;
820
- const ready = await initialization;
821
- if (signal.aborted) return;
822
- await check.stop();
823
- if (signal.aborted) return;
904
+ const manager = ctx.sessionManager;
824
905
  const command = splitArgs(args)[0];
825
- if (ready === false && command !== "help" && command !== "unlock" && command !== "migrate-state") {
826
- ctx.ui.notify(
827
- "pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.",
828
- "error"
829
- );
830
- return;
906
+ let retry;
907
+ let mayResume = false;
908
+ foreground.set(manager, (foreground.get(manager) ?? 0) + 1);
909
+ try {
910
+ const ready = await initialization;
911
+ mayResume = ready !== false;
912
+ if (signal.aborted) return;
913
+ await continuous?.stop(manager);
914
+ if (signal.aborted) return;
915
+ await check.stop();
916
+ if (signal.aborted) return;
917
+ if (ready === false && command !== "help" && command !== "unlock" && command !== "migrate-state") {
918
+ ctx.ui.notify(
919
+ "pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.",
920
+ "error"
921
+ );
922
+ return;
923
+ }
924
+ const run = () => handleCommand(args, ctx, signal, loaders, attention, (setup) => {
925
+ retry = { setup };
926
+ });
927
+ if (command === "migrate-state" || command === "help") await run();
928
+ else await withStateDirectoryAccess(run);
929
+ } finally {
930
+ const count = (foreground.get(manager) ?? 1) - 1;
931
+ if (count) foreground.set(manager, count);
932
+ else foreground.delete(manager);
933
+ if (mayResume) await resumeContinuous(ctx, signal, retry);
831
934
  }
832
- const run = () => handleCommand(args, ctx, signal, loaders, attention);
833
- if (command === "migrate-state" || command === "help") await run();
834
- else await withStateDirectoryAccess(run);
835
935
  }
836
936
  });
837
937
  pi.on("session_start", async (_event, ctx) => {
@@ -840,11 +940,15 @@ function sync(pi, dependencies = {}) {
840
940
  sessionAbort.abort(new DOMException("Session replaced", "AbortError"));
841
941
  sessionAbort = new AbortController();
842
942
  const signal = sessionAbort.signal;
943
+ owner = ctx.sessionManager;
944
+ continuousPossible = false;
843
945
  attention.reset(ctx);
844
946
  const previous = initialization;
845
947
  initialization = (async () => {
846
948
  await previous;
847
949
  if (signal.aborted) return false;
950
+ await continuous?.stop();
951
+ if (signal.aborted) return false;
848
952
  await check.stop();
849
953
  if (signal.aborted) return false;
850
954
  try {
@@ -858,15 +962,24 @@ function sync(pi, dependencies = {}) {
858
962
  }
859
963
  })();
860
964
  const ready = await initialization;
861
- if (ready && !signal.aborted) check.start(ctx, signal, ready);
965
+ if (ready && !signal.aborted) {
966
+ if (ready.continuous && ready.agentMode) await resumeContinuous(ctx, signal);
967
+ else check.start(ctx, signal, ready);
968
+ }
862
969
  });
863
970
  pi.on("agent_start", async (_event, ctx) => {
971
+ await continuous?.stop(ctx.sessionManager);
864
972
  await check.interrupt(ctx);
865
973
  });
866
- pi.on("agent_settled", (_event, ctx) => {
867
- if (!sessionAbort.signal.aborted) check.settled(ctx);
974
+ pi.on("agent_settled", async (_event, ctx) => {
975
+ const signal = sessionAbort.signal;
976
+ if (!signal.aborted) {
977
+ check.settled(ctx);
978
+ if (continuousPossible) await resumeContinuous(ctx, signal);
979
+ }
868
980
  });
869
981
  pi.on("session_shutdown", async (event, ctx) => {
982
+ if (continuous && owner && owner !== ctx.sessionManager) return;
870
983
  sessionAbort.abort(new DOMException("Session shut down", "AbortError"));
871
984
  attention.reset(ctx);
872
985
  shutdownAbort?.abort(new DOMException("Session shut down again", "AbortError"));
@@ -877,6 +990,8 @@ function sync(pi, dependencies = {}) {
877
990
  try {
878
991
  const ready = await initialization;
879
992
  if (signal.aborted) return;
993
+ await continuous?.stop(ctx.sessionManager);
994
+ if (signal.aborted) return;
880
995
  await check.stop();
881
996
  if (signal.aborted) return;
882
997
  if (ready !== false && reason !== "reload") {