@baby-ui/cli 0.0.0-stage → 0.1.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.
Files changed (44) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +36 -2
  3. package/bin.mjs +20 -0
  4. package/dist/add-Dw_xdBjM.js +8472 -0
  5. package/dist/add-Dw_xdBjM.js.map +1 -0
  6. package/dist/auth-Cqd8NPiR.js +52 -0
  7. package/dist/auth-Cqd8NPiR.js.map +1 -0
  8. package/dist/auth-DLL_PGWB.js +41 -0
  9. package/dist/auth-DLL_PGWB.js.map +1 -0
  10. package/dist/banner-b_aKYU5F.js +23 -0
  11. package/dist/banner-b_aKYU5F.js.map +1 -0
  12. package/dist/core-Cd391zXy.js +142 -0
  13. package/dist/core-Cd391zXy.js.map +1 -0
  14. package/dist/dist-Bs-3vZ2T.js +2712 -0
  15. package/dist/dist-Bs-3vZ2T.js.map +1 -0
  16. package/dist/dist-CxDndWiZ.js +6661 -0
  17. package/dist/dist-CxDndWiZ.js.map +1 -0
  18. package/dist/errors-zXXytRXF.js +16 -0
  19. package/dist/errors-zXXytRXF.js.map +1 -0
  20. package/dist/history-l3B-mc6n.js +55 -0
  21. package/dist/history-l3B-mc6n.js.map +1 -0
  22. package/dist/index.js +3097 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/info-mS7KbPJ_.js +43 -0
  25. package/dist/info-mS7KbPJ_.js.map +1 -0
  26. package/dist/init-DO1txT-A.js +168 -0
  27. package/dist/init-DO1txT-A.js.map +1 -0
  28. package/dist/list-DnQNQUNr.js +48 -0
  29. package/dist/list-DnQNQUNr.js.map +1 -0
  30. package/dist/maintain-DeyqYm5K.js +183 -0
  31. package/dist/maintain-DeyqYm5K.js.map +1 -0
  32. package/dist/schemas-DwMX1h2B.js +5160 -0
  33. package/dist/schemas-DwMX1h2B.js.map +1 -0
  34. package/dist/shared-BJaaV-dl.js +96 -0
  35. package/dist/shared-BJaaV-dl.js.map +1 -0
  36. package/dist/state-CsT6LJsH.js +430 -0
  37. package/dist/state-CsT6LJsH.js.map +1 -0
  38. package/dist/targets-Bpv2h7C4.js +316 -0
  39. package/dist/targets-Bpv2h7C4.js.map +1 -0
  40. package/dist/tx-DBnjY8eR.js +226 -0
  41. package/dist/tx-DBnjY8eR.js.map +1 -0
  42. package/dist/ui-Cthxlfe6.js +206 -0
  43. package/dist/ui-Cthxlfe6.js.map +1 -0
  44. package/package.json +50 -3
