@seedvault/cli 0.4.1 → 0.4.2

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.
Files changed (2) hide show
  1. package/dist/sv.js +106 -14
  2. 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 readFileSync2 } from "fs";
6
- import { resolve as resolve6 } from "path";
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;
@@ -2950,6 +2993,21 @@ async function cat(args) {
2950
2993
  process.stdout.write(output);
2951
2994
  }
2952
2995
 
2996
+ // src/commands/sh.ts
2997
+ async function sh(args) {
2998
+ if (args.length === 0) {
2999
+ console.error("Usage: sv sh <command>");
3000
+ console.error('Example: sv sh "ls -la yiliu/"');
3001
+ console.error('Example: sv sh "grep -r pattern ."');
3002
+ process.exit(1);
3003
+ }
3004
+ const cmd = args.join(" ");
3005
+ const config = loadConfig();
3006
+ const client = createClient(config.server, config.token);
3007
+ const output = await client.sh(cmd);
3008
+ process.stdout.write(output);
3009
+ }
3010
+
2953
3011
  // src/commands/contributors.ts
2954
3012
  async function contributors() {
2955
3013
  const config = loadConfig();
@@ -2989,6 +3047,31 @@ Share this with the person you want to invite.`);
2989
3047
  }
2990
3048
  }
2991
3049
 
3050
+ // src/commands/upgrade.ts
3051
+ import { readFileSync as readFileSync2 } from "fs";
3052
+ import { resolve as resolve6 } from "path";
3053
+ var {$ } = globalThis.Bun;
3054
+ var INSTALL_SCRIPT_URL = "https://raw.githubusercontent.com/collaborator-ai/seedvault/main/install-cli.sh";
3055
+ async function upgrade() {
3056
+ const pkgPath = resolve6(import.meta.dirname, "..", "..", "package.json");
3057
+ let currentVersion = "unknown";
3058
+ try {
3059
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
3060
+ currentVersion = pkg.version;
3061
+ } catch {}
3062
+ console.log(`Current version: ${currentVersion}`);
3063
+ console.log(`Fetching latest from: ${INSTALL_SCRIPT_URL}
3064
+ `);
3065
+ const result = await $`curl -fsSL ${INSTALL_SCRIPT_URL} | bash -s -- --no-onboard`.quiet().nothrow();
3066
+ if (result.exitCode !== 0) {
3067
+ console.error("Upgrade failed:");
3068
+ console.error(result.stderr.toString());
3069
+ process.exit(1);
3070
+ }
3071
+ console.log(result.stdout.toString());
3072
+ console.log("Upgrade complete. Run 'sv --version' to verify.");
3073
+ }
3074
+
2992
3075
  // src/index.ts
2993
3076
  var USAGE = `
2994
3077
  Seedvault CLI
@@ -2996,9 +3079,10 @@ Seedvault CLI
2996
3079
  Usage: sv <command> [options]
2997
3080
 
2998
3081
  Setup:
2999
- init Interactive first-time setup
3000
- init --server URL --token T --username U Non-interactive (existing token)
3001
- init --server URL --name N Non-interactive (signup)
3082
+ init Interactive first-time setup
3083
+ init --server URL --token T Non-interactive (existing token)
3084
+ init --server URL --name N [--invite CODE] Non-interactive (signup)
3085
+ init --force Overwrite existing config
3002
3086
 
3003
3087
  Collections:
3004
3088
  add <path> [--name N] Add a collection path
@@ -3012,12 +3096,16 @@ Daemon:
3012
3096
  status Show sync status
3013
3097
 
3014
3098
  Files:
3015
- ls [prefix] List files in your contributor
3016
- cat <path> Read a file from the server
3099
+ sh <command> Run a shell command on the vault (ls, cat, grep, etc.)
3100
+ ls [args...] Shorthand for: sv sh "ls [args...]"
3101
+ cat <path> Shorthand for: sv sh "cat <path>"
3017
3102
 
3018
3103
  Vault:
3019
3104
  contributors List all contributors
3020
3105
  invite Generate an invite code (operator only)
3106
+
3107
+ Maintenance:
3108
+ upgrade Upgrade CLI to latest version
3021
3109
  `.trim();
3022
3110
  async function main() {
3023
3111
  const [cmd, ...args] = process.argv.slice(2);
@@ -3026,8 +3114,8 @@ async function main() {
3026
3114
  return;
3027
3115
  }
3028
3116
  if (cmd === "--version" || cmd === "-v") {
3029
- const pkgPath = resolve6(import.meta.dirname, "..", "package.json");
3030
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
3117
+ const pkgPath = resolve7(import.meta.dirname, "..", "package.json");
3118
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
3031
3119
  console.log(pkg.version);
3032
3120
  return;
3033
3121
  }
@@ -3047,6 +3135,8 @@ async function main() {
3047
3135
  return await stop();
3048
3136
  case "status":
3049
3137
  return await status();
3138
+ case "sh":
3139
+ return await sh(args);
3050
3140
  case "ls":
3051
3141
  return await ls(args);
3052
3142
  case "cat":
@@ -3055,6 +3145,8 @@ async function main() {
3055
3145
  return await contributors();
3056
3146
  case "invite":
3057
3147
  return await invite();
3148
+ case "upgrade":
3149
+ return await upgrade();
3058
3150
  default:
3059
3151
  console.error(`Unknown command: ${cmd}
3060
3152
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedvault/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sv": "bin/sv.mjs"