@seedvault/cli 0.4.1 → 0.4.3
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/sv.js +113 -23
- package/package.json +1 -1
package/dist/sv.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
|
-
import { readFileSync as
|
|
6
|
-
import { resolve as
|
|
5
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6
|
+
import { resolve as resolve7 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/commands/init.ts
|
|
9
9
|
import * as readline from "readline/promises";
|
|
@@ -2038,12 +2038,26 @@ function watch(paths, options = {}) {
|
|
|
2038
2038
|
import { relative as relative4 } from "path";
|
|
2039
2039
|
function createWatcher(collections2, onEvent) {
|
|
2040
2040
|
const paths = collections2.map((f) => f.path);
|
|
2041
|
+
const shouldIgnore = (filePath) => {
|
|
2042
|
+
for (const col of collections2) {
|
|
2043
|
+
if (filePath.startsWith(col.path + "/") || filePath === col.path) {
|
|
2044
|
+
const relPath = filePath.slice(col.path.length + 1);
|
|
2045
|
+
const segments = relPath.split("/");
|
|
2046
|
+
for (const seg of segments) {
|
|
2047
|
+
if (seg.startsWith("."))
|
|
2048
|
+
return true;
|
|
2049
|
+
if (seg === "node_modules")
|
|
2050
|
+
return true;
|
|
2051
|
+
if (seg.includes(".tmp."))
|
|
2052
|
+
return true;
|
|
2053
|
+
}
|
|
2054
|
+
return false;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
return false;
|
|
2058
|
+
};
|
|
2041
2059
|
const watcher = watch(paths, {
|
|
2042
|
-
ignored:
|
|
2043
|
-
/(^|[/\\])\./,
|
|
2044
|
-
"**/node_modules/**",
|
|
2045
|
-
"**/*.tmp.*"
|
|
2046
|
-
],
|
|
2060
|
+
ignored: shouldIgnore,
|
|
2047
2061
|
persistent: true,
|
|
2048
2062
|
ignoreInitial: true,
|
|
2049
2063
|
awaitWriteFinish: {
|
|
@@ -2190,8 +2204,37 @@ class Syncer {
|
|
|
2190
2204
|
skipped += result.skipped;
|
|
2191
2205
|
deleted += result.deleted;
|
|
2192
2206
|
}
|
|
2207
|
+
deleted += await this.purgeOrphans();
|
|
2193
2208
|
return { uploaded, skipped, deleted };
|
|
2194
2209
|
}
|
|
2210
|
+
async purgeOrphans() {
|
|
2211
|
+
let deleted = 0;
|
|
2212
|
+
const { files: allServerFiles } = await this.client.listFiles(this.username);
|
|
2213
|
+
const collectionNames = new Set(this.collections.map((c) => c.name));
|
|
2214
|
+
const orphans = allServerFiles.filter((f) => {
|
|
2215
|
+
const prefix = f.path.split("/")[0];
|
|
2216
|
+
return !collectionNames.has(prefix);
|
|
2217
|
+
});
|
|
2218
|
+
if (orphans.length === 0)
|
|
2219
|
+
return 0;
|
|
2220
|
+
this.log(`Purging ${orphans.length} orphaned file(s) from removed collections...`);
|
|
2221
|
+
await pooled(orphans, SYNC_CONCURRENCY, async (f) => {
|
|
2222
|
+
try {
|
|
2223
|
+
await this.client.deleteFile(this.username, f.path);
|
|
2224
|
+
deleted++;
|
|
2225
|
+
} catch {
|
|
2226
|
+
this.queue.enqueue({
|
|
2227
|
+
type: "delete",
|
|
2228
|
+
username: this.username,
|
|
2229
|
+
serverPath: f.path,
|
|
2230
|
+
content: null,
|
|
2231
|
+
queuedAt: new Date().toISOString()
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
});
|
|
2235
|
+
this.log(` Purged ${deleted} orphaned file(s)`);
|
|
2236
|
+
return deleted;
|
|
2237
|
+
}
|
|
2195
2238
|
async syncCollection(collection) {
|
|
2196
2239
|
let uploaded = 0;
|
|
2197
2240
|
let skipped = 0;
|
|
@@ -2737,15 +2780,13 @@ async function startForeground() {
|
|
|
2737
2780
|
collections: config.collections,
|
|
2738
2781
|
onLog: log
|
|
2739
2782
|
});
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
log("Will continue watching for changes...");
|
|
2748
|
-
}
|
|
2783
|
+
log("Running initial sync...");
|
|
2784
|
+
try {
|
|
2785
|
+
const { uploaded, skipped, deleted } = await syncer.initialSync();
|
|
2786
|
+
log(`Initial sync complete: ${uploaded} uploaded, ${skipped} skipped, ${deleted} deleted`);
|
|
2787
|
+
} catch (e) {
|
|
2788
|
+
log(`Initial sync failed: ${e.message}`);
|
|
2789
|
+
log("Will continue watching for changes...");
|
|
2749
2790
|
}
|
|
2750
2791
|
let watcher = null;
|
|
2751
2792
|
const rebuildWatcher = async (collections2) => {
|
|
@@ -2950,6 +2991,21 @@ async function cat(args) {
|
|
|
2950
2991
|
process.stdout.write(output);
|
|
2951
2992
|
}
|
|
2952
2993
|
|
|
2994
|
+
// src/commands/sh.ts
|
|
2995
|
+
async function sh(args) {
|
|
2996
|
+
if (args.length === 0) {
|
|
2997
|
+
console.error("Usage: sv sh <command>");
|
|
2998
|
+
console.error('Example: sv sh "ls -la yiliu/"');
|
|
2999
|
+
console.error('Example: sv sh "grep -r pattern ."');
|
|
3000
|
+
process.exit(1);
|
|
3001
|
+
}
|
|
3002
|
+
const cmd = args.join(" ");
|
|
3003
|
+
const config = loadConfig();
|
|
3004
|
+
const client = createClient(config.server, config.token);
|
|
3005
|
+
const output = await client.sh(cmd);
|
|
3006
|
+
process.stdout.write(output);
|
|
3007
|
+
}
|
|
3008
|
+
|
|
2953
3009
|
// src/commands/contributors.ts
|
|
2954
3010
|
async function contributors() {
|
|
2955
3011
|
const config = loadConfig();
|
|
@@ -2989,6 +3045,31 @@ Share this with the person you want to invite.`);
|
|
|
2989
3045
|
}
|
|
2990
3046
|
}
|
|
2991
3047
|
|
|
3048
|
+
// src/commands/update.ts
|
|
3049
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
3050
|
+
import { resolve as resolve6 } from "path";
|
|
3051
|
+
var {$ } = globalThis.Bun;
|
|
3052
|
+
var INSTALL_SCRIPT_URL = "https://raw.githubusercontent.com/collaborator-ai/seedvault/main/install-cli.sh";
|
|
3053
|
+
async function upgrade() {
|
|
3054
|
+
const pkgPath = resolve6(import.meta.dirname, "..", "..", "package.json");
|
|
3055
|
+
let currentVersion = "unknown";
|
|
3056
|
+
try {
|
|
3057
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
3058
|
+
currentVersion = pkg.version;
|
|
3059
|
+
} catch {}
|
|
3060
|
+
console.log(`Current version: ${currentVersion}`);
|
|
3061
|
+
console.log(`Fetching latest from: ${INSTALL_SCRIPT_URL}
|
|
3062
|
+
`);
|
|
3063
|
+
const result = await $`curl -fsSL ${INSTALL_SCRIPT_URL} | bash -s -- --no-onboard`.quiet().nothrow();
|
|
3064
|
+
if (result.exitCode !== 0) {
|
|
3065
|
+
console.error("Upgrade failed:");
|
|
3066
|
+
console.error(result.stderr.toString());
|
|
3067
|
+
process.exit(1);
|
|
3068
|
+
}
|
|
3069
|
+
console.log(result.stdout.toString());
|
|
3070
|
+
console.log("Upgrade complete. Run 'sv --version' to verify.");
|
|
3071
|
+
}
|
|
3072
|
+
|
|
2992
3073
|
// src/index.ts
|
|
2993
3074
|
var USAGE = `
|
|
2994
3075
|
Seedvault CLI
|
|
@@ -2996,9 +3077,10 @@ Seedvault CLI
|
|
|
2996
3077
|
Usage: sv <command> [options]
|
|
2997
3078
|
|
|
2998
3079
|
Setup:
|
|
2999
|
-
init
|
|
3000
|
-
init --server URL --token T
|
|
3001
|
-
init --server URL --name N
|
|
3080
|
+
init Interactive first-time setup
|
|
3081
|
+
init --server URL --token T Non-interactive (existing token)
|
|
3082
|
+
init --server URL --name N [--invite CODE] Non-interactive (signup)
|
|
3083
|
+
init --force Overwrite existing config
|
|
3002
3084
|
|
|
3003
3085
|
Collections:
|
|
3004
3086
|
add <path> [--name N] Add a collection path
|
|
@@ -3012,12 +3094,16 @@ Daemon:
|
|
|
3012
3094
|
status Show sync status
|
|
3013
3095
|
|
|
3014
3096
|
Files:
|
|
3015
|
-
|
|
3016
|
-
|
|
3097
|
+
sh <command> Run a shell command on the vault (ls, cat, grep, etc.)
|
|
3098
|
+
ls [args...] Shorthand for: sv sh "ls [args...]"
|
|
3099
|
+
cat <path> Shorthand for: sv sh "cat <path>"
|
|
3017
3100
|
|
|
3018
3101
|
Vault:
|
|
3019
3102
|
contributors List all contributors
|
|
3020
3103
|
invite Generate an invite code (operator only)
|
|
3104
|
+
|
|
3105
|
+
Maintenance:
|
|
3106
|
+
update Update CLI to latest version
|
|
3021
3107
|
`.trim();
|
|
3022
3108
|
async function main() {
|
|
3023
3109
|
const [cmd, ...args] = process.argv.slice(2);
|
|
@@ -3026,8 +3112,8 @@ async function main() {
|
|
|
3026
3112
|
return;
|
|
3027
3113
|
}
|
|
3028
3114
|
if (cmd === "--version" || cmd === "-v") {
|
|
3029
|
-
const pkgPath =
|
|
3030
|
-
const pkg = JSON.parse(
|
|
3115
|
+
const pkgPath = resolve7(import.meta.dirname, "..", "package.json");
|
|
3116
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
3031
3117
|
console.log(pkg.version);
|
|
3032
3118
|
return;
|
|
3033
3119
|
}
|
|
@@ -3047,6 +3133,8 @@ async function main() {
|
|
|
3047
3133
|
return await stop();
|
|
3048
3134
|
case "status":
|
|
3049
3135
|
return await status();
|
|
3136
|
+
case "sh":
|
|
3137
|
+
return await sh(args);
|
|
3050
3138
|
case "ls":
|
|
3051
3139
|
return await ls(args);
|
|
3052
3140
|
case "cat":
|
|
@@ -3055,6 +3143,8 @@ async function main() {
|
|
|
3055
3143
|
return await contributors();
|
|
3056
3144
|
case "invite":
|
|
3057
3145
|
return await invite();
|
|
3146
|
+
case "update":
|
|
3147
|
+
return await upgrade();
|
|
3058
3148
|
default:
|
|
3059
3149
|
console.error(`Unknown command: ${cmd}
|
|
3060
3150
|
`);
|