@remotedraw/cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3,10 +3,12 @@ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { spawn } from "node:child_process";
4
4
  import path from "node:path";
5
5
  import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
6
7
  import { emitKeypressEvents } from "node:readline";
7
8
  import { createInterface } from "node:readline/promises";
8
9
  import { createWizardTerminal, runSetupWizard, } from "./setup-wizard.js";
9
- import { assertEnvCanAcceptProvisioning, currentCliAccount, globalConfigPath, loginToRemoteDraw, logoutFromRemoteDraw, provisionRemoteDrawProject, remoteDrawApiBaseUrl, writeProvisionedProjectSetup, } from "./cloud.js";
10
+ import { assertEnvCanAcceptProvisioning, currentCliAccount, DEFAULT_REMOTEDRAW_API_BASE_URL, globalConfigPath, loginToRemoteDraw, logoutFromRemoteDraw, provisionRemoteDrawProject, remoteDrawApiBaseUrl, writeProvisionedProjectSetup, } from "./cloud.js";
11
+ import { checkForUpdate, CLI_PACKAGE_NAME, detectInstallMethod, installMethodDisplay, runInstall, } from "./update.js";
10
12
  const packageMetadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
11
13
  export const CLI_VERSION = typeof packageMetadata.version === "string"
12
14
  ? packageMetadata.version