@@ -0,0 +1,52 @@
1
+ import { a as object, s as string } from "./schemas-DwMX1h2B.js";
2
+ import { dirname, join } from "node:path";
3
+ import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ //#region src/auth.ts
6
+ function authFile() {
7
+ if (process.env.BABY_UI_CONFIG_DIR) return join(process.env.BABY_UI_CONFIG_DIR, "auth.json");
8
+ if (process.platform === "win32") return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "baby-ui", "auth.json");
9
+ return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "baby-ui", "auth.json");
10
+ }
11
+ const AuthSchema = object({
12
+ token: string().min(1),
13
+ savedAt: string()
14
+ });
15
+ /** `BABY_UI_TOKEN` wins (CI), then the saved licence key. */
16
+ async function credential() {
17
+ const env = process.env.BABY_UI_TOKEN;
18
+ if (env) return {
19
+ token: env,
20
+ source: "env"
21
+ };
22
+ try {
23
+ const parsed = AuthSchema.safeParse(JSON.parse(await readFile(authFile(), "utf8")));
24
+ if (parsed.success) return {
25
+ token: parsed.data.token,
26
+ source: "file"
27
+ };
28
+ } catch {}
29
+ }
30
+ async function saveToken(token) {
31
+ const file = authFile();
32
+ await mkdir(dirname(file), { recursive: true });
33
+ await writeFile(file, `${JSON.stringify({
34
+ token,
35
+ savedAt: (/* @__PURE__ */ new Date()).toISOString()
36
+ })}\n`, { mode: 384 });
37
+ if (process.platform !== "win32") await chmod(file, 384);
38
+ return file;
39
+ }
40
+ async function clearToken() {
41
+ try {
42
+ await rm(authFile());
43
+ return true;
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ const maskToken = (token) => token.length <= 8 ? "****" : `${token.slice(0, 4)}…${token.slice(-4)}`;
49
+ //#endregion
50
+ export { saveToken as i, credential as n, maskToken as r, clearToken as t };
51
+
52
+ //# sourceMappingURL=auth-Cqd8NPiR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-Cqd8NPiR.js","names":["z.object","z.string"],"sources":["../src/auth.ts"],"sourcesContent":["import { chmod, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { z } from \"zod\";\n\nexport function authFile(): string {\n\tif (process.env.BABY_UI_CONFIG_DIR)\n\t\treturn join(process.env.BABY_UI_CONFIG_DIR, \"auth.json\");\n\tif (process.platform === \"win32\") {\n\t\treturn join(\n\t\t\tprocess.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\"),\n\t\t\t\"baby-ui\",\n\t\t\t\"auth.json\",\n\t\t);\n\t}\n\treturn join(\n\t\tprocess.env.XDG_CONFIG_HOME ?? join(homedir(), \".config\"),\n\t\t\"baby-ui\",\n\t\t\"auth.json\",\n\t);\n}\n\nconst AuthSchema = z.object({ token: z.string().min(1), savedAt: z.string() });\n\nexport interface Credential {\n\treadonly token: string;\n\treadonly source: \"env\" | \"file\";\n}\n\n/** `BABY_UI_TOKEN` wins (CI), then the saved licence key. */\nexport async function credential(): Promise<Credential | undefined> {\n\tconst env = process.env.BABY_UI_TOKEN;\n\tif (env) return { token: env, source: \"env\" };\n\ttry {\n\t\tconst parsed = AuthSchema.safeParse(JSON.parse(await readFile(authFile(), \"utf8\")));\n\t\tif (parsed.success) return { token: parsed.data.token, source: \"file\" };\n\t} catch {}\n\treturn undefined;\n}\n\n// 0600 on POSIX; on Windows the file lives in the per-user roaming profile.\nexport async function saveToken(token: string): Promise<string> {\n\tconst file = authFile();\n\tawait mkdir(dirname(file), { recursive: true });\n\tawait writeFile(\n\t\tfile,\n\t\t`${JSON.stringify({ token, savedAt: new Date().toISOString() })}\\n`,\n\t\t{\n\t\t\tmode: 0o600,\n\t\t},\n\t);\n\tif (process.platform !== \"win32\") await chmod(file, 0o600);\n\treturn file;\n}\n\nexport async function clearToken(): Promise<boolean> {\n\ttry {\n\t\tawait rm(authFile());\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport const maskToken = (token: string) =>\n\ttoken.length <= 8 ? \"****\" : `${token.slice(0, 4)}…${token.slice(-4)}`;\n"],"mappings":";;;;;AAKA,SAAgB,WAAmB;CAClC,IAAI,QAAQ,IAAI,oBACf,OAAO,KAAK,QAAQ,IAAI,oBAAoB,WAAW;CACxD,IAAI,QAAQ,aAAa,SACxB,OAAO,KACN,QAAQ,IAAI,WAAW,KAAK,QAAQ,GAAG,WAAW,SAAS,GAC3D,WACA,WACD;CAED,OAAO,KACN,QAAQ,IAAI,mBAAmB,KAAK,QAAQ,GAAG,SAAS,GACxD,WACA,WACD;AACD;AAEA,MAAM,aAAaA,OAAS;CAAE,OAAOC,OAAS,CAAC,CAAC,IAAI,CAAC;CAAG,SAASA,OAAS;AAAE,CAAC;;AAQ7E,eAAsB,aAA8C;CACnE,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,KAAK,OAAO;EAAE,OAAO;EAAK,QAAQ;CAAM;CAC5C,IAAI;EACH,MAAM,SAAS,WAAW,UAAU,KAAK,MAAM,MAAM,SAAS,SAAS,GAAG,MAAM,CAAC,CAAC;EAClF,IAAI,OAAO,SAAS,OAAO;GAAE,OAAO,OAAO,KAAK;GAAO,QAAQ;EAAO;CACvE,QAAQ,CAAC;AAEV;AAGA,eAAsB,UAAU,OAAgC;CAC/D,MAAM,OAAO,SAAS;CACtB,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAC9C,MAAM,UACL,MACA,GAAG,KAAK,UAAU;EAAE;EAAO,0BAAS,IAAI,KAAK,EAAA,CAAE,YAAY;CAAE,CAAC,EAAE,KAChE,EACC,MAAM,IACP,CACD;CACA,IAAI,QAAQ,aAAa,SAAS,MAAM,MAAM,MAAM,GAAK;CACzD,OAAO;AACR;AAEA,eAAsB,aAA+B;CACpD,IAAI;EACH,MAAM,GAAG,SAAS,CAAC;EACnB,OAAO;CACR,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAa,aAAa,UACzB,MAAM,UAAU,IAAI,SAAS,GAAG,MAAM,MAAM,GAAG,CAAC,EAAE,GAAG,MAAM,MAAM,EAAE"}
@@ -0,0 +1,41 @@
1
+ import { t as CliError } from "./errors-zXXytRXF.js";
2
+ import { r as isInteractive, u as c } from "./core-Cd391zXy.js";
3
+ import { i as saveToken, n as credential, r as maskToken, t as clearToken } from "./auth-Cqd8NPiR.js";
4
+ import { l as text, n as intro, o as outro, r as message } from "./ui-Cthxlfe6.js";
5
+ //#region src/commands/auth.ts
6
+ const ACCOUNT_URL = "https://baby-ui.nexonauts.com/account";
7
+ /** Stores a licence key; device sign-in arrives with the Pro backend. */
8
+ async function login(options) {
9
+ intro("baby-ui login");
10
+ let token = options.token?.trim();
11
+ if (!token) {
12
+ if (!isInteractive()) throw new CliError("No licence key given.", { hint: "Pass --token <key> or set BABY_UI_TOKEN." });
13
+ message(`Copy your licence key from ${c.brand(ACCOUNT_URL)}`);
14
+ token = (await text({
15
+ message: "Licence key",
16
+ placeholder: "bui_…",
17
+ mask: true,
18
+ validate: (v) => v.trim().length < 8 ? "That key looks too short." : void 0
19
+ })).trim();
20
+ }
21
+ const file = await saveToken(token);
22
+ message(`Saved ${maskToken(token)} to ${c.dim(file)}`);
23
+ if (process.env.BABY_UI_TOKEN) message(c.yellow("BABY_UI_TOKEN is set and takes precedence."));
24
+ outro(`Pro items install with ${c.brand("baby-ui add @baby-ui-pro/<name>")}`);
25
+ }
26
+ async function logout() {
27
+ intro("baby-ui logout");
28
+ message(await clearToken() ? "Licence key removed." : c.dim("No saved licence key."));
29
+ if (process.env.BABY_UI_TOKEN) message(c.yellow("BABY_UI_TOKEN is still set in this shell."));
30
+ outro("Done");
31
+ }
32
+ async function whoami() {
33
+ const cred = await credential();
34
+ intro("baby-ui whoami");
35
+ message(cred ? `Licence key ${maskToken(cred.token)} ${c.dim(cred.source === "env" ? "(BABY_UI_TOKEN)" : "(saved)")}` : c.dim("Not logged in. Free components need no account."));
36
+ outro("Done");
37
+ }
38
+ //#endregion
39
+ export { login, logout, whoami };
40
+
41
+ //# sourceMappingURL=auth-DLL_PGWB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-DLL_PGWB.js","names":[],"sources":["../src/commands/auth.ts"],"sourcesContent":["import { clearToken, credential, maskToken, saveToken } from \"../auth.ts\";\nimport { CliError } from \"../errors.ts\";\nimport { c } from \"../logger.ts\";\nimport { intro, isInteractive, message, outro, text } from \"../ui/index.ts\";\n\nconst ACCOUNT_URL = \"https://baby-ui.nexonauts.com/account\";\n\n/** Stores a licence key; device sign-in arrives with the Pro backend. */\nexport async function login(options: { token?: string }): Promise<void> {\n\tintro(\"baby-ui login\");\n\tlet token = options.token?.trim();\n\tif (!token) {\n\t\tif (!isInteractive()) {\n\t\t\tthrow new CliError(\"No licence key given.\", {\n\t\t\t\thint: \"Pass --token <key> or set BABY_UI_TOKEN.\",\n\t\t\t});\n\t\t}\n\t\tmessage(`Copy your licence key from ${c.brand(ACCOUNT_URL)}`);\n\t\ttoken = (\n\t\t\tawait text({\n\t\t\t\tmessage: \"Licence key\",\n\t\t\t\tplaceholder: \"bui_…\",\n\t\t\t\tmask: true,\n\t\t\t\tvalidate: (v) => (v.trim().length < 8 ? \"That key looks too short.\" : undefined),\n\t\t\t})\n\t\t).trim();\n\t}\n\tconst file = await saveToken(token);\n\tmessage(`Saved ${maskToken(token)} to ${c.dim(file)}`);\n\tif (process.env.BABY_UI_TOKEN)\n\t\tmessage(c.yellow(\"BABY_UI_TOKEN is set and takes precedence.\"));\n\toutro(`Pro items install with ${c.brand(\"baby-ui add @baby-ui-pro/<name>\")}`);\n}\n\nexport async function logout(): Promise<void> {\n\tintro(\"baby-ui logout\");\n\tmessage((await clearToken()) ? \"Licence key removed.\" : c.dim(\"No saved licence key.\"));\n\tif (process.env.BABY_UI_TOKEN)\n\t\tmessage(c.yellow(\"BABY_UI_TOKEN is still set in this shell.\"));\n\toutro(\"Done\");\n}\n\nexport async function whoami(): Promise<void> {\n\tconst cred = await credential();\n\tintro(\"baby-ui whoami\");\n\tmessage(\n\t\tcred\n\t\t\t? `Licence key ${maskToken(cred.token)} ${c.dim(cred.source === \"env\" ? \"(BABY_UI_TOKEN)\" : \"(saved)\")}`\n\t\t\t: c.dim(\"Not logged in. Free components need no account.\"),\n\t);\n\toutro(\"Done\");\n}\n"],"mappings":";;;;;AAKA,MAAM,cAAc;;AAGpB,eAAsB,MAAM,SAA4C;CACvE,MAAM,eAAe;CACrB,IAAI,QAAQ,QAAQ,OAAO,KAAK;CAChC,IAAI,CAAC,OAAO;EACX,IAAI,CAAC,cAAc,GAClB,MAAM,IAAI,SAAS,yBAAyB,EAC3C,MAAM,2CACP,CAAC;EAEF,QAAQ,8BAA8B,EAAE,MAAM,WAAW,GAAG;EAC5D,SACC,MAAM,KAAK;GACV,SAAS;GACT,aAAa;GACb,MAAM;GACN,WAAW,MAAO,EAAE,KAAK,CAAC,CAAC,SAAS,IAAI,8BAA8B,KAAA;EACvE,CAAC,EAAA,CACA,KAAK;CACR;CACA,MAAM,OAAO,MAAM,UAAU,KAAK;CAClC,QAAQ,SAAS,UAAU,KAAK,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG;CACrD,IAAI,QAAQ,IAAI,eACf,QAAQ,EAAE,OAAO,4CAA4C,CAAC;CAC/D,MAAM,0BAA0B,EAAE,MAAM,iCAAiC,GAAG;AAC7E;AAEA,eAAsB,SAAwB;CAC7C,MAAM,gBAAgB;CACtB,QAAS,MAAM,WAAW,IAAK,yBAAyB,EAAE,IAAI,uBAAuB,CAAC;CACtF,IAAI,QAAQ,IAAI,eACf,QAAQ,EAAE,OAAO,2CAA2C,CAAC;CAC9D,MAAM,MAAM;AACb;AAEA,eAAsB,SAAwB;CAC7C,MAAM,OAAO,MAAM,WAAW;CAC9B,MAAM,gBAAgB;CACtB,QACC,OACG,eAAe,UAAU,KAAK,KAAK,EAAE,GAAG,EAAE,IAAI,KAAK,WAAW,QAAQ,oBAAoB,SAAS,MACnG,EAAE,IAAI,iDAAiD,CAC3D;CACA,MAAM,MAAM;AACb"}
@@ -0,0 +1,23 @@
1
+ import { r as isInteractive, u as c } from "./core-Cd391zXy.js";
2
+ //#region src/ui/banner.ts
3
+ const WORDMARK = [
4
+ " _ _ _ ",
5
+ "| |__ __ _| |__ _ _ _ _(_)",
6
+ "| '_ \\ / _` | '_ \\| | | |_____| | | | |",
7
+ "| |_) | (_| | |_) | |_| |_____| |_| | |",
8
+ "|_.__/ \\__,_|_.__/ \\__, | \\__,_|_|",
9
+ " |___/ "
10
+ ];
11
+ /** The `init` banner; skipped on non-interactive streams so piped output stays clean. */
12
+ function printBanner(version) {
13
+ if (!isInteractive()) return;
14
+ const out = process.stdout;
15
+ out.write("\n");
16
+ for (const line of WORDMARK) out.write(` ${c.brand(line)}\n`);
17
+ out.write(`\n ${c.dim("Components for React and Svelte, shadcn compatible")}\n`);
18
+ out.write(` ${c.gray(`v${version} · Apache-2.0 · baby-ui.nexonauts.com`)}\n`);
19
+ }
20
+ //#endregion
21
+ export { printBanner };
22
+
23
+ //# sourceMappingURL=banner-b_aKYU5F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner-b_aKYU5F.js","names":[],"sources":["../src/ui/banner.ts"],"sourcesContent":["import { c } from \"../logger.ts\";\nimport { isInteractive } from \"./core.ts\";\n\nconst WORDMARK = [\n\t\" _ _ _ \",\n\t\"| |__ __ _| |__ _ _ _ _(_)\",\n\t\"| '_ \\\\ / _` | '_ \\\\| | | |_____| | | | |\",\n\t\"| |_) | (_| | |_) | |_| |_____| |_| | |\",\n\t\"|_.__/ \\\\__,_|_.__/ \\\\__, | \\\\__,_|_|\",\n\t\" |___/ \",\n];\n\n/** The `init` banner; skipped on non-interactive streams so piped output stays clean. */\nexport function printBanner(version: string): void {\n\tif (!isInteractive()) return;\n\tconst out = process.stdout;\n\tout.write(\"\\n\");\n\tfor (const line of WORDMARK) out.write(` ${c.brand(line)}\\n`);\n\tout.write(`\\n ${c.dim(\"Components for React and Svelte, shadcn compatible\")}\\n`);\n\tout.write(` ${c.gray(`v${version} · Apache-2.0 · baby-ui.nexonauts.com`)}\\n`);\n}\n"],"mappings":";;AAGA,MAAM,WAAW;CAChB;CACA;CACA;CACA;CACA;CACA;AACD;;AAGA,SAAgB,YAAY,SAAuB;CAClD,IAAI,CAAC,cAAc,GAAG;CACtB,MAAM,MAAM,QAAQ;CACpB,IAAI,MAAM,IAAI;CACd,KAAK,MAAM,QAAQ,UAAU,IAAI,MAAM,MAAM,EAAE,MAAM,IAAI,EAAE,GAAG;CAC9D,IAAI,MAAM,QAAQ,EAAE,IAAI,oDAAoD,EAAE,GAAG;CACjF,IAAI,MAAM,MAAM,EAAE,KAAK,IAAI,QAAQ,sCAAsC,EAAE,GAAG;AAC/E"}
@@ -0,0 +1,142 @@
1
+ import { emitKeypressEvents } from "node:readline";
2
+ //#region src/logger.ts
3
+ const colorEnabled = process.env.FORCE_COLOR === "1" || process.stdout.isTTY === true && process.env.NO_COLOR === void 0;
4
+ const ansi = (code, s) => colorEnabled ? `\x1b[${code}m${s}\x1b[0m` : s;
5
+ const truecolor = /truecolor|24bit/i.test(process.env.COLORTERM ?? "");
6
+ const c = {
7
+ brand: (s) => ansi(truecolor ? "38;2;96;160;245" : "34", s),
8
+ red: (s) => ansi("31", s),
9
+ green: (s) => ansi("32", s),
10
+ yellow: (s) => ansi("33", s),
11
+ white: (s) => ansi("37", s),
12
+ gray: (s) => ansi("90", s),
13
+ bold: (s) => ansi("1", s),
14
+ dim: (s) => ansi("2", s),
15
+ inverse: (s) => ansi("7", s)
16
+ };
17
+ const symbols = {
18
+ tick: "✓",
19
+ cross: "✗",
20
+ diamond: "◆",
21
+ arrow: "→",
22
+ dot: "·"
23
+ };
24
+ const log = {
25
+ info: (msg) => console.log(`${c.brand(symbols.diamond)} ${msg}`),
26
+ success: (msg) => console.log(`${c.green(symbols.tick)} ${msg}`),
27
+ warn: (msg) => console.warn(`${c.yellow("!")} ${msg}`),
28
+ error: (msg) => console.error(`${c.red(symbols.cross)} ${msg}`),
29
+ plain: (msg) => console.log(msg)
30
+ };
31
+ //#endregion
32
+ //#region src/ui/theme.ts
33
+ const S = {
34
+ bar: "│",
35
+ barStart: "┌",
36
+ barEnd: "└",
37
+ active: "◆",
38
+ submit: "◇",
39
+ cancel: "■",
40
+ radioOn: "●",
41
+ radioOff: "○",
42
+ checkOn: "◼",
43
+ checkOff: "◻",
44
+ pointer: "›",
45
+ spinner: [
46
+ "◒",
47
+ "◐",
48
+ "◓",
49
+ "◑"
50
+ ]
51
+ };
52
+ const cursor = {
53
+ hide: "\x1B[?25l",
54
+ show: "\x1B[?25h"
55
+ };
56
+ /** A gray rail segment, optionally carrying content: `│ text`. */
57
+ function bar(text = "") {
58
+ return text ? `${c.gray(S.bar)} ${text}` : c.gray(S.bar);
59
+ }
60
+ function stepGlyph(status) {
61
+ if (status === "submit") return c.green(S.submit);
62
+ if (status === "cancel") return c.red(S.cancel);
63
+ return c.brand(S.active);
64
+ }
65
+ function head(status, message) {
66
+ return `${stepGlyph(status)} ${message}`;
67
+ }
68
+ /** The collapsed `◇ Message › value` line a prompt leaves behind, plus a rail gap. */
69
+ function summary(status, message, value) {
70
+ const shown = status === "cancel" ? c.dim(value) : c.brand(value);
71
+ return `${head(status, message)} ${c.dim(S.pointer)} ${shown}\n${bar()}`;
72
+ }
73
+ //#endregion
74
+ //#region src/ui/core.ts
75
+ var PromptCancelled = class extends Error {
76
+ constructor() {
77
+ super("Prompt cancelled");
78
+ this.name = "PromptCancelled";
79
+ }
80
+ };
81
+ let assumeDefaults = false;
82
+ /** `--yes`: every prompt takes its default, as on a non-interactive stream. */
83
+ function acceptDefaults() {
84
+ assumeDefaults = true;
85
+ }
86
+ /** True when both ends are a TTY outside CI; prompts return their defaults otherwise. */
87
+ function isInteractive() {
88
+ return !assumeDefaults && process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
89
+ }
90
+ function runPrompt(spec) {
91
+ return new Promise((resolve, reject) => {
92
+ const input = process.stdin;
93
+ const out = process.stdout;
94
+ emitKeypressEvents(input);
95
+ const wasRaw = input.isRaw === true;
96
+ if (input.isTTY) input.setRawMode(true);
97
+ input.resume();
98
+ out.write(cursor.hide);
99
+ let status = "active";
100
+ let prevLines = 0;
101
+ let settled = false;
102
+ const paint = () => {
103
+ const frame = spec.frame(status);
104
+ if (prevLines > 0) out.write(`\x1b[${prevLines}A`);
105
+ out.write("\x1B[0J");
106
+ out.write(`${frame}\n`);
107
+ prevLines = frame.split("\n").length;
108
+ };
109
+ const teardown = () => {
110
+ input.off("keypress", onKeypress);
111
+ if (input.isTTY) input.setRawMode(wasRaw);
112
+ input.pause();
113
+ out.write(cursor.show);
114
+ };
115
+ const finish = (next, done) => {
116
+ if (settled) return;
117
+ settled = true;
118
+ status = next;
119
+ paint();
120
+ teardown();
121
+ done();
122
+ };
123
+ const ctx = {
124
+ submit: () => finish("submit", resolve),
125
+ cancel: () => finish("cancel", () => reject(new PromptCancelled()))
126
+ };
127
+ const onKeypress = (_str, key = {}) => {
128
+ if (key.ctrl && key.name === "c" || key.name === "escape") {
129
+ ctx.cancel();
130
+ return;
131
+ }
132
+ spec.onKey(key, ctx);
133
+ if (!settled) paint();
134
+ };
135
+ input.on("keypress", onKeypress);
136
+ paint();
137
+ });
138
+ }
139
+ //#endregion
140
+ export { S as a, head as c, log as d, symbols as f, runPrompt as i, summary as l, acceptDefaults as n, bar as o, isInteractive as r, cursor as s, PromptCancelled as t, c as u };
141
+
142
+ //# sourceMappingURL=core-Cd391zXy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-Cd391zXy.js","names":[],"sources":["../src/logger.ts","../src/ui/theme.ts","../src/ui/core.ts"],"sourcesContent":["export const colorEnabled =\n\tprocess.env.FORCE_COLOR === \"1\" ||\n\t(process.stdout.isTTY === true && process.env.NO_COLOR === undefined);\n\nconst ansi = (code: string, s: string) => (colorEnabled ? `\\x1b[${code}m${s}\\x1b[0m` : s);\n\n// Dark-theme --primary (oklch 70% 0.15 255) on truecolor terminals; plain blue otherwise.\nconst truecolor = /truecolor|24bit/i.test(process.env.COLORTERM ?? \"\");\n\nexport const c = {\n\tbrand: (s: string) => ansi(truecolor ? \"38;2;96;160;245\" : \"34\", s),\n\tred: (s: string) => ansi(\"31\", s),\n\tgreen: (s: string) => ansi(\"32\", s),\n\tyellow: (s: string) => ansi(\"33\", s),\n\twhite: (s: string) => ansi(\"37\", s),\n\tgray: (s: string) => ansi(\"90\", s),\n\tbold: (s: string) => ansi(\"1\", s),\n\tdim: (s: string) => ansi(\"2\", s),\n\tinverse: (s: string) => ansi(\"7\", s),\n};\n\nexport const symbols = { tick: \"✓\", cross: \"✗\", diamond: \"◆\", arrow: \"→\", dot: \"·\" };\n\nexport const log = {\n\tinfo: (msg: string) => console.log(`${c.brand(symbols.diamond)} ${msg}`),\n\tsuccess: (msg: string) => console.log(`${c.green(symbols.tick)} ${msg}`),\n\twarn: (msg: string) => console.warn(`${c.yellow(\"!\")} ${msg}`),\n\terror: (msg: string) => console.error(`${c.red(symbols.cross)} ${msg}`),\n\tplain: (msg: string) => console.log(msg),\n};\n","import { c } from \"../logger.ts\";\n\nexport type StepStatus = \"active\" | \"submit\" | \"cancel\";\n\nexport const S = {\n\tbar: \"│\",\n\tbarStart: \"┌\",\n\tbarEnd: \"└\",\n\tactive: \"◆\",\n\tsubmit: \"◇\",\n\tcancel: \"■\",\n\tradioOn: \"●\",\n\tradioOff: \"○\",\n\tcheckOn: \"◼\",\n\tcheckOff: \"◻\",\n\tpointer: \"›\",\n\tspinner: [\"◒\", \"◐\", \"◓\", \"◑\"],\n} as const;\n\nexport const cursor = { hide: \"\\x1b[?25l\", show: \"\\x1b[?25h\" } as const;\n\n/** A gray rail segment, optionally carrying content: `│ text`. */\nexport function bar(text = \"\"): string {\n\treturn text ? `${c.gray(S.bar)} ${text}` : c.gray(S.bar);\n}\n\nfunction stepGlyph(status: StepStatus): string {\n\tif (status === \"submit\") return c.green(S.submit);\n\tif (status === \"cancel\") return c.red(S.cancel);\n\treturn c.brand(S.active);\n}\n\nexport function head(status: StepStatus, message: string): string {\n\treturn `${stepGlyph(status)} ${message}`;\n}\n\n/** The collapsed `◇ Message › value` line a prompt leaves behind, plus a rail gap. */\nexport function summary(status: StepStatus, message: string, value: string): string {\n\tconst shown = status === \"cancel\" ? c.dim(value) : c.brand(value);\n\treturn `${head(status, message)} ${c.dim(S.pointer)} ${shown}\\n${bar()}`;\n}\n","import { emitKeypressEvents } from \"node:readline\";\nimport { cursor, type StepStatus } from \"./theme.ts\";\n\nexport interface Key {\n\tname?: string;\n\tctrl?: boolean;\n\tmeta?: boolean;\n\tshift?: boolean;\n\tsequence?: string;\n}\n\nexport class PromptCancelled extends Error {\n\tconstructor() {\n\t\tsuper(\"Prompt cancelled\");\n\t\tthis.name = \"PromptCancelled\";\n\t}\n}\n\nlet assumeDefaults = false;\n\n/** `--yes`: every prompt takes its default, as on a non-interactive stream. */\nexport function acceptDefaults(): void {\n\tassumeDefaults = true;\n}\n\n/** True when both ends are a TTY outside CI; prompts return their defaults otherwise. */\nexport function isInteractive(): boolean {\n\treturn (\n\t\t!assumeDefaults &&\n\t\tprocess.stdin.isTTY === true &&\n\t\tprocess.stdout.isTTY === true &&\n\t\t!process.env.CI\n\t);\n}\n\nexport interface PromptActions {\n\tsubmit(): void;\n\tcancel(): void;\n}\n\nexport interface PromptSpec {\n\tframe(status: StepStatus): string;\n\tonKey(key: Key, ctx: PromptActions): void;\n}\n\n// Redraw moves up by the last frame's line count, so frames must never soft-wrap.\nexport function runPrompt(spec: PromptSpec): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst input = process.stdin;\n\t\tconst out = process.stdout;\n\n\t\temitKeypressEvents(input);\n\t\tconst wasRaw = input.isRaw === true;\n\t\tif (input.isTTY) input.setRawMode(true);\n\t\tinput.resume();\n\t\tout.write(cursor.hide);\n\n\t\tlet status: StepStatus = \"active\";\n\t\tlet prevLines = 0;\n\t\tlet settled = false;\n\n\t\tconst paint = (): void => {\n\t\t\tconst frame = spec.frame(status);\n\t\t\tif (prevLines > 0) out.write(`\\x1b[${prevLines}A`);\n\t\t\tout.write(\"\\x1b[0J\");\n\t\t\tout.write(`${frame}\\n`);\n\t\t\tprevLines = frame.split(\"\\n\").length;\n\t\t};\n\n\t\tconst teardown = (): void => {\n\t\t\tinput.off(\"keypress\", onKeypress);\n\t\t\tif (input.isTTY) input.setRawMode(wasRaw);\n\t\t\tinput.pause();\n\t\t\tout.write(cursor.show);\n\t\t};\n\n\t\tconst finish = (next: StepStatus, done: () => void): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tstatus = next;\n\t\t\tpaint();\n\t\t\tteardown();\n\t\t\tdone();\n\t\t};\n\n\t\tconst ctx: PromptActions = {\n\t\t\tsubmit: () => finish(\"submit\", resolve),\n\t\t\tcancel: () => finish(\"cancel\", () => reject(new PromptCancelled())),\n\t\t};\n\n\t\tconst onKeypress = (_str: string | undefined, key: Key = {}): void => {\n\t\t\tif ((key.ctrl && key.name === \"c\") || key.name === \"escape\") {\n\t\t\t\tctx.cancel();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tspec.onKey(key, ctx);\n\t\t\tif (!settled) paint();\n\t\t};\n\n\t\tinput.on(\"keypress\", onKeypress);\n\t\tpaint();\n\t});\n}\n"],"mappings":"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"}