@lifestreamdynamics/vault-cli 1.3.3 → 1.3.5
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/dist/commands/sync.js +33 -3
- package/dist/lib/credential-manager.js +8 -2
- package/dist/lib/keychain.js +13 -1
- package/package.json +1 -1
package/dist/commands/sync.js
CHANGED
|
@@ -24,7 +24,17 @@ export function registerSyncCommands(program) {
|
|
|
24
24
|
.option('--on-conflict <strategy>', 'Conflict strategy: newer, local, remote, ask (default: newer)')
|
|
25
25
|
.option('--ignore <patterns...>', 'Glob patterns to ignore')
|
|
26
26
|
.option('--interval <interval>', 'Auto-sync interval (e.g., 5m, 1h)')
|
|
27
|
-
.option('--auto-sync', 'Enable auto-sync')
|
|
27
|
+
.option('--auto-sync', 'Enable auto-sync')
|
|
28
|
+
.addHelpText('after', `
|
|
29
|
+
Examples:
|
|
30
|
+
lsvault sync init <vaultId> ~/my-vault
|
|
31
|
+
lsvault sync init <vaultId> ~/mirror --mode pull --on-conflict remote
|
|
32
|
+
lsvault sync init <vaultId> ~/docs --mode push --on-conflict local --auto-sync
|
|
33
|
+
|
|
34
|
+
Sync modes:
|
|
35
|
+
pull Download remote changes only (ideal for cron/automation)
|
|
36
|
+
push Upload local changes only (ideal for CI pipelines)
|
|
37
|
+
sync Bidirectional with conflict detection (default)`))
|
|
28
38
|
.action(async (vaultId, localPath, _opts) => {
|
|
29
39
|
const flags = resolveFlags(_opts);
|
|
30
40
|
const out = createOutput(flags);
|
|
@@ -158,11 +168,19 @@ export function registerSyncCommands(program) {
|
|
|
158
168
|
out.debug(`Found ${Object.keys(remoteFiles).length} remote files`);
|
|
159
169
|
out.startSpinner('Computing diff...');
|
|
160
170
|
const diff = computePullDiff(localFiles, remoteFiles, lastState);
|
|
171
|
+
const unchanged = Object.keys(remoteFiles).length - diff.downloads.length;
|
|
161
172
|
const totalOps = diff.downloads.length + diff.deletes.length;
|
|
162
173
|
if (totalOps === 0) {
|
|
163
174
|
out.succeedSpinner('Everything is up to date');
|
|
164
175
|
if (flags.output === 'json') {
|
|
165
|
-
out.record({
|
|
176
|
+
out.record({
|
|
177
|
+
status: 'up-to-date',
|
|
178
|
+
downloaded: 0,
|
|
179
|
+
deleted: 0,
|
|
180
|
+
unchanged: Object.keys(remoteFiles).length,
|
|
181
|
+
bytesTransferred: 0,
|
|
182
|
+
errors: 0,
|
|
183
|
+
});
|
|
166
184
|
}
|
|
167
185
|
return;
|
|
168
186
|
}
|
|
@@ -175,6 +193,7 @@ export function registerSyncCommands(program) {
|
|
|
175
193
|
dryRun: true,
|
|
176
194
|
downloads: diff.downloads.length,
|
|
177
195
|
deletes: diff.deletes.length,
|
|
196
|
+
unchanged,
|
|
178
197
|
totalBytes: diff.totalBytes,
|
|
179
198
|
});
|
|
180
199
|
}
|
|
@@ -201,6 +220,7 @@ export function registerSyncCommands(program) {
|
|
|
201
220
|
out.success('', {
|
|
202
221
|
downloaded: result.filesDownloaded,
|
|
203
222
|
deleted: result.filesDeleted,
|
|
223
|
+
unchanged,
|
|
204
224
|
bytesTransferred: result.bytesTransferred,
|
|
205
225
|
errors: result.errors.length,
|
|
206
226
|
});
|
|
@@ -234,11 +254,19 @@ export function registerSyncCommands(program) {
|
|
|
234
254
|
out.debug(`Found ${Object.keys(remoteFiles).length} remote files`);
|
|
235
255
|
out.startSpinner('Computing diff...');
|
|
236
256
|
const diff = computePushDiff(localFiles, remoteFiles, lastState);
|
|
257
|
+
const unchanged = Object.keys(localFiles).length - diff.uploads.length;
|
|
237
258
|
const totalOps = diff.uploads.length + diff.deletes.length;
|
|
238
259
|
if (totalOps === 0) {
|
|
239
260
|
out.succeedSpinner('Everything is up to date');
|
|
240
261
|
if (flags.output === 'json') {
|
|
241
|
-
out.record({
|
|
262
|
+
out.record({
|
|
263
|
+
status: 'up-to-date',
|
|
264
|
+
uploaded: 0,
|
|
265
|
+
deleted: 0,
|
|
266
|
+
unchanged: Object.keys(localFiles).length,
|
|
267
|
+
bytesTransferred: 0,
|
|
268
|
+
errors: 0,
|
|
269
|
+
});
|
|
242
270
|
}
|
|
243
271
|
return;
|
|
244
272
|
}
|
|
@@ -251,6 +279,7 @@ export function registerSyncCommands(program) {
|
|
|
251
279
|
dryRun: true,
|
|
252
280
|
uploads: diff.uploads.length,
|
|
253
281
|
deletes: diff.deletes.length,
|
|
282
|
+
unchanged,
|
|
254
283
|
totalBytes: diff.totalBytes,
|
|
255
284
|
});
|
|
256
285
|
}
|
|
@@ -277,6 +306,7 @@ export function registerSyncCommands(program) {
|
|
|
277
306
|
out.success('', {
|
|
278
307
|
uploaded: result.filesUploaded,
|
|
279
308
|
deleted: result.filesDeleted,
|
|
309
|
+
unchanged,
|
|
280
310
|
bytesTransferred: result.bytesTransferred,
|
|
281
311
|
errors: result.errors.length,
|
|
282
312
|
});
|
|
@@ -69,8 +69,14 @@ export function createCredentialManager(options = {}) {
|
|
|
69
69
|
async saveCredentials(config) {
|
|
70
70
|
// Prefer keychain if available
|
|
71
71
|
if (await keychain.isAvailable()) {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
try {
|
|
73
|
+
await keychain.saveCredentials(config);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Keychain reported available but failed to save — fall through
|
|
78
|
+
// to encrypted config silently.
|
|
79
|
+
}
|
|
74
80
|
}
|
|
75
81
|
// Fall back to encrypted config
|
|
76
82
|
encryptedConfig.saveCredentials(config, passphrase);
|
package/dist/lib/keychain.js
CHANGED
|
@@ -9,7 +9,19 @@ const ACCOUNT_REFRESH_TOKEN = 'refresh-token';
|
|
|
9
9
|
*/
|
|
10
10
|
async function loadKeytar() {
|
|
11
11
|
try {
|
|
12
|
-
|
|
12
|
+
const mod = await import('keytar');
|
|
13
|
+
// CJS-in-ESM interop: keytar is a native CJS addon, so dynamic import
|
|
14
|
+
// wraps it as { default: { getPassword, setPassword, ... } }.
|
|
15
|
+
const resolved = (mod.default && typeof mod.default.getPassword === 'function')
|
|
16
|
+
? mod.default
|
|
17
|
+
: mod;
|
|
18
|
+
// Validate that the resolved module has the methods we need
|
|
19
|
+
if (typeof resolved.getPassword !== 'function' ||
|
|
20
|
+
typeof resolved.setPassword !== 'function' ||
|
|
21
|
+
typeof resolved.deletePassword !== 'function') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return resolved;
|
|
13
25
|
}
|
|
14
26
|
catch {
|
|
15
27
|
return null;
|