@narumitw/pi-sync 0.54.3 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -11
- package/dist/chunks/agent-candidate-3JN6DJKT.ts +26 -0
- package/dist/chunks/agent-plan-QCUJWBP4.ts +99 -0
- package/dist/chunks/agent-plan-QCUJWBP4.ts.map +7 -0
- package/dist/chunks/agent-runner-E2JU2VZ6.ts +182 -0
- package/dist/chunks/agent-runner-E2JU2VZ6.ts.map +7 -0
- package/dist/chunks/agent-store-A3F6IYWZ.ts +152 -0
- package/dist/chunks/agent-store-A3F6IYWZ.ts.map +7 -0
- package/dist/chunks/chunk-5Q5SSKNG.ts +128 -0
- package/dist/chunks/chunk-5Q5SSKNG.ts.map +7 -0
- package/dist/chunks/chunk-5XZOC7FD.ts +215 -0
- package/dist/chunks/chunk-5XZOC7FD.ts.map +7 -0
- package/dist/chunks/{chunk-GC3QOL6J.ts → chunk-AAEEHR7H.ts} +31 -87
- package/dist/chunks/chunk-AAEEHR7H.ts.map +7 -0
- package/dist/chunks/{chunk-R35N4CL3.ts → chunk-B4QZBDBT.ts} +2 -2
- package/dist/chunks/{chunk-KGE47GCZ.ts → chunk-CRKTAPSL.ts} +8 -8
- package/dist/chunks/chunk-DT7M4VQS.ts +69 -0
- package/dist/chunks/chunk-DT7M4VQS.ts.map +7 -0
- package/dist/chunks/chunk-ED3TYIVW.ts +229 -0
- package/dist/chunks/chunk-ED3TYIVW.ts.map +7 -0
- package/dist/chunks/{chunk-HMXUKU43.ts → chunk-EUMINX7L.ts} +6 -6
- package/dist/chunks/chunk-FQOSHGJ7.ts +215 -0
- package/dist/chunks/chunk-FQOSHGJ7.ts.map +7 -0
- package/dist/chunks/chunk-GNH73BJ5.ts +153 -0
- package/dist/chunks/chunk-GNH73BJ5.ts.map +7 -0
- package/dist/chunks/{chunk-YTHQEW35.ts → chunk-GP5DU62N.ts} +8 -9
- package/dist/chunks/chunk-GP5DU62N.ts.map +7 -0
- package/dist/chunks/{chunk-AAZDBIBJ.ts → chunk-GSNPASKB.ts} +2 -2
- package/dist/chunks/{chunk-E6ONFG57.ts → chunk-IWZH5KYS.ts} +11 -8
- package/dist/chunks/chunk-IWZH5KYS.ts.map +7 -0
- package/dist/chunks/{chunk-CAGJOKB7.ts → chunk-JJTARUSO.ts} +15 -14
- package/dist/chunks/chunk-JJTARUSO.ts.map +7 -0
- package/dist/chunks/{chunk-ITFR6NNQ.ts → chunk-NLWS55B6.ts} +2 -1
- package/dist/chunks/{chunk-ITFR6NNQ.ts.map → chunk-NLWS55B6.ts.map} +2 -2
- package/dist/chunks/{chunk-2FETCGGT.ts → chunk-OEWQVWLC.ts} +4 -4
- package/dist/chunks/{chunk-35GM6XKM.ts → chunk-OTZRCKYP.ts} +128 -382
- package/dist/chunks/chunk-OTZRCKYP.ts.map +7 -0
- package/dist/chunks/{chunk-XU2VXGQV.ts → chunk-OWBAZA6J.ts} +14 -8
- package/dist/chunks/chunk-OWBAZA6J.ts.map +7 -0
- package/dist/chunks/chunk-PRUEIIK7.ts +24 -0
- package/dist/chunks/chunk-PRUEIIK7.ts.map +7 -0
- package/dist/chunks/chunk-QGK445K7.ts +21 -0
- package/dist/chunks/chunk-QGK445K7.ts.map +7 -0
- package/dist/chunks/{chunk-KATKRR3D.ts → chunk-QO333NM4.ts} +32 -11
- package/dist/chunks/chunk-QO333NM4.ts.map +7 -0
- package/dist/chunks/{chunk-I4JYVFUS.ts → chunk-QSHMOL3I.ts} +21 -22
- package/dist/chunks/chunk-QSHMOL3I.ts.map +7 -0
- package/dist/chunks/chunk-S2FMH5FT.ts +97 -0
- package/dist/chunks/chunk-S2FMH5FT.ts.map +7 -0
- package/dist/chunks/{chunk-BVVP33U5.ts → chunk-SWRVXVFD.ts} +12 -9
- package/dist/chunks/chunk-SWRVXVFD.ts.map +7 -0
- package/dist/chunks/{chunk-ZX2Q6THB.ts → chunk-UBV24CG4.ts} +4 -5
- package/dist/chunks/chunk-UBV24CG4.ts.map +7 -0
- package/dist/chunks/chunk-UOHR7LRO.ts +70 -0
- package/dist/chunks/chunk-UOHR7LRO.ts.map +7 -0
- package/dist/chunks/{chunk-VCL7TZYW.ts → chunk-UPNVIUBN.ts} +3 -3
- package/dist/chunks/chunk-VJN7KU4J.ts +350 -0
- package/dist/chunks/chunk-VJN7KU4J.ts.map +7 -0
- package/dist/chunks/chunk-YHT4YTYG.ts +31 -0
- package/dist/chunks/chunk-YHT4YTYG.ts.map +7 -0
- package/dist/chunks/{chunk-A3TFXY4O.ts → chunk-YK52VDXG.ts} +6 -5
- package/dist/chunks/chunk-YK52VDXG.ts.map +7 -0
- package/dist/chunks/config-KGIYTTXQ.ts +37 -0
- package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts → conflict-artifacts-FXFIIBCB.ts} +8 -7
- package/dist/chunks/{conflict-review-ZOTOHL2E.ts → conflict-review-6WIEQLXW.ts} +31 -25
- package/dist/chunks/{conflict-review-ZOTOHL2E.ts.map → conflict-review-6WIEQLXW.ts.map} +1 -1
- package/dist/chunks/continuous-record-LFRVXQBD.ts +30 -0
- package/dist/chunks/continuous-sync-AWAAOXK2.ts +545 -0
- package/dist/chunks/continuous-sync-AWAAOXK2.ts.map +7 -0
- package/dist/chunks/{file-selection-UNHBVVON.ts → file-selection-3JJYOVNR.ts} +5 -5
- package/dist/chunks/{git-backend-FD7AVSK6.ts → git-backend-KYDZ673X.ts} +28 -32
- package/dist/chunks/git-backend-KYDZ673X.ts.map +7 -0
- package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts → manager-result-dispatcher-AGBBVDDS.ts} +10 -9
- package/dist/chunks/{manager-ui-ZIN4BUSF.ts → manager-ui-KRAW3NE2.ts} +184 -45
- package/dist/chunks/manager-ui-KRAW3NE2.ts.map +7 -0
- package/dist/chunks/{merge-baseline-store-ICXVTCML.ts → merge-baseline-store-RFCAH7KL.ts} +5 -5
- package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts → remote-selection-ui-5725JDNC.ts} +9 -8
- package/dist/chunks/remote-selection-ui-5725JDNC.ts.map +7 -0
- package/dist/chunks/{s3-backend-Y4P3O5B5.ts → s3-backend-Y7WSCLJI.ts} +38 -38
- package/dist/chunks/s3-backend-Y7WSCLJI.ts.map +7 -0
- package/dist/chunks/{setup-switch-ZMW5C4M7.ts → setup-switch-E7PHKI6J.ts} +7 -6
- package/dist/chunks/setup-switch-E7PHKI6J.ts.map +7 -0
- package/dist/chunks/{setup-wizard-VW7F3JN4.ts → setup-wizard-65DROCIJ.ts} +14 -13
- package/dist/chunks/setup-wizard-65DROCIJ.ts.map +7 -0
- package/dist/chunks/{sync-inspection-3EMS2J5B.ts → sync-inspection-XFJOAMJD.ts} +8 -8
- package/dist/chunks/sync-inspection-XFJOAMJD.ts.map +7 -0
- package/dist/chunks/{sync-operations-2CWST333.ts → sync-operations-HDUDT5PD.ts} +62 -63
- package/dist/chunks/sync-operations-HDUDT5PD.ts.map +7 -0
- package/dist/chunks/{webdav-backend-TBILVEQK.ts → webdav-backend-6K26F6LT.ts} +39 -48
- package/dist/chunks/webdav-backend-6K26F6LT.ts.map +7 -0
- package/dist/index.ts +165 -85
- package/dist/index.ts.map +3 -3
- package/docs/agent-mode-verification.md +99 -0
- package/docs/continuous-sync-verification.md +87 -0
- package/docs/settings.md +32 -247
- package/package.json +11 -5
- package/skills/configure-pi-sync/SKILL.md +54 -0
- package/skills/configure-pi-sync/references/configuration.md +650 -0
- package/src/backends/git/git-backend.ts +1 -4
- package/src/backends/git/git-runner.ts +1 -5
- package/src/backends/s3/s3-backend.ts +3 -25
- package/src/backends/s3/s3-client.ts +14 -2
- package/src/backends/snapshot-pointer.ts +27 -0
- package/src/backends/webdav/webdav-backend.ts +3 -29
- package/src/backends/webdav/webdav-client.ts +11 -7
- package/src/commands/command-execution.ts +5 -2
- package/src/commands/command-handler.ts +15 -3
- package/src/commands/command-types.ts +6 -0
- package/src/commands/command.ts +1 -0
- package/src/settings/config.ts +7 -0
- package/src/settings/settings-store.ts +0 -34
- package/src/settings/settings-types.ts +8 -0
- package/src/settings/settings-validation.ts +1 -1
- package/src/snapshot/snapshot-codec.ts +1 -5
- package/src/state/lock.ts +13 -10
- package/src/state/merge-baseline-store.ts +2 -2
- package/src/state/state-directory.ts +8 -1
- package/src/sync/agent-candidate.ts +251 -0
- package/src/sync/agent-plan.ts +87 -0
- package/src/sync/agent-policy.ts +13 -0
- package/src/sync/agent-request.ts +17 -0
- package/src/sync/agent-runner.ts +188 -0
- package/src/sync/agent-store.ts +151 -0
- package/src/sync/agent-sync.ts +91 -0
- package/src/sync/automatic-sync.ts +2 -1
- package/src/sync/continuous-errors.ts +85 -0
- package/src/sync/continuous-lease.ts +221 -0
- package/src/sync/continuous-record.ts +179 -0
- package/src/sync/continuous-storage.ts +55 -0
- package/src/sync/continuous-sync.ts +516 -0
- package/src/sync/continuous-watch.ts +59 -0
- package/src/sync/merged-sync.ts +70 -12
- package/src/sync/remote-snapshot.ts +2 -3
- package/src/sync/settings-merge.ts +19 -3
- package/src/sync/setup-switch.ts +1 -5
- package/src/sync/startup-check.ts +15 -11
- package/src/sync/sync-inspection.ts +8 -1
- package/src/sync/sync-mutations.ts +6 -17
- package/src/sync/sync-queries.ts +5 -0
- package/src/sync/text-merge.ts +3 -3
- package/src/sync-extension.ts +75 -19
- package/src/ui/agent-mode-setting.ts +91 -0
- package/src/ui/manager-state.ts +2 -0
- package/src/ui/remote-selection-ui.ts +5 -5
- package/src/ui/settings-ui.ts +83 -1
- package/src/ui/setup/s3-credentials-ui.ts +1 -5
- package/src/ui/setup/setup-name-ui.ts +2 -5
- package/src/ui/setup/setup-switcher.ts +2 -0
- package/src/ui/sync-setups-ui.ts +3 -5
- package/dist/chunks/chunk-26PMXY7E.ts +0 -362
- package/dist/chunks/chunk-26PMXY7E.ts.map +0 -7
- package/dist/chunks/chunk-35GM6XKM.ts.map +0 -7
- package/dist/chunks/chunk-A3TFXY4O.ts.map +0 -7
- package/dist/chunks/chunk-BVVP33U5.ts.map +0 -7
- package/dist/chunks/chunk-CAGJOKB7.ts.map +0 -7
- package/dist/chunks/chunk-E6ONFG57.ts.map +0 -7
- package/dist/chunks/chunk-GC3QOL6J.ts.map +0 -7
- package/dist/chunks/chunk-I4JYVFUS.ts.map +0 -7
- package/dist/chunks/chunk-KATKRR3D.ts.map +0 -7
- package/dist/chunks/chunk-XU2VXGQV.ts.map +0 -7
- package/dist/chunks/chunk-YTHQEW35.ts.map +0 -7
- package/dist/chunks/chunk-ZX2Q6THB.ts.map +0 -7
- package/dist/chunks/git-backend-FD7AVSK6.ts.map +0 -7
- package/dist/chunks/manager-ui-ZIN4BUSF.ts.map +0 -7
- package/dist/chunks/s3-backend-Y4P3O5B5.ts.map +0 -7
- package/dist/chunks/setup-wizard-VW7F3JN4.ts.map +0 -7
- package/dist/chunks/sync-operations-2CWST333.ts.map +0 -7
- package/dist/chunks/webdav-backend-TBILVEQK.ts.map +0 -7
- /package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts.map → agent-candidate-3JN6DJKT.ts.map} +0 -0
- /package/dist/chunks/{chunk-R35N4CL3.ts.map → chunk-B4QZBDBT.ts.map} +0 -0
- /package/dist/chunks/{chunk-KGE47GCZ.ts.map → chunk-CRKTAPSL.ts.map} +0 -0
- /package/dist/chunks/{chunk-HMXUKU43.ts.map → chunk-EUMINX7L.ts.map} +0 -0
- /package/dist/chunks/{chunk-AAZDBIBJ.ts.map → chunk-GSNPASKB.ts.map} +0 -0
- /package/dist/chunks/{chunk-2FETCGGT.ts.map → chunk-OEWQVWLC.ts.map} +0 -0
- /package/dist/chunks/{chunk-VCL7TZYW.ts.map → chunk-UPNVIUBN.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts.map → config-KGIYTTXQ.ts.map} +0 -0
- /package/dist/chunks/{merge-baseline-store-ICXVTCML.ts.map → conflict-artifacts-FXFIIBCB.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts.map → continuous-record-LFRVXQBD.ts.map} +0 -0
- /package/dist/chunks/{file-selection-UNHBVVON.ts.map → file-selection-3JJYOVNR.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-ZMW5C4M7.ts.map → manager-result-dispatcher-AGBBVDDS.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-3EMS2J5B.ts.map → merge-baseline-store-RFCAH7KL.ts.map} +0 -0
|
@@ -1,16 +1,29 @@
|
|
|
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
|
-
|
|
4
|
+
confirmMergeReview
|
|
5
|
+
} from "./chunk-5XZOC7FD.ts";
|
|
6
|
+
import {
|
|
7
|
+
formatRemoteSelectionStatus,
|
|
8
|
+
readSnapshotForHead,
|
|
9
|
+
requireCompatibleRemoteSelection
|
|
10
|
+
} from "./chunk-YK52VDXG.ts";
|
|
11
|
+
import {
|
|
12
|
+
createSyncBackend
|
|
13
|
+
} from "./chunk-OEWQVWLC.ts";
|
|
14
|
+
import {
|
|
5
15
|
conflictArtifactFingerprint,
|
|
6
16
|
conflictDirectory,
|
|
7
17
|
conflictGroups,
|
|
8
|
-
mergeJournalIdentity,
|
|
9
18
|
readConflictArtifact,
|
|
19
|
+
saveConflictArtifact
|
|
20
|
+
} from "./chunk-ED3TYIVW.ts";
|
|
21
|
+
import {
|
|
22
|
+
clearMergeJournal,
|
|
23
|
+
mergeJournalIdentity,
|
|
10
24
|
readMergeJournal,
|
|
11
|
-
saveConflictArtifact,
|
|
12
25
|
writeMergeJournal
|
|
13
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-GNH73BJ5.ts";
|
|
14
27
|
import {
|
|
15
28
|
fileHashMap,
|
|
16
29
|
hasLocalChanges,
|
|
@@ -18,69 +31,44 @@ import {
|
|
|
18
31
|
sameHashes,
|
|
19
32
|
syncPolicyChanged
|
|
20
33
|
} from "./chunk-BDB4IDM3.ts";
|
|
21
|
-
import {
|
|
22
|
-
formatRemoteSelectionStatus,
|
|
23
|
-
readSnapshotForHead,
|
|
24
|
-
requireCompatibleRemoteSelection
|
|
25
|
-
} from "./chunk-A3TFXY4O.ts";
|
|
26
|
-
import {
|
|
27
|
-
createSyncBackend
|
|
28
|
-
} from "./chunk-2FETCGGT.ts";
|
|
29
34
|
import {
|
|
30
35
|
applySnapshotTransaction,
|
|
31
36
|
recoverPendingSnapshotTransactions,
|
|
32
37
|
syncMutationParents
|
|
33
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-CRKTAPSL.ts";
|
|
34
39
|
import {
|
|
35
40
|
backupLocal,
|
|
36
41
|
captureMutationOwner,
|
|
37
42
|
protectedSessionPaths
|
|
38
|
-
} from "./chunk-
|
|
39
|
-
import {
|
|
40
|
-
createStartupTimings
|
|
41
|
-
} from "./chunk-UZPMDLTL.ts";
|
|
43
|
+
} from "./chunk-UOHR7LRO.ts";
|
|
42
44
|
import {
|
|
43
45
|
safeTerminalText,
|
|
44
46
|
snapshotPathLabel
|
|
45
47
|
} from "./chunk-AMJRUXFT.ts";
|
|
46
48
|
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
isMergeTextPath,
|
|
50
|
-
mergeSession,
|
|
51
|
-
mergeText,
|
|
52
|
-
pruneMergeBaselines,
|
|
53
|
-
readMergeAncestor,
|
|
54
|
-
readMergeAncestors,
|
|
55
|
-
stageMergeBaseline
|
|
56
|
-
} from "./chunk-E6ONFG57.ts";
|
|
57
|
-
import {
|
|
58
|
-
mergePathIdentity,
|
|
59
|
-
planFileMerge
|
|
60
|
-
} from "./chunk-76NB4R7U.ts";
|
|
49
|
+
createStartupTimings
|
|
50
|
+
} from "./chunk-UZPMDLTL.ts";
|
|
61
51
|
import {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
syncStateFingerprint,
|
|
65
|
-
writeStateForConfig
|
|
66
|
-
} from "./chunk-VCL7TZYW.ts";
|
|
52
|
+
SyncDecisionRequiredError
|
|
53
|
+
} from "./chunk-7D5SF7P3.ts";
|
|
67
54
|
import {
|
|
68
55
|
loadConfig,
|
|
69
56
|
syncCheckConfigFingerprint,
|
|
70
57
|
syncConfigReviewIdentity
|
|
71
|
-
} from "./chunk-
|
|
72
|
-
import {
|
|
73
|
-
SyncBackendConflictError,
|
|
74
|
-
expectedRemoteHead
|
|
75
|
-
} from "./chunk-YDVQYUHE.ts";
|
|
76
|
-
import {
|
|
77
|
-
SyncDecisionRequiredError
|
|
78
|
-
} from "./chunk-7D5SF7P3.ts";
|
|
58
|
+
} from "./chunk-QO333NM4.ts";
|
|
79
59
|
import {
|
|
80
60
|
overlayLocalFields,
|
|
81
61
|
portableSnapshot,
|
|
82
62
|
sameLocalFields
|
|
83
63
|
} from "./chunk-A6HU4ERM.ts";
|
|
64
|
+
import {
|
|
65
|
+
SyncBackendConflictError,
|
|
66
|
+
expectedRemoteHead
|
|
67
|
+
} from "./chunk-YDVQYUHE.ts";
|
|
68
|
+
import {
|
|
69
|
+
mergeSettingsJson,
|
|
70
|
+
resolveContentConflicts
|
|
71
|
+
} from "./chunk-5Q5SSKNG.ts";
|
|
84
72
|
import {
|
|
85
73
|
agentDir,
|
|
86
74
|
createSnapshot,
|
|
@@ -100,10 +88,26 @@ import {
|
|
|
100
88
|
snapshotTarget
|
|
101
89
|
} from "./chunk-QOFMXPM5.ts";
|
|
102
90
|
import {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
91
|
+
TEXT_MERGE_WORK_LIMIT,
|
|
92
|
+
hasCurrentMergeBaseline,
|
|
93
|
+
pruneMergeBaselines,
|
|
94
|
+
readMergeAncestor,
|
|
95
|
+
readMergeAncestors,
|
|
96
|
+
stageMergeBaseline
|
|
97
|
+
} from "./chunk-IWZH5KYS.ts";
|
|
98
|
+
import {
|
|
99
|
+
mergePathIdentity,
|
|
100
|
+
planFileMerge
|
|
101
|
+
} from "./chunk-76NB4R7U.ts";
|
|
102
|
+
import {
|
|
103
|
+
startupTransferEnabled
|
|
104
|
+
} from "./chunk-PRUEIIK7.ts";
|
|
105
|
+
import {
|
|
106
|
+
readStateForConfig,
|
|
107
|
+
statePathForConfig,
|
|
108
|
+
syncStateFingerprint,
|
|
109
|
+
writeStateForConfig
|
|
110
|
+
} from "./chunk-UPNVIUBN.ts";
|
|
107
111
|
import {
|
|
108
112
|
assertWithinRoot,
|
|
109
113
|
isDeniedPath,
|
|
@@ -114,213 +118,8 @@ import {
|
|
|
114
118
|
toPosix
|
|
115
119
|
} from "./chunk-HUZ5CR4W.ts";
|
|
116
120
|
|
|
117
|
-
// src/ui/merge-review.ts
|
|
118
|
-
import { truncateToWidth as truncateToWidth2 } from "@earendil-works/pi-tui";
|
|
119
|
-
import { defineMenu, runCustomInteraction, runDocumentReview, runMenu } from "@narumitw/pi-tui-kit";
|
|
120
|
-
|
|
121
|
-
// src/ui/sync-confirmation.ts
|
|
122
|
-
import { Key, matchesKey, SelectList, truncateToWidth } from "@earendil-works/pi-tui";
|
|
123
|
-
import { HorizontalRule, hardWrapTerminalDocument, sanitizeTerminalText } from "@narumitw/pi-tui-kit";
|
|
124
|
-
function createSyncConfirmation(options) {
|
|
125
|
-
const { tui, theme, keybindings } = options;
|
|
126
|
-
const choices = ["cancel", "approve", "details"];
|
|
127
|
-
const list = new SelectList(
|
|
128
|
-
[
|
|
129
|
-
{ value: "cancel", label: "No, cancel" },
|
|
130
|
-
{ value: "approve", label: `Yes, ${sanitizeTerminalText(options.confirmationLabel)}` },
|
|
131
|
-
{ value: "details", label: "View details" }
|
|
132
|
-
],
|
|
133
|
-
3,
|
|
134
|
-
{
|
|
135
|
-
selectedPrefix: (text) => theme.fg("accent", text),
|
|
136
|
-
selectedText: (text) => theme.fg("accent", text),
|
|
137
|
-
description: (text) => theme.fg("muted", text),
|
|
138
|
-
scrollInfo: (text) => theme.fg("dim", text),
|
|
139
|
-
noMatch: (text) => theme.fg("muted", text)
|
|
140
|
-
}
|
|
141
|
-
);
|
|
142
|
-
const rule = new HorizontalRule({ ruleStyle: (text) => theme.fg("border", text) });
|
|
143
|
-
let selected = 0;
|
|
144
|
-
let offset = 0;
|
|
145
|
-
let maximumOffset = 0;
|
|
146
|
-
let lastWidth = 0;
|
|
147
|
-
let lastRows = 0;
|
|
148
|
-
let seen = /* @__PURE__ */ new Set();
|
|
149
|
-
let summary = [];
|
|
150
|
-
let reviewed = false;
|
|
151
|
-
let disposed = false;
|
|
152
|
-
let finished = false;
|
|
153
|
-
let summaryStart = 0;
|
|
154
|
-
let summaryEnd = 0;
|
|
155
|
-
let actionsStart = 0;
|
|
156
|
-
const finish = (choice) => {
|
|
157
|
-
if (disposed || finished) return;
|
|
158
|
-
finished = true;
|
|
159
|
-
options.complete(choice);
|
|
160
|
-
};
|
|
161
|
-
const select = (index) => {
|
|
162
|
-
selected = (index + choices.length) % choices.length;
|
|
163
|
-
list.setSelectedIndex(selected);
|
|
164
|
-
};
|
|
165
|
-
list.onSelectionChange = (item) => {
|
|
166
|
-
selected = Math.max(0, choices.indexOf(item.value));
|
|
167
|
-
};
|
|
168
|
-
list.onSelect = (item) => {
|
|
169
|
-
const choice = choices[selected] ?? "cancel";
|
|
170
|
-
if (item.value === choice && (choice !== "approve" || reviewed)) finish(choice);
|
|
171
|
-
};
|
|
172
|
-
const component = {
|
|
173
|
-
render(width, expose = true) {
|
|
174
|
-
if (!Number.isFinite(width) || width <= 0) {
|
|
175
|
-
reviewed = false;
|
|
176
|
-
return [];
|
|
177
|
-
}
|
|
178
|
-
const cells = Math.floor(width);
|
|
179
|
-
const rows = Math.max(1, Math.floor(tui.terminal.rows) - 3);
|
|
180
|
-
if (cells !== lastWidth || rows !== lastRows) {
|
|
181
|
-
summary = options.lines.flatMap((line) => hardWrapTerminalDocument(line, cells));
|
|
182
|
-
seen = /* @__PURE__ */ new Set();
|
|
183
|
-
offset = 0;
|
|
184
|
-
select(0);
|
|
185
|
-
lastWidth = cells;
|
|
186
|
-
lastRows = rows;
|
|
187
|
-
}
|
|
188
|
-
const framed = rows >= 9;
|
|
189
|
-
const actions = list.render(cells);
|
|
190
|
-
const viewport = Math.max(0, rows - actions.length - 3 - (framed ? 2 : 0));
|
|
191
|
-
maximumOffset = Math.max(0, summary.length - viewport);
|
|
192
|
-
offset = Math.min(offset, maximumOffset);
|
|
193
|
-
const visible = summary.slice(offset, offset + viewport);
|
|
194
|
-
if (expose) for (let index = offset; index < offset + visible.length; index++) seen.add(index);
|
|
195
|
-
reviewed = viewport > 0 && seen.size === summary.length;
|
|
196
|
-
const hint = reviewed ? "Select an action." : "Navigation keys scroll the summary before selecting Yes.";
|
|
197
|
-
const body = [
|
|
198
|
-
theme.fg("accent", theme.bold(hardWrapTerminalDocument(options.title, cells).join(" "))),
|
|
199
|
-
...visible.map((line) => theme.fg("text", line)),
|
|
200
|
-
theme.fg(
|
|
201
|
-
"muted",
|
|
202
|
-
`Summary ${visible.length ? offset + 1 : 0}-${offset + visible.length}/${summary.length}${reviewed ? "" : " \u2014 review before Yes"}`
|
|
203
|
-
),
|
|
204
|
-
...actions,
|
|
205
|
-
theme.fg("dim", hint)
|
|
206
|
-
];
|
|
207
|
-
summaryStart = Number(framed) + 1;
|
|
208
|
-
summaryEnd = summaryStart + visible.length;
|
|
209
|
-
actionsStart = summaryEnd + 1;
|
|
210
|
-
const frame = framed ? [...rule.render(cells), ...body, ...rule.render(cells)] : body;
|
|
211
|
-
return frame.slice(0, rows).map((line) => truncateToWidth(line, cells, ""));
|
|
212
|
-
},
|
|
213
|
-
invalidate() {
|
|
214
|
-
list.invalidate();
|
|
215
|
-
rule.invalidate();
|
|
216
|
-
},
|
|
217
|
-
handleInput(data) {
|
|
218
|
-
if (disposed || finished) return;
|
|
219
|
-
if (matchesKey(data, Key.ctrl("c")) || keybindings.matches(data, "tui.select.cancel")) {
|
|
220
|
-
finish("cancel");
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
component.render(tui.terminal.columns ?? lastWidth, false);
|
|
224
|
-
if (keybindings.matches(data, "tui.select.up")) {
|
|
225
|
-
if (!reviewed || selected === 0 && offset > 0) offset = Math.max(0, offset - 1);
|
|
226
|
-
else select(selected - 1);
|
|
227
|
-
} else if (keybindings.matches(data, "tui.select.down")) {
|
|
228
|
-
if (!reviewed || selected === 0 && offset < maximumOffset) offset = Math.min(maximumOffset, offset + 1);
|
|
229
|
-
else select(selected + 1);
|
|
230
|
-
} else if (keybindings.matches(data, "tui.select.confirm")) {
|
|
231
|
-
const choice = choices[selected] ?? "cancel";
|
|
232
|
-
if (choice !== "approve" || reviewed) finish(choice);
|
|
233
|
-
}
|
|
234
|
-
tui.requestRender();
|
|
235
|
-
},
|
|
236
|
-
handleMouse(event) {
|
|
237
|
-
if (disposed || finished || event.width !== lastWidth) return void 0;
|
|
238
|
-
component.render(event.width, false);
|
|
239
|
-
if (event.y >= summaryStart && event.y < summaryEnd && event.type === "wheel" && event.wheelDelta) {
|
|
240
|
-
offset = Math.max(0, Math.min(maximumOffset, offset + (event.wheelDelta < 0 ? -1 : 1)));
|
|
241
|
-
select(0);
|
|
242
|
-
tui.requestRender();
|
|
243
|
-
return { handled: true, render: true };
|
|
244
|
-
}
|
|
245
|
-
if (event.y < actionsStart || event.y >= actionsStart + choices.length || event.y >= lastRows) return void 0;
|
|
246
|
-
return list.handleMouse({ ...event, y: event.y - actionsStart, height: choices.length });
|
|
247
|
-
},
|
|
248
|
-
dispose() {
|
|
249
|
-
disposed = true;
|
|
250
|
-
seen.clear();
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
return component;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// src/ui/merge-review.ts
|
|
257
|
-
async function confirmMergeReview(ctx, title, content, signal, isCurrent, confirmationLabel = "apply changes", summaryLines) {
|
|
258
|
-
const lines = summaryLines ?? [
|
|
259
|
-
...content.split("\n").slice(0, 6).map((line) => truncateToWidth2(safeTerminalText(line), 100)),
|
|
260
|
-
"View details for the complete review."
|
|
261
|
-
];
|
|
262
|
-
while (isCurrent() && !signal?.aborted) {
|
|
263
|
-
const choice = { value: "cancel" };
|
|
264
|
-
const menu = defineMenu({
|
|
265
|
-
start: "confirm",
|
|
266
|
-
screens: {
|
|
267
|
-
confirm: () => ({
|
|
268
|
-
kind: "choice",
|
|
269
|
-
title,
|
|
270
|
-
lines,
|
|
271
|
-
initialItemId: "cancel",
|
|
272
|
-
items: [
|
|
273
|
-
{ id: "cancel", label: "No, cancel" },
|
|
274
|
-
{ id: "approve", label: `Yes, ${confirmationLabel}` },
|
|
275
|
-
{ id: "details", label: "View details" }
|
|
276
|
-
],
|
|
277
|
-
action: "choose",
|
|
278
|
-
hint: "close"
|
|
279
|
-
})
|
|
280
|
-
},
|
|
281
|
-
actions: {
|
|
282
|
-
choose: ({ itemId }) => {
|
|
283
|
-
if (itemId === "approve" || itemId === "details") choice.value = itemId;
|
|
284
|
-
return { kind: "close" };
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
const result = ctx.mode === "tui" && ctx.hasUI ? await runCustomInteraction(ctx, {
|
|
289
|
-
create: ({ tui, theme, keybindings, complete }) => createSyncConfirmation({ title, lines, confirmationLabel, tui, theme, keybindings, complete }),
|
|
290
|
-
signal,
|
|
291
|
-
isCurrent,
|
|
292
|
-
onError: () => {
|
|
293
|
-
}
|
|
294
|
-
}) : await runMenu(ctx, menu, { getState: () => void 0, signal, isCurrent, onError: () => {
|
|
295
|
-
} });
|
|
296
|
-
if (!isCurrent() || signal?.aborted) return false;
|
|
297
|
-
if (result.kind === "error") throw new Error("Sync review failed; no transfer was performed.");
|
|
298
|
-
if (result.kind === "unsupported")
|
|
299
|
-
throw new Error("Sync review requires observable TUI or RPC; review the plan before using --yes.");
|
|
300
|
-
if (result.kind === "completed") choice.value = result.value;
|
|
301
|
-
else if (result.kind !== "closed") return false;
|
|
302
|
-
if (choice.value === "approve") return true;
|
|
303
|
-
if (choice.value !== "details") return false;
|
|
304
|
-
const detail = await runDocumentReview(ctx, {
|
|
305
|
-
title: "Sync change details",
|
|
306
|
-
content,
|
|
307
|
-
format: { kind: "text" },
|
|
308
|
-
viewportSize: "adaptive",
|
|
309
|
-
hint: "back",
|
|
310
|
-
signal,
|
|
311
|
-
isCurrent,
|
|
312
|
-
onError: () => {
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
if (!isCurrent() || signal?.aborted) return false;
|
|
316
|
-
if (detail.kind === "error") throw new Error("Sync review failed; no transfer was performed.");
|
|
317
|
-
if (detail.kind !== "cancelled" || detail.reason !== "back") return false;
|
|
318
|
-
}
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
121
|
// src/ui/merged-sync-summary.ts
|
|
323
|
-
import { truncateToWidth
|
|
122
|
+
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
324
123
|
|
|
325
124
|
// src/ui/transfer-changes.ts
|
|
326
125
|
function transferChanges(before, after, protectedPaths = /* @__PURE__ */ new Set()) {
|
|
@@ -368,7 +167,7 @@ function mergedSyncSummary(input) {
|
|
|
368
167
|
return [
|
|
369
168
|
`${heading}: ${counts.join(", ")}`,
|
|
370
169
|
...(compact ? items.slice(0, 3) : items).map(
|
|
371
|
-
(item) => ` ${compact ?
|
|
170
|
+
(item) => ` ${compact ? truncateToWidth(label(item, side), 80) : label(item, side)}`
|
|
372
171
|
),
|
|
373
172
|
...compact && items.length > 3 ? [` ${items.length - 3} more files \u2014 View details`] : []
|
|
374
173
|
];
|
|
@@ -388,7 +187,7 @@ function mergedSyncSummary(input) {
|
|
|
388
187
|
title,
|
|
389
188
|
confirmationLabel,
|
|
390
189
|
lines: [
|
|
391
|
-
...context.map((line) =>
|
|
190
|
+
...context.map((line) => truncateToWidth(line, 100)),
|
|
392
191
|
...section(local, "local", true),
|
|
393
192
|
...section(remote, "remote", true),
|
|
394
193
|
...safety
|
|
@@ -551,76 +350,18 @@ async function pruneCompletedConflicts(config, backend, state, local, remote, va
|
|
|
551
350
|
}
|
|
552
351
|
}
|
|
553
352
|
|
|
554
|
-
// src/sync/content-conflicts.ts
|
|
555
|
-
import { createHash } from "node:crypto";
|
|
556
|
-
function snapshotFile(filePath, bytes) {
|
|
557
|
-
return {
|
|
558
|
-
path: filePath,
|
|
559
|
-
contentBase64: bytes.toString("base64"),
|
|
560
|
-
sha256: createHash("sha256").update(bytes).digest("hex")
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
async function resolveContentConflicts(config, state, local, remote, plan, protectedPaths, options = {}) {
|
|
564
|
-
if (plan.kind !== "planned" || !config.mergeContent) return plan;
|
|
565
|
-
options.signal?.throwIfAborted();
|
|
566
|
-
const budget = options.textBudget ?? { remaining: TEXT_MERGE_WORK_LIMIT };
|
|
567
|
-
const decisions = [...plan.decisions];
|
|
568
|
-
let ancestors = [];
|
|
569
|
-
try {
|
|
570
|
-
ancestors = await readMergeAncestors(config, state) ?? [];
|
|
571
|
-
} catch {
|
|
572
|
-
options.signal?.throwIfAborted();
|
|
573
|
-
return plan;
|
|
574
|
-
}
|
|
575
|
-
options.signal?.throwIfAborted();
|
|
576
|
-
const oursByPath = new Map(local.files.map((file) => [file.path, file]));
|
|
577
|
-
const theirsByPath = new Map(remote.files.map((file) => [file.path, file]));
|
|
578
|
-
const ancestorsByPath = new Map(ancestors.map((file) => [file.path, file]));
|
|
579
|
-
const decisionIndex = new Map(decisions.map((decision, index) => [decision.path, index]));
|
|
580
|
-
const protectedKeys = new Set([...protectedPaths].map(mergePathIdentity));
|
|
581
|
-
for (const conflict of plan.conflicts) {
|
|
582
|
-
options.signal?.throwIfAborted();
|
|
583
|
-
if (conflict.reason !== "both-changed" || protectedKeys.has(mergePathIdentity(conflict.path))) continue;
|
|
584
|
-
const session = conflict.path.startsWith("sessions/") && conflict.path.endsWith(".jsonl");
|
|
585
|
-
if (!session && (!isMergeTextPath(conflict.path) || budget.remaining === 0)) continue;
|
|
586
|
-
const ours = oursByPath.get(conflict.path);
|
|
587
|
-
const theirs = theirsByPath.get(conflict.path);
|
|
588
|
-
if (!ours || !theirs) continue;
|
|
589
|
-
const ancestor = ancestorsByPath.get(conflict.path);
|
|
590
|
-
const base = ancestor ? Buffer.from(ancestor.contentBase64, "base64") : void 0;
|
|
591
|
-
if (!base) continue;
|
|
592
|
-
const localBytes = Buffer.from(ours.contentBase64, "base64");
|
|
593
|
-
const remoteBytes = Buffer.from(theirs.contentBase64, "base64");
|
|
594
|
-
const bytes = session ? mergeSession(base, localBytes, remoteBytes) : mergeText(base, localBytes, remoteBytes, { budget, signal: options.signal });
|
|
595
|
-
if (!bytes) continue;
|
|
596
|
-
const index = decisionIndex.get(conflict.path);
|
|
597
|
-
if (index === void 0) continue;
|
|
598
|
-
decisions[index] = {
|
|
599
|
-
kind: "accepted",
|
|
600
|
-
path: conflict.path,
|
|
601
|
-
source: "merged",
|
|
602
|
-
file: snapshotFile(conflict.path, bytes)
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
return {
|
|
606
|
-
kind: "planned",
|
|
607
|
-
decisions,
|
|
608
|
-
conflicts: decisions.filter((item) => item.kind === "conflict")
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
|
|
612
353
|
// src/sync/merge-apply.ts
|
|
613
|
-
import { createHash as
|
|
354
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
614
355
|
import fs4 from "node:fs/promises";
|
|
615
356
|
import path4 from "node:path";
|
|
616
357
|
import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
|
|
617
358
|
|
|
618
359
|
// src/snapshot/snapshot-apply.ts
|
|
619
|
-
import { createHash
|
|
360
|
+
import { createHash } from "node:crypto";
|
|
620
361
|
import fs3 from "node:fs/promises";
|
|
621
362
|
import path3 from "node:path";
|
|
622
363
|
function sha256(value) {
|
|
623
|
-
return
|
|
364
|
+
return createHash("sha256").update(value).digest("hex");
|
|
624
365
|
}
|
|
625
366
|
function fileHashMap2(snapshot) {
|
|
626
367
|
return Object.fromEntries(snapshot.files.map((file) => [file.path, file.sha256]));
|
|
@@ -929,7 +670,7 @@ async function assertReviewedTree(directory, relative, beforeHashes) {
|
|
|
929
670
|
const stat = await fs4.lstat(child);
|
|
930
671
|
if (stat.isDirectory()) {
|
|
931
672
|
await assertReviewedTree(child, childRelative, beforeHashes);
|
|
932
|
-
} else if (stat.isFile() && stat.nlink === 1 && beforeHashes[childRelative] ===
|
|
673
|
+
} else if (stat.isFile() && stat.nlink === 1 && beforeHashes[childRelative] === createHash2("sha256").update(await fs4.readFile(child)).digest("hex")) {
|
|
933
674
|
continue;
|
|
934
675
|
} else {
|
|
935
676
|
throw new Error("Reviewed directory contains unknown or changed files; publication refused.");
|
|
@@ -1099,7 +840,7 @@ async function applyMergedSnapshot(before, after, protectedPaths, options, valid
|
|
|
1099
840
|
} else {
|
|
1100
841
|
if (!stat.isFile() || stat.nlink > 1)
|
|
1101
842
|
throw new Error("Merged transfer target is no longer an independent regular file.");
|
|
1102
|
-
hash =
|
|
843
|
+
hash = createHash2("sha256").update(await fs4.readFile(target2)).digest("hex");
|
|
1103
844
|
}
|
|
1104
845
|
} catch (error) {
|
|
1105
846
|
if (error.code !== "ENOENT") throw error;
|
|
@@ -1277,53 +1018,7 @@ function progressState(config, head, snapshot, progress) {
|
|
|
1277
1018
|
}
|
|
1278
1019
|
|
|
1279
1020
|
// src/sync/settings-conflicts.ts
|
|
1280
|
-
import { createHash as
|
|
1281
|
-
|
|
1282
|
-
// src/sync/settings-merge.ts
|
|
1283
|
-
var COUPLED_FIELDS = [
|
|
1284
|
-
["defaultProvider", "defaultModel"],
|
|
1285
|
-
["queueMode", "steeringMode"],
|
|
1286
|
-
["websockets", "transport"],
|
|
1287
|
-
["skills", "enableSkillCommands"],
|
|
1288
|
-
["enableAnalytics", "trackingId"]
|
|
1289
|
-
];
|
|
1290
|
-
function mergeSettingsJson(ancestor, local, remote) {
|
|
1291
|
-
let documents;
|
|
1292
|
-
try {
|
|
1293
|
-
documents = [ancestor, local, remote].map(parseSettingsDocument);
|
|
1294
|
-
} catch {
|
|
1295
|
-
return { kind: "review", reason: "unsupported-format", fields: [] };
|
|
1296
|
-
}
|
|
1297
|
-
const [base, left, right] = documents;
|
|
1298
|
-
const selected = /* @__PURE__ */ new Map();
|
|
1299
|
-
const fields = new Set(documents.flatMap((document) => [...document.root.members.keys()]));
|
|
1300
|
-
const units = COUPLED_FIELDS.map((group) => [...group]);
|
|
1301
|
-
const coupled = new Set(units.flat());
|
|
1302
|
-
units.push(...[...fields].filter((field) => !coupled.has(field)).map((field) => [field]));
|
|
1303
|
-
const conflicts = [];
|
|
1304
|
-
for (const unit of units) {
|
|
1305
|
-
const equal = (first, second) => unit.every(
|
|
1306
|
-
(field) => jsonEqual(first.root.members.get(field)?.node.value, second.root.members.get(field)?.node.value)
|
|
1307
|
-
);
|
|
1308
|
-
const source = equal(left, right) ? left : equal(left, base) ? right : equal(right, base) ? left : void 0;
|
|
1309
|
-
if (!source) {
|
|
1310
|
-
conflicts.push(...unit.filter((field) => fields.has(field)));
|
|
1311
|
-
continue;
|
|
1312
|
-
}
|
|
1313
|
-
for (const field of unit) {
|
|
1314
|
-
const member = source.root.members.get(field);
|
|
1315
|
-
if (member) selected.set(field, { document: source, node: member.node });
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
if (conflicts.length) return { kind: "review", reason: "field-conflict", fields: conflicts };
|
|
1319
|
-
try {
|
|
1320
|
-
return { kind: "merged", content: renderSettingsMembers(left, selected) };
|
|
1321
|
-
} catch {
|
|
1322
|
-
return { kind: "review", reason: "unsupported-format", fields: [] };
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
// src/sync/settings-conflicts.ts
|
|
1021
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
1327
1022
|
async function resolveSettingsConflicts(config, state, local, remote, plan) {
|
|
1328
1023
|
if (plan.kind !== "planned") return { plan, fields: [] };
|
|
1329
1024
|
const fields = [];
|
|
@@ -1353,7 +1048,7 @@ async function resolveSettingsConflicts(config, state, local, remote, plan) {
|
|
|
1353
1048
|
file: {
|
|
1354
1049
|
path: decision.path,
|
|
1355
1050
|
contentBase64: merged.content.toString("base64"),
|
|
1356
|
-
sha256:
|
|
1051
|
+
sha256: createHash3("sha256").update(merged.content).digest("hex")
|
|
1357
1052
|
}
|
|
1358
1053
|
};
|
|
1359
1054
|
}
|
|
@@ -1536,7 +1231,11 @@ function safeList(values) {
|
|
|
1536
1231
|
var MAX_ATTEMPTS = 3;
|
|
1537
1232
|
async function mergeSync(ctx, options, factory = createSyncBackend, resolution) {
|
|
1538
1233
|
const timings = options.startupTimings ?? createStartupTimings();
|
|
1539
|
-
const
|
|
1234
|
+
const sessionOwner = captureMutationOwner(ctx, options.signal);
|
|
1235
|
+
const validateOwner = (config2) => {
|
|
1236
|
+
sessionOwner();
|
|
1237
|
+
options.background?.validate(config2);
|
|
1238
|
+
};
|
|
1540
1239
|
const isCurrent = () => {
|
|
1541
1240
|
try {
|
|
1542
1241
|
validateOwner();
|
|
@@ -1546,7 +1245,9 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1546
1245
|
}
|
|
1547
1246
|
};
|
|
1548
1247
|
const config = await loadConfig(options.setup);
|
|
1248
|
+
validateOwner(config);
|
|
1549
1249
|
const configToken = syncCheckConfigFingerprint(config);
|
|
1250
|
+
const modelToken = JSON.stringify(ctx.model);
|
|
1550
1251
|
const sessionRoot = config.include.includes("sessions") ? await effectiveSessionRoot(ctx) : void 0;
|
|
1551
1252
|
validateOwner();
|
|
1552
1253
|
const snapshotOptions = {
|
|
@@ -1557,7 +1258,7 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1557
1258
|
const validate = () => timings.measure("transfer authorization", async () => {
|
|
1558
1259
|
validateOwner();
|
|
1559
1260
|
const latest = await loadConfig(options.setup);
|
|
1560
|
-
validateOwner();
|
|
1261
|
+
validateOwner(latest);
|
|
1561
1262
|
if (configToken !== syncCheckConfigFingerprint(latest))
|
|
1562
1263
|
throw new Error("Sync setup or settings changed during transfer; reopen sync.");
|
|
1563
1264
|
if (sessionRoot !== void 0) {
|
|
@@ -1566,23 +1267,30 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1566
1267
|
if (currentRoot !== sessionRoot)
|
|
1567
1268
|
throw new Error("Session storage root changed during transfer; evidence retained for review.");
|
|
1568
1269
|
}
|
|
1569
|
-
if (
|
|
1270
|
+
if (config.agentMode && JSON.stringify(ctx.model) !== modelToken)
|
|
1271
|
+
throw new Error("Agent mode paused: selected model changed during transfer.");
|
|
1272
|
+
if (options.auto && (!startupTransferEnabled(latest) || !ctx.isIdle()))
|
|
1570
1273
|
throw new Error("Automatic transfer is no longer authorized at this idle boundary.");
|
|
1571
1274
|
});
|
|
1572
1275
|
await validate();
|
|
1573
1276
|
const backend = await timings.measure("transfer backend initialization", () => factory(config));
|
|
1574
1277
|
await validate();
|
|
1575
|
-
if (options.auto && backend.capability === "read-check-write-verify") {
|
|
1576
|
-
throw new Error(
|
|
1577
|
-
"Automatic transfer requires conditional publication or a lease; this backend supports only read/check/write/verify. Use manual sync."
|
|
1578
|
-
);
|
|
1579
|
-
}
|
|
1580
1278
|
const pending = await timings.measure("transfer journal read", () => readMergeJournal(config));
|
|
1581
1279
|
await validate();
|
|
1582
1280
|
if (pending) {
|
|
1583
1281
|
const recovered = await timings.measure(
|
|
1584
1282
|
"transfer journal recovery",
|
|
1585
|
-
() => completeJournal(
|
|
1283
|
+
() => completeJournal(
|
|
1284
|
+
ctx,
|
|
1285
|
+
config,
|
|
1286
|
+
backend,
|
|
1287
|
+
pending,
|
|
1288
|
+
validate,
|
|
1289
|
+
timings,
|
|
1290
|
+
options.signal,
|
|
1291
|
+
options.auto,
|
|
1292
|
+
options.background?.validate
|
|
1293
|
+
)
|
|
1586
1294
|
);
|
|
1587
1295
|
if (!recovered) {
|
|
1588
1296
|
if ((options.auto || !options.silent) && !options.signal?.aborted)
|
|
@@ -1596,6 +1304,11 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1596
1304
|
ctx.ui.notify("Recovered the committed merged transfer. Run sync again to inspect newer changes.", "info");
|
|
1597
1305
|
return "applied";
|
|
1598
1306
|
}
|
|
1307
|
+
if ((options.auto || config.agentMode) && backend.capability === "read-check-write-verify") {
|
|
1308
|
+
throw new Error(
|
|
1309
|
+
"Automatic transfer requires conditional publication or a lease; this backend supports only read/check/write/verify. Disable Agent mode and use manual sync."
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1599
1312
|
const textBudget = { remaining: TEXT_MERGE_WORK_LIMIT };
|
|
1600
1313
|
const createdArtifacts = [];
|
|
1601
1314
|
const ownedStatePath = statePathForConfig(config);
|
|
@@ -1729,7 +1442,30 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1729
1442
|
);
|
|
1730
1443
|
await validate();
|
|
1731
1444
|
}
|
|
1732
|
-
if (
|
|
1445
|
+
if (config.agentMode && !resolution) {
|
|
1446
|
+
const { resolveAgentPlan } = await import("./agent-plan-QCUJWBP4.ts");
|
|
1447
|
+
await validate();
|
|
1448
|
+
plan = await resolveAgentPlan(
|
|
1449
|
+
ctx,
|
|
1450
|
+
options,
|
|
1451
|
+
config,
|
|
1452
|
+
backend,
|
|
1453
|
+
state,
|
|
1454
|
+
local,
|
|
1455
|
+
localRaw,
|
|
1456
|
+
remote,
|
|
1457
|
+
head,
|
|
1458
|
+
plan,
|
|
1459
|
+
snapshotOptions,
|
|
1460
|
+
validate
|
|
1461
|
+
);
|
|
1462
|
+
await validate();
|
|
1463
|
+
if (plan.kind !== "planned" || plan.conflicts.length && !config.partialSync)
|
|
1464
|
+
throw new Error(
|
|
1465
|
+
"Agent mode paused: unsupported or refused conflict groups remain; no transfer was performed."
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
if (plan.kind !== "planned" || plan.conflicts.length && (!config.partialSync || options.auto && !config.agentMode)) {
|
|
1733
1469
|
const decision = review(
|
|
1734
1470
|
selectionCompatible ? `Conflicting or protected paths require review; no merged transfer was performed. Use /sync diff and an explicit direction.${resolved.fields.length ? ` Settings fields: ${resolved.fields.map(safeTerminalText).join(", ")}` : ""}` : "Remote selection metadata is unavailable; review the included content and choose an explicit direction before merging.",
|
|
1735
1471
|
selectionCompatible ? "both-changed" : "remote-or-policy-changed"
|
|
@@ -1878,7 +1614,7 @@ An explicit direction adopts this setup's included-content policy; no automatic
|
|
|
1878
1614
|
await validate();
|
|
1879
1615
|
if (!config.skipSecretScan && scanSnapshot(upload).length)
|
|
1880
1616
|
throw new Error("Refusing to merge possible secrets. Review managed content before syncing.");
|
|
1881
|
-
if (!options.yes) {
|
|
1617
|
+
if (!options.yes && !config.agentMode) {
|
|
1882
1618
|
const summary = mergedSyncSummary({
|
|
1883
1619
|
setupName: config.setupName,
|
|
1884
1620
|
destination: backend.destination,
|
|
@@ -1989,7 +1725,17 @@ An explicit direction adopts this setup's included-content policy; no automatic
|
|
|
1989
1725
|
}
|
|
1990
1726
|
const completed = await timings.measure(
|
|
1991
1727
|
"transfer journal recovery",
|
|
1992
|
-
() => completeJournal(
|
|
1728
|
+
() => completeJournal(
|
|
1729
|
+
ctx,
|
|
1730
|
+
config,
|
|
1731
|
+
backend,
|
|
1732
|
+
journal,
|
|
1733
|
+
validate,
|
|
1734
|
+
timings,
|
|
1735
|
+
options.signal,
|
|
1736
|
+
options.auto,
|
|
1737
|
+
options.background?.validate
|
|
1738
|
+
)
|
|
1993
1739
|
);
|
|
1994
1740
|
if (!completed) {
|
|
1995
1741
|
if (!options.signal?.aborted && (options.auto || !options.silent))
|
|
@@ -2016,7 +1762,7 @@ An explicit direction adopts this setup's included-content policy; no automatic
|
|
|
2016
1762
|
await timings.measure("transfer cleanup", () => releaseConflictArtifacts(config, ownedStatePath, createdArtifacts));
|
|
2017
1763
|
}
|
|
2018
1764
|
}
|
|
2019
|
-
async function completeJournal(ctx, config, backend, journal, validate, timings, signal, auto = false) {
|
|
1765
|
+
async function completeJournal(ctx, config, backend, journal, validate, timings, signal, auto = false, validateBackground) {
|
|
2020
1766
|
if (journal.identity !== mergeJournalIdentity(config, backend.identity) || !sameLocalFields(journal.upload.localFields, config.localFields))
|
|
2021
1767
|
throw new Error(
|
|
2022
1768
|
"Merge journal belongs to a different setup, selection or local-field policy; preserve it for reviewed recovery."
|
|
@@ -2103,6 +1849,7 @@ async function completeJournal(ctx, config, backend, journal, validate, timings,
|
|
|
2103
1849
|
const validateOwner = captureMutationOwner(ctx, signal);
|
|
2104
1850
|
const validateMutation = () => {
|
|
2105
1851
|
validateOwner();
|
|
1852
|
+
validateBackground?.();
|
|
2106
1853
|
if (auto && !ctx.isIdle()) throw new Error("Automatic file apply is no longer idle; evidence retained.");
|
|
2107
1854
|
};
|
|
2108
1855
|
await timings.measure(
|
|
@@ -2178,7 +1925,6 @@ async function writeAcceptedState(config, head, snapshot, validate, progress) {
|
|
|
2178
1925
|
}
|
|
2179
1926
|
|
|
2180
1927
|
export {
|
|
2181
|
-
confirmMergeReview,
|
|
2182
1928
|
applySnapshot,
|
|
2183
1929
|
addTopLevelCaseVariantDeletes,
|
|
2184
1930
|
formatDiff,
|
|
@@ -2191,4 +1937,4 @@ export {
|
|
|
2191
1937
|
createSyncDecision,
|
|
2192
1938
|
mergeSync
|
|
2193
1939
|
};
|
|
2194
|
-
//# sourceMappingURL=chunk-
|
|
1940
|
+
//# sourceMappingURL=chunk-OTZRCKYP.ts.map
|