@narumitw/pi-sync 0.50.3 → 0.51.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 +4 -1
- package/dist/chunks/{chunk-6LP3MCR2.ts → chunk-2JZFHNLM.ts} +3 -5
- package/dist/chunks/chunk-2JZFHNLM.ts.map +7 -0
- package/dist/chunks/{chunk-LCRI3ABW.ts → chunk-2RZSQWBH.ts} +8 -19
- package/dist/chunks/chunk-2RZSQWBH.ts.map +7 -0
- package/dist/chunks/{chunk-IJ6FJFA5.ts → chunk-4AIHXRKE.ts} +11 -17
- package/dist/chunks/chunk-4AIHXRKE.ts.map +7 -0
- package/dist/chunks/{chunk-C7XY5NF5.ts → chunk-4MPIH46N.ts} +29 -51
- package/dist/chunks/chunk-4MPIH46N.ts.map +7 -0
- package/dist/chunks/{chunk-5B3FXBLE.ts → chunk-6546TS54.ts} +16 -20
- package/dist/chunks/chunk-6546TS54.ts.map +7 -0
- package/dist/chunks/{chunk-Q2TUM5X6.ts → chunk-6NT3YFGY.ts} +2 -2
- package/dist/chunks/chunk-6NT3YFGY.ts.map +7 -0
- package/dist/chunks/{chunk-2B2ELUF5.ts → chunk-7D5SF7P3.ts} +1 -1
- package/dist/chunks/chunk-7D5SF7P3.ts.map +7 -0
- package/dist/chunks/{chunk-YDWUZVPN.ts → chunk-7KHKWL3Q.ts} +28 -47
- package/dist/chunks/chunk-7KHKWL3Q.ts.map +7 -0
- package/dist/chunks/{chunk-ZI5MXMEX.ts → chunk-BVVP33U5.ts} +2 -4
- package/dist/chunks/chunk-BVVP33U5.ts.map +7 -0
- package/dist/chunks/{chunk-SZWBGPID.ts → chunk-DM4X4FIA.ts} +8 -13
- package/dist/chunks/chunk-DM4X4FIA.ts.map +7 -0
- package/dist/chunks/{chunk-SL64RLXR.ts → chunk-DZUSTGQV.ts} +8 -16
- package/dist/chunks/chunk-DZUSTGQV.ts.map +7 -0
- package/dist/chunks/{chunk-YHEMENKV.ts → chunk-E42GXD6D.ts} +13 -19
- package/dist/chunks/chunk-E42GXD6D.ts.map +7 -0
- package/dist/chunks/{chunk-Z4DQF6L3.ts → chunk-ECYCNZOE.ts} +1 -1
- package/dist/chunks/chunk-ECYCNZOE.ts.map +7 -0
- package/dist/chunks/{chunk-OEX4ABY6.ts → chunk-EEJPYTWE.ts} +11 -21
- package/dist/chunks/chunk-EEJPYTWE.ts.map +7 -0
- package/dist/chunks/{chunk-CPEHGXJV.ts → chunk-G4RUXRWZ.ts} +3 -5
- package/dist/chunks/chunk-G4RUXRWZ.ts.map +7 -0
- package/dist/chunks/{chunk-T2B5IU74.ts → chunk-HGJH56KR.ts} +4 -4
- package/dist/chunks/chunk-HGJH56KR.ts.map +7 -0
- package/dist/chunks/{chunk-JAAKLL6M.ts → chunk-IVXEDPAD.ts} +10 -34
- package/dist/chunks/chunk-IVXEDPAD.ts.map +7 -0
- package/dist/chunks/chunk-K3RIEL6J.ts +20 -0
- package/dist/chunks/chunk-K3RIEL6J.ts.map +7 -0
- package/dist/chunks/{chunk-LTBWGSBV.ts → chunk-MSSW6F3R.ts} +1 -1
- package/dist/chunks/chunk-MSSW6F3R.ts.map +7 -0
- package/dist/chunks/{chunk-T3HH3UEJ.ts → chunk-OVDTF5CH.ts} +4 -10
- package/dist/chunks/chunk-OVDTF5CH.ts.map +7 -0
- package/dist/chunks/{chunk-NJFUIVYL.ts → chunk-PWMWOJP4.ts} +1 -1
- package/dist/chunks/chunk-PWMWOJP4.ts.map +7 -0
- package/dist/chunks/{chunk-HUDQATCL.ts → chunk-Q32CQWPM.ts} +6 -8
- package/dist/chunks/chunk-Q32CQWPM.ts.map +7 -0
- package/dist/chunks/{chunk-ETTRJDNP.ts → chunk-QLSN7AGX.ts} +6 -13
- package/dist/chunks/chunk-QLSN7AGX.ts.map +7 -0
- package/dist/chunks/{chunk-THMF4BVL.ts → chunk-SWUXA3MH.ts} +1 -1
- package/dist/chunks/chunk-SWUXA3MH.ts.map +7 -0
- package/dist/chunks/{chunk-TEN2ZBJV.ts → chunk-T2SJD3N7.ts} +2 -4
- package/dist/chunks/chunk-T2SJD3N7.ts.map +7 -0
- package/dist/chunks/{chunk-AUSDLD6F.ts → chunk-T56RNRZJ.ts} +10 -26
- package/dist/chunks/chunk-T56RNRZJ.ts.map +7 -0
- package/dist/chunks/{chunk-DHVFS4QK.ts → chunk-UA7RXOIT.ts} +37 -90
- package/dist/chunks/chunk-UA7RXOIT.ts.map +7 -0
- package/dist/chunks/{chunk-D5X27LCA.ts → chunk-UETBKTDI.ts} +1 -1
- package/dist/chunks/chunk-UETBKTDI.ts.map +7 -0
- package/dist/chunks/{chunk-CHH26D4F.ts → chunk-YFADF5ZQ.ts} +7 -6
- package/dist/chunks/chunk-YFADF5ZQ.ts.map +7 -0
- package/dist/chunks/{chunk-CCSN3F47.ts → chunk-YPXGU5OR.ts} +4 -4
- package/dist/chunks/chunk-YPXGU5OR.ts.map +7 -0
- package/dist/chunks/{file-selection-FTTKAOYX.ts → file-selection-RAVHRYFG.ts} +14 -26
- package/dist/chunks/file-selection-RAVHRYFG.ts.map +7 -0
- package/dist/chunks/{git-backend-GMVS4PD4.ts → git-backend-IAANDL3K.ts} +41 -104
- package/dist/chunks/git-backend-IAANDL3K.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +23 -0
- package/dist/chunks/{manager-ui-IPAOAWZA.ts → manager-ui-763NEKJY.ts} +124 -251
- package/dist/chunks/manager-ui-763NEKJY.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +22 -0
- package/dist/chunks/{s3-backend-66O4FGBH.ts → s3-backend-XGXUOPUN.ts} +23 -54
- package/dist/chunks/s3-backend-XGXUOPUN.ts.map +7 -0
- package/dist/chunks/{setup-switch-IS2PEZ3J.ts → setup-switch-5G2VNJHL.ts} +9 -9
- package/dist/chunks/{setup-wizard-JUJZYNNM.ts → setup-wizard-YIEWGX32.ts} +12 -12
- package/dist/chunks/setup-wizard-YIEWGX32.ts.map +7 -0
- package/dist/chunks/{snapshot-HKEWCVK6.ts → snapshot-JL5DFSXI.ts} +5 -5
- package/dist/chunks/sync-inspection-P3ENJLNF.ts +20 -0
- package/dist/chunks/{sync-operations-LBX3GKCM.ts → sync-operations-AR76EB6C.ts} +85 -201
- package/dist/chunks/sync-operations-AR76EB6C.ts.map +7 -0
- package/dist/chunks/{sync-state-Q2FTXTW6.ts → sync-state-VHJUZ4YG.ts} +6 -6
- package/dist/chunks/{webdav-backend-ECIKD7SO.ts → webdav-backend-3EGUONAT.ts} +20 -51
- package/dist/chunks/webdav-backend-3EGUONAT.ts.map +7 -0
- package/dist/index.ts +49 -74
- package/dist/index.ts.map +3 -3
- package/docs/settings.md +9 -0
- package/package.json +61 -62
- package/src/backends/backend-factory.ts +15 -15
- package/src/backends/backend-identity.ts +31 -31
- package/src/backends/backend-types.ts +42 -42
- package/src/backends/git/git-backend.ts +714 -788
- package/src/backends/git/git-config.ts +104 -111
- package/src/backends/git/git-runner.ts +230 -247
- package/src/backends/git/git-storage.ts +228 -245
- package/src/backends/s3/s3-backend.ts +408 -441
- package/src/backends/s3/s3-client.ts +288 -333
- package/src/backends/sync-backend.ts +65 -65
- package/src/backends/webdav/webdav-backend.ts +542 -589
- package/src/backends/webdav/webdav-client.ts +292 -316
- package/src/backends/webdav/webdav-config.ts +57 -68
- package/src/commands/command-execution.ts +270 -289
- package/src/commands/command-handler.ts +160 -163
- package/src/commands/command-types.ts +13 -13
- package/src/commands/command.ts +190 -196
- package/src/commands/setup-completions.ts +1 -1
- package/src/paths.ts +47 -47
- package/src/settings/config-errors.ts +4 -5
- package/src/settings/config-file.ts +473 -506
- package/src/settings/config.ts +171 -174
- package/src/settings/settings-management.ts +191 -216
- package/src/settings/settings-store.ts +63 -77
- package/src/settings/settings-types.ts +78 -75
- package/src/settings/settings-validation.ts +328 -364
- package/src/snapshot/session-paths.ts +41 -55
- package/src/snapshot/snapshot-apply.ts +197 -229
- package/src/snapshot/snapshot-codec.ts +29 -31
- package/src/snapshot/snapshot-paths.ts +4 -6
- package/src/snapshot/snapshot-transaction.ts +161 -170
- package/src/snapshot/snapshot-types.ts +24 -24
- package/src/snapshot/snapshot.ts +310 -343
- package/src/state/json-file.ts +11 -11
- package/src/state/lock.ts +226 -242
- package/src/state/lockfile-fs.ts +20 -20
- package/src/state/operation-availability.ts +36 -41
- package/src/state/state-directory.ts +171 -173
- package/src/state/state-types.ts +15 -15
- package/src/state/sync-state-store.ts +23 -23
- package/src/sync/automatic-sync.ts +75 -80
- package/src/sync/remote-snapshot.ts +52 -60
- package/src/sync/setup-switch.ts +99 -114
- package/src/sync/signals.ts +3 -5
- package/src/sync/startup-check.ts +97 -111
- package/src/sync/sync-decision.ts +76 -80
- package/src/sync/sync-error-guidance.ts +41 -48
- package/src/sync/sync-errors.ts +10 -10
- package/src/sync/sync-inspection.ts +29 -33
- package/src/sync/sync-loaders.ts +28 -36
- package/src/sync/sync-mutations.ts +510 -622
- package/src/sync/sync-operations.ts +7 -7
- package/src/sync/sync-policy.ts +296 -326
- package/src/sync/sync-queries.ts +175 -194
- package/src/sync/sync-state.ts +74 -100
- package/src/sync-extension.ts +89 -101
- package/src/sync.ts +26 -26
- package/src/types.ts +37 -37
- package/src/ui/automatic-sync-summary.ts +1 -3
- package/src/ui/cancellable-operation.ts +89 -101
- package/src/ui/file-selection.ts +250 -274
- package/src/ui/manager-attention.ts +51 -63
- package/src/ui/manager-recovery.ts +48 -57
- package/src/ui/manager-result-dispatcher.ts +62 -76
- package/src/ui/manager-state.ts +200 -232
- package/src/ui/manager-ui.ts +264 -362
- package/src/ui/remote-selection-ui.ts +547 -588
- package/src/ui/secret-input.ts +197 -205
- package/src/ui/settings-ui.ts +175 -172
- package/src/ui/setup/git-ui.ts +232 -261
- package/src/ui/setup/s3-credentials-ui.ts +58 -65
- package/src/ui/setup/s3-ui.ts +171 -195
- package/src/ui/setup/setup-actions.ts +91 -101
- package/src/ui/setup/setup-location-ui.ts +121 -137
- package/src/ui/setup/setup-name-ui.ts +27 -27
- package/src/ui/setup/setup-prompts.ts +65 -65
- package/src/ui/setup/setup-review.ts +58 -59
- package/src/ui/setup/setup-switcher.ts +156 -160
- package/src/ui/setup/setup-wizard.ts +28 -28
- package/src/ui/setup/text-input.ts +54 -58
- package/src/ui/setup/webdav-ui.ts +246 -293
- package/src/ui/storage-connections-ui.ts +317 -369
- package/src/ui/sync-attention.ts +148 -164
- package/src/ui/sync-format.ts +110 -121
- package/src/ui/sync-resolution-ui.ts +147 -153
- package/src/ui/sync-setups-ui.ts +218 -238
- package/src/ui/sync-status.ts +17 -0
- package/src/ui/terminal-text.ts +2 -2
- package/dist/chunks/chunk-2B2ELUF5.ts.map +0 -7
- package/dist/chunks/chunk-5B3FXBLE.ts.map +0 -7
- package/dist/chunks/chunk-6LP3MCR2.ts.map +0 -7
- package/dist/chunks/chunk-AUSDLD6F.ts.map +0 -7
- package/dist/chunks/chunk-C7XY5NF5.ts.map +0 -7
- package/dist/chunks/chunk-CCSN3F47.ts.map +0 -7
- package/dist/chunks/chunk-CHH26D4F.ts.map +0 -7
- package/dist/chunks/chunk-CPEHGXJV.ts.map +0 -7
- package/dist/chunks/chunk-D5X27LCA.ts.map +0 -7
- package/dist/chunks/chunk-DHVFS4QK.ts.map +0 -7
- package/dist/chunks/chunk-ETTRJDNP.ts.map +0 -7
- package/dist/chunks/chunk-HUDQATCL.ts.map +0 -7
- package/dist/chunks/chunk-IJ6FJFA5.ts.map +0 -7
- package/dist/chunks/chunk-JAAKLL6M.ts.map +0 -7
- package/dist/chunks/chunk-LCRI3ABW.ts.map +0 -7
- package/dist/chunks/chunk-LTBWGSBV.ts.map +0 -7
- package/dist/chunks/chunk-NJFUIVYL.ts.map +0 -7
- package/dist/chunks/chunk-OEX4ABY6.ts.map +0 -7
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +0 -7
- package/dist/chunks/chunk-SL64RLXR.ts.map +0 -7
- package/dist/chunks/chunk-SZWBGPID.ts.map +0 -7
- package/dist/chunks/chunk-T2B5IU74.ts.map +0 -7
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +0 -7
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +0 -7
- package/dist/chunks/chunk-THMF4BVL.ts.map +0 -7
- package/dist/chunks/chunk-YDWUZVPN.ts.map +0 -7
- package/dist/chunks/chunk-YHEMENKV.ts.map +0 -7
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +0 -7
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +0 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +0 -7
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-ASKGOSW5.ts +0 -22
- package/dist/chunks/manager-ui-IPAOAWZA.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-QDNR7WEI.ts +0 -21
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
- package/dist/chunks/setup-wizard-JUJZYNNM.ts.map +0 -7
- package/dist/chunks/sync-inspection-CST2KL65.ts +0 -20
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +0 -7
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +0 -7
- /package/dist/chunks/{manager-result-dispatcher-ASKGOSW5.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-QDNR7WEI.ts.map → remote-selection-ui-TZTJF32Y.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-IS2PEZ3J.ts.map → setup-switch-5G2VNJHL.ts.map} +0 -0
- /package/dist/chunks/{snapshot-HKEWCVK6.ts.map → snapshot-JL5DFSXI.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-CST2KL65.ts.map → sync-inspection-P3ENJLNF.ts.map} +0 -0
- /package/dist/chunks/{sync-state-Q2FTXTW6.ts.map → sync-state-VHJUZ4YG.ts.map} +0 -0
package/src/sync-extension.ts
CHANGED
|
@@ -9,113 +9,101 @@ import { createStartupCheck } from "./sync/startup-check.js";
|
|
|
9
9
|
import { errorMessage } from "./sync/sync-errors.js";
|
|
10
10
|
import { createSyncLoaders, type SyncDependencies } from "./sync/sync-loaders.js";
|
|
11
11
|
import { createSyncAttentionController } from "./ui/sync-attention.js";
|
|
12
|
+
import { setSyncStatus } from "./ui/sync-status.js";
|
|
12
13
|
import { safeTerminalText } from "./ui/terminal-text.js";
|
|
13
14
|
|
|
14
|
-
const STATUS_KEY = "sync";
|
|
15
|
-
|
|
16
15
|
export default function sync(pi: ExtensionAPI, dependencies: Partial<SyncDependencies> = {}) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const loaders = createSyncLoaders(dependencies);
|
|
17
|
+
const attention = createSyncAttentionController();
|
|
18
|
+
const check = createStartupCheck(loaders, attention);
|
|
19
|
+
let sessionAbort = new AbortController();
|
|
20
|
+
let shutdownAbort: AbortController | undefined;
|
|
21
|
+
let initialization = Promise.resolve<AnySyncConfig | false | undefined>(undefined);
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const run = () => handleCommand(args, ctx, signal, loaders, attention);
|
|
52
|
-
// Drain background cache/child cleanup before entering any foreground guard.
|
|
53
|
-
// Help must remain reachable when the state roots themselves need repair.
|
|
54
|
-
if (command === "migrate-state" || command === "help") await run();
|
|
55
|
-
else await withStateDirectoryAccess(run);
|
|
56
|
-
},
|
|
57
|
-
});
|
|
23
|
+
pi.registerCommand("sync", {
|
|
24
|
+
description: "Sync Pi settings through Git, WebDAV, R2, or S3-compatible storage",
|
|
25
|
+
getArgumentCompletions: completeSyncArguments,
|
|
26
|
+
handler: async (args, ctx) => {
|
|
27
|
+
if (!ctx.hasUI) {
|
|
28
|
+
throw new Error("/sync requires TUI or RPC mode so results and safety prompts are observable.");
|
|
29
|
+
}
|
|
30
|
+
const signal = sessionAbort.signal;
|
|
31
|
+
const ready = await initialization;
|
|
32
|
+
if (signal.aborted) return;
|
|
33
|
+
await check.stop();
|
|
34
|
+
if (signal.aborted) return;
|
|
35
|
+
const command = splitArgs(args)[0];
|
|
36
|
+
if (ready === false && command !== "help" && command !== "unlock" && command !== "migrate-state") {
|
|
37
|
+
ctx.ui.notify(
|
|
38
|
+
"pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.",
|
|
39
|
+
"error",
|
|
40
|
+
);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const run = () => handleCommand(args, ctx, signal, loaders, attention);
|
|
44
|
+
// Drain background cache/child cleanup before entering any foreground guard.
|
|
45
|
+
// Help must remain reachable when the state roots themselves need repair.
|
|
46
|
+
if (command === "migrate-state" || command === "help") await run();
|
|
47
|
+
else await withStateDirectoryAccess(run);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const ready = await initialization;
|
|
86
|
-
if (ready && !signal.aborted) check.start(ctx, signal, ready);
|
|
87
|
-
});
|
|
51
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
52
|
+
shutdownAbort?.abort(new DOMException("Session replaced", "AbortError"));
|
|
53
|
+
shutdownAbort = undefined;
|
|
54
|
+
sessionAbort.abort(new DOMException("Session replaced", "AbortError"));
|
|
55
|
+
sessionAbort = new AbortController();
|
|
56
|
+
const signal = sessionAbort.signal;
|
|
57
|
+
attention.reset(ctx);
|
|
58
|
+
const previous = initialization;
|
|
59
|
+
initialization = (async () => {
|
|
60
|
+
await previous;
|
|
61
|
+
if (signal.aborted) return false;
|
|
62
|
+
await check.stop();
|
|
63
|
+
if (signal.aborted) return false;
|
|
64
|
+
try {
|
|
65
|
+
const config = await withStateDirectoryAccess(() => startSession(ctx, signal));
|
|
66
|
+
return signal.aborted ? false : config;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (!signal.aborted && ctx.hasUI) {
|
|
69
|
+
ctx.ui.notify(`pi-sync recovery required: ${safeTerminalText(errorMessage(error))}`, "error");
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
const ready = await initialization;
|
|
75
|
+
if (ready && !signal.aborted) check.start(ctx, signal, ready);
|
|
76
|
+
});
|
|
88
77
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
78
|
+
pi.on("session_shutdown", async (event, ctx) => {
|
|
79
|
+
sessionAbort.abort(new DOMException("Session shut down", "AbortError"));
|
|
80
|
+
attention.reset(ctx);
|
|
81
|
+
shutdownAbort?.abort(new DOMException("Session shut down again", "AbortError"));
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
shutdownAbort = controller;
|
|
84
|
+
const signal = combineSignals(controller.signal, AbortSignal.timeout(30_000));
|
|
85
|
+
const reason = typeof event === "object" && event ? (event as { reason?: string }).reason : undefined;
|
|
86
|
+
try {
|
|
87
|
+
const ready = await initialization;
|
|
88
|
+
if (signal.aborted) return;
|
|
89
|
+
await check.stop();
|
|
90
|
+
if (signal.aborted) return;
|
|
91
|
+
if (ready !== false && reason !== "reload") {
|
|
92
|
+
await withStateDirectoryAccess(async () => {
|
|
93
|
+
if (signal.aborted) return;
|
|
94
|
+
await autoPushSessions(ctx, signal, loaders);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (!signal.aborted) {
|
|
99
|
+
ctx.ui.notify(`pi-sync session push skipped: ${errorMessage(error)}`, "warning");
|
|
100
|
+
}
|
|
101
|
+
} finally {
|
|
102
|
+
if (shutdownAbort === controller) shutdownAbort = undefined;
|
|
103
|
+
}
|
|
104
|
+
if (signal.aborted) return;
|
|
105
|
+
setSyncStatus(ctx, undefined);
|
|
106
|
+
});
|
|
119
107
|
}
|
|
120
108
|
|
|
121
109
|
export type { SyncDependencies } from "./sync/sync-loaders.js";
|
package/src/sync.ts
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
export { completeSyncArguments, parseOptions, splitArgs } from "./commands/command.js";
|
|
2
2
|
export { encodeKey, posixJoin, safeJoin, safeName } from "./paths.js";
|
|
3
3
|
export {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
isEnabled,
|
|
5
|
+
isExplicitlyEnabled,
|
|
6
|
+
loadConfig,
|
|
7
|
+
sessionTokenWarnings,
|
|
8
8
|
} from "./settings/config.js";
|
|
9
9
|
export { isCloudflareR2Endpoint } from "./settings/settings-validation.js";
|
|
10
10
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
canonicalSnapshotPathForConfig,
|
|
12
|
+
collectFiles,
|
|
13
|
+
filterSnapshotForConfigPolicy,
|
|
14
|
+
isConfiguredSnapshotPath,
|
|
15
|
+
isDeniedPath,
|
|
16
|
+
isSessionPath,
|
|
17
|
+
mergeRemotePreservedFiles,
|
|
18
|
+
mergeRemoteSessionFiles,
|
|
19
|
+
scanSnapshot,
|
|
20
|
+
sessionSnapshotPathFromAbsolute,
|
|
21
|
+
snapshotWithoutSessions,
|
|
22
22
|
} from "./snapshot/snapshot.js";
|
|
23
23
|
export {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
addTopLevelCaseVariantDeletes,
|
|
25
|
+
appliedFileHashMap,
|
|
26
|
+
preflightSnapshotApply,
|
|
27
|
+
protectSnapshotApplyPlan,
|
|
28
28
|
} from "./snapshot/snapshot-apply.js";
|
|
29
29
|
export {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
canPullRemoteSessionsOnFirstSync,
|
|
31
|
+
canPullRemoteSettingsOnFirstSync,
|
|
32
|
+
hasRemoteChanges,
|
|
33
|
+
sessionHashMap,
|
|
34
|
+
settingsHashesMatchState,
|
|
35
|
+
settingsHashMap,
|
|
36
|
+
settingsHashMapFromState,
|
|
37
37
|
} from "./sync/sync-state.js";
|
|
38
38
|
export { default, type SyncDependencies } from "./sync-extension.js";
|
package/src/types.ts
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
// Compatibility type surface; implementation modules import from the owning domain.
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
LatestPointer,
|
|
5
|
+
RemoteObject,
|
|
6
|
+
ResolvedGitBackend,
|
|
7
|
+
ResolvedGitDestination,
|
|
8
|
+
ResolvedGitStorageProfile,
|
|
9
|
+
ResolvedS3Backend,
|
|
10
|
+
ResolvedS3Destination,
|
|
11
|
+
ResolvedS3StorageProfile,
|
|
12
|
+
ResolvedSyncBackend,
|
|
13
|
+
ResolvedWebDavBackend,
|
|
14
|
+
ResolvedWebDavDestination,
|
|
15
|
+
ResolvedWebDavStorageProfile,
|
|
16
16
|
} from "./backends/backend-types.js";
|
|
17
17
|
export type { CommandArgumentCompletion, CommandOptions } from "./commands/command-types.js";
|
|
18
18
|
export type {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
19
|
+
AnySyncConfig,
|
|
20
|
+
CommonSyncConfig,
|
|
21
|
+
CommonSyncSetupStorageSettings,
|
|
22
|
+
GitStorageConnectionSettings,
|
|
23
|
+
GitSyncSetupStorageSettings,
|
|
24
|
+
OnSwitchAction,
|
|
25
|
+
PartialConfig,
|
|
26
|
+
PiSyncSettingsV3,
|
|
27
|
+
S3CredentialsSettings,
|
|
28
|
+
S3StorageConnectionSettings,
|
|
29
|
+
S3SyncSetupStorageSettings,
|
|
30
|
+
StorageConnectionSettings,
|
|
31
|
+
StorageConnectionType,
|
|
32
|
+
SyncConfig,
|
|
33
|
+
SyncPolicySettings,
|
|
34
|
+
SyncSetupSettings,
|
|
35
|
+
SyncSetupStorageSettings,
|
|
36
|
+
WebDavCredentialsSettings,
|
|
37
|
+
WebDavStorageConnectionSettings,
|
|
38
|
+
WebDavSyncSetupStorageSettings,
|
|
39
39
|
} from "./settings/settings-types.js";
|
|
40
40
|
export type {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
Snapshot,
|
|
42
|
+
SnapshotApplyPlan,
|
|
43
|
+
SnapshotFile,
|
|
44
|
+
SnapshotOptions,
|
|
45
|
+
SnapshotSelection,
|
|
46
46
|
} from "./snapshot/snapshot-types.js";
|
|
47
47
|
export type { LockFile, SyncState } from "./state/state-types.js";
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/** Keep the setting's automatic transfer scope visible in every setup summary. */
|
|
2
2
|
export function automaticSyncSummary(enabled: boolean) {
|
|
3
|
-
|
|
4
|
-
? "On (startup check; shutdown pushes selected content if sessions included)"
|
|
5
|
-
: "Off";
|
|
3
|
+
return enabled ? "On (startup check; shutdown pushes selected content if sessions included)" : "Off";
|
|
6
4
|
}
|
|
@@ -6,118 +6,106 @@ import type { SyncDecision } from "../sync/sync-decision.js";
|
|
|
6
6
|
import type { RemoteSelectionDecision } from "../sync/sync-policy.js";
|
|
7
7
|
|
|
8
8
|
export type RunRouteResult =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
| { kind: "completed"; outcome?: SetupPullOutcome }
|
|
10
|
+
| { kind: "decision-required"; decision: SyncDecision }
|
|
11
|
+
| { kind: "remote-selection-required"; decision: RemoteSelectionDecision }
|
|
12
|
+
| { kind: "failed" };
|
|
13
13
|
|
|
14
14
|
export type RunRoute = (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
route: string,
|
|
16
|
+
signal?: AbortSignal,
|
|
17
|
+
onCommit?: () => void,
|
|
18
|
+
target?: string,
|
|
19
19
|
) => Promise<RunRouteResult | undefined>;
|
|
20
20
|
|
|
21
|
-
export type CancellableOperationResult =
|
|
22
|
-
| RunRouteResult
|
|
23
|
-
| { kind: "closed" }
|
|
24
|
-
| { kind: "cancelled" };
|
|
21
|
+
export type CancellableOperationResult = RunRouteResult | { kind: "closed" } | { kind: "cancelled" };
|
|
25
22
|
|
|
26
23
|
interface CancellableOperationOptions {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
commitAware?: boolean;
|
|
25
|
+
cancelledMessage?: string | null;
|
|
26
|
+
target?: string;
|
|
27
|
+
signal?: AbortSignal;
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
export async function runCancellableOperation(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
ctx: ExtensionContext,
|
|
32
|
+
message: string,
|
|
33
|
+
route: string,
|
|
34
|
+
runRoute: RunRoute,
|
|
35
|
+
options: CancellableOperationOptions = {},
|
|
39
36
|
): Promise<CancellableOperationResult> {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
110
|
-
if (interaction.kind === "error") throw interaction.error;
|
|
111
|
-
if (interaction.kind !== "completed") return { kind: "closed" };
|
|
112
|
-
if (interaction.value.cancelled) {
|
|
113
|
-
if (cancelledMessage) ctx.ui.notify(cancelledMessage, "info");
|
|
114
|
-
return { kind: "cancelled" };
|
|
115
|
-
}
|
|
116
|
-
if (interaction.value.error) throw interaction.value.error;
|
|
117
|
-
return routeResult ?? { kind: "failed" };
|
|
37
|
+
const {
|
|
38
|
+
commitAware = false,
|
|
39
|
+
cancelledMessage = "Check cancelled; no settings or files were changed.",
|
|
40
|
+
target,
|
|
41
|
+
signal,
|
|
42
|
+
} = options;
|
|
43
|
+
if (ctx.mode !== "tui") {
|
|
44
|
+
return (await runRoute(route, signal, undefined, target)) ?? { kind: "failed" };
|
|
45
|
+
}
|
|
46
|
+
let commitStarted = false;
|
|
47
|
+
let routeResult: RunRouteResult | undefined;
|
|
48
|
+
const interaction = await runCustomInteraction<{ cancelled?: boolean; error?: unknown }, ExtensionContext>(ctx, {
|
|
49
|
+
signal,
|
|
50
|
+
isCurrent: () => !signal?.aborted,
|
|
51
|
+
create: ({ tui, theme, keybindings, signal: interactionSignal, complete }) => {
|
|
52
|
+
const loader = new BorderedLoader(tui, theme, message, { cancellable: false });
|
|
53
|
+
const cancelHint = formatInteractionHints(keybindings, [
|
|
54
|
+
{
|
|
55
|
+
keys: [...keybindings.getKeys("tui.select.cancel").filter((key) => !hasControlCharacter(key)), "ctrl+c"],
|
|
56
|
+
label: "cancel",
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
const operation = runRoute(
|
|
60
|
+
route,
|
|
61
|
+
interactionSignal,
|
|
62
|
+
commitAware ? () => (commitStarted = true) : undefined,
|
|
63
|
+
target,
|
|
64
|
+
).then(
|
|
65
|
+
(result) => {
|
|
66
|
+
routeResult = result;
|
|
67
|
+
complete({});
|
|
68
|
+
},
|
|
69
|
+
(error: unknown) => complete({ error }),
|
|
70
|
+
);
|
|
71
|
+
return {
|
|
72
|
+
render(width: number) {
|
|
73
|
+
const safeWidth = Math.max(1, width);
|
|
74
|
+
const lines = loader.render(safeWidth);
|
|
75
|
+
const bottomBorder = lines.at(-1);
|
|
76
|
+
return [
|
|
77
|
+
...lines.slice(0, -1),
|
|
78
|
+
truncateToWidth(theme.fg("dim", cancelHint), safeWidth, ""),
|
|
79
|
+
...(bottomBorder === undefined ? [] : [bottomBorder]),
|
|
80
|
+
];
|
|
81
|
+
},
|
|
82
|
+
invalidate: () => loader.invalidate(),
|
|
83
|
+
handleInput(data: string) {
|
|
84
|
+
if (!matchesKey(data, Key.ctrl("c")) && !keybindings.matches(data, "tui.select.cancel")) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (commitStarted) {
|
|
88
|
+
ctx.ui.notify("Applying or publishing has started and cannot be cancelled safely.", "warning");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
complete({ cancelled: true });
|
|
92
|
+
},
|
|
93
|
+
dispose: () => loader.dispose(),
|
|
94
|
+
waitForPending: () => operation,
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
if (interaction.kind === "error") throw interaction.error;
|
|
99
|
+
if (interaction.kind !== "completed") return { kind: "closed" };
|
|
100
|
+
if (interaction.value.cancelled) {
|
|
101
|
+
if (cancelledMessage) ctx.ui.notify(cancelledMessage, "info");
|
|
102
|
+
return { kind: "cancelled" };
|
|
103
|
+
}
|
|
104
|
+
if (interaction.value.error) throw interaction.value.error;
|
|
105
|
+
return routeResult ?? { kind: "failed" };
|
|
118
106
|
}
|
|
119
107
|
|
|
120
108
|
function hasControlCharacter(value: string) {
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: Unsafe key labels must be omitted.
|
|
110
|
+
return /[\u0000-\u001f\u007f-\u009f]/u.test(value);
|
|
123
111
|
}
|