@xanots/sdk 0.0.4 → 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 (78) hide show
  1. package/CHANGELOG.md +21 -10
  2. package/README.md +7 -3
  3. package/dist/.build-fingerprint +1 -0
  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-EAIR6VUL.js → chunk-4HDOP7LH.js} +8 -67
  10. package/dist/chunk-4PTSTDIG.js +59 -0
  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-AJ7JQ4OU.js → chunk-AAFBSOSD.js} +3 -3
  14. package/dist/{chunk-VWGJQTNA.js → chunk-CEFYM6N5.js} +4 -4
  15. package/dist/{chunk-YUPQOLFX.js → chunk-CQBJNFDK.js} +2 -2
  16. package/dist/{chunk-FN4OQT2J.js → chunk-CU5VOSTW.js} +4 -4
  17. package/dist/{chunk-YUBJLB6G.js → chunk-EFH4NFPY.js} +6 -3
  18. package/dist/chunk-EQW3YT5U.js +159 -0
  19. package/dist/{chunk-CYJ7R3AD.js → chunk-GC7ZQHW7.js} +22 -10
  20. package/dist/{chunk-KGNJM4LN.js → chunk-JQLR64UC.js} +6 -5
  21. package/dist/{chunk-PXXLBXOP.js → chunk-JRGDLAEA.js} +2 -2
  22. package/dist/{chunk-7REDODS2.js → chunk-LLWK6H77.js} +20 -2
  23. package/dist/{chunk-WGDAOOXG.js → chunk-MU3O43L2.js} +3 -3
  24. package/dist/{chunk-YYSJAAJM.js → chunk-OKNSR7MT.js} +51 -3
  25. package/dist/{chunk-MFIHIS6B.js → chunk-OLQLJY5T.js} +2 -2
  26. package/dist/{chunk-ACQCK4DT.js → chunk-OR43PDCW.js} +2 -2
  27. package/dist/{chunk-QUUB7HYK.js → chunk-P5C2YKAM.js} +2 -2
  28. package/dist/{chunk-D6OGU2AI.js → chunk-P5OAM3G2.js} +2 -2
  29. package/dist/{chunk-6DHJVLYP.js → chunk-Q77KNEUL.js} +1 -1
  30. package/dist/{chunk-SWIXWJIY.js → chunk-QVSUMHNN.js} +3 -3
  31. package/dist/{chunk-C56BC2FY.js → chunk-SG4UBJ47.js} +2 -2
  32. package/dist/{chunk-DUC3PXDG.js → chunk-SOCYCBYG.js} +54 -27
  33. package/dist/{chunk-VKD3EBKG.js → chunk-TYBB7ON3.js} +58 -38
  34. package/dist/{chunk-VTIL47DT.js → chunk-W5NOKYEG.js} +6 -2
  35. package/dist/{chunk-DGSF2Q5H.js → chunk-WJYB7DSI.js} +2 -2
  36. package/dist/{chunk-T6N3VMMO.js → chunk-Y7BARS25.js} +2 -2
  37. package/dist/cli.d.ts +36 -3
  38. package/dist/cli.js +7 -7
  39. package/dist/{codegen-command-Z7WQMOJ7.js → codegen-command-6XXOIQ25.js} +18 -18
  40. package/dist/{completion-4GYN752B.js → completion-A6BZ3XGU.js} +8 -7
  41. package/dist/{deploy-command-M2S4HHLC.js → deploy-command-MTQQXPOO.js} +16 -16
  42. package/dist/{env-target-GSFCYHKZ.js → env-target-C5JFLDK3.js} +6 -6
  43. package/dist/{ephemeral-command-6WJW7LP6.js → ephemeral-command-K3UJSDS4.js} +13 -13
  44. package/dist/index.d.ts +67 -24
  45. package/dist/index.js +6 -6
  46. package/dist/init-command-AY4KSXR5.js +30 -0
  47. package/dist/internal.js +13 -11
  48. package/dist/{io-7VIA5SON.js → io-65CJNLYI.js} +3 -3
  49. package/dist/live-diff-QK4KC2FJ.js +12 -0
  50. package/dist/{lock-KXOJIGCG.js → lock-PDFCNYUW.js} +2 -2
  51. package/dist/{lock-commands-7IH7RSSP.js → lock-commands-MC6I3MZA.js} +8 -8
  52. package/dist/{login-command-QM5SBBI2.js → login-command-LCOOOPO2.js} +139 -36
  53. package/dist/{logout-command-THPASOHM.js → logout-command-J2AG5NKC.js} +2 -2
  54. package/dist/{marketplace-command-463DT7O7.js → marketplace-command-BCOAAN2I.js} +3 -3
  55. package/dist/{meta-client-OW5WKWW7.js → meta-client-57ZWVHST.js} +2 -2
  56. package/dist/node.js +10 -10
  57. package/dist/{profile-command-EUWPVWED.js → profile-command-ZPC2DPFV.js} +3 -3
  58. package/dist/{release-command-M4CVNTWL.js → release-command-V4K4IORX.js} +193 -25
  59. package/dist/{sandbox-details-command-BRII3QHG.js → sandbox-details-command-DMY2KGA2.js} +4 -4
  60. package/dist/{sandbox-export-command-PCZ5FL4U.js → sandbox-export-command-R6QMEK3D.js} +5 -5
  61. package/dist/scaffold.d.ts +10 -13
  62. package/dist/scaffold.js +3 -3
  63. package/dist/{test-command-U4G5Y3UM.js → test-command-OEBIGOPP.js} +8 -8
  64. package/dist/{upgrade-command-CKJ4BS2P.js → upgrade-command-52AAZ3NV.js} +13 -13
  65. package/dist/{validate-command-S5N37JRP.js → validate-command-KTLPSSH7.js} +10 -10
  66. package/dist/{workspace-command-RALSEJSW.js → workspace-command-LX5S5N2H.js} +24 -20
  67. package/guides/cli.md +1 -0
  68. package/guides/deploying.md +18 -0
  69. package/guides/environment.md +1 -1
  70. package/guides/scaffold.md +3 -2
  71. package/llms/statements-calls.md +1 -1
  72. package/llms/statements-data.md +2 -1
  73. package/llms-full.txt +4 -3
  74. package/llms.txt +1 -1
  75. package/manifest.json +6 -2
  76. package/package.json +1 -1
  77. package/dist/chunk-ALNQCWAW.js +0 -29
  78. package/dist/init-command-GJUPWTKA.js +0 -30
