@xanots/sdk 0.0.5 → 0.0.6

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 (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -3
  3. package/dist/.build-fingerprint +1 -1
  4. package/dist/{agent-file-refresh-IJ7GN2FJ.js → agent-file-refresh-6XT23SLU.js} +4 -4
  5. package/dist/bin.js +8 -8
  6. package/dist/branch-commands-R4FR75UW.js +134 -0
  7. package/dist/{chunk-7SISR3CS.js → chunk-2SUCC4DV.js} +2 -2
  8. package/dist/{chunk-BPEEGJJA.js → chunk-3FQD3QME.js} +3 -3
  9. package/dist/{chunk-KXCPZUUM.js → chunk-4HDOP7LH.js} +8 -67
  10. package/dist/{chunk-PGBK64U5.js → chunk-4PTSTDIG.js} +2 -2
  11. package/dist/{live-diff-FP4SFNT4.js → chunk-5HCDZ2XN.js} +67 -6
  12. package/dist/{chunk-5WGEURVI.js → chunk-6AAT2AYQ.js} +21 -1
  13. package/dist/{chunk-APOR6TCV.js → chunk-CEFYM6N5.js} +2 -2
  14. package/dist/{chunk-YUPQOLFX.js → chunk-CQBJNFDK.js} +2 -2
  15. package/dist/{chunk-FN4OQT2J.js → chunk-CU5VOSTW.js} +4 -4
  16. package/dist/{chunk-YUBJLB6G.js → chunk-EFH4NFPY.js} +6 -3
  17. package/dist/chunk-EQW3YT5U.js +159 -0
  18. package/dist/{chunk-CYJ7R3AD.js → chunk-GC7ZQHW7.js} +22 -10
  19. package/dist/{chunk-IVP6TS26.js → chunk-JQLR64UC.js} +6 -5
  20. package/dist/{chunk-PXXLBXOP.js → chunk-JRGDLAEA.js} +2 -2
  21. package/dist/{chunk-WGDAOOXG.js → chunk-MU3O43L2.js} +3 -3
  22. package/dist/{chunk-F5T45NAM.js → chunk-OKNSR7MT.js} +45 -2
  23. package/dist/{chunk-MFIHIS6B.js → chunk-OLQLJY5T.js} +2 -2
  24. package/dist/{chunk-QUUB7HYK.js → chunk-P5C2YKAM.js} +2 -2
  25. package/dist/{chunk-D6OGU2AI.js → chunk-P5OAM3G2.js} +2 -2
  26. package/dist/{chunk-6DHJVLYP.js → chunk-Q77KNEUL.js} +1 -1
  27. package/dist/{chunk-QA5ICJ4M.js → chunk-QVSUMHNN.js} +3 -3
  28. package/dist/{chunk-MS3BRZAZ.js → chunk-SOCYCBYG.js} +45 -22
  29. package/dist/{chunk-OARSPAIE.js → chunk-TYBB7ON3.js} +56 -36
  30. package/dist/{chunk-ZGA5MUNC.js → chunk-Y7BARS25.js} +2 -2
  31. package/dist/cli.d.ts +28 -2
  32. package/dist/cli.js +7 -7
  33. package/dist/{codegen-command-BLOS3GR3.js → codegen-command-6XXOIQ25.js} +16 -16
  34. package/dist/{completion-GHP5RRLQ.js → completion-A6BZ3XGU.js} +8 -7
  35. package/dist/{deploy-command-XOH76USO.js → deploy-command-MTQQXPOO.js} +12 -12
  36. package/dist/{env-target-POGJMD6Q.js → env-target-C5JFLDK3.js} +2 -2
  37. package/dist/{ephemeral-command-46SL27GJ.js → ephemeral-command-K3UJSDS4.js} +5 -5
  38. package/dist/index.d.ts +67 -24
  39. package/dist/index.js +6 -6
  40. package/dist/init-command-AY4KSXR5.js +30 -0
  41. package/dist/internal.js +13 -11
  42. package/dist/{io-7VIA5SON.js → io-65CJNLYI.js} +3 -3
  43. package/dist/live-diff-QK4KC2FJ.js +12 -0
  44. package/dist/{lock-KXOJIGCG.js → lock-PDFCNYUW.js} +2 -2
  45. package/dist/{lock-commands-6UONZW26.js → lock-commands-MC6I3MZA.js} +8 -8
  46. package/dist/{login-command-SG7IWTHW.js → login-command-LCOOOPO2.js} +4 -4
  47. package/dist/{marketplace-command-NKTQ3VPS.js → marketplace-command-BCOAAN2I.js} +3 -3
  48. package/dist/{meta-client-OW5WKWW7.js → meta-client-57ZWVHST.js} +2 -2
  49. package/dist/node.js +10 -10
  50. package/dist/{release-command-FKQ6E3TD.js → release-command-V4K4IORX.js} +191 -23
  51. package/dist/scaffold.d.ts +10 -13
  52. package/dist/scaffold.js +3 -3
  53. package/dist/{test-command-56IAEYHX.js → test-command-OEBIGOPP.js} +4 -4
  54. package/dist/{upgrade-command-M2DZ3ZPD.js → upgrade-command-52AAZ3NV.js} +13 -13
  55. package/dist/{validate-command-CIBQJND7.js → validate-command-KTLPSSH7.js} +10 -10
  56. package/dist/{workspace-command-HZS43PHJ.js → workspace-command-LX5S5N2H.js} +20 -16
  57. package/guides/scaffold.md +3 -2
  58. package/llms/statements-calls.md +1 -1
  59. package/llms/statements-data.md +2 -1
  60. package/llms-full.txt +4 -3
  61. package/llms.txt +1 -1
  62. package/manifest.json +1 -1
  63. package/package.json +1 -1
  64. package/dist/init-command-NCRPVFGE.js +0 -30
@@ -1,14 +1,27 @@
1
1
  import {
2
+ assertBranchTargetHonored,
2
3
  importWorkspaceArchive,
3
4
  planWorkspaceImport
4
- } from "./chunk-5WGEURVI.js";
5
+ } from "./chunk-6AAT2AYQ.js";
5
6
  import {
6
7
  assertBundleInput,
7
8
  loadBundleText
8
- } from "./chunk-QA5ICJ4M.js";
9
+ } from "./chunk-QVSUMHNN.js";
10
+ import {
11
+ sharedSchemaChanges
12
+ } from "./chunk-5HCDZ2XN.js";
13
+ import {
14
+ assertBranchAbsent,
15
+ assertUsableBranchLabel,
16
+ createBranch,
17
+ listBranches,
18
+ liveBranchLabel,
19
+ setLiveBranch
20
+ } from "./chunk-EQW3YT5U.js";
21
+ import "./chunk-ZOYMZZ3S.js";
9
22
  import {
10
23
  confirm
11
- } from "./chunk-PGBK64U5.js";
24
+ } from "./chunk-4PTSTDIG.js";
12
25
  import {
13
26
  getAccessToken
14
27
  } from "./chunk-SG4UBJ47.js";