@@ -45,8 +47,10 @@ export function createNodeRuntime() {
45
47
  return {
46
48
  cwd,
47
49
  env,
50
+ binPath: process.argv[1] ?? fileURLToPath(import.meta.url),
48
51
  isInteractive: Boolean(process.stdin.isTTY && process.stderr.isTTY),
49
52
  exists: existsSync,
53
+ spawnCommand: runChildCommand,
50
54
  readFile: async (filePath) => {
51
55
  return await readFile(filePath, "utf8");
52
56
  },
@@ -78,6 +82,18 @@ export function cliEnvironmentForWorkspace(cwd, env, exists = existsSync) {
78
82
  ? { ...env, REMOTEDRAW_API_BASE_URL: env.CONVEX_SITE_URL }
79
83
  : env;
80
84
  }
85
+ async function runChildCommand(command, args) {
86
+ return await new Promise((resolve, reject) => {
87
+ const child = spawn(command, args, {
88
+ stdio: "inherit",
89
+ // Windows resolves npm/pnpm/yarn through .cmd shims, which need a shell.
90
+ shell: process.platform === "win32",
91
+ windowsHide: true,
92
+ });
93
+ child.once("error", reject);
94
+ child.once("close", (code) => resolve({ exitCode: code ?? 1 }));
95
+ });
96
+ }
81
97
  async function openExternalUrl(url) {
82
98
  const parsed = new URL(url);
83
99
  if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
@@ -154,7 +170,7 @@ function terminalSelect(input, output, options) {
154
170
  const selected = options.choices[selectedIndex];
155
171
  cleanup();
156
172
  clearRendered(output, renderedLines);
157
- output.write(`${style("cyan", "?")} ${options.message} ${style("green", selected.label)}\n`);
173
+ output.write(`${style("green", "")} ${options.message} ${style("green", selected.label)}\n`);
158
174
  resolve(selected.value);
159
175
  };
160
176
  const fail = () => {
@@ -197,18 +213,19 @@ function terminalSelect(input, output, options) {
197
213
  });
198
214
  }
199
215
  function selectPromptLines(options, selectedIndex) {
200
- const lines = [`${style("cyan", "?")} ${options.message}`];
216
+ const lines = [`${style("cyan", "?")} ${style("bold", options.message)}`];
201
217
  if (options.helperText)
202
218
  lines.push(style("dim", options.helperText));
203
219
  for (const [index, choiceOption] of options.choices.entries()) {
204
220
  const selected = index === selectedIndex;
221
+ const marker = selected ? style("cyan", "❯ ◉") : style("dim", " ○");
205
222
  const label = selected
206
223
  ? style("bold", choiceOption.label)
207
224
  : choiceOption.label;
208
225
  const hint = choiceOption.hint ? ` ${style("dim", choiceOption.hint)}` : "";
209
- lines.push(`${selected ? ">" : " "} ${label}${hint}`);
226
+ lines.push(`${marker} ${label}${hint}`);
210
227
  }
211
- lines.push(style("dim", "Use up/down arrows, then Enter."));
228
+ lines.push(`${style("dim", "↑/↓")} move · ${style("dim", "Enter")} select · ${style("dim", "Ctrl+C")} quit`);
212
229
  return lines;
213
230
  }
214
231
  function clearRendered(output, lineCount) {
@@ -255,6 +272,8 @@ export async function runCli(args, runtime = createNodeRuntime()) {
255
272
  return await newCommand(commandArgs, runtime);
256
273
  case "init":
257
274
  return await initCommand(commandArgs, runtime);
275
+ case "update":
276
+ return await updateCommand(commandArgs, runtime);
258
277
  case "doctor":
259
278
  return await doctorCommand(commandArgs, runtime);
260
279
  case "dev":
@@ -362,6 +381,7 @@ function mainHelpText() {
362
381
  " init Add RemoteDraw starter code to an existing project.",
363
382
  " dev Print the local sandbox workflow for an integration.",
364
383
  " doctor Check project config, packages, and environment variables.",
384
+ " update Install the latest published RemoteDraw CLI.",
365
385
  " create-input Create or print a test input request payload.",
366
386
  " examples List or install example projects.",
367
387
  " agent Print or install the RemoteDraw agent skill.",
@@ -679,9 +699,89 @@ async function probeApiKey(runtime, apiBaseUrl, apiKey) {
679
699
  return { ok: false, message: probeFailureMessage(error) };
680
700
  }
681
701
  }
702
+ /**
703
+ * npm never refreshes a globally installed binary on its own, so staying
704
+ * current is an explicit step. This command makes that step one word.
705
+ */
706
+ async function updateCommand(args, runtime) {
707
+ const parsed = parseArgs(args, {
708
+ values: ["format"],
709
+ booleans: ["check", "help"],
710
+ });
711
+ if (parsed.booleans.has("help"))
712
+ return ok(updateHelpText());
713
+ const format = outputFormat(parsed);
714
+ const checkOnly = parsed.booleans.has("check");
715
+ const method = detectInstallMethod(runtime.binPath ?? "");
716
+ const command = installMethodDisplay(method);
717
+ // `remotedraw update` is an explicit request, so it ignores the cache and the
718
+ // ambient opt-outs that only silence the passive notice.
719
+ const check = await checkForUpdate(runtime, CLI_VERSION, { force: true });
720
+ if (!check) {
721
+ const message = `Could not reach the npm registry to check for ${CLI_PACKAGE_NAME} updates. Run ${command} to update anyway.`;
722
+ return format === "json"
723
+ ? jsonFailure("update", new Error(message))
724
+ : fail(message);
725
+ }
726
+ if (!check.updateAvailable) {
727
+ const message = `${CLI_PACKAGE_NAME} ${check.current} is already the latest version.`;
728
+ return format === "json"
729
+ ? jsonResult({ ok: true, command: "update", ...check, updated: false })
730
+ : ok(message);
731
+ }
732
+ if (checkOnly || method.ephemeral) {
733
+ const message = method.ephemeral
734
+ ? [
735
+ `Update available: ${check.current} -> ${check.latest}.`,
736
+ `This CLI was run through npx/bunx, which resolves a version per run. Use ${CLI_PACKAGE_NAME}@latest instead of updating in place.`,
737
+ ].join("\n")
738
+ : [
739
+ `Update available: ${check.current} -> ${check.latest}.`,
740
+ `Run ${command} to install it.`,
741
+ ].join("\n");
742
+ return format === "json"
743
+ ? jsonResult({
744
+ ok: true,
745
+ command: "update",
746
+ ...check,
747
+ updated: false,
748
+ installCommand: command,
749
+ ephemeral: method.ephemeral,
750
+ })
751
+ : ok(message);
752
+ }
753
+ const install = await runInstall(runtime, method);
754
+ if (!install.ran) {
755
+ const message = `Update available: ${check.current} -> ${check.latest}. Run ${command} to install it.`;
756
+ return format === "json"
757
+ ? jsonResult({
758
+ ok: true,
759
+ command: "update",
760
+ ...check,
761
+ updated: false,
762
+ installCommand: command,
763
+ })
764
+ : ok(message);
765
+ }
766
+ if (install.exitCode !== 0) {
767
+ const message = `${command} failed with exit code ${install.exitCode}.`;
768
+ return format === "json"
769
+ ? jsonFailure("update", new Error(message))
770
+ : fail(message);
771
+ }
772
+ return format === "json"
773
+ ? jsonResult({
774
+ ok: true,
775
+ command: "update",
776
+ ...check,
777
+ updated: true,
778
+ installCommand: command,
779
+ })
780
+ : ok(`Updated ${CLI_PACKAGE_NAME} to ${check.latest}.`);
781
+ }
682
782
  async function doctorCommand(args, runtime) {
683
783
  const parsed = parseArgs(args, {
684
- values: ["path", "format"],
784
+ values: ["path", "format", "api-base-url"],
685
785
  booleans: ["help", "offline"],
686
786
  });
687
787
  if (parsed.booleans.has("help"))
@@ -693,10 +793,8 @@ async function doctorCommand(args, runtime) {
693
793
  const projectEnv = await environmentForProject(dir, runtime);
694
794
  const configPath = path.join(dir, "remotedraw.config.json");
695
795
  const packagePath = path.join(dir, "package.json");
696
- const envApiBaseUrl = projectEnv.REMOTEDRAW_API_BASE_URL;
697
- const normalizedEnvApiBaseUrl = envApiBaseUrl == null || !isHttpOrigin(envApiBaseUrl)
698
- ? undefined
699
- : normalizedOrigin(envApiBaseUrl);
796
+ const apiBaseUrl = resolveDoctorApiBaseUrl(projectEnv, readString(parsed, "api-base-url"));
797
+ const normalizedEnvApiBaseUrl = apiBaseUrl.state === "ok" ? apiBaseUrl.url : undefined;
700
798
  const envApiKey = projectEnv.REMOTEDRAW_API_KEY;
701
799
  const lines = ["RemoteDraw doctor", ""];
702
800
  const checks = [];
@@ -721,9 +819,11 @@ async function doctorCommand(args, runtime) {
721
819
  ? "React SDK dependency is installed in package.json."
722
820
  : "Install @remotedraw/react or rerun remotedraw init.");
723
821
  }
724
- addCheck(normalizedEnvApiBaseUrl ? "ok" : "warn", "REMOTEDRAW_API_BASE_URL", normalizedEnvApiBaseUrl
725
- ? `Using ${normalizedEnvApiBaseUrl}.`
726
- : "Set this to your Convex site origin, for example https://<deployment>.convex.site.");
822
+ addCheck(apiBaseUrl.state === "ok"
823
+ ? "ok"
824
+ : apiBaseUrl.state === "placeholder"
825
+ ? "warn"
826
+ : "error", "REMOTEDRAW_API_BASE_URL", doctorApiBaseUrlMessage(apiBaseUrl));
727
827
  addCheck(envApiKey?.startsWith("rd_sk_") ? "ok" : "warn", "REMOTEDRAW_API_KEY", envApiKey?.startsWith("rd_sk_")
728
828
  ? "Server-side API key shape looks correct."
729
829
  : "Keep an rd_sk_... key in backend secrets only.");
@@ -734,7 +834,7 @@ async function doctorCommand(args, runtime) {
734
834
  addCheck("warn", "deployment", "Skipped network checks (--offline). Rerun without --offline to verify the key against the deployment.");
735
835
  }
736
836
  else if (!normalizedEnvApiBaseUrl) {
737
- addCheck("warn", "deployment", "Skipped network checks because REMOTEDRAW_API_BASE_URL is not set.");
837
+ addCheck("warn", "deployment", "Skipped network checks because REMOTEDRAW_API_BASE_URL is not a usable HTTP origin.");
738
838
  }
739
839
  else {
740
840
  const health = await probeApiHealth(runtime, normalizedEnvApiBaseUrl);
@@ -754,6 +854,19 @@ async function doctorCommand(args, runtime) {
754
854
  : probe.message);
755
855
  }
756
856
  }
857
+ // A stale global install is the quietest failure mode there is: npm pins the
858
+ // binary at install time and never revisits it, so doctor has to say so.
859
+ if (offline) {
860
+ addCheck("warn", "CLI version", `Running ${CLI_VERSION}. Skipped the update check (--offline).`);
861
+ }
862
+ else {
863
+ const update = await checkForUpdate(runtime, CLI_VERSION, { force: true });
864
+ addCheck(!update || !update.updateAvailable ? "ok" : "warn", "CLI version", !update
865
+ ? `Running ${CLI_VERSION}. Could not reach the npm registry to check for updates.`
866
+ : update.updateAvailable
867
+ ? `Running ${update.current}; ${update.latest} is published. Run remotedraw update.`
868
+ : `Running ${update.current}, the latest published version.`);
869
+ }
757
870
  return format === "json"
758
871
  ? jsonResult({
759
872
  ok: true,
@@ -992,13 +1105,27 @@ function whoamiHelpText() {
992
1105
  function doctorHelpText() {
993
1106
  return [
994
1107
  "Usage:",
995
- " remotedraw doctor [--path <dir>] [--format text|json] [--offline]",
1108
+ " remotedraw doctor [--path <dir>] [--api-base-url <url>] [--format text|json] [--offline]",
996
1109
  "",
997
1110
  "Checks local config, package.json dependencies, and the REMOTEDRAW_API_BASE_URL / REMOTEDRAW_API_KEY environment variables.",
1111
+ `Without an override the API base URL is ${DEFAULT_REMOTEDRAW_API_BASE_URL}; doctor names the source so a non-production URL is visible.`,
998
1112
  "Then reaches the deployment: GET /health, and a free POST /v1/sessions/list to confirm the API key is live.",
1113
+ "It also compares this CLI against the latest published version.",
999
1114
  "Pass --offline to skip the network checks.",
1000
1115
  ].join("\n");
1001
1116
  }
1117
+ function updateHelpText() {
1118
+ return [
1119
+ "Usage:",
1120
+ " remotedraw update [--check] [--format text|json]",
1121
+ "",
1122
+ `Compares this CLI against the latest ${CLI_PACKAGE_NAME} on the npm registry and installs it with the package manager that owns this binary.`,
1123
+ "Global installs never refresh on their own, so this is the only in-place update path.",
1124
+ "Pass --check to report the available version without installing.",
1125
+ "",
1126
+ "The passive 'update available' notice on other commands can be silenced with REMOTEDRAW_CLI_NO_UPDATE_CHECK=1.",
1127
+ ].join("\n");
1128
+ }
1002
1129
  function optionsHelpText() {
1003
1130
  return [
1004
1131
  "Usage:",
@@ -1650,50 +1777,7 @@ export function projectSetupDefinition() {
1650
1777
  packageManager: "npm",
1651
1778
  apiEndpoint: "deployment",
1652
1779
  },
1653
- fields: [
1654
- {
1655
- key: "appName",
1656
- label: "Projectnaam",
1657
- kind: "text",
1658
- validate: validateWizardProjectName,
1659
- },
1660
- {
1661
- key: "target",
1662
- label: "Projecttype",
1663
- kind: "select",
1664
- choices: () => wizardChoices(targetPromptChoices(), targetWizardDetails),
1665
- },
1666
- {
1667
- key: "sender",
1668
- label: "Telefoonzender",
1669
- kind: "select",
1670
- choices: (values) => wizardChoices(senderPromptChoices(choice(values.target, targetChoices, "target")), senderWizardDetails),
1671
- },
1672
- {
1673
- key: "sdk",
1674
- label: "UI-framework / SDK",
1675
- kind: "select",
1676
- choices: (values) => wizardChoices(sdkPromptChoices(choice(values.target, targetChoices, "target"), choice(values.sender, senderChoices, "sender")), sdkWizardDetails),
1677
- },
1678
- {
1679
- key: "preset",
1680
- label: "Startpunt",
1681
- kind: "select",
1682
- choices: () => wizardChoices(presetPromptChoices(), presetWizardDetails),
1683
- },
1684
- {
1685
- key: "packageManager",
1686
- label: "Pakketbeheerder",
1687
- kind: "select",
1688
- choices: () => wizardChoices(packageManagerPromptChoices(), packageManagerWizardDetails),
1689
- },
1690
- {
1691
- key: "apiEndpoint",
1692
- label: "API-eindpunt",
1693
- kind: "select",
1694
- choices: () => wizardChoices(apiEndpointPromptChoices(), apiEndpointWizardDetails),
1695
- },
1696
- ],
1780
+ fields: projectSetupFields(),
1697
1781
  normalize(values, changed) {
1698
1782
  const next = { ...values };
1699
1783
  const target = choice(next.target, targetChoices, "target");
@@ -1713,19 +1797,67 @@ export function projectSetupDefinition() {
1713
1797
  },
1714
1798
  review(values) {
1715
1799
  const plan = planFromWizardValues(values);
1800
+ const label = (key, fallback) => wizardChoiceLabel(key, values) ?? fallback;
1716
1801
  return [
1717
1802
  ["Project", plan.appName],
1718
- ["Map", plan.slug],
1719
- ["Projecttype", plan.target],
1720
- ["Telefoonzender", plan.sender],
1721
- ["SDK", plan.sdk],
1722
- ["Startpunt", plan.preset],
1723
- ["Pakketbeheerder", plan.packageManager],
1803
+ ["Map", `./${plan.slug}`],
1804
+ ["Projecttype", label("target", plan.target)],
1805
+ ["Telefoonzender", label("sender", plan.sender)],
1806
+ ["SDK", label("sdk", plan.sdk)],
1807
+ ["Pakketbeheerder", label("packageManager", plan.packageManager)],
1724
1808
  ["API-eindpunt", plan.apiBaseUrl],
1725
1809
  ];
1726
1810
  },
1727
1811
  };
1728
1812
  }
1813
+ function projectSetupFields() {
1814
+ return [
1815
+ {
1816
+ key: "appName",
1817
+ label: "Projectnaam",
1818
+ kind: "text",
1819
+ validate: validateWizardProjectName,
1820
+ preview: (values) => values.appName.trim() === ""
1821
+ ? undefined
1822
+ : `map ./${slugify(values.appName)} · pakket ${slugify(values.appName)}`,
1823
+ },
1824
+ {
1825
+ key: "target",
1826
+ label: "Projecttype",
1827
+ kind: "select",
1828
+ choices: () => wizardChoices(targetPromptChoices(), targetWizardDetails),
1829
+ },
1830
+ {
1831
+ key: "sender",
1832
+ label: "Telefoonzender",
1833
+ kind: "select",
1834
+ choices: (values) => wizardChoices(senderPromptChoices(choice(values.target, targetChoices, "target")), senderWizardDetails),
1835
+ },
1836
+ {
1837
+ key: "sdk",
1838
+ label: "UI-framework / SDK",
1839
+ kind: "select",
1840
+ choices: (values) => wizardChoices(sdkPromptChoices(choice(values.target, targetChoices, "target"), choice(values.sender, senderChoices, "sender")), sdkWizardDetails),
1841
+ },
1842
+ {
1843
+ key: "packageManager",
1844
+ label: "Pakketbeheerder",
1845
+ kind: "select",
1846
+ choices: () => wizardChoices(packageManagerPromptChoices(), packageManagerWizardDetails),
1847
+ },
1848
+ {
1849
+ key: "apiEndpoint",
1850
+ label: "API-eindpunt",
1851
+ kind: "select",
1852
+ choices: () => wizardChoices(apiEndpointPromptChoices(), apiEndpointWizardDetails),
1853
+ },
1854
+ ];
1855
+ }
1856
+ function wizardChoiceLabel(key, values) {
1857
+ const field = projectSetupFields().find((entry) => entry.key === key);
1858
+ return field?.choices?.(values).find((option) => option.value === values[key])
1859
+ ?.label;
1860
+ }
1729
1861
  function validateWizardProjectName(value) {
1730
1862
  return value.trim() === "" ? "Voer een projectnaam in." : undefined;
1731
1863
  }
@@ -2824,6 +2956,56 @@ export function agentSkillMarkdown() {
2824
2956
  "```",
2825
2957
  ].join("\n");
2826
2958
  }
2959
+ /**
2960
+ * Doctor used to read REMOTEDRAW_API_BASE_URL raw and call an unset value a
2961
+ * problem, which disagreed with login/whoami/new — those all fall back to the
2962
+ * production API. Resolving it the same way here keeps every command pointed at
2963
+ * one deployment, and reporting the source explains a non-production URL
2964
+ * instead of leaving the reader to guess where it came from.
2965
+ */
2966
+ function resolveDoctorApiBaseUrl(projectEnv, requested) {
2967
+ const explicit = requested ?? projectEnv.REMOTEDRAW_API_BASE_URL;
2968
+ const source = requested == null ? "project" : "flag";
2969
+ if (explicit == null || explicit.trim() === "") {
2970
+ return {
2971
+ state: "ok",
2972
+ url: DEFAULT_REMOTEDRAW_API_BASE_URL,
2973
+ source: "default",
2974
+ isProductionDefault: true,
2975
+ };
2976
+ }
2977
+ // `init --offline` writes the literal placeholder, so an unreplaced value is
2978
+ // an expected next step rather than a mistake.
2979
+ if (explicit.includes("<"))
2980
+ return { state: "placeholder", value: explicit };
2981
+ if (!isHttpOrigin(explicit)) {
2982
+ return { state: "invalid", value: explicit, source };
2983
+ }
2984
+ const url = normalizedOrigin(explicit);
2985
+ return {
2986
+ state: "ok",
2987
+ url,
2988
+ source,
2989
+ isProductionDefault: url === DEFAULT_REMOTEDRAW_API_BASE_URL,
2990
+ };
2991
+ }
2992
+ function doctorApiBaseUrlMessage(resolved) {
2993
+ if (resolved.state === "placeholder") {
2994
+ return `Still the ${resolved.value} placeholder. Replace it with ${DEFAULT_REMOTEDRAW_API_BASE_URL}, or with your own deployment origin.`;
2995
+ }
2996
+ if (resolved.state === "invalid") {
2997
+ return `${resolved.value} is not an HTTP origin. Set it to ${DEFAULT_REMOTEDRAW_API_BASE_URL}, or to your own deployment origin.`;
2998
+ }
2999
+ if (resolved.source === "default") {
3000
+ return `Using ${resolved.url} (RemoteDraw production API; nothing overrides it here).`;
3001
+ }
3002
+ const origin = resolved.source === "flag"
3003
+ ? "--api-base-url"
3004
+ : "this project's environment";
3005
+ return resolved.isProductionDefault
3006
+ ? `Using ${resolved.url} (production API, set by ${origin}).`
3007
+ : `Using ${resolved.url} (override from ${origin}, not the ${DEFAULT_REMOTEDRAW_API_BASE_URL} production API).`;
3008
+ }
2827
3009
  function isHttpOrigin(value) {
2828
3010
  if (value == null || value.includes("<"))
2829
3011
  return false;
package/dist/index.js CHANGED
@@ -1,8 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import { createNodeRuntime, runCli } from "./cli.js";
3
- const result = await runCli(process.argv.slice(2), createNodeRuntime());
2
+ import process from "node:process";
3
+ import { CLI_VERSION, createNodeRuntime, runCli } from "./cli.js";
4
+ import { checkForUpdate, detectInstallMethod, updateNotice, } from "./update.js";
5
+ const runtime = createNodeRuntime();
6
+ const result = await runCli(process.argv.slice(2), runtime);
4
7
  if (result.stdout)
5
8
  process.stdout.write(result.stdout);
6
9
  if (result.stderr)
7
10
  process.stderr.write(result.stderr);
8
11
  process.exitCode = result.exitCode;
12
+ // Only a human at a terminal sees this. Piped output, CI, and machine-readable
13
+ // runs stay byte-for-byte what the command produced.
14
+ if (process.stderr.isTTY && process.argv[2] !== "update") {
15
+ try {
16
+ const check = await checkForUpdate(runtime, CLI_VERSION);
17
+ if (check?.updateAvailable) {
18
+ const method = detectInstallMethod(runtime.binPath ?? "");
19
+ process.stderr.write(`\n${updateNotice(check, method)}\n`);
20
+ }
21
+ }
22
+ catch {
23
+ // A failed update check never changes the outcome of the real command.
24
+ }
25
+ }
@@ -18,6 +18,7 @@ export type WizardField = {
18
18
  kind: "text" | "select";
19
19
  choices?: (values: WizardValues) => readonly WizardChoice[];
20
20
  validate?: (value: string) => string | undefined;
21
+ preview?: (values: WizardValues) => string | undefined;
21
22
  };
22
23
  export type WizardDefinition = {
23
24
  fields: readonly WizardField[];
@@ -71,6 +72,8 @@ export type WizardSemanticView = {
71
72
  activeLabel?: string | undefined;
72
73
  value?: string | undefined;
73
74
  valueIsDefault?: boolean | undefined;
75
+ valuePreview?: string | undefined;
76
+ completed?: readonly [string, string][] | undefined;
74
77
  choices?: readonly WizardChoice[] | undefined;
75
78
  selectedChoice?: string | undefined;
76
79
  selectedDetails?: WizardChoiceDetails | undefined;
@@ -91,10 +94,14 @@ export type WizardKey = {
91
94
  };
92
95
  export type WizardTerminal = {
93
96
  columns: number;
97
+ rows?: number;
94
98
  color: boolean;
99
+ trueColor?: boolean;
95
100
  hyperlinks?: boolean;
96
101
  write: (value: string) => void;
97
102
  readKey: () => Promise<WizardKey>;
103
+ readKeyWithin?: (milliseconds: number) => Promise<WizardKey | undefined>;
104
+ hasPendingKey?: () => boolean;
98
105
  openUrl?: (url: string) => void | Promise<void>;
99
106
  enter: () => void | Promise<void>;
100
107
  restore: () => void | Promise<void>;
@@ -112,7 +119,8 @@ export declare function runSetupWizard(options: {
112
119
  state: WizardState;
113
120
  }>;
114
121
  export declare function actionForKey(key: WizardKey, state: WizardState): WizardAction;
115
- export declare function renderWizard(state: WizardState, definition: WizardDefinition, terminal: Pick<WizardTerminal, "columns" | "color" | "hyperlinks">, bannerFrame?: number): string;
122
+ type Painter = Pick<WizardTerminal, "columns" | "rows" | "color" | "hyperlinks" | "trueColor">;
123
+ export declare function renderWizard(state: WizardState, definition: WizardDefinition, terminal: Painter, frame?: number): string;
116
124
  type KeypressInput = NodeJS.ReadStream & {
117
125
  isRaw?: boolean;
118
126
  setRawMode?: (mode: boolean) => KeypressInput;
@@ -1 +1 @@
1
- {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"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"}