@vosjs/cli 0.85.0 → 0.87.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.
@@ -10,7 +10,7 @@ import {
10
10
  reencodeStill,
11
11
  renderStill,
12
12
  videoFormat
13
- } from "./chunk-Q47FUCYN.js";
13
+ } from "./chunk-EXDMMAPT.js";
14
14
  import {
15
15
  PREV_DOC_NAME,
16
16
  PasteFileRefusal,
@@ -46,47 +46,64 @@ import {
46
46
  uploadDocRefs,
47
47
  uploadManifest,
48
48
  writeJson
49
- } from "./chunk-M5ZBQFPG.js";
49
+ } from "./chunk-2UFNOKVY.js";
50
50
  import {
51
+ ACCOUNT_ENV,
51
52
  CREDENTIALS_PATH,
53
+ DEFAULT_STORE,
52
54
  MEDIA_HEAD_BYTES,
53
55
  SYNC_STATE_NAME,
54
56
  UsageError,
57
+ accountFrom,
58
+ accountLabel,
59
+ activate,
55
60
  apiError,
56
61
  apiJson,
57
62
  bearerFor,
58
63
  clientId,
59
64
  containerMismatch,
65
+ credentialAccount,
66
+ credentialFlags,
60
67
  deriveSlug,
61
68
  detailLine,
69
+ findStored,
62
70
  formatChanges,
63
71
  hasFlag,
64
72
  hostedAssetId,
73
+ isActive,
74
+ lastCredential,
75
+ listStored,
65
76
  localFile,
66
77
  manifestRefs,
67
78
  mintAt,
68
79
  nameForType,
69
80
  numFlag2 as numFlag,
81
+ originOf,
70
82
  parseArgs2 as parseArgs,
71
83
  parseVosId,
72
84
  platformOrigin,
73
85
  prepareOutput,
74
86
  programAssets,
75
87
  promptHint,
88
+ readActive,
76
89
  readSyncState,
77
90
  refuseSymlink,
91
+ removeAll,
92
+ removeStored,
78
93
  requireCredential,
79
94
  resolveCredential,
80
95
  resolveMediaType,
81
96
  serverWarnings,
82
97
  sniffMediaType,
83
98
  strFlag,
99
+ switchTarget,
100
+ syncIdentity,
84
101
  writeCredential,
85
102
  writeFileSafe,
86
103
  writeOutput,
87
104
  writeOutputSync,
88
105
  writeSyncState
89
- } from "./chunk-EPSYIF2S.js";
106
+ } from "./chunk-PEW5GIZF.js";
90
107
  import {
91
108
  deadLine,
92
109
  deadWarns
@@ -4856,6 +4873,7 @@ async function deliverTake(browser, dir, opts) {
4856
4873
 
4857
4874
  // src/plugin/login.ts
4858
4875
  import { hostname } from "os";
4876
+ var storeWith = (store) => store ?? ((key, origin, account) => writeCredential(key, origin, void 0, account));
4859
4877
  var LoginUnsupportedError = class extends Error {
4860
4878
  constructor() {
4861
4879
  super("this origin does not support browser login");
@@ -4932,12 +4950,14 @@ async function browserLogin(origin, r, opts) {
4932
4950
  continue;
4933
4951
  }
4934
4952
  if (res.status === 200 && status === "ok") {
4935
- const path = (opts.store ?? writeCredential)(
4953
+ const account = accountFrom(res.body.user);
4954
+ const path = storeWith(opts.store)(
4936
4955
  res.body.key,
4937
- origin
4956
+ origin,
4957
+ account
4938
4958
  );
4939
4959
  const user = typeof res.body.user === "object" && res.body.user !== null ? res.body.user.name ?? "" : "";
4940
- return { path, user };
4960
+ return { path, user, account };
4941
4961
  }
4942
4962
  if (res.status === 429) {
4943
4963
  if (status === "key_limit" && !capNoted) {
@@ -4975,16 +4995,19 @@ async function handoffLogin(url, r, opts = {}) {
4975
4995
  body: { token: parsed.token, hostname: hostname().slice(0, 64) }
4976
4996
  });
4977
4997
  if (res.status === 200 && res.body.status === "ok") {
4978
- const path = (opts.store ?? writeCredential)(
4998
+ const account = accountFrom(res.body.user);
4999
+ const path = storeWith(opts.store)(
4979
5000
  res.body.key,
4980
- parsed.origin
5001
+ parsed.origin,
5002
+ account
4981
5003
  );
4982
5004
  const user = typeof res.body.user === "object" && res.body.user !== null ? res.body.user.name ?? "" : "";
4983
5005
  return {
4984
5006
  path,
4985
5007
  user,
4986
5008
  keyName: String(res.body.keyName ?? ""),
4987
- origin: parsed.origin
5009
+ origin: parsed.origin,
5010
+ account
4988
5011
  };
4989
5012
  }
4990
5013
  if (res.status === 404 && !res.body.status) {
@@ -7445,7 +7468,7 @@ async function planTake(dir, opts = {}) {
7445
7468
  import { createHash } from "crypto";
7446
7469
  import { existsSync as existsSync13, readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
7447
7470
  import { readFile as readFile11 } from "fs/promises";
7448
- import { createInterface as createInterface2 } from "readline/promises";
7471
+ import { createInterface as createInterface3 } from "readline/promises";
7449
7472
  import { basename as basename3, join as join14 } from "path";
7450
7473
  import { lowerToComposition as lowerToComposition3, migrateHostedDoc as migrateHostedDoc2 } from "@vosjs/studio-core";
7451
7474
 
@@ -7526,6 +7549,7 @@ import { mkdir as mkdir6 } from "fs/promises";
7526
7549
  import { join as join13 } from "path";
7527
7550
  import { recipeHints } from "@vosjs/shared/frontmatter";
7528
7551
  import { migrateHostedDoc } from "@vosjs/studio-core";
7552
+ import { createInterface as createInterface2 } from "readline/promises";
7529
7553
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["json", "help", "media"]);
7530
7554
  async function listFolders(origin, key) {
7531
7555
  const r = await apiJson(origin, "/api/folders", { key });
@@ -7546,7 +7570,18 @@ function projectAddress(ref) {
7546
7570
  );
7547
7571
  return m ? { handle: m[1], slug: m[2].toLowerCase() } : null;
7548
7572
  }
7549
- async function resolvePushFolder(origin, key, ref) {
7573
+ function startFromVerdict(at2, mine) {
7574
+ const owner = at2.handle.toLowerCase();
7575
+ const asks = mine !== null && (!mine.handle || mine.handle.toLowerCase() !== owner);
7576
+ const who = mine ? accountLabel(mine) : "this credential";
7577
+ const address = `@${at2.handle}/${at2.slug}`;
7578
+ return {
7579
+ asks,
7580
+ question: `Pushing to ${address} as ${who} would START your own copy of it (its recipes copied in), not continue it. Continue?`,
7581
+ refusal: `vos push --folder ${address} as ${who} would start your own copy of it, not continue it: run it as @${at2.handle} (vos switch ${at2.handle}, or --account ${at2.handle}), or pass --yes to start the copy`
7582
+ };
7583
+ }
7584
+ async function resolvePushFolder(origin, key, ref, opts = {}) {
7550
7585
  const at2 = projectAddress(ref);
7551
7586
  if (!at2) {
7552
7587
  return {
@@ -7554,6 +7589,15 @@ async function resolvePushFolder(origin, key, ref) {
7554
7589
  note: null
7555
7590
  };
7556
7591
  }
7592
+ const mine = await credentialAccount(origin, key);
7593
+ const start = startFromVerdict(at2, mine);
7594
+ if (start.asks && !opts.yes) {
7595
+ if (!process.stdin.isTTY) throw new UsageError(start.refusal);
7596
+ const rl = createInterface2({ input: process.stdin, output: process.stderr });
7597
+ const answer = await rl.question(`${start.question} [y/N] `);
7598
+ rl.close();
7599
+ if (!/^y(es)?$/i.test(answer.trim())) throw new UsageError(start.refusal);
7600
+ }
7557
7601
  const r = await apiJson(
7558
7602
  origin,
7559
7603
  `/api/folders/public/${encodeURIComponent(at2.handle)}/${encodeURIComponent(at2.slug)}/push-target`,
@@ -7603,7 +7647,7 @@ async function cmdList(argv) {
7603
7647
  origin: strFlag(flags, "origin"),
7604
7648
  api: strFlag(flags, "api")
7605
7649
  });
7606
- const key = requireCredential(strFlag(flags, "key"));
7650
+ const key = requireCredential(credentialFlags(flags));
7607
7651
  const rows = await listFolders(origin, key);
7608
7652
  if (r.json) {
7609
7653
  r.done({ folders: rows }, "");
@@ -7628,7 +7672,7 @@ async function cmdCreate(argv) {
7628
7672
  origin: strFlag(flags, "origin"),
7629
7673
  api: strFlag(flags, "api")
7630
7674
  });
7631
- const key = requireCredential(strFlag(flags, "key"));
7675
+ const key = requireCredential(credentialFlags(flags));
7632
7676
  const parentRef = strFlag(flags, "parent");
7633
7677
  let parentId;
7634
7678
  if (parentRef) {
@@ -7663,7 +7707,7 @@ async function cmdMove(argv) {
7663
7707
  origin: strFlag(flags, "origin"),
7664
7708
  api: strFlag(flags, "api")
7665
7709
  });
7666
- const key = requireCredential(strFlag(flags, "key"));
7710
+ const key = requireCredential(credentialFlags(flags));
7667
7711
  const folderId = toRef === "none" ? null : resolveFolder(await listFolders(origin, key), toRef).id;
7668
7712
  let failed = 0;
7669
7713
  const moved = [];
@@ -7723,7 +7767,7 @@ async function cmdPull(argv) {
7723
7767
  origin: strFlag(flags, "origin"),
7724
7768
  api: strFlag(flags, "api")
7725
7769
  });
7726
- const key = requireCredential(strFlag(flags, "key"));
7770
+ const key = requireCredential(credentialFlags(flags));
7727
7771
  const folder = resolveFolder(await listFolders(origin, key), ref);
7728
7772
  const res = await apiJson(origin, `/api/folders/${folder.id}`, { key });
7729
7773
  if (res.status !== 200)
@@ -7791,7 +7835,8 @@ async function cmdPull(argv) {
7791
7835
  vosId: v.id,
7792
7836
  versionId: v.currentVersionId ?? null,
7793
7837
  title: v.title,
7794
- ...v.slug ? { slug: v.slug } : {}
7838
+ ...v.slug ? { slug: v.slug } : {},
7839
+ ...await syncIdentity(origin, key)
7795
7840
  });
7796
7841
  members.push({ dir, id: v.id, title: v.title, take });
7797
7842
  }
@@ -7931,10 +7976,16 @@ function hostOf(origin) {
7931
7976
  }
7932
7977
 
7933
7978
  // src/plugin/sync.ts
7934
- function apiContext(flags) {
7979
+ function apiContext(flags, dir) {
7980
+ const origin = platformOrigin(flags);
7935
7981
  return {
7936
- origin: platformOrigin(flags),
7937
- key: requireCredential(flags.key, platformOrigin(flags))
7982
+ origin,
7983
+ key: requireCredential({
7984
+ key: flags.key,
7985
+ account: flags.account,
7986
+ origin,
7987
+ dir
7988
+ })
7938
7989
  };
7939
7990
  }
7940
7991
  async function api(ctx, path, init) {
@@ -8026,7 +8077,7 @@ async function pushTake(dir, flags, r) {
8026
8077
  await readScript(dir) ?? take.doc.source.script,
8027
8078
  dir
8028
8079
  );
8029
- const ctx = apiContext(flags);
8080
+ const ctx = apiContext(flags, dir);
8030
8081
  const tracked = readSyncState(dir);
8031
8082
  const firstPush = tracked === null;
8032
8083
  if (firstPush && !flags.yes) {
@@ -8035,7 +8086,7 @@ async function pushTake(dir, flags, r) {
8035
8086
  "first push of this take uploads its recording \u2014 pass --yes to consent headlessly"
8036
8087
  );
8037
8088
  }
8038
- const rl = createInterface2({ input: process.stdin, output: process.stderr });
8089
+ const rl = createInterface3({ input: process.stdin, output: process.stderr });
8039
8090
  const answer = await rl.question(
8040
8091
  `Push this take (recording + doc.json) to ${ctx.origin}? [y/N] `
8041
8092
  );
@@ -8071,7 +8122,9 @@ async function pushTake(dir, flags, r) {
8071
8122
  "--folder applies when CREATING a vos \u2014 this take is already pushed; file it with: vos folder move <vosId> --to <folder>"
8072
8123
  );
8073
8124
  }
8074
- const target = await resolvePushFolder(ctx.origin, ctx.key, flags.folder);
8125
+ const target = await resolvePushFolder(ctx.origin, ctx.key, flags.folder, {
8126
+ yes: flags.yes === true
8127
+ });
8075
8128
  folderId = target.id;
8076
8129
  if (target.note) r.log(target.note);
8077
8130
  }
@@ -8164,7 +8217,8 @@ async function pushTake(dir, flags, r) {
8164
8217
  versionId,
8165
8218
  pushedAt: (/* @__PURE__ */ new Date()).toISOString(),
8166
8219
  title,
8167
- slug
8220
+ slug,
8221
+ ...await syncIdentity(ctx.origin, ctx.key)
8168
8222
  });
8169
8223
  return { vosId: vos.id, versionId, versionNumber: 1 };
8170
8224
  }
@@ -8214,7 +8268,8 @@ async function pushTake(dir, flags, r) {
8214
8268
  writeSyncState(dir, {
8215
8269
  vosId: state.vosId,
8216
8270
  versionId: version.id,
8217
- pushedAt: (/* @__PURE__ */ new Date()).toISOString()
8271
+ pushedAt: (/* @__PURE__ */ new Date()).toISOString(),
8272
+ ...await syncIdentity(ctx.origin, ctx.key)
8218
8273
  });
8219
8274
  return {
8220
8275
  vosId: state.vosId,
@@ -8223,7 +8278,7 @@ async function pushTake(dir, flags, r) {
8223
8278
  };
8224
8279
  }
8225
8280
  async function pullTake(dir, flags, r) {
8226
- const ctx = apiContext(flags);
8281
+ const ctx = apiContext(flags, dir);
8227
8282
  const state = readSyncState(dir);
8228
8283
  const vosId = flags.vos ?? state?.vosId;
8229
8284
  if (!vosId) {
@@ -8333,7 +8388,8 @@ async function pullTake(dir, flags, r) {
8333
8388
  writeSyncState(dir, {
8334
8389
  vosId,
8335
8390
  versionId: head,
8336
- pushedAt: state?.pushedAt ?? (/* @__PURE__ */ new Date()).toISOString()
8391
+ pushedAt: state?.pushedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
8392
+ ...await syncIdentity(ctx.origin, ctx.key)
8337
8393
  });
8338
8394
  return {
8339
8395
  vosId,
@@ -8448,7 +8504,7 @@ async function pushTakeClaimable(dir, flags, r) {
8448
8504
  // src/plugin/program.ts
8449
8505
  import { existsSync as existsSync15 } from "fs";
8450
8506
  import { mkdir as mkdir7, readFile as readFile12 } from "fs/promises";
8451
- import { createInterface as createInterface3 } from "readline/promises";
8507
+ import { createInterface as createInterface4 } from "readline/promises";
8452
8508
  import { basename as basename5, dirname as dirname2, join as join15 } from "path";
8453
8509
  import {
8454
8510
  CURRENT_CONFIG_VERSION,
@@ -8677,7 +8733,8 @@ async function cmdFetch(argv) {
8677
8733
  vosId,
8678
8734
  versionId: head,
8679
8735
  ...title ? { title } : {},
8680
- slug
8736
+ slug,
8737
+ ...await syncIdentity(origin, key)
8681
8738
  });
8682
8739
  let take = false;
8683
8740
  let mediaLine = "";
@@ -8944,8 +9001,8 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
8944
9001
  );
8945
9002
  return EXIT_OK;
8946
9003
  }
8947
- const key = requireCredential(strFlag(flags, "key"));
8948
- void flags.yes;
9004
+ const key = requireCredential({ ...credentialFlags(flags), dir });
9005
+ const yes = flags.yes === true;
8949
9006
  const files = await collectFiles(config, programDoc, dir, r);
8950
9007
  await files.upload({ origin, key });
8951
9008
  const overrides = [
@@ -9029,7 +9086,11 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
9029
9086
  }
9030
9087
  const version = res.body.version ?? {};
9031
9088
  if (typeof version.id === "string") {
9032
- writeSyncState(dir, { vosId, versionId: version.id });
9089
+ writeSyncState(dir, {
9090
+ vosId,
9091
+ versionId: version.id,
9092
+ ...await syncIdentity(origin, key)
9093
+ });
9033
9094
  }
9034
9095
  const watchUrl2 = `${origin}/vos/${vosId}`;
9035
9096
  const studioUrl2 = `${origin}/studio?vos=${vosId}`;
@@ -9064,7 +9125,7 @@ ${landedLines(landed2)}` : "")
9064
9125
  const remixOfId = pushTarget.kind === "create" ? pushTarget.remixOfId : void 0;
9065
9126
  const fallbackTitle = state?.title ? `${state.title} remix` : basename5(source).replace(/\.json$/i, "") || "vos remix";
9066
9127
  const title = (strFlag(flags, "title") ?? fallbackTitle).slice(0, 100);
9067
- const pushFolder = folderRef ? await resolvePushFolder(origin, key, folderRef) : void 0;
9128
+ const pushFolder = folderRef ? await resolvePushFolder(origin, key, folderRef, { yes }) : void 0;
9068
9129
  const folderId = pushFolder?.id;
9069
9130
  if (pushFolder?.note) r.log(pushFolder.note);
9070
9131
  const created = await createProgramVos({
@@ -9092,7 +9153,8 @@ ${landedLines(landed2)}` : "")
9092
9153
  versionId: created.currentVersionId,
9093
9154
  title,
9094
9155
  slug: created.slug,
9095
- ...remixOfId ? { remixOfId } : {}
9156
+ ...remixOfId ? { remixOfId } : {},
9157
+ ...await syncIdentity(origin, key)
9096
9158
  });
9097
9159
  const watchUrl = `${origin}/vos/${created.id}`;
9098
9160
  const studioUrl = `${origin}/studio?vos=${created.id}`;
@@ -9159,7 +9221,7 @@ async function cmdPullProgram(argv) {
9159
9221
  `no base version in ${dir}/vos.json \u2014 pass --since <versionId>`
9160
9222
  );
9161
9223
  }
9162
- const key = requireCredential(strFlag(flags, "key"));
9224
+ const key = requireCredential({ ...credentialFlags(flags), dir });
9163
9225
  const res = await apiJson(
9164
9226
  origin,
9165
9227
  `/api/vos/${vosId}/changes?since=${encodeURIComponent(since)}`,
@@ -9231,7 +9293,8 @@ async function cmdPullProgram(argv) {
9231
9293
  await writeFileSafe(configPath, JSON.stringify(headConfig, null, 2));
9232
9294
  writeSyncState(dir, {
9233
9295
  vosId,
9234
- versionId: typeof head.id === "string" ? head.id : since
9296
+ versionId: typeof head.id === "string" ? head.id : since,
9297
+ ...await syncIdentity(origin, key)
9235
9298
  });
9236
9299
  r.done(
9237
9300
  {
@@ -9258,16 +9321,21 @@ async function cmdLogin(argv) {
9258
9321
  });
9259
9322
  const handoffUrl = strFlag(flags, "handoff");
9260
9323
  if (handoffUrl) {
9324
+ const before = await nameActiveCredential(
9325
+ parseHandoffUrl(handoffUrl)?.origin ?? origin
9326
+ );
9261
9327
  const done = await handoffLogin(handoffUrl, r);
9262
9328
  r.done(
9263
9329
  {
9264
9330
  path: done.path,
9265
9331
  origin: done.origin,
9266
9332
  user: done.user,
9333
+ account: done.account,
9267
9334
  keyName: done.keyName,
9335
+ ...setAsideFacts(before, done.account),
9268
9336
  next_step: "the link is spent; vos push when you want the work hosted"
9269
9337
  },
9270
- `Signed in${done.user ? ` as ${done.user}` : ""} \u2014 key "${done.keyName}" stored at ${done.path} (used by every vos platform verb). The link is spent.`
9338
+ `Signed in${signedAs(done.user, done.account)} \u2014 key "${done.keyName}" stored at ${done.path} (used by every vos platform verb). The link is spent.${setAsideLine(before, done.account)}`
9271
9339
  );
9272
9340
  return EXIT_OK;
9273
9341
  }
@@ -9275,13 +9343,14 @@ async function cmdLogin(argv) {
9275
9343
  if (explicit) return storeKey(explicit, origin, r);
9276
9344
  try {
9277
9345
  const openBrowser = process.stdout.isTTY === true && !process.env.SSH_CONNECTION && !process.env.SSH_TTY && flags.json !== true && flags["no-browser"] !== true;
9278
- const { path, user } = await browserLogin(origin, r, {
9346
+ const before = await nameActiveCredential(origin);
9347
+ const { path, user, account } = await browserLogin(origin, r, {
9279
9348
  label: strFlag(flags, "label"),
9280
9349
  openBrowser
9281
9350
  });
9282
9351
  r.done(
9283
- { path, origin, user },
9284
- `Signed in${user ? ` as ${user}` : ""} \u2014 key stored at ${path} (used by every vos platform verb)`
9352
+ { path, origin, user, account, ...setAsideFacts(before, account) },
9353
+ `Signed in${signedAs(user, account)} \u2014 key stored at ${path} (used by every vos platform verb).${setAsideLine(before, account)}`
9285
9354
  );
9286
9355
  return EXIT_OK;
9287
9356
  } catch (e) {
@@ -9292,24 +9361,64 @@ async function cmdLogin(argv) {
9292
9361
  `vos login --key <vos_sk_\u2026> (headless), or run interactively \u2014 mint a key at ${mintAt(origin)}`
9293
9362
  );
9294
9363
  }
9295
- const rl = createInterface3({ input: process.stdin, output: process.stderr });
9364
+ const rl = createInterface4({ input: process.stdin, output: process.stderr });
9296
9365
  const key = (await rl.question(`Paste a content key from ${origin}/app/api: `)).trim();
9297
9366
  rl.close();
9298
9367
  if (!key) throw new UsageError("no key given");
9299
9368
  return storeKey(key, origin, r);
9300
9369
  }
9301
9370
  async function storeKey(key, origin, r) {
9302
- const probe3 = await apiJson(origin, "/api/folders", { key });
9303
- if (probe3.status === 401 || probe3.status === 403) {
9304
- throw new Error(apiError("validate key", probe3));
9371
+ const who = await apiJson(origin, "/api/user/whoami", { key });
9372
+ if (who.status === 401 || who.status === 403) {
9373
+ throw new Error(apiError("validate key", who));
9305
9374
  }
9306
- const path = writeCredential(key, origin);
9375
+ let account = null;
9376
+ if (who.status === 200) account = accountFrom(who.body.user);
9377
+ else {
9378
+ const probe3 = await apiJson(origin, "/api/folders", { key });
9379
+ if (probe3.status === 401 || probe3.status === 403) {
9380
+ throw new Error(apiError("validate key", probe3));
9381
+ }
9382
+ }
9383
+ const before = await nameActiveCredential(origin);
9384
+ const path = writeCredential(key, origin, void 0, account);
9307
9385
  r.done(
9308
- { path, origin },
9309
- `Signed in \u2014 key stored at ${path} (used by every vos platform verb)`
9386
+ { path, origin, account, ...setAsideFacts(before, account) },
9387
+ `Signed in${signedAs("", account)} \u2014 key stored at ${path} (used by every vos platform verb).${setAsideLine(before, account)}`
9310
9388
  );
9311
9389
  return EXIT_OK;
9312
9390
  }
9391
+ function signedAs(user, account) {
9392
+ if (account) return ` as ${accountLabel(account)}`;
9393
+ return user ? ` as ${user}` : "";
9394
+ }
9395
+ async function nameActiveCredential(origin) {
9396
+ const active = readActive(DEFAULT_STORE);
9397
+ if (!active || active.origin !== originOf(origin)) return active;
9398
+ if (active.account) return active;
9399
+ try {
9400
+ const who = await apiJson(origin, "/api/user/whoami", { key: active.key });
9401
+ const account = who.status === 200 ? accountFrom(who.body.user) : null;
9402
+ if (!account) return active;
9403
+ const named = { ...active, account };
9404
+ activate(DEFAULT_STORE, named);
9405
+ return named;
9406
+ } catch {
9407
+ return active;
9408
+ }
9409
+ }
9410
+ function setAsideFacts(before, account) {
9411
+ if (!before || account && before.account?.id === account.id) return {};
9412
+ return before.account ? { setAside: before.account } : { replaced: true };
9413
+ }
9414
+ function setAsideLine(before, account) {
9415
+ const facts = setAsideFacts(before, account);
9416
+ if (facts.setAside)
9417
+ return ` ${accountLabel(facts.setAside)} stays stored; vos switch ${facts.setAside.handle ?? facts.setAside.id} when you need it.`;
9418
+ if (facts.replaced)
9419
+ return " The credential stored before had no name on file and was replaced.";
9420
+ return "";
9421
+ }
9313
9422
  function isTakeDir(target) {
9314
9423
  return directoryKind(target) === "take";
9315
9424
  }
@@ -9625,7 +9734,7 @@ async function cmdRename(argv) {
9625
9734
  origin: strFlag(flags, "origin"),
9626
9735
  api: strFlag(flags, "api")
9627
9736
  });
9628
- const key = requireCredential(strFlag(flags, "key"));
9737
+ const key = requireCredential(credentialFlags(flags));
9629
9738
  const res = await apiJson(origin, `/api/assets/${assetId}`, {
9630
9739
  method: "PATCH",
9631
9740
  key,
@@ -9648,7 +9757,7 @@ async function cmdPush(argv) {
9648
9757
  origin: strFlag(flags, "origin"),
9649
9758
  api: strFlag(flags, "api")
9650
9759
  });
9651
- const key = requireCredential(strFlag(flags, "key"));
9760
+ const key = requireCredential(credentialFlags(flags));
9652
9761
  const folderRef = strFlag(flags, "folder");
9653
9762
  const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
9654
9763
  const uploaded = [];
@@ -9729,7 +9838,7 @@ async function cmdImport(argv) {
9729
9838
  origin: strFlag(flags, "origin"),
9730
9839
  api: strFlag(flags, "api")
9731
9840
  });
9732
- const key = requireCredential(strFlag(flags, "key"));
9841
+ const key = requireCredential(credentialFlags(flags));
9733
9842
  const folderRef = strFlag(flags, "folder");
9734
9843
  const folder = folderRef ? resolveFolder(await listFolders(origin, key), folderRef) : null;
9735
9844
  const refused = fetchRefusal(url);
@@ -9813,7 +9922,7 @@ async function cmdList2(argv) {
9813
9922
  origin: strFlag(flags, "origin"),
9814
9923
  api: strFlag(flags, "api")
9815
9924
  });
9816
- const key = requireCredential(strFlag(flags, "key"));
9925
+ const key = requireCredential(credentialFlags(flags));
9817
9926
  const params = new URLSearchParams({
9818
9927
  limit: String(Math.min(200, Math.max(1, numFlag(flags, "limit", 50))))
9819
9928
  });
@@ -9846,7 +9955,7 @@ async function cmdUsage(argv) {
9846
9955
  origin: strFlag(flags, "origin"),
9847
9956
  api: strFlag(flags, "api")
9848
9957
  });
9849
- const key = requireCredential(strFlag(flags, "key"));
9958
+ const key = requireCredential(credentialFlags(flags));
9850
9959
  const res = await apiJson(origin, "/api/user/usage", { key });
9851
9960
  if (res.status !== 200) throw new Error(apiError("read usage", res));
9852
9961
  const usage = res.body.usage ?? {};
@@ -9873,7 +9982,7 @@ async function cmdWhy(argv) {
9873
9982
  origin: strFlag(flags, "origin"),
9874
9983
  api: strFlag(flags, "api")
9875
9984
  });
9876
- const key = requireCredential(strFlag(flags, "key"));
9985
+ const key = requireCredential(credentialFlags(flags));
9877
9986
  const res = await apiJson(origin, `/api/assets/${assetId}`, { key });
9878
9987
  if (res.status !== 200) throw new Error(apiError(`read ${assetId}`, res));
9879
9988
  const asset = hostedFile(res.body.asset);
@@ -9919,7 +10028,7 @@ async function cmdAsset(argv) {
9919
10028
  // src/plugin/remove.ts
9920
10029
  import { existsSync as existsSync16, rmSync as rmSync2, statSync as statSync3 } from "fs";
9921
10030
  import { join as join16 } from "path";
9922
- import { createInterface as createInterface4 } from "readline/promises";
10031
+ import { createInterface as createInterface5 } from "readline/promises";
9923
10032
 
9924
10033
  // src/plugin/trash.ts
9925
10034
  var BOOLEAN_FLAGS4 = /* @__PURE__ */ new Set(["json", "help"]);
@@ -9968,7 +10077,7 @@ function context(flags) {
9968
10077
  origin: strFlag(flags, "origin"),
9969
10078
  api: strFlag(flags, "api")
9970
10079
  }).replace(/\/+$/, "");
9971
- return { origin, key: requireCredential(strFlag(flags, "key")) };
10080
+ return { origin, key: requireCredential(credentialFlags(flags)) };
9972
10081
  }
9973
10082
  async function readTrash(ctx) {
9974
10083
  const res = await apiJson(ctx.origin, "/api/trash", { key: ctx.key });
@@ -10096,7 +10205,7 @@ async function cmdDelete(argv) {
10096
10205
  origin: strFlag(flags, "origin"),
10097
10206
  api: strFlag(flags, "api")
10098
10207
  }).replace(/\/+$/, "");
10099
- const key = requireCredential(strFlag(flags, "key"));
10208
+ const key = requireCredential(credentialFlags(flags));
10100
10209
  const dir = existsSync16(target) && statSync3(target).isDirectory() ? target : null;
10101
10210
  const vosId = dir ? readSyncState(dir)?.vosId : parseVosId(target);
10102
10211
  if (!vosId)
@@ -10119,7 +10228,7 @@ async function cmdDelete(argv) {
10119
10228
  throw new UsageError(
10120
10229
  `"${title}" (${vosId}) would move to Trash: re-run with --yes to confirm, or --dry-run to only look`
10121
10230
  );
10122
- const rl = createInterface4({ input: process.stdin, output: process.stderr });
10231
+ const rl = createInterface5({ input: process.stdin, output: process.stderr });
10123
10232
  const answer = await rl.question(
10124
10233
  `Move "${title}" (${vosId}) to Trash? It stays restorable there for a while (vos restore ${vosId}). [y/N] `
10125
10234
  );
@@ -12149,7 +12258,7 @@ async function cmdPush2(argv) {
12149
12258
  origin: strFlag(flags, "origin"),
12150
12259
  api: strFlag(flags, "api")
12151
12260
  });
12152
- const key = requireCredential(strFlag(flags, "key"));
12261
+ const key = requireCredential(credentialFlags(flags));
12153
12262
  if (assetId) {
12154
12263
  const res = await apiJson(origin, `/api/assets/${assetId}/file`, {
12155
12264
  method: "PUT",
@@ -18021,7 +18130,6 @@ import {
18021
18130
  existsSync as existsSync30,
18022
18131
  mkdirSync as mkdirSync6,
18023
18132
  readFileSync as readFileSync12,
18024
- rmSync as rmSync3,
18025
18133
  writeFileSync as writeFileSync6
18026
18134
  } from "fs";
18027
18135
  import { homedir as homedir2 } from "os";
@@ -18115,7 +18223,7 @@ var RULES_BODY = `## Product videos (vosso)
18115
18223
  - Hand back: vos open take serves the take into the studio at vos.so, doc.json intact
18116
18224
  - Local by default: vos push only when asked for a link, the shelf or a cloud render
18117
18225
  - Deleting: vos delete moves a vos to Trash and vos restore brings it back; if you deleted by mistake, restore it and say so. Only the person can delete forever, at vos.so/app/trash
18118
- - Credentials: VOS_API_KEY, then ~/.config/vos/credentials, then vos login; never print one
18226
+ - Credentials: VOS_API_KEY, then the account in use at ~/.config/vos/credentials (vos whoami says which; vos switch <handle> changes it), then vos login; never print one
18119
18227
  - Reference: https://vos.so/llms-full.txt`;
18120
18228
  var RULES_BLOCK = `${RULES_BEGIN}
18121
18229
  ${RULES_BODY}
@@ -18195,6 +18303,18 @@ var NODE_MIN_MAJOR = 18;
18195
18303
  function major(version) {
18196
18304
  return parseInt(version.split(".")[0] ?? "0", 10);
18197
18305
  }
18306
+ function credentialLine(facts) {
18307
+ const accounts = facts.accounts ?? [];
18308
+ const active = accounts.find((a) => a.active);
18309
+ const others = accounts.filter((a) => !a.active).map((a) => a.label);
18310
+ if (active) {
18311
+ return `${active.label} \u2713${others.length ? ` (also ${others.join(", ")})` : ""}`;
18312
+ }
18313
+ if (facts.credential) {
18314
+ return `present \u2713${others.length ? ` (stored: ${others.join(", ")}; vos switch to use one)` : ""}`;
18315
+ }
18316
+ return `absent (vos login when you need hosting)${others.length ? `; stored: ${others.join(", ")}, vos switch to use one` : ""}`;
18317
+ }
18198
18318
  function doctorReport(facts) {
18199
18319
  const lines = [];
18200
18320
  const nodeOk = major(facts.node) >= NODE_MIN_MAJOR;
@@ -18220,9 +18340,7 @@ function doctorReport(facts) {
18220
18340
  } else {
18221
18341
  lines.push("skills none \u2717 run: npx vos setup");
18222
18342
  }
18223
- lines.push(
18224
- `credential ${facts.credential ? "present \u2713" : "absent (vos login when you need hosting)"}`
18225
- );
18343
+ lines.push(`credential ${credentialLine(facts)}`);
18226
18344
  if (facts.devServer) {
18227
18345
  const d = facts.devServer;
18228
18346
  lines.push(
@@ -18280,6 +18398,7 @@ var BOOLEAN_FLAGS15 = /* @__PURE__ */ new Set([
18280
18398
  "no-rules",
18281
18399
  "no-browser"
18282
18400
  ]);
18401
+ var LOGOUT_FLAGS = /* @__PURE__ */ new Set([...BOOLEAN_FLAGS15, "all"]);
18283
18402
  var SKILLS_SOURCE = "vosjs/skills";
18284
18403
  var SKILLS_CLI_VERSION = "1.7.2";
18285
18404
  function skillsCatalogAt(version) {
@@ -18349,10 +18468,24 @@ async function doctorFacts(opts) {
18349
18468
  browser: probe2(),
18350
18469
  ffmpeg: ffmpegVersion(),
18351
18470
  skills: skillsFacts(opts.homes),
18352
- credential: resolveCredential() !== null,
18471
+ credential: safeResolve() !== null,
18472
+ accounts: storedAccounts(platformOrigin()),
18353
18473
  ...opts.url ? { devServer: await devServerFact(opts.url) } : {}
18354
18474
  };
18355
18475
  }
18476
+ function safeResolve() {
18477
+ try {
18478
+ return resolveCredential();
18479
+ } catch {
18480
+ return null;
18481
+ }
18482
+ }
18483
+ function storedAccounts(origin, store = DEFAULT_STORE) {
18484
+ return listStored(store, origin).map((c) => ({
18485
+ label: accountLabel(c.account),
18486
+ active: isActive(c, store)
18487
+ }));
18488
+ }
18356
18489
  async function cmdSetup(argv) {
18357
18490
  const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
18358
18491
  const r = reporterFor(flags);
@@ -18512,29 +18645,42 @@ async function cmdWhoami(argv) {
18512
18645
  origin: strFlag(flags, "origin"),
18513
18646
  api: strFlag(flags, "api")
18514
18647
  });
18515
- const key = resolveCredential(strFlag(flags, "key"));
18648
+ const stored = storedAccounts(origin);
18649
+ const others = stored.filter((a) => !a.active).map((a) => a.label);
18650
+ const alsoStored = others.length ? ` Also stored: ${others.join(", ")}; vos switch <name> to use one.` : "";
18651
+ const key = resolveCredential({
18652
+ key: strFlag(flags, "key"),
18653
+ account: strFlag(flags, "account"),
18654
+ origin
18655
+ });
18516
18656
  if (!key) {
18517
18657
  r.done(
18518
18658
  {
18519
18659
  signedIn: false,
18520
18660
  origin,
18661
+ accounts: stored,
18521
18662
  next_step: "vos login (only needed for hosting, sharing or cloud rendering)"
18522
18663
  },
18523
- `Not signed in to ${origin}. Recording and rendering need no account; vos login when you want a link.`
18664
+ `Not signed in to ${origin}. Recording and rendering need no account; vos login when you want a link.${alsoStored}`
18524
18665
  );
18525
18666
  return EXIT_ERROR;
18526
18667
  }
18668
+ const resolved = lastCredential();
18669
+ const via = resolved?.via ?? "stored";
18670
+ const viaLine = via === "flag" ? " (the key passed as --key)" : via === "env" ? " (from VOS_API_KEY, which outranks the stored credential)" : via === "account-flag" ? " (--account)" : via === "account-env" ? ` (${ACCOUNT_ENV})` : "";
18527
18671
  const res = await apiJson(origin, "/api/user/whoami", { key });
18528
18672
  if (res.status === 404) {
18529
18673
  r.done(
18530
18674
  {
18531
18675
  signedIn: true,
18532
18676
  origin,
18677
+ via,
18533
18678
  user: null,
18534
18679
  key: null,
18680
+ accounts: stored,
18535
18681
  next_step: "vos push when you want the work hosted"
18536
18682
  },
18537
- `A credential is present for ${origin} (this origin cannot say whose).`
18683
+ `A credential is present for ${origin}${viaLine} (this origin cannot say whose).${alsoStored}`
18538
18684
  );
18539
18685
  return EXIT_OK;
18540
18686
  }
@@ -18543,44 +18689,150 @@ async function cmdWhoami(argv) {
18543
18689
  {
18544
18690
  signedIn: false,
18545
18691
  origin,
18692
+ via,
18546
18693
  error: apiError("whoami", res),
18694
+ accounts: stored,
18547
18695
  next_step: "vos login"
18548
18696
  },
18549
- `The stored credential is refused by ${origin}: ${apiError("whoami", res)}. Run vos login.`
18697
+ `The stored credential is refused by ${origin}${viaLine}: ${apiError("whoami", res)}. Run vos login.${alsoStored}`
18550
18698
  );
18551
18699
  return EXIT_ERROR;
18552
18700
  }
18553
18701
  if (res.status !== 200) throw new Error(apiError("whoami", res));
18554
18702
  const user = res.body.user;
18703
+ const actor = res.body.actor;
18555
18704
  const k = res.body.key;
18556
18705
  const who = user?.username ? `@${user.username}` : user?.name ?? "an account";
18706
+ const orgLine = user?.kind === "org" ? ` (an organization${actor ? `, ${actor.username ? `@${actor.username}` : actor.name ?? "you"} recorded as the person behind it` : ""})` : "";
18557
18707
  const keyLine = k ? `key "${k.name ?? ""}" (${k.prefix ?? "\u2026"}, ${(k.scopes ?? []).join(", ") || "no scopes"})` : "a session, not a key";
18708
+ if (via === "stored" && resolved && !resolved.account && user?.id) {
18709
+ const active = readActive(DEFAULT_STORE);
18710
+ if (active && active.key === key) {
18711
+ activate(DEFAULT_STORE, {
18712
+ ...active,
18713
+ account: {
18714
+ id: user.id,
18715
+ kind: user.kind === "org" ? "org" : "person",
18716
+ handle: user.username ?? null
18717
+ }
18718
+ });
18719
+ }
18720
+ }
18558
18721
  r.done(
18559
18722
  {
18560
18723
  signedIn: true,
18561
18724
  origin,
18725
+ via,
18562
18726
  user,
18727
+ actor: actor ?? null,
18563
18728
  key: k,
18729
+ accounts: storedAccounts(origin),
18564
18730
  next_step: "vos push when you want the work hosted"
18565
18731
  },
18566
- `Signed in to ${origin} as ${who}, with ${keyLine}.`
18732
+ `Signed in to ${origin} as ${who}${orgLine}, with ${keyLine}${viaLine}.${alsoStored}`
18733
+ );
18734
+ return EXIT_OK;
18735
+ }
18736
+ function cmdSwitch(argv) {
18737
+ const { flags, positionals } = parseArgs(argv, BOOLEAN_FLAGS15);
18738
+ const r = reporterFor(flags);
18739
+ const origin = platformOrigin({
18740
+ origin: strFlag(flags, "origin"),
18741
+ api: strFlag(flags, "api")
18742
+ });
18743
+ const store = DEFAULT_STORE;
18744
+ const stored = listStored(store, origin);
18745
+ const active = readActive(store);
18746
+ const target = switchTarget(
18747
+ stored,
18748
+ active?.key ?? null,
18749
+ positionals[0],
18750
+ origin
18751
+ );
18752
+ if (!target.ok) throw new UsageError(target.error);
18753
+ const to = target.to;
18754
+ if (active && active.key === to.key) {
18755
+ r.done(
18756
+ {
18757
+ origin,
18758
+ account: to.account,
18759
+ changed: false,
18760
+ accounts: storedAccounts(origin, store),
18761
+ next_step: "vos push when you want the work hosted"
18762
+ },
18763
+ `${accountLabel(to.account)} is already the account in use on ${origin}.`
18764
+ );
18765
+ return EXIT_OK;
18766
+ }
18767
+ activate(store, to);
18768
+ const envKey = Boolean(process.env.VOS_API_KEY?.trim());
18769
+ r.done(
18770
+ {
18771
+ origin,
18772
+ account: to.account,
18773
+ changed: true,
18774
+ accounts: storedAccounts(origin, store),
18775
+ next_step: envKey ? "unset VOS_API_KEY; it outranks the stored credential" : "vos push when you want the work hosted"
18776
+ },
18777
+ `Now ${accountLabel(to.account)} on ${origin}${active?.account ? ` (${accountLabel(active.account)} stays stored)` : ""}.${envKey ? " VOS_API_KEY is set in this shell and still outranks it." : ""}`
18567
18778
  );
18568
18779
  return EXIT_OK;
18569
18780
  }
18570
18781
  function cmdLogout(argv) {
18571
- const { flags } = parseArgs(argv, BOOLEAN_FLAGS15);
18782
+ const { flags, positionals } = parseArgs(argv, LOGOUT_FLAGS);
18572
18783
  const r = reporterFor(flags);
18573
- const had = existsSync30(CREDENTIALS_PATH);
18574
- rmSync3(CREDENTIALS_PATH, { force: true });
18784
+ const origin = platformOrigin({
18785
+ origin: strFlag(flags, "origin"),
18786
+ api: strFlag(flags, "api")
18787
+ });
18788
+ const store = DEFAULT_STORE;
18575
18789
  const envKey = Boolean(process.env.VOS_API_KEY?.trim());
18790
+ const envNote = envKey ? " VOS_API_KEY is still set in this shell and still resolves." : "";
18791
+ const envStep = envKey ? "unset VOS_API_KEY as well; it still resolves" : "vos login when you next need hosting";
18792
+ if (flags.all === true) {
18793
+ const { had } = removeAll(store);
18794
+ r.done(
18795
+ {
18796
+ path: CREDENTIALS_PATH,
18797
+ removed: had,
18798
+ all: true,
18799
+ envCredential: envKey,
18800
+ next_step: envStep
18801
+ },
18802
+ (had ? "Removed every stored credential." : "Nothing was stored.") + envNote
18803
+ );
18804
+ return EXIT_OK;
18805
+ }
18806
+ const ref = positionals[0];
18807
+ const target = ref ? findStored(store, origin, ref) : readActive(store);
18808
+ if (!target) {
18809
+ const have = storedAccounts(origin, store);
18810
+ r.done(
18811
+ {
18812
+ path: CREDENTIALS_PATH,
18813
+ removed: false,
18814
+ envCredential: envKey,
18815
+ accounts: have,
18816
+ next_step: envStep
18817
+ },
18818
+ (ref ? `Nothing stored for ${ref.startsWith("@") ? ref : `@${ref}`} on ${origin}.` : `Nothing stored at ${CREDENTIALS_PATH}.`) + (have.length ? ` Stored: ${have.map((a) => a.label).join(", ")}.` : "") + envNote
18819
+ );
18820
+ return EXIT_OK;
18821
+ }
18822
+ const { wasActive } = removeStored(store, target);
18823
+ const left = storedAccounts(origin, store);
18824
+ const leftLine = left.length ? wasActive ? ` Still stored: ${left.map((a) => a.label).join(", ")}; vos switch <name> to use one.` : ` ${left.find((a) => a.active)?.label ?? "another account"} stays in use.` : "";
18576
18825
  r.done(
18577
18826
  {
18578
18827
  path: CREDENTIALS_PATH,
18579
- removed: had,
18828
+ removed: true,
18829
+ account: target.account,
18830
+ wasActive,
18580
18831
  envCredential: envKey,
18581
- next_step: envKey ? "unset VOS_API_KEY as well; it still resolves" : "vos login when you next need hosting"
18832
+ accounts: left,
18833
+ next_step: left.length && wasActive ? "vos switch <name>" : envStep
18582
18834
  },
18583
- (had ? `Removed ${CREDENTIALS_PATH}.` : `Nothing stored at ${CREDENTIALS_PATH}.`) + (envKey ? " VOS_API_KEY is still set in this shell and still resolves." : "")
18835
+ `Removed ${accountLabel(target.account)} (${target.origin}).${leftLine}${envNote}`
18584
18836
  );
18585
18837
  return EXIT_OK;
18586
18838
  }
@@ -18689,15 +18941,22 @@ This machine (no account)
18689
18941
  agent, a credential (present or absent, never printed), and the
18690
18942
  dev server when --url names one. Exit 3 when no browser
18691
18943
  vos whoami [--json]
18692
- the key's name and the account it belongs to, never the key
18693
- vos logout [--json]
18694
- remove ~/.config/vos/credentials (VOS_API_KEY still resolves)
18944
+ the account in use (its key's name, which rung resolved it) and
18945
+ every other account stored for the origin, never a key
18946
+ vos switch [<handle>] [--json]
18947
+ use another stored account (with two stored, the other one);
18948
+ vos login once per account, approving as it, stores them all
18949
+ vos logout [<handle>] [--all] [--json]
18950
+ forget the account in use, a named one, or every stored
18951
+ credential (VOS_API_KEY still resolves)
18695
18952
 
18696
18953
  Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
18697
18954
  vos login [--key <vos_sk_\u2026>] [--handoff <url>] [--label <name>] [--no-browser]
18698
18955
  sign in via the browser (approve at vos.so/cli/auth; works
18699
18956
  headless \u2014 print the URL, a human approves, the key stores
18700
18957
  itself). --key skips the browser (mint at vos.so/app/api).
18958
+ Additive: the person picks the account on the approval page,
18959
+ and every account signed in stays stored (vos switch).
18701
18960
  --handoff https://vos.so/h/\u2026 exchanges the setup link a
18702
18961
  signed-in person's line carries for a key, once, no click
18703
18962
  vos fetch <vosId|watch-url> [--out dir] [--media] [--json]
@@ -18761,7 +19020,8 @@ Platform (vos.so) \u2014 fetch, edit, push, pull, repeat
18761
19020
  kept) or the take's doc.json. ALWAYS pull before editing pushed work.
18762
19021
  --media also downloads the recording (+ mic/cam sidecars) beside
18763
19022
  the doc and re-anchors it, so digest/frames/render run locally
18764
- auth: --key, VOS_API_KEY, or ~/.config/vos/credentials; keys can
19023
+ auth: --key, --account <handle>, VOS_API_KEY, VOS_ACCOUNT, or the
19024
+ stored account in use (~/.config/vos/credentials); keys can
18765
19025
  never publish (visibility stays private; humans publish on vos.so)
18766
19026
  vos folder list
18767
19027
  vos folder create <name> [--parent <folderId|slug>] [--desc <text>]
@@ -18962,13 +19222,16 @@ doc.json edits arrive intact; a human can drag every zoom span. Keeps
18962
19222
  serving until Ctrl-C. The studio is https://vos.so by default (VOS_ORIGIN
18963
19223
  moves it; --studio http://localhost:6060 for a dev server).
18964
19224
 
18965
- push/pull \u2014 the hosted iteration loop (credentials: --key, VOS_API_KEY, or
18966
- ~/.config/vos/credentials via vos login; origin via VOS_ORIGIN, default
18967
- https://vos.so). A take push uploads the recording ONCE (content-addressed),
19225
+ push/pull \u2014 the hosted iteration loop (credentials: --key, --account <handle>,
19226
+ VOS_API_KEY, VOS_ACCOUNT, or the account in use at ~/.config/vos/credentials
19227
+ via vos login, one sign-in per account and vos switch between them; origin
19228
+ via VOS_ORIGIN, default https://vos.so). A take push uploads the recording ONCE (content-addressed),
18968
19229
  lowers doc.json, and creates a private vos (first push asks; --yes for
18969
19230
  headless) or a new version against the base in vos.json \u2014 a stale base
18970
19231
  prints the human's typed changelog and exits 1 (run pull, re-apply, push
18971
- again). A protected conflict means the human touched those nodes in the
19232
+ again). vos.json also names the ACCOUNT the directory belongs to, and a
19233
+ verb on it uses the stored credential for that account before the active
19234
+ one, so a take fetched as an organization pushes as it with no switch. A protected conflict means the human touched those nodes in the
18972
19235
  studio: keep their values, or --override <id> ONLY when the user asked for
18973
19236
  that exact change. ALWAYS pass --label (what you did, one line) and --note
18974
19237
  (why: the user's ask) \u2014 the version history reads as a conversation, and an
@@ -20794,7 +21057,7 @@ reference and the only credential.`
20794
21057
  }).replace(/\/+$/, "");
20795
21058
  const landed = flags.wait === true ? await waitForLanded({
20796
21059
  origin: pushedTo,
20797
- key: requireCredential(strFlag(flags, "key")),
21060
+ key: requireCredential(credentialFlags(flags)),
20798
21061
  vosId: result.vosId,
20799
21062
  versionId: result.versionId ?? null,
20800
21063
  log: (l) => r.log(l)
@@ -20915,6 +21178,8 @@ async function run(argv) {
20915
21178
  return await cmdWhoami(rest);
20916
21179
  case "logout":
20917
21180
  return cmdLogout(rest);
21181
+ case "switch":
21182
+ return cmdSwitch(rest);
20918
21183
  case "push": {
20919
21184
  const target = rest.find((a) => !a.startsWith("-"));
20920
21185
  if (target && isTakeDir(target)) return await cmdPush3(rest);
@@ -21177,4 +21442,4 @@ export {
21177
21442
  verbHelp,
21178
21443
  run
21179
21444
  };
21180
- //# sourceMappingURL=chunk-NJBUBXFE.js.map
21445
+ //# sourceMappingURL=chunk-ACWV3Y6Y.js.map