@@ -24,14 +37,14 @@ import {
24
37
  import "./chunk-3IGNIP6R.js";
25
38
  import {
26
39
  resolveLockPath
27
- } from "./chunk-MS3BRZAZ.js";
40
+ } from "./chunk-SOCYCBYG.js";
28
41
  import {
29
42
  UsageError,
30
43
  assertWritableDest
31
- } from "./chunk-IVP6TS26.js";
44
+ } from "./chunk-JQLR64UC.js";
32
45
  import {
33
46
  readLockFile
34
- } from "./chunk-MFIHIS6B.js";
47
+ } from "./chunk-OLQLJY5T.js";
35
48
  import "./chunk-GNPVYOPB.js";
36
49
  import {
37
50
  blank,
@@ -42,22 +55,57 @@ import {
42
55
  success,
43
56
  warn
44
57
  } from "./chunk-EZG76F7R.js";
45
- import "./chunk-BPEEGJJA.js";
46
- import "./chunk-F5T45NAM.js";
47
- import "./chunk-YUPQOLFX.js";
58
+ import "./chunk-3FQD3QME.js";
59
+ import "./chunk-OKNSR7MT.js";
60
+ import "./chunk-CQBJNFDK.js";
48
61
  import "./chunk-WHOJWOSV.js";
49
62
  import "./chunk-5XZ744TS.js";
50
63
  import {
51
64
  REFERENCEABLE_KIND_PAYLOAD_KEYS,
52
65
  lockKey
53
- } from "./chunk-YUBJLB6G.js";
66
+ } from "./chunk-EFH4NFPY.js";
54
67
 
55
68
  // src/emit/release-command.ts
56
69
  import { existsSync } from "fs";
57
70
  var DESTRUCTIVE_ACTIONS = /* @__PURE__ */ new Set(["delete", "truncate", "drop"]);
58
71
  var IDENTITY_EXEMPT_TYPES = /* @__PURE__ */ new Set(["workspace"]);