package/CHANGELOG.md CHANGED
@@ -11,19 +11,30 @@ listed here.
11
11
 
12
12
  ---
13
13
 
14
- ## 0.0.4Agents get their instructions
14
+ ## 0.0.5Sign in without a loopback
15
15
 
16
- _2026-08-25_ · [release notes](https://github.com/xanots/sdk/releases/tag/v0.0.4)
16
+ _2026-08-26_ · [release notes](https://github.com/xanots/sdk/releases/tag/v0.0.5)
17
17
 
18
- `knowledge()` lands: the markdown a Xano workspace's AI agents read before they act, authored as real `.md` files in your repo instead of typed into a console. Standing instructions, skills, and reference docs are now workspace source reviewed in a diff, versioned with the code they describe, and redeployed with it. Nothing changes for a workspace that declares none.
18
+ `xanots login` only ever worked when the browser finishing consent could reach your machine's `127.0.0.1`. On a remote shell, a container, or a Codespace it can't the redirect lands nowhere and login sits there for five minutes before timing out. `xanots login --paste` fixes that: it binds nothing, prints the URL for you to open anywhere, and you paste the redirect back. This release also corrects two documented promises that were wrong, one of which was actively misleading for exactly this case.
19
19
 
20
- - `knowledge()` authors the instructions your agents follow
21
- - The body is a real markdown file, never a string in a def
22
- - `refs` ships a whole folder the agent searches on demand
23
- - `type` and `mode` decide what the agent actually receives
24
- - Authoring mistakes that used to deploy silently are now build errors
25
- - `xanots codegen` writes the markdown back out as files
26
- - Repeated releases update knowledge instead of duplicating it
20
+ - `xanots login --paste` signs you in where the loopback can't be reached
21
+ - `XANO_NO_BROWSER` never covered remote shells, despite saying it did
22
+ - `--port` documented a default it did not have
23
+
24
+ ---
25
+
26
+ ## 0.0.4 The markdown your agents read
27
+
28
+ _2026-08-26_ · [release notes](https://github.com/xanots/sdk/releases/tag/v0.0.4)
29
+
30
+ Knowledge is now workspace source: the markdown your Xano agents read before they act is authored as real `.md` files, reviewed in a diff, and deployed with the code it describes. Two commands join the CLI — `xanots onboard` puts the scaffold's choices in a browser, and `xanots upgrade` answers the version question on purpose rather than nudging. Windows users should take this one regardless: every npm call in the package was failing before it reached npm.
31
+
32
+ - `knowledge()` — author the markdown your Xano agents read
33
+ - `xanots onboard` — pick the scaffold's look in a browser
34
+ - `xanots upgrade` — the version question asked on purpose
35
+ - Every npm call failed on a current Node for Windows
36
+ - The guides ship in the tarball
37
+ - `CHANGELOG.md` ships, generated from the releases
27
38
 
28
39
  ---
29
40
 
package/README.md CHANGED
@@ -93,6 +93,10 @@ for you, and the target instance comes from your token rather than a flag.
93
93
  npx @xanots/sdk login
94
94
  ```
95
95
 
96
+ > On a remote shell, container, or Codespace — anywhere your browser can't reach this
97
+ > machine's `127.0.0.1` — add `--paste`. It prints the URL for you to open anywhere, and you
98
+ > paste the redirect back. See [Signing in & deploying](https://github.com/xanots/sdk/blob/main/guides/deploying.md).
99
+
96
100
  **2. Scaffold.** `init` writes a complete project: a Vite frontend under `frontend/` (React
97
101
  19 + shadcn/ui by default, or SvelteKit with `--framework svelte`), a XanoTS backend under
98
102
  `xano/`, and the `xano:export` / `xano:deploy` scripts already wired.
@@ -102,9 +106,9 @@ npx @xanots/sdk init my-app && cd my-app
102
106
  npm run dev # the frontend runs immediately
103
107
  ```
104
108
 
105
- In a terminal it asks three questions — framework, theme, AI instruction files — each with a
106
- default. The theme is shadcn's own: a base color plus an optional accent, rendered into the
107
- token stylesheet, with a complete dark palette either way.
109
+ In a terminal it asks two questions — framework and AI instruction files — each with a
110
+ default. The theme is a flag, not a question: it is shadcn's own, a base color plus an
111
+ optional accent, rendered into the token stylesheet with a complete dark palette either way.
108
112
 
109
113
  ```bash
110
114
  npx @xanots/sdk init my-app --theme zinc-blue --dark toggle
@@ -0,0 +1 @@
1
+ 2ea4560ab5068ad3f41aaaccf9f6084502c807310086df6cd6a011bb8ab31aec
@@ -3,10 +3,10 @@ import {
3
3
  codingAgentDetected,
4
4
  isCI,
5
5
  refreshAgentFiles
6
- } from "./chunk-D6OGU2AI.js";
7
- import "./chunk-7SISR3CS.js";
6
+ } from "./chunk-P5OAM3G2.js";
7
+ import "./chunk-2SUCC4DV.js";
8
8
  import "./chunk-ZSYZTGJH.js";
9
- import "./chunk-6DHJVLYP.js";
9
+ import "./chunk-Q77KNEUL.js";
10
10
  import "./chunk-EZG76F7R.js";
11
11
  export {
12
12
  CI_ENV_VARS,
@@ -14,4 +14,4 @@ export {
14
14
  isCI,
15
15
  refreshAgentFiles
16
16
  };
17
- //# sourceMappingURL=agent-file-refresh-IJ7GN2FJ.js.map
17
+ //# sourceMappingURL=agent-file-refresh-6XT23SLU.js.map
package/dist/bin.js CHANGED
@@ -1,27 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  maybeNotifyUpdate
4
- } from "./chunk-T6N3VMMO.js";
4
+ } from "./chunk-Y7BARS25.js";
5
5
  import {
6
6
  readVersion,
7
7
  run
8
- } from "./chunk-DUC3PXDG.js";
8
+ } from "./chunk-SOCYCBYG.js";
9
9
  import {
10
10
  exitCodeOf,
11
11
  reportFailure
12
- } from "./chunk-KGNJM4LN.js";
13
- import "./chunk-MFIHIS6B.js";
12
+ } from "./chunk-JQLR64UC.js";
13
+ import "./chunk-OLQLJY5T.js";
14
14
  import "./chunk-GNPVYOPB.js";
15
15
  import {
16
16
  clearProgress,
17
17
  error
18
18
  } from "./chunk-EZG76F7R.js";
19
- import "./chunk-BPEEGJJA.js";
20
- import "./chunk-YYSJAAJM.js";
21
- import "./chunk-YUPQOLFX.js";
19
+ import "./chunk-3FQD3QME.js";
20
+ import "./chunk-OKNSR7MT.js";
21
+ import "./chunk-CQBJNFDK.js";
22
22
  import "./chunk-WHOJWOSV.js";
23
23
  import "./chunk-5XZ744TS.js";
24
- import "./chunk-YUBJLB6G.js";
24
+ import "./chunk-EFH4NFPY.js";
25
25
 
26
26
  // src/emit/interrupt.ts
27
27
  var EXIT_SIGINT = 130;
@@ -0,0 +1,134 @@
1
+ import {
2
+ deleteBranch,
3
+ listBranches,
4
+ requireBranch,
5
+ setLiveBranch
6
+ } from "./chunk-EQW3YT5U.js";
7
+ import {
8
+ confirm
9
+ } from "./chunk-4PTSTDIG.js";
10
+ import {
11
+ getAccessToken
12
+ } from "./chunk-SG4UBJ47.js";
13
+ import "./chunk-LLWK6H77.js";
14
+ import {
15
+ isMachineOutput,
16
+ writeJson
17
+ } from "./chunk-NUQCEOKA.js";
18
+ import "./chunk-3IGNIP6R.js";
19
+ import {
20
+ UsageError
21
+ } from "./chunk-JQLR64UC.js";
22
+ import "./chunk-GNPVYOPB.js";
23
+ import {
24
+ blank,
25
+ detail,
26
+ info,
27
+ step,
28
+ success,
29
+ warn
30
+ } from "./chunk-EZG76F7R.js";
31
+ import "./chunk-OKNSR7MT.js";
32
+
33
+ // src/emit/branch-commands.ts
34
+ var VERBS = ["list", "set-live", "delete"];
35
+ function assertVerb(verb) {
36
+ if (verb !== void 0 && VERBS.includes(verb)) return verb;
37
+ throw new UsageError(
38
+ verb === void 0 ? `\`xanots workspace branch\` needs a verb: ${VERBS.join(", ")}.` : `\`xanots workspace branch ${verb}\` is not a verb. Expected one of: ${VERBS.join(", ")}.`,
39
+ { helpFor: { command: "workspace", subcommand: "branch" } }
40
+ );
41
+ }
42
+ function requireLabel(label, verb) {
43
+ if (label !== void 0 && label.trim() !== "") return label;
44
+ throw new UsageError(`\`xanots workspace branch ${verb}\` needs a branch label.`, {
45
+ helpFor: { command: "workspace", subcommand: "branch" }
46
+ });
47
+ }
48
+ function renderList(branches, workspaceId) {
49
+ blank();
50
+ step(`Branches in workspace #${workspaceId}`);
51
+ if (branches.length === 0) {
52
+ detail("none reported");
53
+ return;
54
+ }
55
+ for (const b of branches) {
56
+ const tags = [b.live ? "live" : "", b.backup ? "backup" : ""].filter(Boolean).join(", ");
57
+ detail(`${b.label}${tags === "" ? "" : ` (${tags})`}`);
58
+ }
59
+ blank();
60
+ detail("Branches scope logic. Tables and microservices are shared by every branch.");
61
+ }
62
+ async function runBranchCommand(args) {
63
+ const verb = assertVerb(args.positionals[0]);
64
+ const auth = await getAccessToken(args);
65
+ const workspaceId = auth.workspaceId;
66
+ const target = { baseUrl: auth.instance, workspaceId };
67
+ const branches = await listBranches(auth, target);
68
+ if (verb === "list") {
69
+ if (isMachineOutput(args)) {
70
+ writeJson({ workspaceId, instance: auth.instance, branches });
71
+ return;
72
+ }
73
+ renderList(branches, workspaceId);
74
+ return;
75
+ }
76
+ const label = requireLabel(args.positionals[1], verb);
77
+ const branch = requireBranch(branches, label);
78
+ if (verb === "set-live") {
79
+ if (branch.live) {
80
+ success(`Branch "${label}" is already live in workspace #${workspaceId} \u2014 nothing to do.`);
81
+ if (isMachineOutput(args)) writeJson({ workspaceId, branch: label, setLive: false, alreadyLive: true });
82
+ return;
83
+ }
84
+ const outgoing = branches.find((b) => b.live)?.label;
85
+ blank();
86
+ warn(`This is a production cutover for workspace #${workspaceId}.`);
87
+ if (outgoing !== void 0) detail(`The runtime stops serving "${outgoing}" and starts serving "${label}".`);
88
+ detail("Table data is unaffected \u2014 it is shared by every branch either way.");
89
+ blank();
90
+ if (!args.yes && !args.force) {
91
+ const ok = await confirm(`Make "${label}" the live branch?`, {
92
+ flag: "--yes",
93
+ helpFor: { command: "workspace", subcommand: "branch" }
94
+ });
95
+ if (!ok) {
96
+ info("Cancelled \u2014 the live branch is unchanged.");
97
+ return;
98
+ }
99
+ }
100
+ await setLiveBranch(auth, { ...target, label });
101
+ success(`Branch "${label}" is now live in workspace #${workspaceId}.`);
102
+ if (outgoing !== void 0) {
103
+ detail(`Roll back with \`xanots workspace branch set-live ${outgoing}\`.`);
104
+ }
105
+ if (isMachineOutput(args)) {
106
+ writeJson({ workspaceId, branch: label, setLive: true, previousBranch: outgoing });
107
+ }
108
+ return;
109
+ }
110
+ if (branch.live) {
111
+ throw new UsageError(
112
+ `Branch "${label}" is the LIVE branch of workspace #${workspaceId} and cannot be deleted.
113
+ Promote another branch first (\`xanots workspace branch set-live <other>\`), then delete this one.`,
114
+ { helpFor: { command: "workspace", subcommand: "branch" } }
115
+ );
116
+ }
117
+ if (!args.yes && !args.force) {
118
+ const ok = await confirm(`Delete branch "${label}" from workspace #${workspaceId}?`, {
119
+ flag: "--yes",
120
+ helpFor: { command: "workspace", subcommand: "branch" }
121
+ });
122
+ if (!ok) {
123
+ info("Cancelled \u2014 nothing was deleted.");
124
+ return;
125
+ }
126
+ }
127
+ await deleteBranch(auth, { ...target, label });
128
+ success(`Deleted branch "${label}" from workspace #${workspaceId}.`);
129
+ if (isMachineOutput(args)) writeJson({ workspaceId, branch: label, deleted: true });
130
+ }
131
+ export {
132
+ runBranchCommand
133
+ };
134
+ //# sourceMappingURL=branch-commands-R4FR75UW.js.map
@@ -5,7 +5,7 @@ import {
5
5
  defaultThemeChoice,
6
6
  reactPreset,
7
7
  themeGuidanceSection
8
- } from "./chunk-6DHJVLYP.js";
8
+ } from "./chunk-Q77KNEUL.js";
9
9
  import {
10
10
  detail,
11
11
  step,
@@ -442,4 +442,4 @@ export {
442
442
  resolveAiPresets,
443
443
  scaffoldProject
444
444
  };
445
- //# sourceMappingURL=chunk-7SISR3CS.js.map
445
+ //# sourceMappingURL=chunk-2SUCC4DV.js.map
@@ -12,7 +12,7 @@ import {
12
12
  middlewareEntryGuid,
13
13
  stackReferencesAuth,
14
14
  tableColumns
15
- } from "./chunk-YUPQOLFX.js";
15
+ } from "./chunk-CQBJNFDK.js";
16
16
  import {
17
17
  CANONICAL_PAYLOAD_KEYS,
18
18
  REFERENCEABLE_KINDS,
@@ -23,7 +23,7 @@ import {
23
23
  mintCanonical,
24
24
  recordObserved,
25
25
  resolveRef
26
- } from "./chunk-YUBJLB6G.js";
26
+ } from "./chunk-EFH4NFPY.js";
27
27
 
