@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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { requireSettings, updateLocalConfig } from "../settings/settings-store.js";
|
|
4
|
+
import { captureMutationOwner } from "../sync/sync-local.js";
|
|
5
|
+
import { confirmMergeReview } from "./merge-review.js";
|
|
6
|
+
import { safeTerminalText } from "./terminal-text.js";
|
|
7
|
+
|
|
8
|
+
export const AGENT_MODE_DESCRIPTION =
|
|
9
|
+
"This setup, experimental: one autonomous merged sync next startup and on Sync now. Sends eligible conflict text to the selected Pi model; may incur costs and replace/delete selected local and remote content without transfer prompts. No automatic reload. Unsupported conflicts pause.";
|
|
10
|
+
|
|
11
|
+
export const CONTINUOUS_DESCRIPTION =
|
|
12
|
+
"This setup, experimental: recurring sync while Pi is open. Requires Agent mode. 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
|
+
|
|
14
|
+
export function saveContinuousMode(
|
|
15
|
+
ctx: ExtensionCommandContext,
|
|
16
|
+
setupName: string,
|
|
17
|
+
enabled: boolean,
|
|
18
|
+
signal?: AbortSignal,
|
|
19
|
+
) {
|
|
20
|
+
return saveAgentMode(ctx, setupName, enabled, signal, "continuous");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function saveAgentMode(
|
|
24
|
+
ctx: ExtensionCommandContext,
|
|
25
|
+
setupName: string,
|
|
26
|
+
enabled: boolean,
|
|
27
|
+
signal?: AbortSignal,
|
|
28
|
+
preference: "agentMode" | "continuous" = "agentMode",
|
|
29
|
+
) {
|
|
30
|
+
const validate = captureMutationOwner(ctx, signal);
|
|
31
|
+
const settings = await requireSettings();
|
|
32
|
+
validate();
|
|
33
|
+
const setup = settings.syncSetups[setupName];
|
|
34
|
+
if (!setup || settings.activeSyncSetup !== setupName) throw new Error("Current sync setup changed; reopen Settings.");
|
|
35
|
+
const continuous = preference === "continuous";
|
|
36
|
+
const label = continuous ? "Continuous sync" : "Agent mode";
|
|
37
|
+
if (enabled && continuous && !setup.sync.agentMode) throw new Error("Enable Agent mode before Continuous sync.");
|
|
38
|
+
if (Boolean(setup.sync[preference]) === enabled) return true;
|
|
39
|
+
if (enabled) {
|
|
40
|
+
const summary = [
|
|
41
|
+
`Setup: ${safeTerminalText(setupName)}`,
|
|
42
|
+
`Storage connection: ${safeTerminalText(setup.storage.connection)}`,
|
|
43
|
+
`Storage path: ${safeTerminalText(setup.storage.path)}`,
|
|
44
|
+
...(setup.storage.bucket ? [`Bucket: ${safeTerminalText(String(setup.storage.bucket))}`] : []),
|
|
45
|
+
...(setup.storage.branch ? [`Branch: ${safeTerminalText(String(setup.storage.branch))}`] : []),
|
|
46
|
+
`Included paths: ${setup.sync.include.map(safeTerminalText).join(", ")}`,
|
|
47
|
+
continuous ? CONTINUOUS_DESCRIPTION : AGENT_MODE_DESCRIPTION,
|
|
48
|
+
...(continuous
|
|
49
|
+
? [
|
|
50
|
+
"Upgrade all Pi processes sharing this agent directory before enabling Continuous sync. Monitoring starts after the /sync command or manager closes. An elected idle local session uses its selected Pi model; another session can use a different provider/model. Each computer is a separate replica.",
|
|
51
|
+
"Automatic requests are limited to two per candidate and two per replica binding in a rolling 15-minute window, across restarts. Network/storage checks and requests may incur costs. Retries start at five seconds and grow to five minutes. These are request bounds, not a currency cap.",
|
|
52
|
+
]
|
|
53
|
+
: setup.sync.continuous
|
|
54
|
+
? ["The saved Continuous sync preference will resume monitoring after the /sync command or manager closes."]
|
|
55
|
+
: []),
|
|
56
|
+
"Only bounded Markdown/plain-text conflicts and atomic global settings choices are eligible. Model errors can change intended behavior. Session histories, code, deletion conflicts and path collisions are not model-resolved.",
|
|
57
|
+
"The existing baseline, selection, secret-scan and publication checks remain. Pi Sync cannot exclude arbitrary concurrent local writers. Disabling does not undo completed transfers or provider charges. No transfer starts from Settings.",
|
|
58
|
+
].join("\n\n");
|
|
59
|
+
if (
|
|
60
|
+
!(await confirmMergeReview(
|
|
61
|
+
ctx,
|
|
62
|
+
`Enable experimental ${label}?`,
|
|
63
|
+
summary,
|
|
64
|
+
signal,
|
|
65
|
+
() => !signal?.aborted,
|
|
66
|
+
`Enable ${label}`,
|
|
67
|
+
summary.split("\n"),
|
|
68
|
+
))
|
|
69
|
+
)
|
|
70
|
+
return false;
|
|
71
|
+
validate();
|
|
72
|
+
}
|
|
73
|
+
await updateLocalConfig((current) => {
|
|
74
|
+
validate();
|
|
75
|
+
if (
|
|
76
|
+
current.activeSyncSetup !== setupName ||
|
|
77
|
+
!isDeepStrictEqual(current.syncSetups[setupName], setup) ||
|
|
78
|
+
!isDeepStrictEqual(
|
|
79
|
+
current.storageConnections[setup.storage.connection],
|
|
80
|
+
settings.storageConnections[setup.storage.connection],
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
throw new Error("Sync setup or connection changed during Agent mode review; reopen Settings.");
|
|
84
|
+
return {
|
|
85
|
+
...current,
|
|
86
|
+
syncSetups: { ...current.syncSetups, [setupName]: { ...setup, sync: { ...setup.sync, [preference]: enabled } } },
|
|
87
|
+
};
|
|
88
|
+
}, signal);
|
|
89
|
+
// The atomic writer has committed. Later cancellation cannot undo this save.
|
|
90
|
+
return true;
|
|
91
|
+
}
|
package/src/ui/manager-state.ts
CHANGED
|
@@ -163,6 +163,8 @@ export async function describeManagerState(
|
|
|
163
163
|
`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"}`,
|
|
164
164
|
`Automatic sync: ${automaticSyncSummary(config.automatic)}`,
|
|
165
165
|
`Startup transfer: ${startupTransferSummary(config)}`,
|
|
166
|
+
`Agent mode: ${config.agentMode ? "On (experimental; autonomous merged sync)" : "Off"}`,
|
|
167
|
+
...(config.continuous ? await (await import("../sync/continuous-record.js")).continuousStatusLines(config) : []),
|
|
166
168
|
`Last applied: ${lastAppliedSnapshot}`,
|
|
167
169
|
...(noSyncedContent
|
|
168
170
|
? ["", "No included content is selected. Choose included content in Settings before syncing."]
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { SyncSetupReviewChangedError, updateSyncSetup } from "../settings/settings-management.js";
|
|
12
12
|
import type { AnySyncConfig, PartialConfig } from "../settings/settings-types.js";
|
|
13
13
|
import { readSnapshotForHead } from "../sync/remote-snapshot.js";
|
|
14
|
+
import { throwIfAborted } from "../sync/signals.js";
|
|
14
15
|
import { errorMessage } from "../sync/sync-errors.js";
|
|
15
16
|
import {
|
|
16
17
|
compareSyncInclude,
|
|
@@ -240,6 +241,8 @@ async function showSelectionDifference(
|
|
|
240
241
|
include: [...state.decision.remoteInclude],
|
|
241
242
|
automatic: review.config.automatic,
|
|
242
243
|
automaticTransfer: review.config.automaticTransfer,
|
|
244
|
+
agentMode: review.config.agentMode,
|
|
245
|
+
continuous: review.config.continuous,
|
|
243
246
|
onSwitch: review.config.onSwitch,
|
|
244
247
|
showStatus: review.config.showStatus,
|
|
245
248
|
};
|
|
@@ -592,6 +595,8 @@ function sameContinuationReview(left: PartialConfig, right: PartialConfig) {
|
|
|
592
595
|
left.storagePath === right.storagePath &&
|
|
593
596
|
left.bucket === right.bucket &&
|
|
594
597
|
left.branch === right.branch &&
|
|
598
|
+
Boolean(left.agentMode) === Boolean(right.agentMode) &&
|
|
599
|
+
Boolean(left.continuous) === Boolean(right.continuous) &&
|
|
595
600
|
sameSyncInclude(left.include, right.include)
|
|
596
601
|
);
|
|
597
602
|
}
|
|
@@ -639,8 +644,3 @@ function runWithOptionalStateAccess<T>(
|
|
|
639
644
|
function combineSignals(sessionSignal: AbortSignal | undefined, actionSignal: AbortSignal) {
|
|
640
645
|
return sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;
|
|
641
646
|
}
|
|
642
|
-
|
|
643
|
-
function throwIfAborted(signal: AbortSignal) {
|
|
644
|
-
if (!signal.aborted) return;
|
|
645
|
-
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
646
|
-
}
|
package/src/ui/settings-ui.ts
CHANGED
|
@@ -12,6 +12,12 @@ import {
|
|
|
12
12
|
setupSwitchActionLabel,
|
|
13
13
|
} from "../sync/setup-switch.js";
|
|
14
14
|
import { captureMutationOwner } from "../sync/sync-local.js";
|
|
15
|
+
import {
|
|
16
|
+
AGENT_MODE_DESCRIPTION,
|
|
17
|
+
CONTINUOUS_DESCRIPTION,
|
|
18
|
+
saveAgentMode,
|
|
19
|
+
saveContinuousMode,
|
|
20
|
+
} from "./agent-mode-setting.js";
|
|
15
21
|
import type { RunRoute } from "./cancellable-operation.js";
|
|
16
22
|
import { dispatchManagerResult } from "./manager-result-dispatcher.js";
|
|
17
23
|
import { boundedSettingsUI } from "./settings-frame.js";
|
|
@@ -71,6 +77,8 @@ export async function showSyncSettings(
|
|
|
71
77
|
type Action =
|
|
72
78
|
| "automatic"
|
|
73
79
|
| "automatic-transfer"
|
|
80
|
+
| "agent-mode"
|
|
81
|
+
| "continuous"
|
|
74
82
|
| "merge-settings"
|
|
75
83
|
| "local-fields"
|
|
76
84
|
| "content-policy"
|
|
@@ -87,7 +95,10 @@ export async function showSyncSettings(
|
|
|
87
95
|
type Screen = "categories" | Group;
|
|
88
96
|
const groups: Record<Group, { label: string; ids: readonly string[] }> = {
|
|
89
97
|
content: { label: "Sync content", ids: ["include", "remoteInclude", "localFields"] },
|
|
90
|
-
behavior: {
|
|
98
|
+
behavior: {
|
|
99
|
+
label: "Sync behavior",
|
|
100
|
+
ids: ["automatic", "automaticTransfer", "agentMode", "continuous", "onSwitch"],
|
|
101
|
+
},
|
|
91
102
|
storage: { label: "Storage & setups", ids: ["storageLocation", "setups", "connections"] },
|
|
92
103
|
advanced: { label: "Advanced", ids: ["mergeSettings", "contentPolicy", "skipSecretScan", "showStatus", "debug"] },
|
|
93
104
|
all: { label: "All settings (search)", ids: [] },
|
|
@@ -174,6 +185,22 @@ export async function showSyncSettings(
|
|
|
174
185
|
values: ["On", "Off"],
|
|
175
186
|
action: "automatic-transfer",
|
|
176
187
|
},
|
|
188
|
+
{
|
|
189
|
+
id: "agentMode",
|
|
190
|
+
label: "Agent mode (experimental)",
|
|
191
|
+
description: AGENT_MODE_DESCRIPTION,
|
|
192
|
+
currentValue: state.agentMode ? "On" : "Off",
|
|
193
|
+
values: ["On", "Off"],
|
|
194
|
+
action: "agent-mode",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "continuous",
|
|
198
|
+
label: "Continuous sync (experimental)",
|
|
199
|
+
description: `${CONTINUOUS_DESCRIPTION}${state.continuous && !state.agentMode ? " Saved On, but paused until Agent mode is enabled." : ""}`,
|
|
200
|
+
currentValue: state.continuous ? "On" : "Off",
|
|
201
|
+
values: ["On", "Off"],
|
|
202
|
+
action: "continuous",
|
|
203
|
+
},
|
|
177
204
|
{
|
|
178
205
|
id: "onSwitch",
|
|
179
206
|
label: "On setup switch",
|
|
@@ -413,6 +440,61 @@ export async function showSyncSettings(
|
|
|
413
440
|
return { kind: "rejected" };
|
|
414
441
|
}
|
|
415
442
|
},
|
|
443
|
+
"agent-mode": async ({ value, signal: actionSignal }) => {
|
|
444
|
+
const mutationSignal = signal ? AbortSignal.any([signal, actionSignal]) : actionSignal;
|
|
445
|
+
const validate = captureMutationOwner(ctx, mutationSignal);
|
|
446
|
+
try {
|
|
447
|
+
const saved = await saveAgentMode(ctx, setupName, value === "On", mutationSignal);
|
|
448
|
+
if (!saved) return { kind: "rejected" };
|
|
449
|
+
try {
|
|
450
|
+
validate();
|
|
451
|
+
ctx.ui.notify(
|
|
452
|
+
"Agent mode saved. Applies to subsequent sync and the next session start; no transfer started.",
|
|
453
|
+
"info",
|
|
454
|
+
);
|
|
455
|
+
} catch {
|
|
456
|
+
// The save committed. A closed or replaced UI must not report a failed save.
|
|
457
|
+
// The next Settings read shows the persisted value.
|
|
458
|
+
}
|
|
459
|
+
return { kind: "stay" };
|
|
460
|
+
} catch (error) {
|
|
461
|
+
try {
|
|
462
|
+
validate();
|
|
463
|
+
} catch {
|
|
464
|
+
return { kind: "rejected" };
|
|
465
|
+
}
|
|
466
|
+
notifySaveFailure(ctx, error);
|
|
467
|
+
return { kind: "rejected" };
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
continuous: async ({ value, signal: actionSignal }) => {
|
|
471
|
+
const mutationSignal = signal ? AbortSignal.any([signal, actionSignal]) : actionSignal;
|
|
472
|
+
const validate = captureMutationOwner(ctx, mutationSignal);
|
|
473
|
+
try {
|
|
474
|
+
const saved = await saveContinuousMode(ctx, setupName, value === "On", mutationSignal);
|
|
475
|
+
if (!saved) return { kind: "rejected" };
|
|
476
|
+
try {
|
|
477
|
+
validate();
|
|
478
|
+
ctx.ui.notify(
|
|
479
|
+
value === "On"
|
|
480
|
+
? "Continuous sync enabled. Monitoring starts after the /sync command or manager closes; completed work is not undone."
|
|
481
|
+
: "Continuous sync disabled. Completed work is not undone.",
|
|
482
|
+
"info",
|
|
483
|
+
);
|
|
484
|
+
} catch {
|
|
485
|
+
/* committed save; do not use stale UI */
|
|
486
|
+
}
|
|
487
|
+
return { kind: "stay" };
|
|
488
|
+
} catch (error) {
|
|
489
|
+
try {
|
|
490
|
+
validate();
|
|
491
|
+
} catch {
|
|
492
|
+
return { kind: "rejected" };
|
|
493
|
+
}
|
|
494
|
+
notifySaveFailure(ctx, error);
|
|
495
|
+
return { kind: "rejected" };
|
|
496
|
+
}
|
|
497
|
+
},
|
|
416
498
|
"automatic-transfer": async ({ value, signal: actionSignal }) => {
|
|
417
499
|
const automaticTransfer = value === "On";
|
|
418
500
|
const mutationSignal = signal ? AbortSignal.any([signal, actionSignal]) : actionSignal;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { throwIfAborted } from "../../sync/signals.js";
|
|
2
3
|
import { promptSecret } from "../secret-input.js";
|
|
3
4
|
import { requiredValueInput } from "./text-input.js";
|
|
4
5
|
|
|
@@ -70,8 +71,3 @@ export async function chooseS3Credentials(
|
|
|
70
71
|
ready: true,
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
-
function throwIfAborted(signal?: AbortSignal) {
|
|
75
|
-
if (!signal?.aborted) return;
|
|
76
|
-
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
77
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { validateConfigName } from "../../settings/settings-validation.js";
|
|
3
|
+
import { throwIfAborted } from "../../sync/signals.js";
|
|
3
4
|
import { errorMessage } from "../../sync/sync-errors.js";
|
|
4
5
|
import { safeTerminalText } from "../terminal-text.js";
|
|
5
6
|
|
|
@@ -10,11 +11,7 @@ export async function promptInitialSetupName(ctx: ExtensionCommandContext, signa
|
|
|
10
11
|
const guidance = ctx.mode === "tui" ? ctx.ui.theme.fg("muted", hint) : hint;
|
|
11
12
|
// This compact prompt owns its default hint; the general helper would repeat it.
|
|
12
13
|
const value = await ctx.ui.input(`Sync setup name\n${guidance}`, undefined, { signal });
|
|
13
|
-
|
|
14
|
-
throw signal.reason instanceof Error
|
|
15
|
-
? signal.reason
|
|
16
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
17
|
-
}
|
|
14
|
+
throwIfAborted(signal);
|
|
18
15
|
if (value === undefined) return undefined;
|
|
19
16
|
const name = value.trim() || "default";
|
|
20
17
|
try {
|
|
@@ -129,6 +129,8 @@ export async function showSetupSwitcher(
|
|
|
129
129
|
`Included content: ${config.include.length} paths`,
|
|
130
130
|
`Automatic sync: ${automaticSyncSummary(config.automatic)} · Sessions: ${config.include.includes("sessions") ? "On" : "Off"}`,
|
|
131
131
|
`Automatic transfer at startup: ${config.automaticTransfer ? "On — may upload, replace, or delete selected files; no reload" : "Off"}`,
|
|
132
|
+
`Agent mode: ${config.agentMode ? "On (experimental; autonomous merged sync)" : "Off"}`,
|
|
133
|
+
`Continuous sync: ${config.continuous ? (config.agentMode ? "On (experimental; recurring requests and transfers)" : "Saved On; paused until Agent mode is enabled") : "Off"}`,
|
|
132
134
|
"",
|
|
133
135
|
switchEffect,
|
|
134
136
|
].join("\n"),
|
package/src/ui/sync-setups-ui.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
|
|
|
3
3
|
import { loadConfig } from "../settings/config.js";
|
|
4
4
|
import { readLocalConfigObject } from "../settings/settings-store.js";
|
|
5
5
|
import { ownRecord } from "../settings/settings-validation.js";
|
|
6
|
+
import { throwIfAborted } from "../sync/signals.js";
|
|
6
7
|
import { syncErrorGuidance } from "../sync/sync-error-guidance.js";
|
|
7
8
|
import { syncIncludeSelection } from "../sync/sync-policy.js";
|
|
8
9
|
import { safeTerminalText } from "./terminal-text.js";
|
|
@@ -24,11 +25,6 @@ export async function countValidSyncSetups(setups: Record<string, unknown> | und
|
|
|
24
25
|
return count;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function throwIfAborted(signal?: AbortSignal) {
|
|
28
|
-
if (!signal?.aborted) return;
|
|
29
|
-
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
28
|
type SyncSetupActions = {
|
|
33
29
|
add(signal?: AbortSignal): Promise<void>;
|
|
34
30
|
edit(name: string, signal?: AbortSignal): Promise<void>;
|
|
@@ -197,6 +193,8 @@ async function loadSetupMenuState(selectedName: string | undefined, signal?: Abo
|
|
|
197
193
|
`Sessions: ${selection.sessions ? "On — privacy-sensitive" : "Off"}`,
|
|
198
194
|
`Automatic sync: ${config.automatic ? "On" : "Off"}`,
|
|
199
195
|
`Automatic transfer at startup: ${config.automaticTransfer ? "On — may upload, replace, or delete selected files; no reload" : "Off"}`,
|
|
196
|
+
`Agent mode: ${config.agentMode ? "On (experimental; autonomous merged sync)" : "Off"}`,
|
|
197
|
+
`Continuous sync: ${config.continuous ? (config.agentMode ? "On (experimental; recurring requests and transfers)" : "Saved On; paused until Agent mode is enabled") : "Off"}`,
|
|
200
198
|
isCurrent
|
|
201
199
|
? "Edit included content and automatic sync in /sync → Settings."
|
|
202
200
|
: "To edit included content or automatic sync, make this setup current, then open /sync → Settings.",
|