72
+ var BRANCH_INCOMPATIBLE = [
73
+ {
74
+ flag: "--replace",
75
+ why: "a replace wipes the whole workspace, which is not something a branch can scope"
76
+ },
77
+ {
78
+ flag: "--backup-branch",
79
+ why: "a branch release does not overwrite the live branch, so there is nothing for a backup to protect"
80
+ }
81
+ ];
59
82
  function resolveRequest(args) {
83
+ if (args.branch !== void 0) {
84
+ assertUsableBranchLabel(args.branch, "--branch");
85
+ const conflicting = BRANCH_INCOMPATIBLE.filter(
86
+ ({ flag }) => flag === "--replace" ? args.replace : args.backupBranch !== void 0
87
+ );
88
+ if (conflicting.length > 0) {
89
+ const { flag, why } = conflicting[0];
90
+ throw new UsageError(
91
+ `\`--branch\` cannot be combined with \`${flag}\`: ${why}.
92
+ Drop \`${flag}\` to stage this release on "${args.branch}", or drop \`--branch\` to release to the live branch.`,
93
+ { helpFor: { command: "release" } }
94
+ );
95
+ }
96
+ } else if (args.setLive) {
97
+ throw new UsageError(
98
+ "`--set-live` promotes the branch a release just landed on, and this release names no branch.\nAdd `--branch <label>` to stage the release and promote it, or use `xanots workspace branch set-live <label>` to promote a branch that already exists.",
99
+ { helpFor: { command: "release" } }
100
+ );
101
+ }
60
102
  if (args.replace) {
103
+ if (args.backupBranch !== void 0) {
104
+ throw new UsageError(
105
+ "`--replace` cannot be combined with `--backup-branch`: a replace deletes the workspace's non-live branches, so it would destroy the snapshot along with everything else and leave you with a rollback target that does not exist.\nDrop `--replace` to merge (which a backup CAN protect), or take a workspace export first with `xanots workspace export`.",
106
+ { helpFor: { command: "release" } }
107
+ );
108
+ }
61
109
  const conflicting = [
62
110
  args.prune ? "--prune" : "",
63
111
  args.resetData ? "--reset-data" : "",
@@ -75,9 +123,14 @@ function resolveRequest(args) {
75
123
  mode: "merge",
76
124
  prune: args.prune,
77
125
  records: args.seed,
78
- truncate: args.resetData
126
+ truncate: args.resetData,
127
+ ...args.branch !== void 0 ? { branch: args.branch } : {}
79
128
  };
80
129
  }
130
+ function derivedBackupLabel(now) {
131
+ const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
132
+ return `backup-${stamp}`;
133
+ }
81
134
  function isDestructive(req) {
82
135
  return req.mode === "replace" || req.prune === true || req.truncate === true || req.records === true;
83
136
  }
@@ -153,8 +206,8 @@ async function reconcileLockAfterReplace(args, auth, workspaceId) {
153
206
  return;
154
207
  }
155
208
  try {
156
- const { adoptFromBundle } = await import("./lock-KXOJIGCG.js");
157
- const { readLockFile: readLockFile2, writeLockFile } = await import("./io-7VIA5SON.js");
209
+ const { adoptFromBundle } = await import("./lock-PDFCNYUW.js");
210
+ const { readLockFile: readLockFile2, writeLockFile } = await import("./io-65CJNLYI.js");
158
211
  const { lock, added, changed } = adoptFromBundle(readLockFile2(lockPath), live, lockPath);
159
212
  writeLockFile(lockPath, lock);
160
213
  const touched = added.length + changed.length;
@@ -192,7 +245,7 @@ function targetIsEmpty(live) {
192
245
  async function convergedWithLive(live, req, outgoingBundle) {
193
246
  if (live === void 0 || req.mode !== "merge") return false;
194
247
  if (req.records === true || req.truncate === true) return false;
195
- const { compareToLive } = await import("./live-diff-FP4SFNT4.js");
248
+ const { compareToLive } = await import("./live-diff-QK4KC2FJ.js");
196
249
  let result;
197
250
  try {
198
251
  result = compareToLive(JSON.parse(outgoingBundle), live);
@@ -209,7 +262,7 @@ async function warnAboutLiveLosses(live, req, outgoingBundle) {
209
262
  warn("Could not read the target workspace, so this plan does not account for dropped columns or env that will not update.");
210
263
  return { droppedColumns: 0, unchangedEnv: [] };
211
264
  }
212
- const { diffAgainstLive } = await import("./live-diff-FP4SFNT4.js");
265
+ const { diffAgainstLive } = await import("./live-diff-QK4KC2FJ.js");
213
266
  let diff;
214
267
  try {
215
268
  diff = diffAgainstLive(JSON.parse(outgoingBundle), live, { mode: req.mode });
@@ -327,6 +380,46 @@ function renderPlan(plan, req, workspaceId, targetIsEmpty2, converged = false) {
327
380
  warnOnZeroCorrespondence(plan, req, targetIsEmpty2);
328
381
  blank();
329
382
  }
383
+ function assertSharedSchemaAcknowledged(args, live, bundle, branch) {
384
+ const changes = sharedSchemaChanges(JSON.parse(bundle), live, { prune: args.prune });
385
+ if (changes === void 0) {
386
+ if (args.allowSharedSchemaChanges) return void 0;
387
+ throw new UsageError(
388
+ `Refusing to release to branch "${branch}": the live workspace could not be read, so whether this release changes shared schema is unknown.
389
+ Tables and microservices are shared by every branch, so a schema change reaches production even on a branch release. A failed read is not evidence that there is none.
390
+ Retry when the instance is reachable, or pass \`--allow-shared-schema-changes\` to proceed without the check.`,
391
+ { helpFor: { command: "release" } }
392
+ );
393
+ }
394
+ if (changes.length === 0 || args.allowSharedSchemaChanges) return changes;
395
+ const lines = changes.map((c) => {
396
+ const detailText = c.details === void 0 || c.details.length === 0 ? "" : ` \u2014 ${c.details.join(", ")}`;
397
+ return ` ${c.action} ${c.kind === "dbo" ? "table" : "microservice"} "${c.name}"${detailText}`;
398
+ });
399
+ throw new UsageError(
400
+ `\`--branch ${branch}\` cannot stage ${changes.length} change${changes.length === 1 ? "" : "s"} to this workspace's SHARED schema:
401
+ ${lines.join("\n")}
402
+
403
+ Tables and microservices carry no branch in Xano \u2014 one set is shared by every branch. These would be applied to the LIVE workspace by the same import that stages your logic on "${branch}", and the plan would report them as routine.
404
+ Release without \`--branch\` if applying them is what you want, take them out of this release, or pass \`--allow-shared-schema-changes\` to stage the logic and apply the schema knowing both happen.`,
405
+ { helpFor: { command: "release" } }
406
+ );
407
+ }
408
+ function reportBranchCaveats(branch, setLive, changed) {
409
+ blank();
410
+ if (changed === void 0) {
411
+ warn("The live workspace could not be read, so whether this changed shared schema is UNKNOWN.");
412
+ detail("Tables and microservices are shared by every branch \u2014 a change there reached production.");
413
+ } else if (changed > 0) {
414
+ warn(`${changed} shared-schema change${changed === 1 ? "" : "s"} were applied to the LIVE workspace.`);
415
+ detail("Tables and microservices are shared by every branch \u2014 only your logic is staged.");
416
+ } else {
417
+ detail(`Only logic was staged on "${branch}" \u2014 this release changed no shared schema.`);
418
+ }
419
+ if (!setLive) {
420
+ detail(`Nothing serves "${branch}" yet. Promote it with \`xanots workspace branch set-live ${branch}\`.`);
421
+ }
422
+ }
330
423
  async function runReleaseCommand(args) {
331
424
  assertWritableDest(args.dest, "release");
332
425
  const req = resolveRequest(args);
@@ -338,7 +431,7 @@ async function runReleaseCommand(args) {
338
431
  { withSeed: req.records === true }
339
432
  );
340
433
  if (args.static !== void 0) {
341
- const { assertNoSeedLeaks } = await import("./deploy-command-XOH76USO.js");
434
+ const { assertNoSeedLeaks } = await import("./deploy-command-MTQQXPOO.js");
342
435
  await assertNoSeedLeaks(args.static, nonPublicSeedValues, args.allowSeedInStatic);
343
436
  }
344
437
  const workspaceId = auth.workspaceId;
@@ -347,21 +440,27 @@ async function runReleaseCommand(args) {
347
440
  warn("`--seed` was passed, but no table in this project declares seed rows \u2014 no rows will be written.");
348
441
  }
349
442
  const target = { baseUrl: auth.instance, archive, workspaceId, ...req };
443
+ const branches = req.branch !== void 0 || args.backupBranch !== void 0 ? await listBranches(auth, { baseUrl: auth.instance, workspaceId }) : [];
444
+ if (req.branch !== void 0) assertBranchAbsent(branches, req.branch);
350
445
  step(
351
- `Releasing ${source} \u2192 instance workspace #${workspaceId}` + (req.mode === "replace" ? " (full replace)" : " (merge)")
446
+ `Releasing ${source} \u2192 instance workspace #${workspaceId}` + (req.branch !== void 0 ? ` branch "${req.branch}"` : "") + (req.mode === "replace" ? " (full replace)" : " (merge)")
352
447
  );
353
448
  const plan = await planWorkspaceImport(auth, target);
449
+ if (req.branch !== void 0) assertBranchTargetHonored(plan, req.branch, auth.instance);
354
450
  const live = await readLiveWorkspace(auth, workspaceId);
355
451
  const converged = await convergedWithLive(live, req, bundle);
356
452
  renderPlan(plan, req, workspaceId, targetIsEmpty(live), converged);
357
453
  const losses = await warnAboutLiveLosses(live, req, bundle);
454
+ const sharedChanges = req.branch === void 0 ? [] : assertSharedSchemaAcknowledged(args, live, bundle, req.branch);
358
455
  if (req.prune === true) assertPruneStaysInScope(args, plan);
359
456
  if (args.dryRun) {
360
457
  info("Dry run \u2014 nothing was sent.");
361
458
  if (isMachineOutput(args)) writeJson({ released: false, dryRun: true, workspaceId, plan });
362
459
  return;
363
460
  }
364
- const upToDate = plan.operations.length === 0 || converged;
461
+ let backupLabel;
462
+ let promoted = args.setLive;
463
+ const upToDate = req.branch === void 0 && (plan.operations.length === 0 || converged);
365
464
  if (upToDate) {
366
465
  success(`Workspace #${workspaceId} is already up to date \u2014 no import sent.`);
367
466
  } else {
@@ -375,8 +474,72 @@ async function runReleaseCommand(args) {
375
474
  return;
376
475
  }
377
476
  }
378
- await importWorkspaceArchive(auth, target);
379
- success(`Released to instance workspace #${workspaceId}`);
477
+ if (args.backupBranch !== void 0) {
478
+ const sourceLabel = liveBranchLabel(branches);
479
+ const label = typeof args.backupBranch === "string" ? args.backupBranch : derivedBackupLabel(/* @__PURE__ */ new Date());
480
+ assertUsableBranchLabel(label, "--backup-branch");
481
+ assertBranchAbsent(branches, label);
482
+ step(`Snapshotting the live branch as "${label}" before importing\u2026`);
483
+ try {
484
+ await createBranch(auth, {
485
+ baseUrl: auth.instance,
486
+ workspaceId,
487
+ label,
488
+ ...sourceLabel !== void 0 ? { sourceBranch: sourceLabel } : {},
489
+ description: `Pre-release snapshot taken by xanots from ${source}`
490
+ });
491
+ } catch (err) {
492
+ throw new Error(
493
+ `The pre-release backup branch could not be created, so the release was not sent.
494
+ Nothing has changed in workspace #${workspaceId}.
495
+ Retry, or drop \`--backup-branch\` to release without one.`,
496
+ { cause: err }
497
+ );
498
+ }
499
+ backupLabel = label;
500
+ success(`Live branch snapshotted as "${label}".`);
501
+ }
502
+ try {
503
+ await importWorkspaceArchive(auth, target);
504
+ } catch (err) {
505
+ if (backupLabel !== void 0) {
506
+ blank();
507
+ warn(`The import failed. Your pre-release snapshot is on branch "${backupLabel}".`);
508
+ detail(`Restore it with \`xanots workspace branch set-live ${backupLabel}\`.`);
509
+ }
510
+ throw err;
511
+ }
512
+ success(
513
+ req.branch !== void 0 ? `Released to workspace #${workspaceId} on branch "${req.branch}"` : `Released to instance workspace #${workspaceId}`
514
+ );
515
+ if (req.branch !== void 0) {
516
+ if (args.setLive) {
517
+ const previous = liveBranchLabel(branches);
518
+ blank();
519
+ warn(`Promoting "${req.branch}" is a production cutover for workspace #${workspaceId}.`);
520
+ if (previous !== void 0) {
521
+ detail(`The runtime stops serving "${previous}" and starts serving "${req.branch}".`);
522
+ }
523
+ if (!args.yes && !args.force && !await confirm(`Make "${req.branch}" the live branch?`, {
524
+ flag: "--yes",
525
+ helpFor: { command: "release" }
526
+ })) {
527
+ info(`Cancelled the promote \u2014 the release is staged on "${req.branch}" and nothing serves it yet.`);
528
+ detail(`Promote it later with \`xanots workspace branch set-live ${req.branch}\`.`);
529
+ promoted = false;
530
+ } else {
531
+ await setLiveBranch(auth, { baseUrl: auth.instance, workspaceId, label: req.branch });
532
+ success(`Branch "${req.branch}" is now live.`);
533
+ if (previous !== void 0) {
534
+ detail(`Roll back with \`xanots workspace branch set-live ${previous}\`.`);
535
+ }
536
+ }
537
+ }
538
+ reportBranchCaveats(req.branch, promoted, sharedChanges?.length);
539
+ } else if (backupLabel !== void 0) {
540
+ blank();
541
+ detail(`Roll back this release with \`xanots workspace branch set-live ${backupLabel}\`.`);
542
+ }
380
543
  if (req.mode === "replace") await reconcileLockAfterReplace(args, auth, workspaceId);
381
544
  }
382
545
  link(auth.instance);
@@ -402,10 +565,15 @@ async function runReleaseCommand(args) {
402
565
  // beside `upToDate: true` would contradict it.
403
566
  operations: upToDate ? 0 : plan.operations.length,
404
567
  droppedColumns: losses.droppedColumns,
405
- unchangedEnv: losses.unchangedEnv
568
+ unchangedEnv: losses.unchangedEnv,
569
+ // Present only when they mean something: a plain release carries no branch
570
+ // fields at all, so a wrapper reading `branch` cannot mistake "released to
571
+ // live" for "released to a branch named undefined".
572
+ ...req.branch !== void 0 ? { branch: req.branch, setLive: promoted, sharedSchemaChanges: sharedChanges?.length } : {},
573
+ ...backupLabel !== void 0 ? { backupBranch: backupLabel } : {}
406
574
  };
407
575
  if (args.static !== void 0) {
408
- const { buildStaticEnv, deployStaticTo } = await import("./deploy-command-XOH76USO.js");
576
+ const { buildStaticEnv, deployStaticTo } = await import("./deploy-command-MTQQXPOO.js");
409
577
  const env = buildStaticEnv(auth.instance, args.staticEnv);
410
578
  const explicit = Object.keys(args.staticEnv).length > 0;
411
579
  summary.static = await deployStaticTo(
@@ -424,4 +592,4 @@ async function runReleaseCommand(args) {
424
592
  export {
425
593
  runReleaseCommand
426
594
  };
427
- //# sourceMappingURL=release-command-FKQ6E3TD.js.map
595
+ //# sourceMappingURL=release-command-V4K4IORX.js.map
@@ -1319,8 +1319,7 @@ declare function iconLibraryOf(id: IconLibraryId | undefined): IconLibrary;
1319
1319
  * light/dark token map under a schema, so it lands as a {@link Theme} too.
1320
1320
  *
1321
1321
  * Browser-safe: pure string building and arithmetic, no node:* imports. The
1322
- * flag parsing that reads a URL and the prompt that reads a TTY live in
1323
- * `theme-resolve.ts`, mirroring the `frontend-presets` / `frontend-resolve`
1322
+ * flag parsing that reads a URL lives in `theme-resolve.ts`, mirroring the `frontend-presets` / `frontend-resolve`
1324
1323
  * split.
1325
1324
  */
1326
1325
 
@@ -1357,7 +1356,7 @@ declare const DEFAULT_DARK_MODE: DarkMode;
1357
1356
  interface Theme {
1358
1357
  /** Stable id — `neutral`, `zinc-blue`, or an imported item's registry name. */
1359
1358
  readonly id: string;
1360
- /** Human label for prose and the interactive prompt, e.g. `Zinc Blue`. */
1359
+ /** Human label for prose and any theme picker, e.g. `Zinc Blue`. */
1361
1360
  readonly label: string;
1362
1361
  /**
1363
1362
  * The base color this theme was built from, for `components.json`'s
@@ -1493,15 +1492,13 @@ declare function isAccent(id: string): id is AccentId;
1493
1492
  /** Validate a `--dark` value, mirroring the other scaffold flags' hard errors. */
1494
1493
  declare function resolveDarkModeFlag(raw: string): DarkMode;
1495
1494
  /**
1496
- * The interactive menu: a short, opinionated list rather than all 126
1497
- * combinations.
1495
+ * The shortlist: a short, opinionated set for anyone offering a theme picker
1496
+ * over this module, rather than all 126 combinations.
1498
1497
  *
1499
- * A prompt is for someone who wants to not think about this. The full space
1500
- * stays reachablethe prompt accepts any `<base>-<accent>` or URL typed in
1501
- * place of a number, and `--theme` accepts the same so this list is a
1502
- * shortcut, not the supported set. One entry per base color, each paired with
1503
- * an accent that suits its temperature, keeps the menu one screen tall while
1504
- * still showing what every base looks like.
1498
+ * The full space stays reachable `--theme` takes any `<base>-<accent>` or
1499
+ * registry URLso this list is a shortcut, not the supported set. One entry
1500
+ * per base color, each paired with an accent that suits its temperature, shows
1501
+ * what every base looks like in one screen.
1505
1502
  */
1506
1503
  declare const CURATED_THEMES: readonly string[];
1507
1504
  /** {@link CURATED_THEMES}, resolved. Throws at import time if an id ever rots. */
@@ -1574,14 +1571,14 @@ declare function colorTokens(vars: Readonly<Record<string, string>>): string[];
1574
1571
  * is a second source of truth for one boolean.
1575
1572
  */
1576
1573
  declare function themeGuidanceSection(choice: ThemeChoice): string;
1577
- /** An sRGB triple, 0–255, for painting a swatch in the interactive prompt. */
1574
+ /** An sRGB triple, 0–255, for painting a theme swatch. */
1578
1575
  interface Rgb {
1579
1576
  readonly r: number;
1580
1577
  readonly g: number;
1581
1578
  readonly b: number;
1582
1579
  }
1583
1580
  /**
1584
- * The colors that identify a theme at a glance in the prompt: the primary, the
1581
+ * The colors that identify a theme at a glance in a picker: the primary, the
1585
1582
  * page background, and a muted midtone.
1586
1583
  *
1587
1584
  * Three is the smallest set that distinguishes the menu's entries — the accent
package/dist/scaffold.js CHANGED
@@ -4,10 +4,10 @@ import {
4
4
  allFrontendPresets,
5
5
  findFrontendPreset,
6
6
  resolveFrameworkFlag
7
- } from "./chunk-WGDAOOXG.js";
7
+ } from "./chunk-MU3O43L2.js";
8
8
  import {
9
9
  renderIndexCss
10
- } from "./chunk-QUUB7HYK.js";
10
+ } from "./chunk-P5C2YKAM.js";
11
11
  import {
12
12
  ACCENTS,
13
13
  ACCENT_TOKENS,
@@ -50,7 +50,7 @@ import {
50
50
  themeGuidanceSection,
51
51
  themeSwatch,
52
52
  withRadius
53
- } from "./chunk-6DHJVLYP.js";
53
+ } from "./chunk-Q77KNEUL.js";
54
54
  export {
55
55
  ACCENTS,
56
56
  ACCENT_TOKENS,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveMetaTarget
3
- } from "./chunk-APOR6TCV.js";
3
+ } from "./chunk-CEFYM6N5.js";
4
4
  import "./chunk-WJYB7DSI.js";
5
5
  import "./chunk-OR43PDCW.js";
6
6
  import "./chunk-NDZFBZHC.js";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-3IGNIP6R.js";
20
20
  import {
21
21
  unknownSubcommand
22
- } from "./chunk-IVP6TS26.js";
22
+ } from "./chunk-JQLR64UC.js";
23
23
  import "./chunk-GNPVYOPB.js";
24
24
  import {
25
25
  blank,
@@ -29,7 +29,7 @@ import {
29
29
  success,
30
30
  warn
31
31
  } from "./chunk-EZG76F7R.js";
32
- import "./chunk-F5T45NAM.js";
32
+ import "./chunk-OKNSR7MT.js";
33
33
 
34
34
  // src/deploy/tests.ts
35
35
  var TIMEOUT_MS = 12e4;
@@ -380,4 +380,4 @@ export {
380
380
  runSuite,
381
381
  runTestCommand
382
382
  };
383
- //# sourceMappingURL=test-command-56IAEYHX.js.map
383
+ //# sourceMappingURL=test-command-OEBIGOPP.js.map
@@ -7,25 +7,25 @@ import {
7
7
  } from "./chunk-NUQCEOKA.js";
8
8
  import {
9
9
  refreshAgentFiles
10
- } from "./chunk-D6OGU2AI.js";
11
- import "./chunk-7SISR3CS.js";
10
+ } from "./chunk-P5OAM3G2.js";
11
+ import "./chunk-2SUCC4DV.js";
12
12
  import {
13
13
  runNpm
14
14
  } from "./chunk-ZSYZTGJH.js";
15
15
  import {
16
16
  sdkDep
17
- } from "./chunk-QUUB7HYK.js";
18
- import "./chunk-6DHJVLYP.js";
17
+ } from "./chunk-P5C2YKAM.js";
18
+ import "./chunk-Q77KNEUL.js";
19
19
  import {
20
20
  checkForUpgrade,
21
21
  detectInstallMode,
22
22
  registryUrl,
23
23
  suppressUpdateNotice,
24
24
  upgradeCommand
25
- } from "./chunk-ZGA5MUNC.js";
26
- import "./chunk-MS3BRZAZ.js";
27
- import "./chunk-IVP6TS26.js";
28
- import "./chunk-MFIHIS6B.js";
25
+ } from "./chunk-Y7BARS25.js";
26
+ import "./chunk-SOCYCBYG.js";
27
+ import "./chunk-JQLR64UC.js";
28
+ import "./chunk-OLQLJY5T.js";
29
29
  import "./chunk-GNPVYOPB.js";
30
30
  import {
31
31
  blank,
@@ -35,12 +35,12 @@ import {
35
35
  success,
36
36
  warn
37
37
  } from "./chunk-EZG76F7R.js";
38
- import "./chunk-BPEEGJJA.js";
39
- import "./chunk-F5T45NAM.js";
40
- import "./chunk-YUPQOLFX.js";
38
+ import "./chunk-3FQD3QME.js";
39
+ import "./chunk-OKNSR7MT.js";
40
+ import "./chunk-CQBJNFDK.js";
41
41
  import "./chunk-WHOJWOSV.js";
42
42
  import "./chunk-5XZ744TS.js";
43
- import "./chunk-YUBJLB6G.js";
43
+ import "./chunk-EFH4NFPY.js";
44
44
 
45
45
  // src/emit/upgrade-command.ts
46
46
  import { readFileSync, writeFileSync } from "fs";
@@ -174,4 +174,4 @@ function messageOf(err) {
174
174
  export {
175
175
  runUpgradeCommand
176
176
  };
177
- //# sourceMappingURL=upgrade-command-M2DZ3ZPD.js.map
177
+ //# sourceMappingURL=upgrade-command-52AAZ3NV.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  assertBundleInput,
3
3
  loadBundleText
4
- } from "./chunk-QA5ICJ4M.js";
5
- import "./chunk-MS3BRZAZ.js";
6
- import "./chunk-IVP6TS26.js";
7
- import "./chunk-MFIHIS6B.js";
4
+ } from "./chunk-QVSUMHNN.js";
5
+ import "./chunk-SOCYCBYG.js";
6
+ import "./chunk-JQLR64UC.js";
7
+ import "./chunk-OLQLJY5T.js";
8
8
  import "./chunk-GNPVYOPB.js";
9
9
  import {
10
10
  blank,
@@ -14,19 +14,19 @@ import {
14
14
  success,
15
15
  warn
16
16
  } from "./chunk-EZG76F7R.js";
17
- import "./chunk-BPEEGJJA.js";
18
- import "./chunk-F5T45NAM.js";
19
- import "./chunk-YUPQOLFX.js";
17
+ import "./chunk-3FQD3QME.js";
18
+ import "./chunk-OKNSR7MT.js";
19
+ import "./chunk-CQBJNFDK.js";
20
20
  import "./chunk-WHOJWOSV.js";
21
21
  import "./chunk-5XZ744TS.js";
22
- import "./chunk-YUBJLB6G.js";
22
+ import "./chunk-EFH4NFPY.js";
23
23
 
24
24
  // src/emit/validate-command.ts
25
25
  var EXIT_VALIDATION_FAILED = 2;
26
26
  async function runValidateCommand(args) {
27
27
  assertBundleInput(args, { command: "validate" });
28
28
  const { resolveValidateConfig, verifyToken } = await import("./config-NL33PN4D.js");
29
- const { MetaClient } = await import("./meta-client-OW5WKWW7.js");
29
+ const { MetaClient } = await import("./meta-client-57ZWVHST.js");
30
30
  const config = resolveValidateConfig({ instance: args.instance });
31
31
  const who = await verifyToken(config);
32
32
  const host = new URL(config.instance).host;
@@ -119,4 +119,4 @@ function fmt(v) {
119
119
  export {
120
120
  runValidateCommand
121
121
  };
122
- //# sourceMappingURL=validate-command-CIBQJND7.js.map
122
+ //# sourceMappingURL=validate-command-KTLPSSH7.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  fetchWorkspaceBundle,
3
3
  runCodegenCommand
4
- } from "./chunk-OARSPAIE.js";
4
+ } from "./chunk-TYBB7ON3.js";
5
5
  import "./chunk-ZOYMZZ3S.js";
6
6
  import {
7
7
  resolveOutputTarget
@@ -19,30 +19,30 @@ import "./chunk-LLWK6H77.js";
19
19
  import "./chunk-QTNO2WD6.js";
20
20
  import "./chunk-ZUTSMMAG.js";
21
21
  import "./chunk-X4DVXBFY.js";
22
- import "./chunk-KXCPZUUM.js";
22
+ import "./chunk-4HDOP7LH.js";
23
23
  import {
24
24
  isMachineOutput,
25
25
  writeJson
26
26
  } from "./chunk-NUQCEOKA.js";
27
- import "./chunk-7SISR3CS.js";
27
+ import "./chunk-2SUCC4DV.js";
28
28
  import "./chunk-ZSYZTGJH.js";
29
29
  import {
30
30
  fetchOrExplain,
31
31
  httpFailure
32
32
  } from "./chunk-3IGNIP6R.js";
33
- import "./chunk-PXXLBXOP.js";
33
+ import "./chunk-JRGDLAEA.js";
34
34
  import "./chunk-LU7TRWMC.js";
35
- import "./chunk-WGDAOOXG.js";
36
- import "./chunk-QUUB7HYK.js";
37
- import "./chunk-6DHJVLYP.js";
35
+ import "./chunk-MU3O43L2.js";
36
+ import "./chunk-P5C2YKAM.js";
37
+ import "./chunk-Q77KNEUL.js";
38
38
  import "./chunk-4BXJGVZ3.js";
39
- import "./chunk-CYJ7R3AD.js";
40
- import "./chunk-MS3BRZAZ.js";
39
+ import "./chunk-GC7ZQHW7.js";
40
+ import "./chunk-SOCYCBYG.js";
41
41
  import {
42
42
  removedSubcommand,
43
43
  unknownSubcommand
44
- } from "./chunk-IVP6TS26.js";
45
- import "./chunk-MFIHIS6B.js";
44
+ } from "./chunk-JQLR64UC.js";
45
+ import "./chunk-OLQLJY5T.js";
46
46
  import "./chunk-GNPVYOPB.js";
47
47
  import {
48
48
  formatFields,
@@ -50,12 +50,12 @@ import {
50
50
  step,
51
51
  success
52
52
  } from "./chunk-EZG76F7R.js";
53
- import "./chunk-BPEEGJJA.js";
54
- import "./chunk-F5T45NAM.js";
55
- import "./chunk-YUPQOLFX.js";
53
+ import "./chunk-3FQD3QME.js";
54
+ import "./chunk-OKNSR7MT.js";
55
+ import "./chunk-CQBJNFDK.js";
56
56
  import "./chunk-WHOJWOSV.js";
57
57
  import "./chunk-5XZ744TS.js";
58
- import "./chunk-YUBJLB6G.js";
58
+ import "./chunk-EFH4NFPY.js";
59
59
 
60
60
  // src/emit/workspace-command.ts
61
61
  import { writeFileSync } from "fs";
@@ -69,6 +69,10 @@ async function runWorkspaceCommand(args) {
69
69
  return runExport(args);
70
70
  case "codegen":
71
71
  return runCodegenCommand(args, { kind: "workspace" });
72
+ case "branch": {
73
+ const { runBranchCommand } = await import("./branch-commands-R4FR75UW.js");
74
+ return runBranchCommand(args);
75
+ }
72
76
  case "deploy":
73
77
  throw removedSubcommand("workspace", "deploy");
74
78
  default:
@@ -156,4 +160,4 @@ async function runExport(args) {
156
160
  export {
157
161
  runWorkspaceCommand
158
162
  };
159
- //# sourceMappingURL=workspace-command-HZS43PHJ.js.map
163
+ //# sourceMappingURL=workspace-command-LX5S5N2H.js.map
@@ -12,8 +12,9 @@ What `xanots init` writes, the two frontend presets, theming, add-ons, and the S
12
12
  `--marketplace <pkg>` (repeatable, comma-separated; installs add-ons and
13
13
  registers them — below), `--force` (scaffold into a non-empty folder),
14
14
  `--no-install` (skip `npm install`).
15
- In a terminal, `init` prompts for the framework, the theme, and the AI files;
16
- every prompt has a default, so pressing enter three times is a valid answer.
15
+ In a terminal, `init` prompts for the framework and the AI files; every prompt
16
+ has a default, so pressing enter twice is a valid answer. The look is never
17
+ prompted for — it comes from the flags above, or from `xanots onboard`.
17
18
  The starter backend is empty but already compiles and deploys — grow it from the
18
19
  walkthrough in `xano/EXAMPLE.md`.
19
20
 
@@ -13,7 +13,7 @@ Auth & calls:
13
13
  - `s.stream.from_request({ url, method?, …tls, as? })` — streaming external HTTP request (`mvp:streaming_api_request`); same typed field surface as `s.api.request` (no description/output envelope). `url` is REQUIRED — it shares `api.request`'s engine declaration, which has no default.
14
14
  - `s.webflow.request({ path, method?, …tls, as? })` — Webflow API request (`mvp:connect_webflow_api_request`); like `s.api.request` but addressed by `path` (host is engine-supplied), and `path` is REQUIRED — the engine rejects an empty one. No `headers`: the engine builds its own from the workspace's Webflow connection and ignores an authored value.
15
15
  - `s.task.call` / `s.tool.call` / `s.trigger.call` / `s.middleware.call` / `s.addon.call` — same `{ <target>, input?, as? }` shape against the named kind. `s.task.call` and `s.trigger.call` are WORKFLOW-TEST ONLY (see Gotchas in `llms.txt`); `s.tool.call`, `s.middleware.call` and `s.addon.call` run from any stack.
16
- - `s.action.call({ action, package?, input?, as? })` / `s.action.package.call()` — invoke a marketplace action; `package` is its slug.
16
+ - `s.action.call({ actionId, input?, registry?, as? })` / `s.action.package.call({ traceId, versionId, slug, input?, registry?, as? })` — invoke an installed action. Ids are SUPPLIED, never derived from a name: an action is installed onto the instance, so its identity is assigned at install and differs per instance — read them off a call in a pulled workspace. The package form needs all three parts; they are one composite and two of them address nothing. `registry` is the action's own settings, `input` the per-call arguments.
17
17
  - `s.cloud.job({ image, command, args?, secret?, template?, await?, as? })` — launch a containerized job. `image`/`command` are REQUIRED; omitted → `Missing param`. ⚠ `await` is SECONDS (default 60), not a boolean.
18
18
  - `s.cloud.job.status({ id, as? })` · `s.cloud.job.await({ ids, timeout, as? })` — poll one job, or block on several (`ids` a list `Value`, `timeout` in seconds; both required).
19
19