28
28
  // src/workspace/seed-coerce.ts
29
29
  function coerceScalarValue(label, column, type, value, values) {
@@ -1652,4 +1652,4 @@ export {
1652
1652
  Xano,
1653
1653
  workspace
1654
1654
  };
1655
- //# sourceMappingURL=chunk-BPEEGJJA.js.map
1655
+ //# sourceMappingURL=chunk-3FQD3QME.js.map
@@ -2,7 +2,7 @@ import {
2
2
  presetFilePath,
3
3
  resolveAiPresets,
4
4
  scaffoldProject
5
- } from "./chunk-7SISR3CS.js";
5
+ } from "./chunk-2SUCC4DV.js";
6
6
  import {
7
7
  runNpmCapturingStderr
8
8
  } from "./chunk-ZSYZTGJH.js";
@@ -11,7 +11,7 @@ import {
11
11
  allFrontendPresets,
12
12
  findFrontendPreset,
13
13
  resolveFrameworkFlag
14
- } from "./chunk-WGDAOOXG.js";
14
+ } from "./chunk-MU3O43L2.js";
15
15
  import {
16
16
  initLanding,
17
17
  renderApiTs,
@@ -27,11 +27,9 @@ import {
27
27
  renderViteConfig,
28
28
  renderXanoExampleMd,
29
29
  renderXanoIndex
30
- } from "./chunk-QUUB7HYK.js";
30
+ } from "./chunk-P5C2YKAM.js";
31
31
  import {
32
32
  DEFAULT_DARK_MODE,
33
- curatedThemes,
34
- defaultTheme,
35
33
  defaultThemeChoice,
36
34
  normalizeRadius,
37
35
  resolveDarkModeFlag,
@@ -39,15 +37,14 @@ import {
39
37
  resolveIconsFlag,
40
38
  resolveThemeFlag,
41
39
  themeFromRegistryItem,
42
- themeSwatch,
43
40
  withRadius
44
- } from "./chunk-6DHJVLYP.js";
41
+ } from "./chunk-Q77KNEUL.js";
45
42
  import {
46
43
  readVersion
47
- } from "./chunk-DUC3PXDG.js";
44
+ } from "./chunk-SOCYCBYG.js";
48
45
  import {
49
46
  UsageError
50
- } from "./chunk-KGNJM4LN.js";
47
+ } from "./chunk-JQLR64UC.js";
51
48
  import {
52
49
  blank,
53
50
  detail,
@@ -291,7 +288,6 @@ async function resolveFrontendPreset(flag) {
291
288
  }
292
289
 
293
290
  // src/emit/theme-resolve.ts
294
- import { createInterface as createInterface2 } from "readline/promises";
295
291
  import { readFileSync as readFileSync2 } from "fs";
296
292
  import { resolve as resolvePath } from "path";
297
293
  function isRegistryRef(value) {
@@ -332,54 +328,6 @@ function parseJson(text, source) {
332
328
  async function themeFromFlag(raw) {
333
329
  return isRegistryRef(raw.trim()) ? loadRegistryTheme(raw.trim()) : resolveThemeFlag(raw);
334
330
  }
335
- function swatch(theme, color) {
336
- if (!color) return "";
337
- const blocks = themeSwatch(theme).map(({ r, g, b }) => `\x1B[38;2;${r};${g};${b}m\u2588\x1B[0m`).join("");
338
- return blocks === "" ? "" : `${blocks} `;
339
- }
340
- function colorEnabled() {
341
- if (process.env.FORCE_COLOR) return process.env.FORCE_COLOR !== "0";
342
- return !process.env.NO_COLOR && process.stderr.isTTY === true;
343
- }
344
- async function promptTheme() {
345
- const themes = curatedThemes();
346
- const color = colorEnabled();
347
- const rl = createInterface2({ input: process.stdin, output: process.stderr });
348
- try {
349
- process.stderr.write(
350
- `
351
- Which theme? (shadcn/ui color tokens \u2014 everything else is identical)
352
- ` + themes.map((t, i) => ` ${i + 1}) ${swatch(t, color)}${t.label}${i === 0 ? " (default)" : ""}`).join("\n") + `
353
- ${style.dim(
354
- ` \u2026or any <base>-<accent> pair, or a registry theme URL. See \`xanots init --help\`.`
355
- )}
356
- `
357
- );
358
- for (; ; ) {
359
- const answer = (await rl.question(`Enter a number, a theme, or leave blank for the default: `)).trim();
360
- if (answer === "") return defaultTheme();
361
- const byIndex = Number.parseInt(answer, 10);
362
- if (Number.isInteger(byIndex) && byIndex >= 1 && byIndex <= themes.length) {
363
- return themes[byIndex - 1];
364
- }
365
- if (!isRegistryRef(answer)) {
366
- try {
367
- return resolveThemeFlag(answer);
368
- } catch {
369
- return defaultTheme();
370
- }
371
- }
372
- try {
373
- return await loadRegistryTheme(answer);
374
- } catch (err) {
375
- process.stderr.write(`${style.yellow("!")} ${err instanceof Error ? err.message : String(err)}
376
- `);
377
- }
378
- }
379
- } finally {
380
- rl.close();
381
- }
382
- }
383
331
  async function resolveThemeChoice(args) {
384
332
  const dark = args.dark === void 0 || args.dark === "" ? DEFAULT_DARK_MODE : resolveDarkModeFlag(args.dark);
385
333
  const fonts = {
@@ -388,14 +336,7 @@ async function resolveThemeChoice(args) {
388
336
  ...args.fontHeading !== void 0 && args.fontHeading !== "" ? { heading: resolveFontFlag(args.fontHeading, "heading") } : {}
389
337
  };
390
338
  const icons = args.icons === void 0 || args.icons === "" ? void 0 : resolveIconsFlag(args.icons).id;
391
- let theme;
392
- if (args.theme !== void 0 && args.theme !== "") {
393
- theme = await themeFromFlag(args.theme);
394
- } else if (process.stdin.isTTY && process.stderr.isTTY) {
395
- theme = await promptTheme();
396
- } else {
397
- theme = defaultThemeChoice().theme;
398
- }
339
+ let theme = args.theme !== void 0 && args.theme !== "" ? await themeFromFlag(args.theme) : defaultThemeChoice().theme;
399
340
  if (args.radius !== void 0 && args.radius !== "") {
400
341
  theme = withRadius(theme, normalizeRadius(args.radius));
401
342
  }
@@ -529,4 +470,4 @@ export {
529
470
  projectShellFiles,
530
471
  runInitCommand
531
472
  };
532
- //# sourceMappingURL=chunk-EAIR6VUL.js.map
473
+ //# sourceMappingURL=chunk-4HDOP7LH.js.map
@@ -0,0 +1,59 @@
1
+ import {
2
+ UsageError
3
+ } from "./chunk-JQLR64UC.js";
4
+ import {
5
+ style
6
+ } from "./chunk-EZG76F7R.js";
7
+
8
+ // src/emit/prompt.ts
9
+ import { createInterface } from "readline";
10
+ async function confirm(message, opts) {
11
+ if (process.stdin.isTTY !== true) {
12
+ throw new UsageError(
13
+ `Cannot ask for confirmation: stdin is not a terminal. Re-run with ${opts.flag} to confirm without being asked.`,
14
+ { helpFor: opts.helpFor }
15
+ );
16
+ }
17
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
18
+ try {
19
+ const answer = await new Promise((res) => rl.question(`${style.yellow("?")} ${message} (y/N) `, res));
20
+ return /^y(es)?$/i.test(answer.trim());
21
+ } finally {
22
+ rl.close();
23
+ }
24
+ }
25
+ var MAX_EMPTY_ANSWERS = 3;
26
+ async function promptLine(message, opts) {
27
+ if (process.stdin.isTTY !== true) {
28
+ throw new UsageError(
29
+ `Cannot prompt: stdin is not a terminal. ${opts.noTtyHint}`,
30
+ { helpFor: opts.helpFor }
31
+ );
32
+ }
33
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
34
+ try {
35
+ for (let attempt = 0; attempt < MAX_EMPTY_ANSWERS; attempt++) {
36
+ const onClose = () => settle(null);
37
+ let settle;
38
+ const answer = await new Promise((resolve) => {
39
+ settle = resolve;
40
+ rl.once("close", onClose);
41
+ rl.question(`${style.yellow("?")} ${message} `, resolve);
42
+ }).finally(() => rl.off("close", onClose));
43
+ if (answer === null) throw new UsageError(`Input ended before an answer arrived. ${opts.noTtyHint}`);
44
+ const trimmed = answer.trim();
45
+ if (trimmed !== "") return trimmed;
46
+ process.stderr.write(`${style.yellow("!")} A value is required.
47
+ `);
48
+ }
49
+ throw new UsageError(`No value entered. ${opts.noTtyHint}`, { helpFor: opts.helpFor });
50
+ } finally {
51
+ rl.close();
52
+ }
53
+ }
54
+
55
+ export {
56
+ confirm,
57
+ promptLine
58
+ };
59
+ //# sourceMappingURL=chunk-4PTSTDIG.js.map
@@ -11,10 +11,19 @@ function rows(bundle, key) {
11
11
  return Array.isArray(value) ? value.filter((r) => r !== null && typeof r === "object") : [];
12
12
  }
13
13
  function columnsOf(table) {
14
+ return new Set(typedColumnsOf(table).keys());
15
+ }
16
+ function typedColumnsOf(table) {
17
+ const out = /* @__PURE__ */ new Map();
14
18
  const schema = table.schema;
15
- if (!Array.isArray(schema)) return /* @__PURE__ */ new Set();
16
- const names = schema.map((c) => c !== null && typeof c === "object" ? c.name : void 0).filter((n) => typeof n === "string" && n !== "");
17
- return new Set(names);
19
+ if (!Array.isArray(schema)) return out;
20
+ for (const entry of schema) {
21
+ if (entry === null || typeof entry !== "object") continue;
22
+ const { name, type } = entry;
23
+ if (typeof name !== "string" || name === "") continue;
24
+ out.set(name, typeof type === "string" ? type : "");
25
+ }
26
+ return out;
18
27
  }
19
28
  function identify(table) {
20
29
  const guid = table.guid;
@@ -69,6 +78,56 @@ function diffAgainstLive(outgoing, live, opts) {
69
78
  }
70
79
  return { droppedColumns, unchangedEnv };
71
80
  }
81
+ function sharedSchemaChanges(outgoing, live, opts = {}) {
82
+ if (live === void 0) return void 0;
83
+ const changes = [];
84
+ for (const kind of ["dbo", "microservice"]) {
85
+ const liveRows = new Map(rows(live, kind).map((r) => [identify(r), r]));
86
+ const outgoingRows = new Map(rows(outgoing, kind).map((r) => [identify(r), r]));
87
+ for (const [key, out] of outgoingRows) {
88
+ const current = liveRows.get(key);
89
+ const name = nameOf(out);
90
+ if (current === void 0) {
91
+ changes.push({ kind, name, action: "create" });
92
+ continue;
93
+ }
94
+ const details = kind === "dbo" ? tableDelta(current, out) : objectDelta(current, out);
95
+ if (details.length > 0) changes.push({ kind, name, action: "alter", details });
96
+ }
97
+ if (opts.prune === true) {
98
+ for (const [key, current] of liveRows) {
99
+ if (!outgoingRows.has(key)) changes.push({ kind, name: nameOf(current), action: "remove" });
100
+ }
101
+ }
102
+ }
103
+ return changes;
104
+ }
105
+ function tableDelta(live, outgoing) {
106
+ const details = [];
107
+ const before = typedColumnsOf(live);
108
+ const after = typedColumnsOf(outgoing);
109
+ const liveName = nameOf(live);
110
+ const outgoingName = nameOf(outgoing);
111
+ if (liveName !== outgoingName) details.push(`renamed from "${liveName}" to "${outgoingName}"`);
112
+ for (const [column, type] of after) {
113
+ const current = before.get(column);
114
+ if (current === void 0) {
115
+ details.push(`add column "${column}"`);
116
+ } else if (current !== type) {
117
+ details.push(`retype column "${column}" (${current} \u2192 ${type})`);
118
+ }
119
+ }
120
+ for (const column of before.keys()) {
121
+ if (!after.has(column)) details.push(`drop column "${column}"`);
122
+ }
123
+ return details;
124
+ }
125
+ function objectDelta(live, outgoing) {
126
+ const liveName = nameOf(live);
127
+ const outgoingName = nameOf(outgoing);
128
+ if (liveName !== outgoingName) return [`renamed from "${liveName}" to "${outgoingName}"`];
129
+ return deepEqual(normalize(live), normalize(outgoing)) ? [] : ["configuration differs"];
130
+ }
72
131
  var WORKSPACE_KEY = "workspace";
73
132
  var ENV_KEY = "env";
74
133
  var SETTINGS_KEYS_COMPARED_ELSEWHERE = /* @__PURE__ */ new Set([WORKSPACE_KEY, ENV_KEY, "canonical"]);
@@ -189,8 +248,10 @@ function compareToLive(outgoing, live) {
189
248
  }
190
249
  return { converged: compared > 0 && differingCount === 0, compared, differing, differingCount, liveOnly };
191
250
  }
251
+
192
252
  export {
193
- compareToLive,
194
- diffAgainstLive
253
+ diffAgainstLive,
254
+ sharedSchemaChanges,
255
+ compareToLive
195
256
  };
196
- //# sourceMappingURL=live-diff-FP4SFNT4.js.map
257
+ //# sourceMappingURL=chunk-5HCDZ2XN.js.map
@@ -7,12 +7,20 @@ import {
7
7
  // src/deploy/import.ts
8
8
  var IMPORT_TIMEOUT_MS = 12e4;
9
9
  var PROBE_TIMEOUT_MS = 15e3;
10
+ function plannedBranch(parsed) {
11
+ const summary = parsed.summary !== null && typeof parsed.summary === "object" && !Array.isArray(parsed.summary) ? parsed.summary : {};
12
+ for (const candidate of [parsed.branch, parsed.branch_label, summary.branch, summary.branch_label]) {
13
+ if (typeof candidate === "string" && candidate !== "") return candidate;
14
+ }
15
+ return void 0;
16
+ }
10
17
  function query(opts) {
11
18
  const params = new URLSearchParams();
12
19
  if (opts.mode !== void 0) params.set("mode", opts.mode);
13
20
  if (opts.prune !== void 0) params.set("delete", String(opts.prune));
14
21
  if (opts.records !== void 0) params.set("records", String(opts.records));
15
22
  if (opts.truncate !== void 0) params.set("truncate", String(opts.truncate));
23
+ if (opts.branch !== void 0) params.set("branch", opts.branch);
16
24
  const qs = params.toString();
17
25
  return qs === "" ? "" : `?${qs}`;
18
26
  }
@@ -66,6 +74,16 @@ async function assertMergeSupported(auth, opts) {
66
74
  ${text}`
67
75
  );
68
76
  }
77
+ function assertBranchTargetHonored(plan, requested, baseUrl) {
78
+ if (plan.branch === requested) return;
79
+ const observed = plan.branch === void 0 ? `it did not say which branch the plan targets` : `it planned against "${plan.branch}"`;
80
+ throw new Error(
81
+ `Refusing to release to branch "${requested}": ${observed}.
82
+ instance: ${baseUrl}
83
+ An instance that predates branch support IGNORES the branch parameter, imports into whichever branch is LIVE, and still answers 200 \u2014 so a release that looked staged would have overwritten production. That is not recoverable, so it is not attempted on an instance that has not confirmed the target.
84
+ Update the instance, or drop \`--branch\` to release to the live branch deliberately.`
85
+ );
86
+ }
69
87
  function body(archive) {
70
88
  const form = new FormData();
71
89
  form.append("file", new Blob([archive], { type: "application/gzip" }), "workspace.gz");
@@ -145,12 +163,14 @@ ${text}`);
145
163
  hasRecords: parsed.has_records === true,
146
164
  hasEnv: parsed.has_env === true,
147
165
  operations,
166
+ branch: plannedBranch(parsed),
148
167
  raw: text
149
168
  };
150
169
  }
151
170
 
152
171
  export {
172
+ assertBranchTargetHonored,
153
173
  importWorkspaceArchive,
154
174
  planWorkspaceImport
155
175
  };
156
- //# sourceMappingURL=chunk-5WGEURVI.js.map
176
+ //# sourceMappingURL=chunk-6AAT2AYQ.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  sandboxBaseUrl
3
- } from "./chunk-ACQCK4DT.js";
3
+ } from "./chunk-OR43PDCW.js";
4
4
  import {
5
5
  getAccessToken
6
- } from "./chunk-C56BC2FY.js";
6
+ } from "./chunk-SG4UBJ47.js";
7
7
  import {
8
8
  exportWorkspaceBundle
9
9
  } from "./chunk-QTNO2WD6.js";
@@ -115,4 +115,4 @@ export {
115
115
  fetchSandboxBundle,
116
116
  runSandboxExportCommand
117
117
  };
118
- //# sourceMappingURL=chunk-AJ7JQ4OU.js.map
118
+ //# sourceMappingURL=chunk-AAFBSOSD.js.map