@narumitw/pi-sync 0.49.15 → 0.50.1
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 +49 -16
- package/dist/chunks/attention-widget-Z7G3SYYJ.ts +9 -0
- package/dist/chunks/attention-widget-Z7G3SYYJ.ts.map +7 -0
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
- package/dist/chunks/{chunk-ARN2672F.ts → chunk-4CHTZMEO.ts} +23 -55
- package/dist/chunks/chunk-4CHTZMEO.ts.map +7 -0
- package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
- package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
- package/dist/chunks/{chunk-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-5T442OP3.ts → chunk-C7XY5NF5.ts} +210 -373
- package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
- package/dist/chunks/chunk-CCSN3F47.ts +51 -0
- package/dist/chunks/chunk-CCSN3F47.ts.map +7 -0
- package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
- package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
- package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
- package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
- package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
- package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
- package/dist/chunks/{chunk-WSOBYHIZ.ts → chunk-ETTRJDNP.ts} +4 -4
- package/dist/chunks/chunk-ETTRJDNP.ts.map +7 -0
- package/dist/chunks/{chunk-44LPGQTI.ts → chunk-G4RNQQZS.ts} +9 -7
- package/dist/chunks/chunk-G4RNQQZS.ts.map +7 -0
- package/dist/chunks/{chunk-5LZALPCD.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
- package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-IJ6FJFA5.ts} +9 -9
- package/dist/chunks/chunk-IJ6FJFA5.ts.map +7 -0
- package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
- package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
- package/dist/chunks/chunk-KW7YQEZN.ts +1255 -0
- package/dist/chunks/chunk-KW7YQEZN.ts.map +7 -0
- package/dist/chunks/{chunk-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -8
- package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
- package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
- package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
- package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
- package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
- package/dist/chunks/{chunk-HVUSHMVL.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
- package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
- package/dist/chunks/chunk-S7YBZR42.ts +146 -0
- package/dist/chunks/chunk-S7YBZR42.ts.map +7 -0
- package/dist/chunks/{chunk-GLQLN5GV.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
- package/dist/chunks/chunk-SZWBGPID.ts +57 -0
- package/dist/chunks/chunk-SZWBGPID.ts.map +7 -0
- package/dist/chunks/chunk-T2B5IU74.ts +25 -0
- package/dist/chunks/chunk-T2B5IU74.ts.map +7 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
- package/dist/chunks/chunk-THMF4BVL.ts +18 -0
- package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
- package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
- package/dist/chunks/{file-selection-RKEHALNQ.ts → file-selection-FTTKAOYX.ts} +10 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
- package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-GMVS4PD4.ts} +39 -14
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-FKIBM3GO.ts +22 -0
- package/dist/chunks/manager-ui-R3XPUFFS.ts +1680 -0
- package/dist/chunks/manager-ui-R3XPUFFS.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-D7RBRJNL.ts +21 -0
- package/dist/chunks/{s3-backend-552LXHE4.ts → s3-backend-66O4FGBH.ts} +94 -16
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +7 -0
- package/dist/chunks/{setup-switch-5YDG5YGJ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-IUB6ESEU.ts +89 -0
- package/dist/chunks/setup-wizard-IUB6ESEU.ts.map +7 -0
- package/dist/chunks/{snapshot-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-CST2KL65.ts +20 -0
- package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-LBX3GKCM.ts} +369 -289
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +7 -0
- package/dist/chunks/{sync-state-SRN6YRBK.ts → sync-state-Q2FTXTW6.ts} +6 -6
- package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
- package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
- package/dist/index.ts +476 -341
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +30 -6
- package/package.json +1 -1
- package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
- package/src/backends/backend-identity.ts +40 -0
- package/src/backends/backend-types.ts +81 -0
- package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
- package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
- package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
- package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
- package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
- package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
- package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
- package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
- package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
- package/src/commands/command-execution.ts +330 -0
- package/src/commands/command-handler.ts +201 -0
- package/src/commands/command-types.ts +18 -0
- package/src/{command.ts → commands/command.ts} +2 -1
- package/src/commands/setup-completions.ts +6 -0
- package/src/settings/config.ts +238 -0
- package/src/{settings-management.ts → settings/settings-management.ts} +39 -14
- package/src/settings/settings-store.ts +109 -0
- package/src/settings/settings-types.ts +128 -0
- package/src/settings/settings-validation.ts +443 -0
- package/src/snapshot/session-paths.ts +84 -0
- package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
- package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
- package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
- package/src/snapshot/snapshot-types.ts +38 -0
- package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
- package/src/state/json-file.ts +20 -0
- package/src/{lock.ts → state/lock.ts} +3 -2
- package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
- package/src/state/state-types.ts +20 -0
- package/src/state/sync-state-store.ts +62 -0
- package/src/sync/automatic-sync.ts +103 -0
- package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
- package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
- package/src/sync/signals.ts +10 -0
- package/src/sync/startup-check.ts +128 -0
- package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
- package/src/sync/sync-error-guidance.ts +53 -0
- package/src/sync/sync-inspection.ts +51 -0
- package/src/sync/sync-loaders.ts +54 -0
- package/src/{sync-operations.ts → sync/sync-mutations.ts} +34 -325
- package/src/sync/sync-operations.ts +12 -0
- package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
- package/src/sync/sync-queries.ts +235 -0
- package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
- package/src/sync-extension.ts +64 -708
- package/src/sync.ts +8 -8
- package/src/types.ts +47 -286
- package/src/ui/attention-widget.ts +1 -0
- package/src/ui/automatic-sync-summary.ts +6 -0
- package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
- package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
- package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
- package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
- package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
- package/src/ui/manager-ui.ts +386 -0
- package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
- package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
- package/src/{settings-ui.ts → ui/settings-ui.ts} +17 -13
- package/src/ui/setup/git-ui.ts +293 -0
- package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
- package/src/ui/setup/s3-ui.ts +217 -0
- package/src/ui/setup/setup-actions.ts +127 -0
- package/src/ui/setup/setup-location-ui.ts +167 -0
- package/src/ui/setup/setup-name-ui.ts +34 -0
- package/src/ui/setup/setup-prompts.ts +92 -0
- package/src/ui/setup/setup-review.ts +70 -0
- package/src/ui/setup/setup-switcher.ts +181 -0
- package/src/ui/setup/setup-wizard.ts +39 -0
- package/src/ui/setup/text-input.ts +78 -0
- package/src/ui/setup/webdav-ui.ts +330 -0
- package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
- package/src/ui/sync-attention.ts +187 -0
- package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
- package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
- package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
- package/src/ui/terminal-text.ts +4 -0
- package/dist/chunks/chunk-44LPGQTI.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
- package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
- package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
- package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
- package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
- package/dist/chunks/chunk-E4COSV32.ts +0 -82
- package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
- package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
- package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
- package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
- package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
- package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
- package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
- package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -923
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/sync-attention.ts +0 -100
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-LWPYJAD5.ts.map → manager-result-dispatcher-FKIBM3GO.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-D7RBRJNL.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-SRN6YRBK.ts.map → sync-inspection-CST2KL65.ts.map} +0 -0
- /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
- /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
- /package/src/{config-file.ts → settings/config-file.ts} +0 -0
- /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
- /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
- /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
- /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
- /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
- /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
|
|
4
|
+
// src/backends/git/git-config.ts
|
|
5
|
+
var DEFAULT_GIT_BRANCH = "pi-sync";
|
|
6
|
+
var DEFAULT_GIT_DIRECTORY = "pi-sync";
|
|
7
|
+
function normalizeGitRemote(value) {
|
|
8
|
+
const normalized = normalizeOptionalString(value);
|
|
9
|
+
if (!normalized) return void 0;
|
|
10
|
+
if (hasControlCharacter(normalized) || /\s/u.test(normalized) || normalized.startsWith("-") || normalized.includes("\\")) {
|
|
11
|
+
throw new Error("Invalid pi-sync Git remote.");
|
|
12
|
+
}
|
|
13
|
+
if (!normalized.includes("://") && /^(?:[A-Za-z0-9._-]+@)?(?:\[[0-9A-Fa-f:]+\]|[A-Za-z0-9.-]+):(?!-)[^:].+$/u.test(normalized)) {
|
|
14
|
+
return normalized;
|
|
15
|
+
}
|
|
16
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(normalized) && !normalized.includes("://")) {
|
|
17
|
+
throw new Error("Invalid pi-sync Git remote: unsupported transport or remote-helper syntax.");
|
|
18
|
+
}
|
|
19
|
+
let url;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(normalized);
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error("Invalid pi-sync Git remote: use an SSH or HTTPS remote.");
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol !== "https:" && url.protocol !== "ssh:") {
|
|
26
|
+
throw new Error("Invalid pi-sync Git remote: only SSH and HTTPS are supported.");
|
|
27
|
+
}
|
|
28
|
+
if (url.password || url.protocol === "https:" && url.username) {
|
|
29
|
+
throw new Error("Invalid pi-sync Git remote: URL credentials or userinfo are not allowed.");
|
|
30
|
+
}
|
|
31
|
+
if (url.search || url.hash || !url.hostname || !url.pathname || url.pathname === "/") {
|
|
32
|
+
throw new Error("Invalid pi-sync Git remote.");
|
|
33
|
+
}
|
|
34
|
+
return url.toString();
|
|
35
|
+
}
|
|
36
|
+
function normalizeGitRemoteIdentity(value) {
|
|
37
|
+
const normalized = normalizeGitRemote(value);
|
|
38
|
+
if (!normalized) return "";
|
|
39
|
+
if (!normalized.includes("://")) {
|
|
40
|
+
const match = /^(?<user>[A-Za-z0-9._-]+@)?(?<host>\[[0-9A-Fa-f:]+\]|[A-Za-z0-9.-]+):(?<path>.+)$/u.exec(
|
|
41
|
+
normalized
|
|
42
|
+
);
|
|
43
|
+
if (!match?.groups) return normalized;
|
|
44
|
+
const userAndHost = `${match.groups.user ?? ""}${match.groups.host.toLowerCase()}`;
|
|
45
|
+
const remotePath = match.groups.path.replace(/\/+$/gu, "");
|
|
46
|
+
return remotePath.startsWith("/") ? `scp-absolute://${userAndHost}${remotePath}` : `ssh://${userAndHost}/${remotePath}`;
|
|
47
|
+
}
|
|
48
|
+
const url = new URL(normalized);
|
|
49
|
+
url.hostname = url.hostname.toLowerCase();
|
|
50
|
+
if (url.protocol === "ssh:" && url.port === "22") url.port = "";
|
|
51
|
+
url.pathname = url.pathname.replace(/\/+$/gu, "");
|
|
52
|
+
if (url.protocol === "ssh:") {
|
|
53
|
+
return `ssh://${url.username ? `${url.username}@` : ""}${url.host}${url.pathname}`;
|
|
54
|
+
}
|
|
55
|
+
return url.toString();
|
|
56
|
+
}
|
|
57
|
+
function normalizeGitBranch(value) {
|
|
58
|
+
const branch = normalizeOptionalString(value) ?? DEFAULT_GIT_BRANCH;
|
|
59
|
+
if (branch === "@" || branch.startsWith("-") || branch.startsWith("refs/") || branch.startsWith("/") || branch.endsWith("/") || branch.endsWith(".") || branch.includes("..") || branch.includes("@{") || branch.includes("\\") || hasControlCharacter(branch) || /[ ~^:?*[\]]/u.test(branch) || branch.split("/").some((segment) => !segment || segment.startsWith(".") || segment.endsWith(".lock"))) {
|
|
60
|
+
throw new Error("Invalid pi-sync Git branch.");
|
|
61
|
+
}
|
|
62
|
+
return branch;
|
|
63
|
+
}
|
|
64
|
+
function normalizeGitDirectory(value) {
|
|
65
|
+
if (value?.trim() === "." || value?.trim() === "./") return "./";
|
|
66
|
+
const directory = trimSlashes(normalizeOptionalString(value) ?? DEFAULT_GIT_DIRECTORY);
|
|
67
|
+
if (!directory || directory.startsWith("-") || directory.includes("\\") || hasControlCharacter(directory) || directory.split("/").some((segment) => !segment || segment === "." || segment === ".." || segment === ".git")) {
|
|
68
|
+
throw new Error("Invalid pi-sync Git directory.");
|
|
69
|
+
}
|
|
70
|
+
return directory;
|
|
71
|
+
}
|
|
72
|
+
function validateGitNamespace(value) {
|
|
73
|
+
if (value.length > 256 || value === "." || value === ".." || value.includes("/") || value.includes("\\") || hasControlCharacter(value)) {
|
|
74
|
+
throw new Error("Invalid pi-sync Git namespace.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function normalizeOptionalString(value) {
|
|
78
|
+
if (value !== void 0 && typeof value !== "string") {
|
|
79
|
+
throw new Error("Invalid pi-sync settings: expected a string.");
|
|
80
|
+
}
|
|
81
|
+
const normalized = value?.trim();
|
|
82
|
+
return normalized || void 0;
|
|
83
|
+
}
|
|
84
|
+
function trimSlashes(value) {
|
|
85
|
+
return value.replace(/^\/+|\/+$/gu, "");
|
|
86
|
+
}
|
|
87
|
+
function hasControlCharacter(value) {
|
|
88
|
+
return [...value].some((character) => {
|
|
89
|
+
const code = character.codePointAt(0) ?? 0;
|
|
90
|
+
return code < 32 || code >= 127 && code <= 159;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
normalizeGitRemote,
|
|
96
|
+
normalizeGitRemoteIdentity,
|
|
97
|
+
normalizeGitBranch,
|
|
98
|
+
normalizeGitDirectory,
|
|
99
|
+
validateGitNamespace
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=chunk-TEN2ZBJV.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/backends/git/git-config.ts"],
|
|
4
|
+
"sourcesContent": ["const DEFAULT_GIT_BRANCH = \"pi-sync\";\nconst DEFAULT_GIT_DIRECTORY = \"pi-sync\";\n\nexport function normalizeGitRemote(value: string | undefined) {\n\tconst normalized = normalizeOptionalString(value);\n\tif (!normalized) return undefined;\n\tif (\n\t\thasControlCharacter(normalized) ||\n\t\t/\\s/u.test(normalized) ||\n\t\tnormalized.startsWith(\"-\") ||\n\t\tnormalized.includes(\"\\\\\")\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote.\");\n\t}\n\tif (\n\t\t!normalized.includes(\"://\") &&\n\t\t/^(?:[A-Za-z0-9._-]+@)?(?:\\[[0-9A-Fa-f:]+\\]|[A-Za-z0-9.-]+):(?!-)[^:].+$/u.test(normalized)\n\t) {\n\t\treturn normalized;\n\t}\n\tif (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(normalized) && !normalized.includes(\"://\")) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: unsupported transport or remote-helper syntax.\");\n\t}\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(normalized);\n\t} catch {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: use an SSH or HTTPS remote.\");\n\t}\n\tif (url.protocol !== \"https:\" && url.protocol !== \"ssh:\") {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: only SSH and HTTPS are supported.\");\n\t}\n\tif (url.password || (url.protocol === \"https:\" && url.username)) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: URL credentials or userinfo are not allowed.\");\n\t}\n\tif (url.search || url.hash || !url.hostname || !url.pathname || url.pathname === \"/\") {\n\t\tthrow new Error(\"Invalid pi-sync Git remote.\");\n\t}\n\treturn url.toString();\n}\n\nexport function normalizeGitRemoteIdentity(value: string) {\n\tconst normalized = normalizeGitRemote(value);\n\tif (!normalized) return \"\";\n\tif (!normalized.includes(\"://\")) {\n\t\tconst match =\n\t\t\t/^(?<user>[A-Za-z0-9._-]+@)?(?<host>\\[[0-9A-Fa-f:]+\\]|[A-Za-z0-9.-]+):(?<path>.+)$/u.exec(\n\t\t\t\tnormalized,\n\t\t\t);\n\t\tif (!match?.groups) return normalized;\n\t\tconst userAndHost = `${match.groups.user ?? \"\"}${match.groups.host.toLowerCase()}`;\n\t\tconst remotePath = match.groups.path.replace(/\\/+$/gu, \"\");\n\t\treturn remotePath.startsWith(\"/\")\n\t\t\t? `scp-absolute://${userAndHost}${remotePath}`\n\t\t\t: `ssh://${userAndHost}/${remotePath}`;\n\t}\n\tconst url = new URL(normalized);\n\turl.hostname = url.hostname.toLowerCase();\n\tif (url.protocol === \"ssh:\" && url.port === \"22\") url.port = \"\";\n\turl.pathname = url.pathname.replace(/\\/+$/gu, \"\");\n\tif (url.protocol === \"ssh:\") {\n\t\treturn `ssh://${url.username ? `${url.username}@` : \"\"}${url.host}${url.pathname}`;\n\t}\n\treturn url.toString();\n}\n\nexport function normalizeGitBranch(value: string | undefined) {\n\tconst branch = normalizeOptionalString(value) ?? DEFAULT_GIT_BRANCH;\n\tif (\n\t\tbranch === \"@\" ||\n\t\tbranch.startsWith(\"-\") ||\n\t\tbranch.startsWith(\"refs/\") ||\n\t\tbranch.startsWith(\"/\") ||\n\t\tbranch.endsWith(\"/\") ||\n\t\tbranch.endsWith(\".\") ||\n\t\tbranch.includes(\"..\") ||\n\t\tbranch.includes(\"@{\") ||\n\t\tbranch.includes(\"\\\\\") ||\n\t\thasControlCharacter(branch) ||\n\t\t/[ ~^:?*[\\]]/u.test(branch) ||\n\t\tbranch\n\t\t\t.split(\"/\")\n\t\t\t.some((segment) => !segment || segment.startsWith(\".\") || segment.endsWith(\".lock\"))\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git branch.\");\n\t}\n\treturn branch;\n}\n\nexport function normalizeGitDirectory(value: string | undefined) {\n\tif (value?.trim() === \".\" || value?.trim() === \"./\") return \"./\";\n\tconst directory = trimSlashes(normalizeOptionalString(value) ?? DEFAULT_GIT_DIRECTORY);\n\tif (\n\t\t!directory ||\n\t\tdirectory.startsWith(\"-\") ||\n\t\tdirectory.includes(\"\\\\\") ||\n\t\thasControlCharacter(directory) ||\n\t\tdirectory\n\t\t\t.split(\"/\")\n\t\t\t.some((segment) => !segment || segment === \".\" || segment === \"..\" || segment === \".git\")\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git directory.\");\n\t}\n\treturn directory;\n}\n\nexport function validateGitNamespace(value: string) {\n\tif (\n\t\tvalue.length > 256 ||\n\t\tvalue === \".\" ||\n\t\tvalue === \"..\" ||\n\t\tvalue.includes(\"/\") ||\n\t\tvalue.includes(\"\\\\\") ||\n\t\thasControlCharacter(value)\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git namespace.\");\n\t}\n}\n\nfunction normalizeOptionalString(value: unknown) {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new Error(\"Invalid pi-sync settings: expected a string.\");\n\t}\n\tconst normalized = value?.trim();\n\treturn normalized || undefined;\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/gu, \"\");\n}\n\nfunction hasControlCharacter(value: string) {\n\treturn [...value].some((character) => {\n\t\tconst code = character.codePointAt(0) ?? 0;\n\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t});\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
|
|
4
|
+
// src/snapshot/snapshot-paths.ts
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
function expandHome(value) {
|
|
7
|
+
if (value === "~") return process.env.HOME ?? value;
|
|
8
|
+
if (value.startsWith("~/")) return path.join(process.env.HOME ?? "~", value.slice(2));
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function sessionStorageRoot(root, configuredSessionDir) {
|
|
12
|
+
return configuredSessionDir ? path.resolve(expandHome(configuredSessionDir)) : path.resolve(root, "sessions");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
sessionStorageRoot
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=chunk-THMF4BVL.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/snapshot/snapshot-paths.ts"],
|
|
4
|
+
"sourcesContent": ["import path from \"node:path\";\n\nfunction expandHome(value: string) {\n\tif (value === \"~\") return process.env.HOME ?? value;\n\tif (value.startsWith(\"~/\")) return path.join(process.env.HOME ?? \"~\", value.slice(2));\n\treturn value;\n}\n\nexport function sessionStorageRoot(root: string, configuredSessionDir?: string) {\n\treturn configuredSessionDir\n\t\t? path.resolve(expandHome(configuredSessionDir))\n\t\t: path.resolve(root, \"sessions\");\n}\n"],
|
|
5
|
+
"mappings": ";;;;AAAA,OAAO,UAAU;AAEjB,SAAS,WAAW,OAAe;AAClC,MAAI,UAAU,IAAK,QAAO,QAAQ,IAAI,QAAQ;AAC9C,MAAI,MAAM,WAAW,IAAI,EAAG,QAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,MAAM,CAAC,CAAC;AACpF,SAAO;AACR;AAEO,SAAS,mBAAmB,MAAc,sBAA+B;AAC/E,SAAO,uBACJ,KAAK,QAAQ,WAAW,oBAAoB,CAAC,IAC7C,KAAK,QAAQ,MAAM,UAAU;AACjC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
|
|
4
|
+
// src/ui/automatic-sync-summary.ts
|
|
5
|
+
function automaticSyncSummary(enabled) {
|
|
6
|
+
return enabled ? "On (startup check; shutdown pushes selected content if sessions included)" : "Off";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
automaticSyncSummary
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=chunk-Z4DQF6L3.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/automatic-sync-summary.ts"],
|
|
4
|
+
"sourcesContent": ["/** Keep the setting's automatic transfer scope visible in every setup summary. */\nexport function automaticSyncSummary(enabled: boolean) {\n\treturn enabled\n\t\t? \"On (startup check; shutdown pushes selected content if sessions included)\"\n\t\t: \"Off\";\n}\n"],
|
|
5
|
+
"mappings": ";;;;AACO,SAAS,qBAAqB,SAAkB;AACtD,SAAO,UACJ,8EACA;AACJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,107 +1,18 @@
|
|
|
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
|
|
|
4
|
-
// src/
|
|
5
|
-
var DEFAULT_GIT_BRANCH = "pi-sync";
|
|
6
|
-
var DEFAULT_GIT_DIRECTORY = "pi-sync";
|
|
7
|
-
function normalizeGitRemote(value) {
|
|
8
|
-
const normalized = normalizeOptionalString(value);
|
|
9
|
-
if (!normalized) return void 0;
|
|
10
|
-
if (hasControlCharacter(normalized) || /\s/u.test(normalized) || normalized.startsWith("-") || normalized.includes("\\")) {
|
|
11
|
-
throw new Error("Invalid pi-sync Git remote.");
|
|
12
|
-
}
|
|
13
|
-
if (!normalized.includes("://") && /^(?:[A-Za-z0-9._-]+@)?(?:\[[0-9A-Fa-f:]+\]|[A-Za-z0-9.-]+):(?!-)[^:].+$/u.test(normalized)) {
|
|
14
|
-
return normalized;
|
|
15
|
-
}
|
|
16
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(normalized) && !normalized.includes("://")) {
|
|
17
|
-
throw new Error("Invalid pi-sync Git remote: unsupported transport or remote-helper syntax.");
|
|
18
|
-
}
|
|
19
|
-
let url;
|
|
20
|
-
try {
|
|
21
|
-
url = new URL(normalized);
|
|
22
|
-
} catch {
|
|
23
|
-
throw new Error("Invalid pi-sync Git remote: use an SSH or HTTPS remote.");
|
|
24
|
-
}
|
|
25
|
-
if (url.protocol !== "https:" && url.protocol !== "ssh:") {
|
|
26
|
-
throw new Error("Invalid pi-sync Git remote: only SSH and HTTPS are supported.");
|
|
27
|
-
}
|
|
28
|
-
if (url.password || url.protocol === "https:" && url.username) {
|
|
29
|
-
throw new Error("Invalid pi-sync Git remote: URL credentials or userinfo are not allowed.");
|
|
30
|
-
}
|
|
31
|
-
if (url.search || url.hash || !url.hostname || !url.pathname || url.pathname === "/") {
|
|
32
|
-
throw new Error("Invalid pi-sync Git remote.");
|
|
33
|
-
}
|
|
34
|
-
return url.toString();
|
|
35
|
-
}
|
|
36
|
-
function normalizeGitRemoteIdentity(value) {
|
|
37
|
-
const normalized = normalizeGitRemote(value);
|
|
38
|
-
if (!normalized) return "";
|
|
39
|
-
if (!normalized.includes("://")) {
|
|
40
|
-
const match = /^(?<user>[A-Za-z0-9._-]+@)?(?<host>\[[0-9A-Fa-f:]+\]|[A-Za-z0-9.-]+):(?<path>.+)$/u.exec(
|
|
41
|
-
normalized
|
|
42
|
-
);
|
|
43
|
-
if (!match?.groups) return normalized;
|
|
44
|
-
const userAndHost = `${match.groups.user ?? ""}${match.groups.host.toLowerCase()}`;
|
|
45
|
-
const remotePath = match.groups.path.replace(/\/+$/gu, "");
|
|
46
|
-
return remotePath.startsWith("/") ? `scp-absolute://${userAndHost}${remotePath}` : `ssh://${userAndHost}/${remotePath}`;
|
|
47
|
-
}
|
|
48
|
-
const url = new URL(normalized);
|
|
49
|
-
url.hostname = url.hostname.toLowerCase();
|
|
50
|
-
if (url.protocol === "ssh:" && url.port === "22") url.port = "";
|
|
51
|
-
url.pathname = url.pathname.replace(/\/+$/gu, "");
|
|
52
|
-
if (url.protocol === "ssh:") {
|
|
53
|
-
return `ssh://${url.username ? `${url.username}@` : ""}${url.host}${url.pathname}`;
|
|
54
|
-
}
|
|
55
|
-
return url.toString();
|
|
56
|
-
}
|
|
57
|
-
function normalizeGitBranch(value) {
|
|
58
|
-
const branch = normalizeOptionalString(value) ?? DEFAULT_GIT_BRANCH;
|
|
59
|
-
if (branch === "@" || branch.startsWith("-") || branch.startsWith("refs/") || branch.startsWith("/") || branch.endsWith("/") || branch.endsWith(".") || branch.includes("..") || branch.includes("@{") || branch.includes("\\") || hasControlCharacter(branch) || /[ ~^:?*[\]]/u.test(branch) || branch.split("/").some((segment) => !segment || segment.startsWith(".") || segment.endsWith(".lock"))) {
|
|
60
|
-
throw new Error("Invalid pi-sync Git branch.");
|
|
61
|
-
}
|
|
62
|
-
return branch;
|
|
63
|
-
}
|
|
64
|
-
function normalizeGitDirectory(value) {
|
|
65
|
-
const directory = trimSlashes(normalizeOptionalString(value) ?? DEFAULT_GIT_DIRECTORY);
|
|
66
|
-
if (!directory || directory.startsWith("-") || directory.includes("\\") || hasControlCharacter(directory) || directory.split("/").some((segment) => !segment || segment === "." || segment === ".." || segment === ".git")) {
|
|
67
|
-
throw new Error("Invalid pi-sync Git directory.");
|
|
68
|
-
}
|
|
69
|
-
return directory;
|
|
70
|
-
}
|
|
71
|
-
function validateGitNamespace(value) {
|
|
72
|
-
if (value.length > 256 || value === "." || value === ".." || value.includes("/") || value.includes("\\") || hasControlCharacter(value)) {
|
|
73
|
-
throw new Error("Invalid pi-sync Git namespace.");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function normalizeOptionalString(value) {
|
|
77
|
-
if (value !== void 0 && typeof value !== "string") {
|
|
78
|
-
throw new Error("Invalid pi-sync settings: expected a string.");
|
|
79
|
-
}
|
|
80
|
-
const normalized = value?.trim();
|
|
81
|
-
return normalized || void 0;
|
|
82
|
-
}
|
|
83
|
-
function trimSlashes(value) {
|
|
84
|
-
return value.replace(/^\/+|\/+$/gu, "");
|
|
85
|
-
}
|
|
86
|
-
function hasControlCharacter(value) {
|
|
87
|
-
return [...value].some((character) => {
|
|
88
|
-
const code = character.codePointAt(0) ?? 0;
|
|
89
|
-
return code < 32 || code >= 127 && code <= 159;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// src/state-directory.ts
|
|
4
|
+
// src/state/state-directory.ts
|
|
94
5
|
import { lstatSync } from "node:fs";
|
|
95
6
|
import fs from "node:fs/promises";
|
|
96
7
|
import path from "node:path";
|
|
97
8
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
98
9
|
import lockfile from "proper-lockfile";
|
|
99
10
|
|
|
100
|
-
// src/lock-policy.ts
|
|
11
|
+
// src/state/lock-policy.ts
|
|
101
12
|
var LOCK_GUARD_STALE_MS = 3e4;
|
|
102
13
|
var LOCK_GUARD_UPDATE_MS = 1e4;
|
|
103
14
|
|
|
104
|
-
// src/lockfile-fs.ts
|
|
15
|
+
// src/state/lockfile-fs.ts
|
|
105
16
|
import {
|
|
106
17
|
mkdir,
|
|
107
18
|
mkdirSync,
|
|
@@ -127,7 +38,7 @@ var LOCKFILE_FS_ADAPTER = {
|
|
|
127
38
|
utimesSync
|
|
128
39
|
};
|
|
129
40
|
|
|
130
|
-
// src/state-directory.ts
|
|
41
|
+
// src/state/state-directory.ts
|
|
131
42
|
var CANONICAL_DIRECTORY_NAME = "pi-sync";
|
|
132
43
|
var LEGACY_DIRECTORY_NAME = ".pisync";
|
|
133
44
|
var MIGRATION_LOCK_NAME = ".pi-sync-state-migration.lock";
|
|
@@ -325,11 +236,6 @@ async function pathExists(filePath) {
|
|
|
325
236
|
}
|
|
326
237
|
|
|
327
238
|
export {
|
|
328
|
-
normalizeGitRemote,
|
|
329
|
-
normalizeGitRemoteIdentity,
|
|
330
|
-
normalizeGitBranch,
|
|
331
|
-
normalizeGitDirectory,
|
|
332
|
-
validateGitNamespace,
|
|
333
239
|
LOCK_GUARD_STALE_MS,
|
|
334
240
|
LOCK_GUARD_UPDATE_MS,
|
|
335
241
|
LOCKFILE_FS_ADAPTER,
|
|
@@ -338,4 +244,4 @@ export {
|
|
|
338
244
|
withStateDirectoryAccess,
|
|
339
245
|
migrateLegacyStateDirectory
|
|
340
246
|
};
|
|
341
|
-
//# sourceMappingURL=chunk-
|
|
247
|
+
//# sourceMappingURL=chunk-ZI5MXMEX.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/state/state-directory.ts", "../../src/state/lock-policy.ts", "../../src/state/lockfile-fs.ts"],
|
|
4
|
+
"sourcesContent": ["import { lstatSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\nimport lockfile from \"proper-lockfile\";\nimport { LOCK_GUARD_STALE_MS } from \"./lock-policy.js\";\nimport { LOCKFILE_FS_ADAPTER } from \"./lockfile-fs.js\";\n\nconst CANONICAL_DIRECTORY_NAME = \"pi-sync\";\nconst LEGACY_DIRECTORY_NAME = \".pisync\";\nconst MIGRATION_LOCK_NAME = \".pi-sync-state-migration.lock\";\nconst MIGRATION_LOCK_STALE_MS = 30_000;\nconst MIGRATION_LOCK_UPDATE_MS = 10_000;\n\nexport type StateDirectoryPreparation =\n\t| { status: \"ready\" }\n\t| { status: \"migrated\"; message: string }\n\t| { status: \"deferred\"; message: string };\n\ninterface StateDirectoryGuard {\n\trelease: () => Promise<void>;\n\tthrowIfCompromised: () => void;\n}\n\ninterface SharedStateDirectoryGuard {\n\tguard: Promise<StateDirectoryGuard>;\n\tusers: number;\n\tclosing?: Promise<void>;\n}\n\nconst sharedStateDirectoryGuards = new Map<string, SharedStateDirectoryGuard>();\n\nexport function stateDir() {\n\tconst roots = inspectStateRoots();\n\tif (roots.canonical) return canonicalStateDir();\n\tif (roots.legacy) return legacyStateDir();\n\treturn canonicalStateDir();\n}\n\nexport function legacyStateDir() {\n\treturn path.join(getAgentDir(), LEGACY_DIRECTORY_NAME);\n}\n\nexport function stateDirectoryMigrationNotice() {\n\tconst roots = inspectStateRoots();\n\tif (!roots.legacy) return undefined;\n\treturn \"Legacy pi-sync state is still stored in .pisync. Close other Pi sessions, then run /sync migrate-state to move it to pi-sync/.\";\n}\n\nexport async function withStateDirectoryAccess<T>(fn: () => Promise<T>): Promise<T> {\n\tconst roots = inspectStateRoots();\n\tif (!roots.legacy) return fn();\n\treturn runWithStateDirectoryGuard(await acquireSharedStateDirectoryGuard(), fn);\n}\n\nexport async function migrateLegacyStateDirectory(): Promise<StateDirectoryPreparation> {\n\tconst initial = inspectStateRoots();\n\tif (initial.canonical || !initial.legacy) return { status: \"ready\" };\n\n\tlet guard: StateDirectoryGuard;\n\ttry {\n\t\tguard = await acquireStateDirectoryGuard();\n\t} catch (error) {\n\t\tif (!isLockHeldError(error)) throw error;\n\t\treturn {\n\t\t\tstatus: \"deferred\",\n\t\t\tmessage:\n\t\t\t\t\"pi-sync state migration was deferred because another state user is active. Close other Pi sessions and retry.\",\n\t\t};\n\t}\n\treturn runWithStateDirectoryGuard(guard, async () => {\n\t\tconst roots = inspectStateRoots();\n\t\tif (roots.canonical || !roots.legacy) return { status: \"ready\" };\n\n\t\tconst legacyLock = path.join(legacyStateDir(), \"lock\");\n\t\tconst legacyGuardHeld = await lockfile.check(legacyLock, {\n\t\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\t\tlockfilePath: `${legacyLock}.guard`,\n\t\t\trealpath: false,\n\t\t\tstale: LOCK_GUARD_STALE_MS,\n\t\t});\n\t\tif (legacyGuardHeld || (await pathExists(legacyLock))) {\n\t\t\treturn {\n\t\t\t\tstatus: \"deferred\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"pi-sync state migration was deferred because the legacy directory is busy. Close other Pi sessions, clear any confirmed stale sync lock, and retry.\",\n\t\t\t};\n\t\t}\n\t\tguard.throwIfCompromised();\n\t\tawait fs.rename(legacyStateDir(), canonicalStateDir());\n\t\tguard.throwIfCompromised();\n\t\tinspectStateRoots();\n\t\treturn {\n\t\t\tstatus: \"migrated\",\n\t\t\tmessage: `Migrated pi-sync state from ${legacyStateDir()} to ${canonicalStateDir()}.`,\n\t\t};\n\t});\n}\n\nasync function acquireSharedStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n\tconst key = migrationLockPath();\n\tfor (;;) {\n\t\tlet shared = sharedStateDirectoryGuards.get(key);\n\t\tif (shared?.closing) {\n\t\t\tawait shared.closing;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!shared) {\n\t\t\tshared = { guard: acquireStateDirectoryGuard(), users: 0 };\n\t\t\tsharedStateDirectoryGuards.set(key, shared);\n\t\t}\n\t\tshared.users += 1;\n\t\tlet guard: StateDirectoryGuard;\n\t\ttry {\n\t\t\tguard = await shared.guard;\n\t\t} catch (error) {\n\t\t\tif (sharedStateDirectoryGuards.get(key) === shared) {\n\t\t\t\tsharedStateDirectoryGuards.delete(key);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tlet released = false;\n\t\treturn {\n\t\t\tthrowIfCompromised: guard.throwIfCompromised,\n\t\t\trelease: async () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tshared.users -= 1;\n\t\t\t\tif (shared.users > 0) return;\n\t\t\t\tconst closing = guard.release();\n\t\t\t\tshared.closing = closing;\n\t\t\t\ttry {\n\t\t\t\t\tawait closing;\n\t\t\t\t} finally {\n\t\t\t\t\tif (sharedStateDirectoryGuards.get(key) === shared) {\n\t\t\t\t\t\tsharedStateDirectoryGuards.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n}\n\nasync function acquireStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n\tlet compromisedError: Error | undefined;\n\tconst release = await lockfile.lock(getAgentDir(), {\n\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\tlockfilePath: migrationLockPath(),\n\t\trealpath: false,\n\t\tstale: MIGRATION_LOCK_STALE_MS,\n\t\tupdate: MIGRATION_LOCK_UPDATE_MS,\n\t\tretries: { retries: 20, minTimeout: 10, maxTimeout: 50 },\n\t\tonCompromised: (error) => {\n\t\t\tcompromisedError = error;\n\t\t},\n\t});\n\treturn {\n\t\trelease,\n\t\tthrowIfCompromised: () => {\n\t\t\tif (compromisedError) throw compromisedError;\n\t\t},\n\t};\n}\n\nasync function runWithStateDirectoryGuard<T>(guard: StateDirectoryGuard, fn: () => Promise<T>) {\n\tlet result: T | undefined;\n\tlet failed = false;\n\tlet failure: unknown;\n\ttry {\n\t\tguard.throwIfCompromised();\n\t\tresult = await fn();\n\t\tguard.throwIfCompromised();\n\t} catch (error) {\n\t\tfailed = true;\n\t\tfailure = error;\n\t}\n\ttry {\n\t\tawait guard.release();\n\t} catch (error) {\n\t\tif (!failed) {\n\t\t\tfailed = true;\n\t\t\tfailure = error;\n\t\t}\n\t}\n\tif (failed) throw failure;\n\treturn result as T;\n}\n\nfunction isLockHeldError(error: unknown) {\n\treturn (error as NodeJS.ErrnoException).code === \"ELOCKED\";\n}\n\nfunction canonicalStateDir() {\n\treturn path.join(getAgentDir(), CANONICAL_DIRECTORY_NAME);\n}\n\nfunction migrationLockPath() {\n\treturn path.join(getAgentDir(), MIGRATION_LOCK_NAME);\n}\n\nfunction inspectStateRoots() {\n\tconst canonical = isDirectoryRoot(canonicalStateDir(), \"canonical\");\n\tconst legacy = isDirectoryRoot(legacyStateDir(), \"legacy\");\n\tif (canonical && legacy) {\n\t\tthrow new Error(\n\t\t\t`Both legacy ${legacyStateDir()} and canonical ${canonicalStateDir()} pi-sync state directories exist. Close all Pi sessions and reconcile the directories manually; pi-sync will not merge or delete either directory.`,\n\t\t);\n\t}\n\treturn { canonical, legacy };\n}\n\nfunction isDirectoryRoot(directory: string, label: string) {\n\ttry {\n\t\tconst entry = lstatSync(directory);\n\t\tif (entry.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to use ${label} pi-sync state directory symbolic link: ${directory}`,\n\t\t\t);\n\t\t}\n\t\tif (!entry.isDirectory()) {\n\t\t\tthrow new Error(`${label} pi-sync state path is not a directory: ${directory}`);\n\t\t}\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n\nasync function pathExists(filePath: string) {\n\ttry {\n\t\tawait fs.lstat(filePath);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n", "export const LOCK_GUARD_STALE_MS = 30_000;\nexport const LOCK_GUARD_UPDATE_MS = 10_000;\n", "import {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n} from \"node:fs\";\n\nexport const LOCKFILE_FS_ADAPTER = {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
updateSyncSetup
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LCRI3ABW.ts";
|
|
6
6
|
import {
|
|
7
|
-
agentDir,
|
|
8
7
|
loadConfig,
|
|
9
8
|
localConfigPath
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-C7XY5NF5.ts";
|
|
10
|
+
import "./chunk-6LP3MCR2.ts";
|
|
11
|
+
import "./chunk-TEN2ZBJV.ts";
|
|
12
|
+
import {
|
|
13
|
+
agentDir
|
|
14
|
+
} from "./chunk-T3HH3UEJ.ts";
|
|
12
15
|
import {
|
|
13
16
|
BUILT_IN_SYNC_ROOTS,
|
|
14
17
|
isSafeCustomIncludePath,
|
|
15
18
|
normalizeSyncInclude,
|
|
16
19
|
syncIncludeSelection
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-JAAKLL6M.ts";
|
|
18
21
|
|
|
19
|
-
// src/file-selection.ts
|
|
22
|
+
// src/ui/file-selection.ts
|
|
20
23
|
import fs from "node:fs/promises";
|
|
21
24
|
import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
|
|
22
25
|
var BUILT_IN_PREFIX = "builtin:";
|
|
@@ -287,4 +290,4 @@ function safeTerminalText(value) {
|
|
|
287
290
|
export {
|
|
288
291
|
showFileSelection
|
|
289
292
|
};
|
|
290
|
-
//# sourceMappingURL=file-selection-
|
|
293
|
+
//# sourceMappingURL=file-selection-FTTKAOYX.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/file-selection.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs/promises\";\nimport type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { loadConfig } from \"../settings/config.js\";\nimport { localConfigPath } from \"../settings/config-file.js\";\nimport { updateSyncSetup } from \"../settings/settings-management.js\";\nimport { agentDir } from \"../snapshot/session-paths.js\";\nimport {\n\tBUILT_IN_SYNC_ROOTS,\n\tisSafeCustomIncludePath,\n\tnormalizeSyncInclude,\n\tsyncIncludeSelection,\n} from \"../sync/sync-policy.js\";\n\nconst BUILT_IN_PREFIX = \"builtin:\";\nconst CUSTOM_PREFIX = \"custom:\";\nconst SESSIONS_ID = \"sessions\";\nconst ADD_CUSTOM_ID = \"add-custom\";\n\ninterface SelectionDraft {\n\tbuiltIns: Set<string>;\n\tcustom: Set<string>;\n\tsessions: boolean;\n}\n\nexport async function showFileSelection(\n\tctx: ExtensionCommandContext,\n\tsetupName?: string,\n\tsignal?: AbortSignal,\n) {\n\tconst config = await loadConfig(setupName);\n\tif (signal?.aborted) return;\n\tconst selection = syncIncludeSelection(config.include);\n\tconst original: SelectionDraft = {\n\t\tbuiltIns: new Set(selection.builtIns),\n\t\tcustom: new Set(selection.custom),\n\t\tsessions: selection.sessions,\n\t};\n\tconst draft = cloneDraft(original);\n\tconst customCandidates = await listCustomCandidates(draft.custom);\n\n\tif (ctx.mode !== \"tui\") {\n\t\tctx.ui.notify(\n\t\t\t[\n\t\t\t\t`pi-sync included content for sync setup ${safeTerminalText(config.setupName)}:`,\n\t\t\t\t`include: ${config.include.map(safeTerminalText).join(\", \") || \"none\"}`,\n\t\t\t\t`Edit sync.include in ${safeTerminalText(localConfigPath())}.`,\n\t\t\t].join(\"\\n\"),\n\t\t\t\"info\",\n\t\t);\n\t\treturn;\n\t}\n\n\twhile (!signal?.aborted) {\n\t\tawait showDraftEditor(ctx, config.setupName, draft, customCandidates, signal);\n\t\tif (signal?.aborted || sameDraft(original, draft)) return;\n\t\tconst choice = await showDraftReview(ctx, original, draft, signal);\n\t\tif (signal?.aborted) return;\n\t\tif (choice === \"Continue editing\") continue;\n\t\tif (choice !== \"Save changes\") {\n\t\t\tctx.ui.notify(\"Included-content changes discarded.\", \"info\");\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (!original.sessions && draft.sessions) {\n\t\t\t\tconst acknowledged = await ctx.ui.confirm(\n\t\t\t\t\t\"Include session conversations?\",\n\t\t\t\t\t\"Session JSONL may contain prompts, tool output, file paths, images, and secrets. Continue only with storage you trust.\",\n\t\t\t\t\t{ signal },\n\t\t\t\t);\n\t\t\t\tif (signal?.aborted) return;\n\t\t\t\tif (!acknowledged) {\n\t\t\t\t\tctx.ui.notify(\"Session inclusion was not saved.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst include = [\n\t\t\t\t...BUILT_IN_SYNC_ROOTS.filter((candidate) => draft.builtIns.has(candidate)),\n\t\t\t\t...draft.custom,\n\t\t\t\t...(draft.sessions ? [\"sessions\"] : []),\n\t\t\t];\n\t\t\tif (signal?.aborted) return;\n\t\t\tawait updateSyncSetup(\n\t\t\t\tconfig.setupName,\n\t\t\t\t(setup) => ({\n\t\t\t\t\t...setup,\n\t\t\t\t\tsync: { ...setup.sync, include },\n\t\t\t\t}),\n\t\t\t\t{ expectedInclude: config.include, signal },\n\t\t\t);\n\t\t\tif (signal?.aborted) return;\n\t\t\tctx.ui.notify(\n\t\t\t\t`Saved included content for sync setup \u201C${safeTerminalText(config.setupName)}\u201D. It applies to the next manual or automatic sync.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted) return;\n\t\t\tctx.ui.notify(\n\t\t\t\t`Could not save pi-sync file selection: ${safeTerminalText(error instanceof Error ? error.message : String(error))}`,\n\t\t\t\t\"error\",\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n}\n\nasync function showDraftEditor(\n\tctx: ExtensionCommandContext,\n\tsetupName: string,\n\tdraft: SelectionDraft,\n\tcustomCandidates: string[],\n\tsignal?: AbortSignal,\n) {\n\tconst menu = defineMenu<undefined, \"editor\", \"toggle\" | \"addCustom\", ExtensionCommandContext>({\n\t\tstart: \"editor\",\n\t\tscreens: {\n\t\t\teditor: () => ({\n\t\t\t\tkind: \"multiSelect\",\n\t\t\t\ttitle: `Included Content \u00B7 ${safeTerminalText(setupName)}`,\n\t\t\t\tlines: [\"Draft only \u00B7 leaving this screen opens Save, Discard, or Continue editing.\"],\n\t\t\t\tviewportSize: 12,\n\t\t\t\titems: [\n\t\t\t\t\t...BUILT_IN_SYNC_ROOTS.map((relativePath) => ({\n\t\t\t\t\t\tid: `${BUILT_IN_PREFIX}${relativePath}`,\n\t\t\t\t\t\tlabel: relativePath,\n\t\t\t\t\t\tdescription: relativePath.includes(\".\")\n\t\t\t\t\t\t\t? `Sync the top-level ${relativePath} file when present.`\n\t\t\t\t\t\t\t: `Recursively sync every safe file under ${relativePath}/.`,\n\t\t\t\t\t\tselected: draft.builtIns.has(relativePath),\n\t\t\t\t\t})),\n\t\t\t\t\t...customCandidates.map((relativePath) => ({\n\t\t\t\t\t\tid: `${CUSTOM_PREFIX}${relativePath}`,\n\t\t\t\t\t\tlabel: safeTerminalText(relativePath),\n\t\t\t\t\t\tdescription: \"Additional safe agent-relative file or directory.\",\n\t\t\t\t\t\tselected: draft.custom.has(relativePath),\n\t\t\t\t\t})),\n\t\t\t\t\t{\n\t\t\t\t\t\tid: SESSIONS_ID,\n\t\t\t\t\t\tlabel: \"sessions\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Session JSONL may contain prompts, tool output, paths, images, and secrets. Sync only to storage you trust.\",\n\t\t\t\t\t\tselected: draft.sessions,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\taction: \"toggle\",\n\t\t\t\tactions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: ADD_CUSTOM_ID,\n\t\t\t\t\t\tlabel: \"Add custom path\u2026\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Include an agent-relative file or directory even when it exists only remotely.\",\n\t\t\t\t\t\taction: \"addCustom\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t\tdoneLabel: \"Review changes\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\ttoggle: async ({ itemId, selected }) => {\n\t\t\t\tupdateDraft(draft, itemId, selected === true);\n\t\t\t\treturn { kind: \"stay\" };\n\t\t\t},\n\t\t\taddCustom: async ({ ctx: actionCtx, signal: actionSignal }) => {\n\t\t\t\tconst entered = await actionCtx.ui.input(\n\t\t\t\t\t\"Add included content\",\n\t\t\t\t\t\"Agent-relative path, for example custom.toml or snippets\",\n\t\t\t\t\t{ signal: actionSignal },\n\t\t\t\t);\n\t\t\t\tif (actionSignal.aborted) return { kind: \"stay\" };\n\t\t\t\tconst requested = entered?.trim();\n\t\t\t\tif (!requested) return { kind: \"stay\" };\n\t\t\t\tconst existing = customCandidates.find(\n\t\t\t\t\t(candidate) => candidate.toLowerCase() === requested.toLowerCase(),\n\t\t\t\t);\n\t\t\t\tconst relativePath = existing ?? requested;\n\t\t\t\tif (draft.custom.has(relativePath)) return { kind: \"stay\" };\n\t\t\t\ttry {\n\t\t\t\t\tif (!isSafeCustomIncludePath(relativePath)) {\n\t\t\t\t\t\tthrow new Error(\"Enter a safe agent-relative file or directory path.\");\n\t\t\t\t\t}\n\t\t\t\t\tnormalizeSyncInclude([\n\t\t\t\t\t\t...draft.builtIns,\n\t\t\t\t\t\t...draft.custom,\n\t\t\t\t\t\t...(draft.sessions ? [\"sessions\"] : []),\n\t\t\t\t\t\trelativePath,\n\t\t\t\t\t]);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (actionSignal.aborted) return { kind: \"stay\" };\n\t\t\t\t\tactionCtx.ui.notify(\n\t\t\t\t\t\t`Could not add included content: ${safeTerminalText(error instanceof Error ? error.message : String(error))}`,\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t);\n\t\t\t\t\treturn { kind: \"stay\" };\n\t\t\t\t}\n\t\t\t\tif (!existing) {\n\t\t\t\t\tcustomCandidates.push(relativePath);\n\t\t\t\t\tcustomCandidates.sort((left, right) => left.localeCompare(right));\n\t\t\t\t}\n\t\t\t\tdraft.custom.add(relativePath);\n\t\t\t\treturn { kind: \"stay\" };\n\t\t\t},\n\t\t},\n\t});\n\tawait runMenu(ctx, menu, {\n\t\tgetState: () => undefined,\n\t\tsignal,\n\t\tisCurrent: () => !signal?.aborted,\n\t});\n}\n\nasync function showDraftReview(\n\tctx: ExtensionCommandContext,\n\toriginal: SelectionDraft,\n\tdraft: SelectionDraft,\n\tsignal?: AbortSignal,\n) {\n\tlet choice: \"Save changes\" | \"Discard changes\" | \"Continue editing\" | undefined;\n\tconst menu = defineMenu<undefined, \"review\", \"choose\", ExtensionCommandContext>({\n\t\tstart: \"review\",\n\t\tscreens: {\n\t\t\treview: () => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: \"Review included-content changes\",\n\t\t\t\tlines: formatDraftPreview(original, draft).split(\"\\n\").slice(2),\n\t\t\t\titems: [\n\t\t\t\t\t{ id: \"save\", label: \"Save changes\", action: \"choose\" },\n\t\t\t\t\t{ id: \"discard\", label: \"Discard changes\", action: \"choose\" },\n\t\t\t\t\t{ id: \"continue\", label: \"Continue editing\", action: \"choose\" },\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\tchoose: async ({ itemId }) => {\n\t\t\t\tchoice =\n\t\t\t\t\titemId === \"save\"\n\t\t\t\t\t\t? \"Save changes\"\n\t\t\t\t\t\t: itemId === \"continue\"\n\t\t\t\t\t\t\t? \"Continue editing\"\n\t\t\t\t\t\t\t: \"Discard changes\";\n\t\t\t\treturn { kind: \"close\" };\n\t\t\t},\n\t\t},\n\t});\n\tawait runMenu(ctx, menu, {\n\t\tgetState: () => undefined,\n\t\tsignal,\n\t\tisCurrent: () => !signal?.aborted,\n\t});\n\treturn choice;\n}\n\nfunction updateDraft(draft: SelectionDraft, id: string, included: boolean) {\n\tif (id.startsWith(BUILT_IN_PREFIX))\n\t\treturn updateSet(draft.builtIns, id.slice(BUILT_IN_PREFIX.length), included);\n\tif (id.startsWith(CUSTOM_PREFIX))\n\t\treturn updateSet(draft.custom, id.slice(CUSTOM_PREFIX.length), included);\n\tif (id === SESSIONS_ID) {\n\t\tdraft.sessions = included;\n\t\treturn;\n\t}\n\tthrow new Error(`Unknown file selection: ${id}`);\n}\n\nfunction updateSet(set: Set<string>, value: string, included: boolean) {\n\tif (included) set.add(value);\n\telse set.delete(value);\n}\n\nfunction formatDraftPreview(original: SelectionDraft, draft: SelectionDraft) {\n\tconst lines = [\"Review included-content changes\", \"\"];\n\tfor (const item of new Set([\n\t\t...original.builtIns,\n\t\t...draft.builtIns,\n\t\t...original.custom,\n\t\t...draft.custom,\n\t])) {\n\t\tconst before = original.builtIns.has(item) || original.custom.has(item);\n\t\tconst after = draft.builtIns.has(item) || draft.custom.has(item);\n\t\tif (before !== after) lines.push(`${after ? \"Include\" : \"Exclude\"}: ${safeTerminalText(item)}`);\n\t}\n\tif (original.sessions !== draft.sessions)\n\t\tlines.push(`${draft.sessions ? \"Include\" : \"Exclude\"}: sessions`);\n\tlines.push(\"\", \"Saving does not start a network sync.\");\n\treturn lines.join(\"\\n\");\n}\n\nasync function listCustomCandidates(configured: Set<string>) {\n\tconst candidates = new Map([...configured].map((item) => [item.toLowerCase(), item]));\n\ttry {\n\t\tfor (const entry of await fs.readdir(agentDir(), { withFileTypes: true })) {\n\t\t\tif ((!entry.isFile() && !entry.isDirectory()) || !isSafeCustomIncludePath(entry.name))\n\t\t\t\tcontinue;\n\t\t\tif (!candidates.has(entry.name.toLowerCase()))\n\t\t\t\tcandidates.set(entry.name.toLowerCase(), entry.name);\n\t\t}\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t}\n\treturn [...candidates.values()].sort((left, right) => left.localeCompare(right));\n}\n\nfunction cloneDraft(value: SelectionDraft): SelectionDraft {\n\treturn {\n\t\tbuiltIns: new Set(value.builtIns),\n\t\tcustom: new Set(value.custom),\n\t\tsessions: value.sessions,\n\t};\n}\n\nfunction sameDraft(left: SelectionDraft, right: SelectionDraft) {\n\treturn (\n\t\tleft.sessions === right.sessions &&\n\t\tsameSet(left.builtIns, right.builtIns) &&\n\t\tsameSet(left.custom, right.custom)\n\t);\n}\n\nfunction sameSet(left: Set<string>, right: Set<string>) {\n\treturn left.size === right.size && [...left].every((item) => right.has(item));\n}\n\nfunction safeTerminalText(value: string) {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.\n\treturn value.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \"?\");\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,QAAQ;AAEf,SAAS,YAAY,eAAe;AAYpC,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAQtB,eAAsB,kBACrB,KACA,WACA,QACC;AACD,QAAM,SAAS,MAAM,WAAW,SAAS;AACzC,MAAI,QAAQ,QAAS;AACrB,QAAM,YAAY,qBAAqB,OAAO,OAAO;AACrD,QAAM,WAA2B;AAAA,IAChC,UAAU,IAAI,IAAI,UAAU,QAAQ;AAAA,IACpC,QAAQ,IAAI,IAAI,UAAU,MAAM;AAAA,IAChC,UAAU,UAAU;AAAA,EACrB;AACA,QAAM,QAAQ,WAAW,QAAQ;AACjC,QAAM,mBAAmB,MAAM,qBAAqB,MAAM,MAAM;AAEhE,MAAI,IAAI,SAAS,OAAO;AACvB,QAAI,GAAG;AAAA,MACN;AAAA,QACC,2CAA2C,iBAAiB,OAAO,SAAS,CAAC;AAAA,QAC7E,YAAY,OAAO,QAAQ,IAAI,gBAAgB,EAAE,KAAK,IAAI,KAAK,MAAM;AAAA,QACrE,wBAAwB,iBAAiB,gBAAgB,CAAC,CAAC;AAAA,MAC5D,EAAE,KAAK,IAAI;AAAA,MACX;AAAA,IACD;AACA;AAAA,EACD;AAEA,SAAO,CAAC,QAAQ,SAAS;AACxB,UAAM,gBAAgB,KAAK,OAAO,WAAW,OAAO,kBAAkB,MAAM;AAC5E,QAAI,QAAQ,WAAW,UAAU,UAAU,KAAK,EAAG;AACnD,UAAM,SAAS,MAAM,gBAAgB,KAAK,UAAU,OAAO,MAAM;AACjE,QAAI,QAAQ,QAAS;AACrB,QAAI,WAAW,mBAAoB;AACnC,QAAI,WAAW,gBAAgB;AAC9B,UAAI,GAAG,OAAO,uCAAuC,MAAM;AAC3D;AAAA,IACD;AACA,QAAI;AACH,UAAI,CAAC,SAAS,YAAY,MAAM,UAAU;AACzC,cAAM,eAAe,MAAM,IAAI,GAAG;AAAA,UACjC;AAAA,UACA;AAAA,UACA,EAAE,OAAO;AAAA,QACV;AACA,YAAI,QAAQ,QAAS;AACrB,YAAI,CAAC,cAAc;AAClB,cAAI,GAAG,OAAO,oCAAoC,MAAM;AACxD;AAAA,QACD;AAAA,MACD;AACA,YAAM,UAAU;AAAA,QACf,GAAG,oBAAoB,OAAO,CAAC,cAAc,MAAM,SAAS,IAAI,SAAS,CAAC;AAAA,QAC1E,GAAG,MAAM;AAAA,QACT,GAAI,MAAM,WAAW,CAAC,UAAU,IAAI,CAAC;AAAA,MACtC;AACA,UAAI,QAAQ,QAAS;AACrB,YAAM;AAAA,QACL,OAAO;AAAA,QACP,CAAC,WAAW;AAAA,UACX,GAAG;AAAA,UACH,MAAM,EAAE,GAAG,MAAM,MAAM,QAAQ;AAAA,QAChC;AAAA,QACA,EAAE,iBAAiB,OAAO,SAAS,OAAO;AAAA,MAC3C;AACA,UAAI,QAAQ,QAAS;AACrB,UAAI,GAAG;AAAA,QACN,+CAA0C,iBAAiB,OAAO,SAAS,CAAC;AAAA,QAC5E;AAAA,MACD;AAAA,IACD,SAAS,OAAO;AACf,UAAI,QAAQ,QAAS;AACrB,UAAI,GAAG;AAAA,QACN,0CAA0C,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;AAAA,QAClH;AAAA,MACD;AAAA,IACD;AACA;AAAA,EACD;AACD;AAEA,eAAe,gBACd,KACA,WACA,OACA,kBACA,QACC;AACD,QAAM,OAAO,WAAiF;AAAA,IAC7F,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,QACd,MAAM;AAAA,QACN,OAAO,yBAAsB,iBAAiB,SAAS,CAAC;AAAA,QACxD,OAAO,CAAC,+EAA4E;AAAA,QACpF,cAAc;AAAA,QACd,OAAO;AAAA,UACN,GAAG,oBAAoB,IAAI,CAAC,kBAAkB;AAAA,YAC7C,IAAI,GAAG,eAAe,GAAG,YAAY;AAAA,YACrC,OAAO;AAAA,YACP,aAAa,aAAa,SAAS,GAAG,IACnC,sBAAsB,YAAY,wBAClC,0CAA0C,YAAY;AAAA,YACzD,UAAU,MAAM,SAAS,IAAI,YAAY;AAAA,UAC1C,EAAE;AAAA,UACF,GAAG,iBAAiB,IAAI,CAAC,kBAAkB;AAAA,YAC1C,IAAI,GAAG,aAAa,GAAG,YAAY;AAAA,YACnC,OAAO,iBAAiB,YAAY;AAAA,YACpC,aAAa;AAAA,YACb,UAAU,MAAM,OAAO,IAAI,YAAY;AAAA,UACxC,EAAE;AAAA,UACF;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aACC;AAAA,YACD,UAAU,MAAM;AAAA,UACjB;AAAA,QACD;AAAA,QACA,QAAQ;AAAA,QACR,SAAS;AAAA,UACR;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aACC;AAAA,YACD,QAAQ;AAAA,UACT;AAAA,QACD;AAAA,QACA,MAAM;AAAA,QACN,WAAW;AAAA,MACZ;AAAA,IACD;AAAA,IACA,SAAS;AAAA,MACR,QAAQ,OAAO,EAAE,QAAQ,SAAS,MAAM;AACvC,oBAAY,OAAO,QAAQ,aAAa,IAAI;AAC5C,eAAO,EAAE,MAAM,OAAO;AAAA,MACvB;AAAA,MACA,WAAW,OAAO,EAAE,KAAK,WAAW,QAAQ,aAAa,MAAM;AAC9D,cAAM,UAAU,MAAM,UAAU,GAAG;AAAA,UAClC;AAAA,UACA;AAAA,UACA,EAAE,QAAQ,aAAa;AAAA,QACxB;AACA,YAAI,aAAa,QAAS,QAAO,EAAE,MAAM,OAAO;AAChD,cAAM,YAAY,SAAS,KAAK;AAChC,YAAI,CAAC,UAAW,QAAO,EAAE,MAAM,OAAO;AACtC,cAAM,WAAW,iBAAiB;AAAA,UACjC,CAAC,cAAc,UAAU,YAAY,MAAM,UAAU,YAAY;AAAA,QAClE;AACA,cAAM,eAAe,YAAY;AACjC,YAAI,MAAM,OAAO,IAAI,YAAY,EAAG,QAAO,EAAE,MAAM,OAAO;AAC1D,YAAI;AACH,cAAI,CAAC,wBAAwB,YAAY,GAAG;AAC3C,kBAAM,IAAI,MAAM,qDAAqD;AAAA,UACtE;AACA,+BAAqB;AAAA,YACpB,GAAG,MAAM;AAAA,YACT,GAAG,MAAM;AAAA,YACT,GAAI,MAAM,WAAW,CAAC,UAAU,IAAI,CAAC;AAAA,YACrC;AAAA,UACD,CAAC;AAAA,QACF,SAAS,OAAO;AACf,cAAI,aAAa,QAAS,QAAO,EAAE,MAAM,OAAO;AAChD,oBAAU,GAAG;AAAA,YACZ,mCAAmC,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;AAAA,YAC3G;AAAA,UACD;AACA,iBAAO,EAAE,MAAM,OAAO;AAAA,QACvB;AACA,YAAI,CAAC,UAAU;AACd,2BAAiB,KAAK,YAAY;AAClC,2BAAiB,KAAK,CAAC,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;AAAA,QACjE;AACA,cAAM,OAAO,IAAI,YAAY;AAC7B,eAAO,EAAE,MAAM,OAAO;AAAA,MACvB;AAAA,IACD;AAAA,EACD,CAAC;AACD,QAAM,QAAQ,KAAK,MAAM;AAAA,IACxB,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,WAAW,MAAM,CAAC,QAAQ;AAAA,EAC3B,CAAC;AACF;AAEA,eAAe,gBACd,KACA,UACA,OACA,QACC;AACD,MAAI;AACJ,QAAM,OAAO,WAAmE;AAAA,IAC/E,OAAO;AAAA,IACP,SAAS;AAAA,MACR,QAAQ,OAAO;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,mBAAmB,UAAU,KAAK,EAAE,MAAM,IAAI,EAAE,MAAM,CAAC;AAAA,QAC9D,OAAO;AAAA,UACN,EAAE,IAAI,QAAQ,OAAO,gBAAgB,QAAQ,SAAS;AAAA,UACtD,EAAE,IAAI,WAAW,OAAO,mBAAmB,QAAQ,SAAS;AAAA,UAC5D,EAAE,IAAI,YAAY,OAAO,oBAAoB,QAAQ,SAAS;AAAA,QAC/D;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,IACA,SAAS;AAAA,MACR,QAAQ,OAAO,EAAE,OAAO,MAAM;AAC7B,iBACC,WAAW,SACR,iBACA,WAAW,aACV,qBACA;AACL,eAAO,EAAE,MAAM,QAAQ;AAAA,MACxB;AAAA,IACD;AAAA,EACD,CAAC;AACD,QAAM,QAAQ,KAAK,MAAM;AAAA,IACxB,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,WAAW,MAAM,CAAC,QAAQ;AAAA,EAC3B,CAAC;AACD,SAAO;AACR;AAEA,SAAS,YAAY,OAAuB,IAAY,UAAmB;AAC1E,MAAI,GAAG,WAAW,eAAe;AAChC,WAAO,UAAU,MAAM,UAAU,GAAG,MAAM,gBAAgB,MAAM,GAAG,QAAQ;AAC5E,MAAI,GAAG,WAAW,aAAa;AAC9B,WAAO,UAAU,MAAM,QAAQ,GAAG,MAAM,cAAc,MAAM,GAAG,QAAQ;AACxE,MAAI,OAAO,aAAa;AACvB,UAAM,WAAW;AACjB;AAAA,EACD;AACA,QAAM,IAAI,MAAM,2BAA2B,EAAE,EAAE;AAChD;AAEA,SAAS,UAAU,KAAkB,OAAe,UAAmB;AACtE,MAAI,SAAU,KAAI,IAAI,KAAK;AAAA,MACtB,KAAI,OAAO,KAAK;AACtB;AAEA,SAAS,mBAAmB,UAA0B,OAAuB;AAC5E,QAAM,QAAQ,CAAC,mCAAmC,EAAE;AACpD,aAAW,QAAQ,oBAAI,IAAI;AAAA,IAC1B,GAAG,SAAS;AAAA,IACZ,GAAG,MAAM;AAAA,IACT,GAAG,SAAS;AAAA,IACZ,GAAG,MAAM;AAAA,EACV,CAAC,GAAG;AACH,UAAM,SAAS,SAAS,SAAS,IAAI,IAAI,KAAK,SAAS,OAAO,IAAI,IAAI;AACtE,UAAM,QAAQ,MAAM,SAAS,IAAI,IAAI,KAAK,MAAM,OAAO,IAAI,IAAI;AAC/D,QAAI,WAAW,MAAO,OAAM,KAAK,GAAG,QAAQ,YAAY,SAAS,KAAK,iBAAiB,IAAI,CAAC,EAAE;AAAA,EAC/F;AACA,MAAI,SAAS,aAAa,MAAM;AAC/B,UAAM,KAAK,GAAG,MAAM,WAAW,YAAY,SAAS,YAAY;AACjE,QAAM,KAAK,IAAI,uCAAuC;AACtD,SAAO,MAAM,KAAK,IAAI;AACvB;AAEA,eAAe,qBAAqB,YAAyB;AAC5D,QAAM,aAAa,IAAI,IAAI,CAAC,GAAG,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,YAAY,GAAG,IAAI,CAAC,CAAC;AACpF,MAAI;AACH,eAAW,SAAS,MAAM,GAAG,QAAQ,SAAS,GAAG,EAAE,eAAe,KAAK,CAAC,GAAG;AAC1E,UAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,YAAY,KAAM,CAAC,wBAAwB,MAAM,IAAI;AACnF;AACD,UAAI,CAAC,WAAW,IAAI,MAAM,KAAK,YAAY,CAAC;AAC3C,mBAAW,IAAI,MAAM,KAAK,YAAY,GAAG,MAAM,IAAI;AAAA,IACrD;AAAA,EACD,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,EAC/D;AACA,SAAO,CAAC,GAAG,WAAW,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;AAChF;AAEA,SAAS,WAAW,OAAuC;AAC1D,SAAO;AAAA,IACN,UAAU,IAAI,IAAI,MAAM,QAAQ;AAAA,IAChC,QAAQ,IAAI,IAAI,MAAM,MAAM;AAAA,IAC5B,UAAU,MAAM;AAAA,EACjB;AACD;AAEA,SAAS,UAAU,MAAsB,OAAuB;AAC/D,SACC,KAAK,aAAa,MAAM,YACxB,QAAQ,KAAK,UAAU,MAAM,QAAQ,KACrC,QAAQ,KAAK,QAAQ,MAAM,MAAM;AAEnC;AAEA,SAAS,QAAQ,MAAmB,OAAoB;AACvD,SAAO,KAAK,SAAS,MAAM,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,SAAS,MAAM,IAAI,IAAI,CAAC;AAC7E;AAEA,SAAS,iBAAiB,OAAe;AAExC,SAAO,MAAM,QAAQ,kCAAkC,GAAG;AAC3D;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,29 +1,35 @@
|
|
|
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
|
+
import {
|
|
4
|
+
stateDir
|
|
5
|
+
} from "./chunk-ZI5MXMEX.ts";
|
|
3
6
|
import {
|
|
4
7
|
normalizeGitBranch,
|
|
5
8
|
normalizeGitDirectory,
|
|
6
9
|
normalizeGitRemote,
|
|
7
10
|
normalizeGitRemoteIdentity,
|
|
8
|
-
stateDir,
|
|
9
11
|
validateGitNamespace
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TEN2ZBJV.ts";
|
|
11
13
|
import {
|
|
12
14
|
SyncBackendConflictError,
|
|
13
15
|
SyncBackendPublicationOutcomeUnknownError
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-D5X27LCA.ts";
|
|
17
|
+
import {
|
|
18
|
+
syncErrorGuidance
|
|
19
|
+
} from "./chunk-CPEHGXJV.ts";
|
|
20
|
+
import "./chunk-2B2ELUF5.ts";
|
|
15
21
|
import {
|
|
16
22
|
portableSnapshotSelection,
|
|
17
23
|
posixJoin,
|
|
18
24
|
snapshotSelectionInclude
|
|
19
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-JAAKLL6M.ts";
|
|
20
26
|
|
|
21
|
-
// src/git-backend.ts
|
|
27
|
+
// src/backends/git/git-backend.ts
|
|
22
28
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
23
29
|
import fs from "node:fs/promises";
|
|
24
30
|
import path from "node:path";
|
|
25
31
|
|
|
26
|
-
// src/git-runner.ts
|
|
32
|
+
// src/backends/git/git-runner.ts
|
|
27
33
|
import { spawn } from "node:child_process";
|
|
28
34
|
import process2 from "node:process";
|
|
29
35
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -262,7 +268,7 @@ function throwIfAborted(signal) {
|
|
|
262
268
|
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
263
269
|
}
|
|
264
270
|
|
|
265
|
-
// src/git-storage.ts
|
|
271
|
+
// src/backends/git/git-storage.ts
|
|
266
272
|
import { createHash } from "node:crypto";
|
|
267
273
|
var GIT_MANIFEST_VERSION = 2;
|
|
268
274
|
var MAX_GIT_MANIFEST_BYTES = 1024 * 1024;
|
|
@@ -428,7 +434,7 @@ function hasControlCharacter(value) {
|
|
|
428
434
|
return /[\u0000-\u001f\u007f-\u009f]/u.test(value);
|
|
429
435
|
}
|
|
430
436
|
|
|
431
|
-
// src/git-backend.ts
|
|
437
|
+
// src/backends/git/git-backend.ts
|
|
432
438
|
var COMMAND_TIMEOUT_MS = 3e4;
|
|
433
439
|
var POST_COMMIT_TIMEOUT_MS = 45e3;
|
|
434
440
|
var gitCacheMutationQueues = /* @__PURE__ */ new Map();
|
|
@@ -440,7 +446,7 @@ var GitSyncBackend = class {
|
|
|
440
446
|
if (!this.allowLocalRemotes) assertProductionRemote(config.profile.remote);
|
|
441
447
|
this.identity = gitBackendIdentity(config);
|
|
442
448
|
this.destination = gitDestination(config);
|
|
443
|
-
this.cacheRoot = options.cacheRoot ?? path.join(stateDir(), "git");
|
|
449
|
+
this.cacheRoot = path.resolve(options.cacheRoot ?? path.join(stateDir(), "git"));
|
|
444
450
|
this.cacheDir = path.join(this.cacheRoot, this.identity.slice("git:".length), "repository.git");
|
|
445
451
|
this.commandTimeoutMs = options.commandTimeoutMs ?? COMMAND_TIMEOUT_MS;
|
|
446
452
|
this.postCommitTimeoutMs = options.postCommitTimeoutMs ?? POST_COMMIT_TIMEOUT_MS;
|
|
@@ -627,7 +633,13 @@ var GitSyncBackend = class {
|
|
|
627
633
|
return entries;
|
|
628
634
|
}
|
|
629
635
|
async diagnose(signal) {
|
|
630
|
-
const diagnostics = [
|
|
636
|
+
const diagnostics = [
|
|
637
|
+
{
|
|
638
|
+
key: "git-scope",
|
|
639
|
+
level: "info",
|
|
640
|
+
message: "git check scope: read remote snapshots and inspect the local cache. Write access is not tested."
|
|
641
|
+
}
|
|
642
|
+
];
|
|
631
643
|
try {
|
|
632
644
|
const version = await runGit(["--version"], {
|
|
633
645
|
signal,
|
|
@@ -641,7 +653,13 @@ var GitSyncBackend = class {
|
|
|
641
653
|
message: supported ? versionText : `${versionText || "unknown Git version"}; pi-sync requires Git 2.30 or newer`
|
|
642
654
|
});
|
|
643
655
|
} catch (error) {
|
|
644
|
-
return [
|
|
656
|
+
return [
|
|
657
|
+
{
|
|
658
|
+
key: "git-version",
|
|
659
|
+
level: "error",
|
|
660
|
+
message: syncErrorGuidance(new Error(this.safeError(error)))
|
|
661
|
+
}
|
|
662
|
+
];
|
|
645
663
|
}
|
|
646
664
|
try {
|
|
647
665
|
const head = await this.readHead(signal);
|
|
@@ -660,7 +678,7 @@ var GitSyncBackend = class {
|
|
|
660
678
|
diagnostics.push({
|
|
661
679
|
key: "git-remote",
|
|
662
680
|
level: "error",
|
|
663
|
-
message: `git remote: ${this.safeError(error)}`
|
|
681
|
+
message: `git remote: ${syncErrorGuidance(new Error(this.safeError(error)))}`
|
|
664
682
|
});
|
|
665
683
|
}
|
|
666
684
|
return diagnostics;
|
|
@@ -877,12 +895,14 @@ var GitSyncBackend = class {
|
|
|
877
895
|
try {
|
|
878
896
|
recreate = !await this.cacheUsesSha1(signal);
|
|
879
897
|
} catch {
|
|
898
|
+
throwIfAborted2(signal);
|
|
880
899
|
recreate = true;
|
|
881
900
|
}
|
|
882
901
|
}
|
|
883
902
|
} catch (error) {
|
|
884
903
|
if (error.code !== "ENOENT") throw error;
|
|
885
904
|
}
|
|
905
|
+
throwIfAborted2(signal);
|
|
886
906
|
if (recreate) await fs.rm(this.cacheDir, { recursive: true, force: true });
|
|
887
907
|
try {
|
|
888
908
|
await fs.access(this.cacheDir);
|
|
@@ -920,7 +940,7 @@ var GitSyncBackend = class {
|
|
|
920
940
|
return `refs/heads/${this.config.destination.branch}`;
|
|
921
941
|
}
|
|
922
942
|
publicationPath() {
|
|
923
|
-
return this.config.destination.directory;
|
|
943
|
+
return this.config.destination.directory === "./" ? "" : this.config.destination.directory;
|
|
924
944
|
}
|
|
925
945
|
manifestPath() {
|
|
926
946
|
return posixJoin(this.publicationPath(), "manifest.json");
|
|
@@ -1049,8 +1069,10 @@ function assertProductionRemote(remote) {
|
|
|
1049
1069
|
}
|
|
1050
1070
|
async function withGitCacheMutation(cacheDir, run, signal) {
|
|
1051
1071
|
const previous = gitCacheMutationQueues.get(cacheDir) ?? Promise.resolve();
|
|
1072
|
+
let started = false;
|
|
1052
1073
|
const operation = previous.catch(() => void 0).then(() => {
|
|
1053
1074
|
throwIfAborted2(signal);
|
|
1075
|
+
started = true;
|
|
1054
1076
|
return run();
|
|
1055
1077
|
});
|
|
1056
1078
|
const tail = operation.then(
|
|
@@ -1072,6 +1094,9 @@ async function withGitCacheMutation(cacheDir, run, signal) {
|
|
|
1072
1094
|
if (signal.aborted) onAbort();
|
|
1073
1095
|
try {
|
|
1074
1096
|
return await Promise.race([operation, aborted]);
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
if (started) await tail;
|
|
1099
|
+
throw error;
|
|
1075
1100
|
} finally {
|
|
1076
1101
|
signal.removeEventListener("abort", onAbort);
|
|
1077
1102
|
}
|
|
@@ -1101,4 +1126,4 @@ export {
|
|
|
1101
1126
|
gitBackendIdentity,
|
|
1102
1127
|
isSupportedGitVersion
|
|
1103
1128
|
};
|
|
1104
|
-
//# sourceMappingURL=git-backend-
|
|
1129
|
+
//# sourceMappingURL=git-backend-GMVS4PD4.ts.map
|