@narumitw/pi-sync 0.49.14 → 0.50.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 +134 -241
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.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-6UHKGALE.ts +134 -0
- package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
- package/dist/chunks/{chunk-RGJ6SOYR.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-3NDD5QPM.ts → chunk-AXXS2BPA.ts} +9 -9
- package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
- package/dist/chunks/{chunk-APZVBSM6.ts → chunk-C7XY5NF5.ts} +214 -365
- package/dist/chunks/chunk-C7XY5NF5.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-LJDSHNS3.ts → chunk-GWMHAQG4.ts} +4 -4
- package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
- package/dist/chunks/{chunk-FR6CVXAL.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.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-JSYMGJQQ.ts +51 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
- package/dist/chunks/chunk-L7TBO32M.ts +25 -0
- package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
- package/dist/chunks/{chunk-4F3W4CSC.ts → chunk-LCRI3ABW.ts} +22 -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-EWX3TPLQ.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
- package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
- package/dist/chunks/chunk-OUHGBFYF.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-BHJUISB4.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.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-LONPFFNP.ts → chunk-X5OM6GXT.ts} +9 -7
- package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
- package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
- package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
- package/dist/chunks/{chunk-5WJNWFTG.ts → chunk-YKJHPTGO.ts} +23 -55
- package/dist/chunks/chunk-YKJHPTGO.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-4UABOP44.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-OQW46G2X.ts} +42 -17
- package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
- package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
- package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
- package/dist/chunks/{s3-backend-3QZGO2EF.ts → s3-backend-3P33LQHU.ts} +96 -18
- package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
- package/dist/chunks/{setup-switch-X3W3FALZ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
- package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
- package/dist/chunks/{snapshot-WBSV4MQG.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
- package/dist/chunks/{sync-operations-MPAFVVHA.ts → sync-operations-ONJ27QRL.ts} +381 -299
- package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
- package/dist/chunks/{sync-state-36H7ULG2.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 +477 -342
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +211 -0
- package/package.json +6 -8
- 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} +40 -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} +41 -330
- 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 -284
- 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} +42 -11
- 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/{sync-attention.ts → ui/sync-attention.ts} +75 -6
- 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-3NDD5QPM.ts.map +0 -7
- package/dist/chunks/chunk-4F3W4CSC.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5WJNWFTG.ts.map +0 -7
- package/dist/chunks/chunk-APZVBSM6.ts.map +0 -7
- package/dist/chunks/chunk-BHJUISB4.ts.map +0 -7
- package/dist/chunks/chunk-EWX3TPLQ.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-FR6CVXAL.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-JNOOSPEW.ts +0 -82
- package/dist/chunks/chunk-JNOOSPEW.ts.map +0 -7
- package/dist/chunks/chunk-LJDSHNS3.ts.map +0 -7
- package/dist/chunks/chunk-LONPFFNP.ts.map +0 -7
- package/dist/chunks/chunk-RGJ6SOYR.ts.map +0 -7
- package/dist/chunks/chunk-W64NEHXT.ts +0 -167
- package/dist/chunks/chunk-W64NEHXT.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-4UABOP44.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-RNRQA3PW.ts +0 -18
- package/dist/chunks/manager-ui-QO2P4V3Z.ts +0 -2757
- package/dist/chunks/manager-ui-QO2P4V3Z.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-LHSAGKGA.ts +0 -17
- package/dist/chunks/s3-backend-3QZGO2EF.ts.map +0 -7
- package/dist/chunks/sync-operations-MPAFVVHA.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -910
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-RNRQA3PW.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-X3W3FALZ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-WBSV4MQG.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-36H7ULG2.ts.map → sync-inspection-FEP4L5TR.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
package/src/git-ui.ts
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { normalizeGitBranch, normalizeGitDirectory, normalizeGitRemote } from "./git-config.js";
|
|
3
|
-
import { requiredInput, safeTerminalText } from "./manager-helpers.js";
|
|
4
|
-
import {
|
|
5
|
-
addStorageConnection,
|
|
6
|
-
addSyncSetup,
|
|
7
|
-
saveNewV3Settings,
|
|
8
|
-
updateStorageConnection,
|
|
9
|
-
updateSyncSetup,
|
|
10
|
-
} from "./settings-management.js";
|
|
11
|
-
import { DEFAULT_SYNC_INCLUDE } from "./sync-policy.js";
|
|
12
|
-
import type { PartialConfig } from "./types.js";
|
|
13
|
-
|
|
14
|
-
export async function showGitSetup(
|
|
15
|
-
ctx: ExtensionCommandContext,
|
|
16
|
-
targetName: string,
|
|
17
|
-
signal?: AbortSignal,
|
|
18
|
-
) {
|
|
19
|
-
const profileName = await requiredInput(ctx, "Name this Git storage connection", "git", signal);
|
|
20
|
-
if (!profileName) return false;
|
|
21
|
-
const remoteInput = await requiredInput(
|
|
22
|
-
ctx,
|
|
23
|
-
"Git SSH or HTTPS remote",
|
|
24
|
-
"git@github.com:owner/private-pi-sync.git",
|
|
25
|
-
signal,
|
|
26
|
-
);
|
|
27
|
-
if (!remoteInput) return false;
|
|
28
|
-
const destination = await promptGitDestination(ctx, targetName, signal);
|
|
29
|
-
if (!destination) return false;
|
|
30
|
-
const automatic = await ctx.ui.select(
|
|
31
|
-
"Automatic sync for this setup",
|
|
32
|
-
["Enable automatic sync", "Keep automatic sync off", "Cancel"],
|
|
33
|
-
{ signal },
|
|
34
|
-
);
|
|
35
|
-
throwIfAborted(signal);
|
|
36
|
-
if (!automatic || automatic === "Cancel") return false;
|
|
37
|
-
let remote: string | undefined;
|
|
38
|
-
try {
|
|
39
|
-
remote = normalizeGitRemote(remoteInput);
|
|
40
|
-
} catch (error) {
|
|
41
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
if (!remote) return false;
|
|
45
|
-
const choice = await ctx.ui.select(
|
|
46
|
-
[
|
|
47
|
-
"Review Git sync setup",
|
|
48
|
-
"",
|
|
49
|
-
`Sync setup: ${safeTerminalText(targetName)}`,
|
|
50
|
-
`Storage connection: ${safeTerminalText(profileName)} (Git)`,
|
|
51
|
-
`Remote: ${safeGitRemote(remote)}`,
|
|
52
|
-
`Owned branch: ${safeTerminalText(destination.branch)}`,
|
|
53
|
-
`Storage location: ${safeTerminalText(destination.directory)}`,
|
|
54
|
-
`Included content: ${DEFAULT_SYNC_INCLUDE.length} built-in groups · Sessions: Off`,
|
|
55
|
-
`Automatic sync: ${automatic === "Enable automatic sync" ? "On" : "Off"}`,
|
|
56
|
-
"Authentication: existing non-interactive Git/SSH credentials; no credentials are stored by pi-sync.",
|
|
57
|
-
"The remote repository must already exist. The owned branch may be created on first push.",
|
|
58
|
-
].join("\n"),
|
|
59
|
-
["Save setup", "Cancel"],
|
|
60
|
-
{ signal },
|
|
61
|
-
);
|
|
62
|
-
throwIfAborted(signal);
|
|
63
|
-
if (choice !== "Save setup") return false;
|
|
64
|
-
await saveNewV3Settings(
|
|
65
|
-
{
|
|
66
|
-
setupName: targetName,
|
|
67
|
-
connectionName: profileName,
|
|
68
|
-
connection: { type: "git", remote },
|
|
69
|
-
setup: {
|
|
70
|
-
storage: {
|
|
71
|
-
connection: profileName,
|
|
72
|
-
branch: destination.branch,
|
|
73
|
-
path: destination.directory,
|
|
74
|
-
},
|
|
75
|
-
sync: {
|
|
76
|
-
include: [...DEFAULT_SYNC_INCLUDE],
|
|
77
|
-
automatic: automatic === "Enable automatic sync",
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
signal,
|
|
82
|
-
);
|
|
83
|
-
if (signal?.aborted) return true;
|
|
84
|
-
ctx.ui.notify(
|
|
85
|
-
`Saved Git sync setup “${safeTerminalText(targetName)}”. Run /sync doctor.`,
|
|
86
|
-
"info",
|
|
87
|
-
);
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export async function showAddGitStorageProfile(ctx: ExtensionCommandContext, signal?: AbortSignal) {
|
|
92
|
-
const name = await requiredInput(ctx, "Name this Git storage connection", "git", signal);
|
|
93
|
-
if (!name) return false;
|
|
94
|
-
const remoteInput = await requiredInput(
|
|
95
|
-
ctx,
|
|
96
|
-
"Git SSH or HTTPS remote",
|
|
97
|
-
"git@github.com:owner/private-pi-sync.git",
|
|
98
|
-
signal,
|
|
99
|
-
);
|
|
100
|
-
if (!remoteInput) return false;
|
|
101
|
-
let remote: string | undefined;
|
|
102
|
-
try {
|
|
103
|
-
remote = normalizeGitRemote(remoteInput);
|
|
104
|
-
} catch (error) {
|
|
105
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
if (!remote) return false;
|
|
109
|
-
const choice = await ctx.ui.select(
|
|
110
|
-
`Review storage connection\n\nName: ${safeTerminalText(name)}\nType: Git\nRemote: ${safeGitRemote(remote)}\nCredentials: existing Git/SSH authentication (not stored)\nAdding a connection does not contact the remote or start syncing.`,
|
|
111
|
-
["Add storage connection", "Cancel"],
|
|
112
|
-
{ signal },
|
|
113
|
-
);
|
|
114
|
-
throwIfAborted(signal);
|
|
115
|
-
if (choice !== "Add storage connection") return false;
|
|
116
|
-
await addStorageConnection(name, { type: "git", remote }, signal);
|
|
117
|
-
if (signal?.aborted) return true;
|
|
118
|
-
ctx.ui.notify(`Added storage connection “${safeTerminalText(name)}”.`, "info");
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export async function showEditGitStorageProfile(
|
|
123
|
-
ctx: ExtensionCommandContext,
|
|
124
|
-
name: string,
|
|
125
|
-
profile: Record<string, unknown>,
|
|
126
|
-
signal?: AbortSignal,
|
|
127
|
-
affectedSetups?: string[],
|
|
128
|
-
) {
|
|
129
|
-
const remoteInput = await requiredInput(
|
|
130
|
-
ctx,
|
|
131
|
-
"Git SSH or HTTPS remote",
|
|
132
|
-
typeof profile.remote === "string"
|
|
133
|
-
? profile.remote
|
|
134
|
-
: "git@github.com:owner/private-pi-sync.git",
|
|
135
|
-
signal,
|
|
136
|
-
);
|
|
137
|
-
if (!remoteInput) return false;
|
|
138
|
-
let remote: string | undefined;
|
|
139
|
-
try {
|
|
140
|
-
remote = normalizeGitRemote(remoteInput);
|
|
141
|
-
} catch (error) {
|
|
142
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
if (!remote) return false;
|
|
146
|
-
const choice = await ctx.ui.select(
|
|
147
|
-
`Review storage connection\n\nStorage connection: ${safeTerminalText(name)}\nRemote: ${safeGitRemote(String(profile.remote ?? "missing"))} → ${safeGitRemote(remote)}\nAffected sync setups: ${affectedSetups && affectedSetups.length > 0 ? affectedSetups.map(safeTerminalText).join(", ") : "None"}\nSaving changes future storage access for every affected setup; it does not move or delete remote history.`,
|
|
148
|
-
["Save storage connection", "Cancel"],
|
|
149
|
-
{ signal },
|
|
150
|
-
);
|
|
151
|
-
throwIfAborted(signal);
|
|
152
|
-
if (choice !== "Save storage connection") return false;
|
|
153
|
-
await updateStorageConnection(
|
|
154
|
-
name,
|
|
155
|
-
(current) => {
|
|
156
|
-
if (current.type !== "git") throw new Error("Storage connection type changed; reopen it.");
|
|
157
|
-
return { ...current, remote };
|
|
158
|
-
},
|
|
159
|
-
affectedSetups,
|
|
160
|
-
signal,
|
|
161
|
-
);
|
|
162
|
-
if (signal?.aborted) return true;
|
|
163
|
-
ctx.ui.notify(`Saved storage connection “${safeTerminalText(name)}”.`, "info");
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export async function showAddGitTarget(
|
|
168
|
-
ctx: ExtensionCommandContext,
|
|
169
|
-
name: string,
|
|
170
|
-
profile: string,
|
|
171
|
-
signal?: AbortSignal,
|
|
172
|
-
) {
|
|
173
|
-
const destination = await promptGitDestination(ctx, name, signal);
|
|
174
|
-
if (!destination) return false;
|
|
175
|
-
const preset = await ctx.ui.select(
|
|
176
|
-
"Choose included content",
|
|
177
|
-
["Recommended Pi settings", "Minimal settings", "Cancel"],
|
|
178
|
-
{ signal },
|
|
179
|
-
);
|
|
180
|
-
throwIfAborted(signal);
|
|
181
|
-
if (!preset || preset === "Cancel") return false;
|
|
182
|
-
const syncFiles =
|
|
183
|
-
preset === "Minimal settings" ? ["settings.json", "AGENTS.md"] : [...DEFAULT_SYNC_INCLUDE];
|
|
184
|
-
const automatic = await ctx.ui.select(
|
|
185
|
-
"Automatic sync for this setup",
|
|
186
|
-
["Enable automatic sync", "Keep automatic sync off", "Cancel"],
|
|
187
|
-
{ signal },
|
|
188
|
-
);
|
|
189
|
-
throwIfAborted(signal);
|
|
190
|
-
if (!automatic || automatic === "Cancel") return false;
|
|
191
|
-
const choice = await ctx.ui.select(
|
|
192
|
-
`Review Git sync setup\n\nSync setup: ${safeTerminalText(name)}\nStorage connection: ${safeTerminalText(profile)}\nOwned branch: ${safeTerminalText(destination.branch)}\nStorage location: ${safeTerminalText(destination.directory)}\nIncluded content: ${syncFiles.length} built-in groups · Sessions: Off\nAutomatic sync: ${automatic === "Enable automatic sync" ? "On" : "Off"}`,
|
|
193
|
-
["Add sync setup", "Cancel"],
|
|
194
|
-
{ signal },
|
|
195
|
-
);
|
|
196
|
-
throwIfAborted(signal);
|
|
197
|
-
if (choice !== "Add sync setup") return false;
|
|
198
|
-
await addSyncSetup(
|
|
199
|
-
name,
|
|
200
|
-
{
|
|
201
|
-
storage: {
|
|
202
|
-
connection: profile,
|
|
203
|
-
branch: destination.branch,
|
|
204
|
-
path: destination.directory,
|
|
205
|
-
},
|
|
206
|
-
sync: {
|
|
207
|
-
include: syncFiles,
|
|
208
|
-
automatic: automatic === "Enable automatic sync",
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
signal,
|
|
212
|
-
);
|
|
213
|
-
if (signal?.aborted) return true;
|
|
214
|
-
ctx.ui.notify(`Added sync setup “${safeTerminalText(name)}”.`, "info");
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export async function showEditGitTarget(
|
|
219
|
-
ctx: ExtensionCommandContext,
|
|
220
|
-
partial: PartialConfig,
|
|
221
|
-
signal?: AbortSignal,
|
|
222
|
-
) {
|
|
223
|
-
const targetName = partial.setupName;
|
|
224
|
-
const destination = await promptGitDestination(ctx, targetName, signal, partial);
|
|
225
|
-
if (!destination) return false;
|
|
226
|
-
if (destination.directory !== partial.storagePath && destination.branch === partial.branch) {
|
|
227
|
-
ctx.ui.notify(
|
|
228
|
-
"Changing a Git storage path requires a new Git branch so the existing branch remains readable.",
|
|
229
|
-
"warning",
|
|
230
|
-
);
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
const choice = await ctx.ui.select(
|
|
234
|
-
`Review sync setup “${safeTerminalText(targetName)}”\n\nBranch: ${safeTerminalText(partial.branch ?? "pi-sync")} → ${safeTerminalText(destination.branch)}\nStorage path: ${safeTerminalText(partial.storagePath)} → ${safeTerminalText(destination.directory)}\nSaving changes the future storage location only; it does not move or delete remote history.`,
|
|
235
|
-
["Save sync setup", "Cancel"],
|
|
236
|
-
{ signal },
|
|
237
|
-
);
|
|
238
|
-
throwIfAborted(signal);
|
|
239
|
-
if (choice !== "Save sync setup") return false;
|
|
240
|
-
await updateSyncSetup(
|
|
241
|
-
targetName,
|
|
242
|
-
(setup) => {
|
|
243
|
-
if (typeof setup.storage.branch !== "string") {
|
|
244
|
-
throw new Error("Sync setup storage type changed; reopen it.");
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
...setup,
|
|
248
|
-
storage: {
|
|
249
|
-
...setup.storage,
|
|
250
|
-
branch: destination.branch,
|
|
251
|
-
path: destination.directory,
|
|
252
|
-
},
|
|
253
|
-
};
|
|
254
|
-
},
|
|
255
|
-
{ expectedStorage: partial, signal },
|
|
256
|
-
);
|
|
257
|
-
if (signal?.aborted) return true;
|
|
258
|
-
ctx.ui.notify(`Saved sync setup “${safeTerminalText(targetName)}”.`, "info");
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
async function promptGitDestination(
|
|
263
|
-
ctx: ExtensionCommandContext,
|
|
264
|
-
targetName: string,
|
|
265
|
-
signal?: AbortSignal,
|
|
266
|
-
current: Partial<PartialConfig> = {},
|
|
267
|
-
) {
|
|
268
|
-
const branchInput = await requiredInput(
|
|
269
|
-
ctx,
|
|
270
|
-
"Owned Git branch",
|
|
271
|
-
current.branch ?? `pi-sync/${targetName}`,
|
|
272
|
-
signal,
|
|
273
|
-
);
|
|
274
|
-
if (!branchInput) return undefined;
|
|
275
|
-
const pathInput = await requiredInput(
|
|
276
|
-
ctx,
|
|
277
|
-
"Git storage path",
|
|
278
|
-
current.storagePath ?? `pi-sync/${targetName}`,
|
|
279
|
-
signal,
|
|
280
|
-
);
|
|
281
|
-
if (!pathInput) return undefined;
|
|
282
|
-
try {
|
|
283
|
-
const branch = normalizeGitBranch(branchInput);
|
|
284
|
-
const directory = normalizeGitDirectory(pathInput);
|
|
285
|
-
const namespace = directory.slice(directory.lastIndexOf("/") + 1);
|
|
286
|
-
return { branch, directory, namespace };
|
|
287
|
-
} catch (error) {
|
|
288
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
289
|
-
return undefined;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function throwIfAborted(signal?: AbortSignal) {
|
|
294
|
-
if (!signal?.aborted) return;
|
|
295
|
-
throw signal.reason instanceof Error
|
|
296
|
-
? signal.reason
|
|
297
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function safeGitRemote(remote: string) {
|
|
301
|
-
try {
|
|
302
|
-
const url = new URL(remote);
|
|
303
|
-
return safeTerminalText(`${url.protocol}//${url.host}${url.pathname}`);
|
|
304
|
-
} catch {
|
|
305
|
-
return safeTerminalText(remote);
|
|
306
|
-
}
|
|
307
|
-
}
|
package/src/manager-helpers.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { isCloudflareR2Endpoint } from "./config.js";
|
|
3
|
-
|
|
4
|
-
export async function requiredExistingBucket(
|
|
5
|
-
ctx: ExtensionCommandContext,
|
|
6
|
-
example: string,
|
|
7
|
-
signal?: AbortSignal,
|
|
8
|
-
) {
|
|
9
|
-
const value = await ctx.ui.input("Existing bucket", `Example: ${example}`, { signal });
|
|
10
|
-
if (signal?.aborted) {
|
|
11
|
-
throw signal.reason instanceof Error
|
|
12
|
-
? signal.reason
|
|
13
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
14
|
-
}
|
|
15
|
-
if (value === undefined) return undefined;
|
|
16
|
-
const normalized = value.trim();
|
|
17
|
-
if (!normalized) {
|
|
18
|
-
ctx.ui.notify("Enter the name of an existing R2/S3 bucket, or cancel setup.", "warning");
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
return normalized;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function requiredInput(
|
|
25
|
-
ctx: ExtensionCommandContext,
|
|
26
|
-
title: string,
|
|
27
|
-
placeholder: string,
|
|
28
|
-
signal?: AbortSignal,
|
|
29
|
-
) {
|
|
30
|
-
const value = await ctx.ui.input(title, placeholder, { signal });
|
|
31
|
-
if (signal?.aborted) {
|
|
32
|
-
throw signal.reason instanceof Error
|
|
33
|
-
? signal.reason
|
|
34
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
35
|
-
}
|
|
36
|
-
if (value === undefined) return undefined;
|
|
37
|
-
const normalized = value.trim() || placeholder;
|
|
38
|
-
return normalized.includes("<") || normalized.includes(">") ? undefined : normalized;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function storageDescription(
|
|
42
|
-
kind: string | undefined,
|
|
43
|
-
endpoint: string | undefined,
|
|
44
|
-
bucket: string | undefined,
|
|
45
|
-
) {
|
|
46
|
-
const label =
|
|
47
|
-
kind === "r2" || isCloudflareR2Endpoint(endpoint) ? "Cloudflare R2" : "S3-compatible";
|
|
48
|
-
return `${label} · ${safeTerminalText(bucket ?? "bucket missing")}`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function ownRecord(value: unknown): Record<string, unknown> | undefined {
|
|
52
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
53
|
-
? (value as Record<string, unknown>)
|
|
54
|
-
: undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function safeTerminalText(value: string) {
|
|
58
|
-
// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.
|
|
59
|
-
return value.replace(/[\u0000-\u001f\u007f-\u009f]/gu, "?");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function errorMessage(error: unknown) {
|
|
63
|
-
return error instanceof Error ? error.message : String(error);
|
|
64
|
-
}
|