@scalebun-release/cli 2.5.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 (210) hide show
  1. package/bin/scalebun.js +2 -0
  2. package/lib/api/client.d.ts +52 -0
  3. package/lib/api/client.d.ts.map +1 -0
  4. package/lib/api/client.js +335 -0
  5. package/lib/api/client.js.map +1 -0
  6. package/lib/commands/ci-init.d.ts +3 -0
  7. package/lib/commands/ci-init.d.ts.map +1 -0
  8. package/lib/commands/ci-init.js +348 -0
  9. package/lib/commands/ci-init.js.map +1 -0
  10. package/lib/commands/doctor.d.ts +31 -0
  11. package/lib/commands/doctor.d.ts.map +1 -0
  12. package/lib/commands/doctor.js +559 -0
  13. package/lib/commands/doctor.js.map +1 -0
  14. package/lib/commands/launch.d.ts +3 -0
  15. package/lib/commands/launch.d.ts.map +1 -0
  16. package/lib/commands/launch.js +23 -0
  17. package/lib/commands/launch.js.map +1 -0
  18. package/lib/commands/link.d.ts +16 -0
  19. package/lib/commands/link.d.ts.map +1 -0
  20. package/lib/commands/link.js +164 -0
  21. package/lib/commands/link.js.map +1 -0
  22. package/lib/commands/login.d.ts +12 -0
  23. package/lib/commands/login.d.ts.map +1 -0
  24. package/lib/commands/login.js +124 -0
  25. package/lib/commands/login.js.map +1 -0
  26. package/lib/commands/migrate-codepush.d.ts +13 -0
  27. package/lib/commands/migrate-codepush.d.ts.map +1 -0
  28. package/lib/commands/migrate-codepush.js +98 -0
  29. package/lib/commands/migrate-codepush.js.map +1 -0
  30. package/lib/commands/ota-bundle.d.ts +22 -0
  31. package/lib/commands/ota-bundle.d.ts.map +1 -0
  32. package/lib/commands/ota-bundle.js +253 -0
  33. package/lib/commands/ota-bundle.js.map +1 -0
  34. package/lib/commands/ota-channels.d.ts +3 -0
  35. package/lib/commands/ota-channels.d.ts.map +1 -0
  36. package/lib/commands/ota-channels.js +231 -0
  37. package/lib/commands/ota-channels.js.map +1 -0
  38. package/lib/commands/ota-delete-bundle.d.ts +16 -0
  39. package/lib/commands/ota-delete-bundle.d.ts.map +1 -0
  40. package/lib/commands/ota-delete-bundle.js +96 -0
  41. package/lib/commands/ota-delete-bundle.js.map +1 -0
  42. package/lib/commands/ota-inspect.d.ts +3 -0
  43. package/lib/commands/ota-inspect.d.ts.map +1 -0
  44. package/lib/commands/ota-inspect.js +258 -0
  45. package/lib/commands/ota-inspect.js.map +1 -0
  46. package/lib/commands/ota-keys.d.ts +91 -0
  47. package/lib/commands/ota-keys.d.ts.map +1 -0
  48. package/lib/commands/ota-keys.js +765 -0
  49. package/lib/commands/ota-keys.js.map +1 -0
  50. package/lib/commands/ota-promote.d.ts +3 -0
  51. package/lib/commands/ota-promote.d.ts.map +1 -0
  52. package/lib/commands/ota-promote.js +194 -0
  53. package/lib/commands/ota-promote.js.map +1 -0
  54. package/lib/commands/ota-publish.d.ts +26 -0
  55. package/lib/commands/ota-publish.d.ts.map +1 -0
  56. package/lib/commands/ota-publish.js +892 -0
  57. package/lib/commands/ota-publish.js.map +1 -0
  58. package/lib/commands/ota-rollout.d.ts +3 -0
  59. package/lib/commands/ota-rollout.d.ts.map +1 -0
  60. package/lib/commands/ota-rollout.js +265 -0
  61. package/lib/commands/ota-rollout.js.map +1 -0
  62. package/lib/commands/ota-sign.d.ts +19 -0
  63. package/lib/commands/ota-sign.d.ts.map +1 -0
  64. package/lib/commands/ota-sign.js +245 -0
  65. package/lib/commands/ota-sign.js.map +1 -0
  66. package/lib/commands/push-apns.d.ts +3 -0
  67. package/lib/commands/push-apns.d.ts.map +1 -0
  68. package/lib/commands/push-apns.js +166 -0
  69. package/lib/commands/push-apns.js.map +1 -0
  70. package/lib/commands/quickstart.d.ts +4 -0
  71. package/lib/commands/quickstart.d.ts.map +1 -0
  72. package/lib/commands/quickstart.js +672 -0
  73. package/lib/commands/quickstart.js.map +1 -0
  74. package/lib/commands/shell.d.ts +28 -0
  75. package/lib/commands/shell.d.ts.map +1 -0
  76. package/lib/commands/shell.js +512 -0
  77. package/lib/commands/shell.js.map +1 -0
  78. package/lib/commands/tls-pins.d.ts +27 -0
  79. package/lib/commands/tls-pins.d.ts.map +1 -0
  80. package/lib/commands/tls-pins.js +209 -0
  81. package/lib/commands/tls-pins.js.map +1 -0
  82. package/lib/index.d.ts +2 -0
  83. package/lib/index.d.ts.map +1 -0
  84. package/lib/index.js +233 -0
  85. package/lib/index.js.map +1 -0
  86. package/lib/ui/banner.d.ts +23 -0
  87. package/lib/ui/banner.d.ts.map +1 -0
  88. package/lib/ui/banner.js +162 -0
  89. package/lib/ui/banner.js.map +1 -0
  90. package/lib/ui/graphics.d.ts +18 -0
  91. package/lib/ui/graphics.d.ts.map +1 -0
  92. package/lib/ui/graphics.js +134 -0
  93. package/lib/ui/graphics.js.map +1 -0
  94. package/lib/ui/mark.d.ts +4 -0
  95. package/lib/ui/mark.d.ts.map +1 -0
  96. package/lib/ui/mark.js +21 -0
  97. package/lib/ui/mark.js.map +1 -0
  98. package/lib/ui/menu.d.ts +109 -0
  99. package/lib/ui/menu.d.ts.map +1 -0
  100. package/lib/ui/menu.js +314 -0
  101. package/lib/ui/menu.js.map +1 -0
  102. package/lib/ui/sixel.d.ts +6 -0
  103. package/lib/ui/sixel.d.ts.map +1 -0
  104. package/lib/ui/sixel.js +9 -0
  105. package/lib/ui/sixel.js.map +1 -0
  106. package/lib/utils/apps.d.ts +29 -0
  107. package/lib/utils/apps.d.ts.map +1 -0
  108. package/lib/utils/apps.js +19 -0
  109. package/lib/utils/apps.js.map +1 -0
  110. package/lib/utils/browser.d.ts +9 -0
  111. package/lib/utils/browser.d.ts.map +1 -0
  112. package/lib/utils/browser.js +39 -0
  113. package/lib/utils/browser.js.map +1 -0
  114. package/lib/utils/bundle.d.ts +153 -0
  115. package/lib/utils/bundle.d.ts.map +1 -0
  116. package/lib/utils/bundle.js +459 -0
  117. package/lib/utils/bundle.js.map +1 -0
  118. package/lib/utils/bundleStore.d.ts +128 -0
  119. package/lib/utils/bundleStore.d.ts.map +1 -0
  120. package/lib/utils/bundleStore.js +250 -0
  121. package/lib/utils/bundleStore.js.map +1 -0
  122. package/lib/utils/context.d.ts +88 -0
  123. package/lib/utils/context.d.ts.map +1 -0
  124. package/lib/utils/context.js +247 -0
  125. package/lib/utils/context.js.map +1 -0
  126. package/lib/utils/credentials.d.ts +59 -0
  127. package/lib/utils/credentials.d.ts.map +1 -0
  128. package/lib/utils/credentials.js +147 -0
  129. package/lib/utils/credentials.js.map +1 -0
  130. package/lib/utils/guide.d.ts +63 -0
  131. package/lib/utils/guide.d.ts.map +1 -0
  132. package/lib/utils/guide.js +191 -0
  133. package/lib/utils/guide.js.map +1 -0
  134. package/lib/utils/hash.d.ts +3 -0
  135. package/lib/utils/hash.d.ts.map +1 -0
  136. package/lib/utils/hash.js +44 -0
  137. package/lib/utils/hash.js.map +1 -0
  138. package/lib/utils/native-id.d.ts +17 -0
  139. package/lib/utils/native-id.d.ts.map +1 -0
  140. package/lib/utils/native-id.js +105 -0
  141. package/lib/utils/native-id.js.map +1 -0
  142. package/lib/utils/output.d.ts +96 -0
  143. package/lib/utils/output.d.ts.map +1 -0
  144. package/lib/utils/output.js +135 -0
  145. package/lib/utils/output.js.map +1 -0
  146. package/lib/utils/prompt.d.ts +106 -0
  147. package/lib/utils/prompt.d.ts.map +1 -0
  148. package/lib/utils/prompt.js +457 -0
  149. package/lib/utils/prompt.js.map +1 -0
  150. package/lib/utils/provenance.d.ts +30 -0
  151. package/lib/utils/provenance.d.ts.map +1 -0
  152. package/lib/utils/provenance.js +157 -0
  153. package/lib/utils/provenance.js.map +1 -0
  154. package/lib/utils/resolve.d.ts +81 -0
  155. package/lib/utils/resolve.d.ts.map +1 -0
  156. package/lib/utils/resolve.js +139 -0
  157. package/lib/utils/resolve.js.map +1 -0
  158. package/lib/utils/sdkBin.d.ts +18 -0
  159. package/lib/utils/sdkBin.d.ts.map +1 -0
  160. package/lib/utils/sdkBin.js +76 -0
  161. package/lib/utils/sdkBin.js.map +1 -0
  162. package/lib/utils/signer.d.ts +94 -0
  163. package/lib/utils/signer.d.ts.map +1 -0
  164. package/lib/utils/signer.js +230 -0
  165. package/lib/utils/signer.js.map +1 -0
  166. package/lib/utils/signing.d.ts +102 -0
  167. package/lib/utils/signing.d.ts.map +1 -0
  168. package/lib/utils/signing.js +229 -0
  169. package/lib/utils/signing.js.map +1 -0
  170. package/lib/utils/transportSecurity.d.ts +36 -0
  171. package/lib/utils/transportSecurity.d.ts.map +1 -0
  172. package/lib/utils/transportSecurity.js +74 -0
  173. package/lib/utils/transportSecurity.js.map +1 -0
  174. package/lib/utils/trustAnchor.d.ts +109 -0
  175. package/lib/utils/trustAnchor.d.ts.map +1 -0
  176. package/lib/utils/trustAnchor.js +169 -0
  177. package/lib/utils/trustAnchor.js.map +1 -0
  178. package/lib/utils/ui.d.ts +12 -0
  179. package/lib/utils/ui.d.ts.map +1 -0
  180. package/lib/utils/ui.js +60 -0
  181. package/lib/utils/ui.js.map +1 -0
  182. package/lib/utils/validate.d.ts +62 -0
  183. package/lib/utils/validate.d.ts.map +1 -0
  184. package/lib/utils/validate.js +189 -0
  185. package/lib/utils/validate.js.map +1 -0
  186. package/lib/vendor/ota-protocol/base64.d.ts +11 -0
  187. package/lib/vendor/ota-protocol/base64.d.ts.map +1 -0
  188. package/lib/vendor/ota-protocol/base64.js +39 -0
  189. package/lib/vendor/ota-protocol/base64.js.map +1 -0
  190. package/lib/vendor/ota-protocol/codec.d.ts +26 -0
  191. package/lib/vendor/ota-protocol/codec.d.ts.map +1 -0
  192. package/lib/vendor/ota-protocol/codec.js +349 -0
  193. package/lib/vendor/ota-protocol/codec.js.map +1 -0
  194. package/lib/vendor/ota-protocol/hex.d.ts +8 -0
  195. package/lib/vendor/ota-protocol/hex.d.ts.map +1 -0
  196. package/lib/vendor/ota-protocol/hex.js +31 -0
  197. package/lib/vendor/ota-protocol/hex.js.map +1 -0
  198. package/lib/vendor/ota-protocol/index.d.ts +17 -0
  199. package/lib/vendor/ota-protocol/index.d.ts.map +1 -0
  200. package/lib/vendor/ota-protocol/index.js +41 -0
  201. package/lib/vendor/ota-protocol/index.js.map +1 -0
  202. package/lib/vendor/ota-protocol/limits.d.ts +39 -0
  203. package/lib/vendor/ota-protocol/limits.d.ts.map +1 -0
  204. package/lib/vendor/ota-protocol/limits.js +42 -0
  205. package/lib/vendor/ota-protocol/limits.js.map +1 -0
  206. package/lib/vendor/ota-protocol/types.d.ts +73 -0
  207. package/lib/vendor/ota-protocol/types.d.ts.map +1 -0
  208. package/lib/vendor/ota-protocol/types.js +24 -0
  209. package/lib/vendor/ota-protocol/types.js.map +1 -0
  210. package/package.json +37 -0
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WORDMARK = exports.MARK = void 0;
7
+ exports.termWidth = termWidth;
8
+ exports.banner = banner;
9
+ exports.shouldShowArt = shouldShowArt;
10
+ // scalebun/src/ui/banner.ts
11
+ // Ported from the reference banner.mjs — do NOT retune the width thresholds, the
12
+ // gradient stops, the colour ladder, or the mark art. The mark is pre-rendered;
13
+ // regenerate with `pnpm --filter @scalebun/cli gen:mark` if the logo changes.
14
+ // Glyph set is ▀ ▄ █ + space only: the CP437 legacy subset that every monospace
15
+ // font ships (braille U+2800 does NOT ship in DejaVu Sans Mono / Liberation Mono
16
+ // and renders as tofu).
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const mark_1 = require("./mark");
19
+ Object.defineProperty(exports, "MARK", { enumerable: true, get: function () { return mark_1.MARK; } });
20
+ const MARK_H = mark_1.MARK.length;
21
+ exports.WORDMARK = [
22
+ '███████╗ ██████╗ █████╗ ██╗ ███████╗██████╗ ██╗ ██╗███╗ ██╗',
23
+ '██╔════╝██╔════╝██╔══██╗██║ ██╔════╝██╔══██╗██║ ██║████╗ ██║',
24
+ '███████╗██║ ███████║██║ █████╗ ██████╔╝██║ ██║██╔██╗ ██║',
25
+ '╚════██║██║ ██╔══██║██║ ██╔══╝ ██╔══██╗██║ ██║██║╚██╗██║',
26
+ '███████║╚██████╗██║ ██║███████╗███████╗██████╔╝╚██████╔╝██║ ╚████║',
27
+ '╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═══╝',
28
+ ];
29
+ const WORD_W = exports.WORDMARK[0].length;
30
+ /* ── colour ─────────────────────────────────────────────────────────── */
31
+ // Detection is chalk's (`chalk.level`), the CLI's single source of truth for
32
+ // colour support — it also parses argv, so `--no-color` / `--color=never` are
33
+ // honoured here exactly as they are for the status box and command table. The
34
+ // raw-ANSI emitters below stay local: they do per-character gradient with
35
+ // repeat-collapsing, which chalk does not offer.
36
+ const BRAND = [80, 70, 229]; // #5046E5, flat logo indigo
37
+ // Flat: the wordmark is solid brand indigo, identical to the mark (and to the
38
+ // sixel logo). The old purple→pink gradient never matched the real brand logo.
39
+ const GRAD = [
40
+ BRAND,
41
+ BRAND,
42
+ ];
43
+ function rgb256(r, g, b) {
44
+ const q = (v) => Math.round((v / 255) * 5);
45
+ return 16 + 36 * q(r) + 6 * q(g) + q(b);
46
+ }
47
+ function fg(level, r, g, b) {
48
+ if (level >= 3)
49
+ return `\x1b[38;2;${r};${g};${b}m`;
50
+ if (level === 2)
51
+ return `\x1b[38;5;${rgb256(r, g, b)}m`;
52
+ if (level === 1)
53
+ return '\x1b[95m'; // bright magenta
54
+ return '';
55
+ }
56
+ const RESET = (lvl) => (lvl ? '\x1b[0m' : '');
57
+ const STEPS = 12; // quantised: 12 stops instead of one escape per character
58
+ function mix(t) {
59
+ const [a, b] = GRAD;
60
+ const q = Math.round(t * (STEPS - 1)) / (STEPS - 1);
61
+ return [
62
+ Math.round(a[0] + (b[0] - a[0]) * q),
63
+ Math.round(a[1] + (b[1] - a[1]) * q),
64
+ Math.round(a[2] + (b[2] - a[2]) * q),
65
+ ];
66
+ }
67
+ /** Per-character horizontal gradient. Falls back to one flat escape below truecolor. */
68
+ function gradient(line, level) {
69
+ if (level === 0)
70
+ return line;
71
+ if (level < 3)
72
+ return fg(level, GRAD[0][0], GRAD[0][1], GRAD[0][2]) + line + RESET(level);
73
+ let out = '';
74
+ let last = '';
75
+ for (let i = 0; i < line.length; i++) {
76
+ const [r, g, b] = mix(i / Math.max(1, line.length - 1));
77
+ const c = fg(3, r, g, b);
78
+ if (c !== last) {
79
+ out += c;
80
+ last = c;
81
+ } // collapse repeats
82
+ out += line[i];
83
+ }
84
+ return out + RESET(level);
85
+ }
86
+ /* ── layout ─────────────────────────────────────────────────────────── */
87
+ /** Real TTY width wins; COLUMNS only covers the non-TTY case (pipes, tests). */
88
+ function termWidth() {
89
+ return process.stdout.columns || Number(process.env.COLUMNS) || 80;
90
+ }
91
+ const pad = (s, n) => s + ' '.repeat(Math.max(0, n - s.length));
92
+ function banner(o = {}) {
93
+ const version = o.version ?? '0.0.0';
94
+ const tagline = o.tagline ?? 'Enterprise OTA Update & Telemetry Control Plane';
95
+ const level = o.level ?? chalk_1.default.level; // 0 none · 1 basic · 2 256 · 3 truecolor
96
+ const width = o.width ?? termWidth();
97
+ const dim = level ? '\x1b[90m' : '';
98
+ const R = RESET(level);
99
+ // Narrow terminals: no art at all. One line beats a broken picture.
100
+ if (width < 46)
101
+ return `${fg(level, BRAND[0], BRAND[1], BRAND[2])}scalebun${R} ${dim}v${version}${R}\n`;
102
+ const GAP = 5; // must match GAP/TOP in graphics.ts (sixel path)
103
+ const OFF = GAP; // compact lockup uses the same gap
104
+ const brand = fg(level, BRAND[0], BRAND[1], BRAND[2]);
105
+ const lines = [];
106
+ // Full lockup — mark + block wordmark, wordmark optically centred.
107
+ if (o.mark !== false && width >= mark_1.MARK_W + GAP + WORD_W) {
108
+ const top = 2; // lifts the logo optically — matches graphics.ts TOP
109
+ for (let i = 0; i < MARK_H; i++) {
110
+ const left = brand + pad(mark_1.MARK[i] ?? '', mark_1.MARK_W) + R;
111
+ const wi = i - top;
112
+ let right = '';
113
+ if (wi >= 0 && wi < exports.WORDMARK.length)
114
+ right = gradient(exports.WORDMARK[wi], level);
115
+ else if (wi === exports.WORDMARK.length)
116
+ right = `${dim}v${version} · ${tagline}${R}`;
117
+ lines.push(right ? left + ' '.repeat(GAP) + right : left);
118
+ }
119
+ return lines.join('\n').replace(/[ \t]+$/gm, '') + '\n';
120
+ }
121
+ // Compact lockup — mark + type. Same composition as the `quiet` direction, so
122
+ // an 80-column terminal still gets the rabbit.
123
+ const shortTag = 'OTA updates and telemetry';
124
+ const tag = width >= mark_1.MARK_W + OFF + tagline.length ? tagline : shortTag;
125
+ if (o.mark !== false && width >= mark_1.MARK_W + OFF + shortTag.length) {
126
+ const bold = level ? '\x1b[1m' : '';
127
+ const type = [
128
+ `${bold}${fg(level, GRAD[0][0], GRAD[0][1], GRAD[0][2])}scalebun${R} ${dim}v${version}${R}`,
129
+ `${dim}${tag}${R}`,
130
+ ];
131
+ const top = Math.floor((MARK_H - type.length) / 2);
132
+ for (let i = 0; i < MARK_H; i++) {
133
+ const left = brand + pad(mark_1.MARK[i] ?? '', mark_1.MARK_W) + R;
134
+ const ti = i - top;
135
+ const right = ti >= 0 && ti < type.length ? type[ti] : '';
136
+ lines.push(right ? left + ' '.repeat(OFF) + right : left);
137
+ }
138
+ return lines.join('\n').replace(/[ \t]+$/gm, '') + '\n';
139
+ }
140
+ // No room beside the mark: type only.
141
+ if (width >= WORD_W)
142
+ exports.WORDMARK.forEach((l) => lines.push(gradient(l, level)));
143
+ else
144
+ lines.push(`${fg(level, BRAND[0], BRAND[1], BRAND[2])}scalebun${R}`);
145
+ lines.push('');
146
+ lines.push(`${dim}v${version} · ${width >= 60 ? tagline : shortTag}${R}`);
147
+ return lines.join('\n') + '\n';
148
+ }
149
+ /**
150
+ * Gates the ART ONLY (mark + wordmark). The splash body — status line and
151
+ * command table — is the output of the no-arg command, not banner decoration,
152
+ * so it must NOT be gated by this. Keep the two concerns separate.
153
+ */
154
+ function shouldShowArt(argv = process.argv.slice(2)) {
155
+ if (argv.includes('--no-banner') || process.env.SCALEBUN_NO_BANNER)
156
+ return false;
157
+ if (process.env.CI && !process.stdout.isTTY)
158
+ return false;
159
+ const cmd = argv.find((a) => !a.startsWith('-'));
160
+ return !cmd || cmd === 'help'; // bare `scalebun` and `scalebun help` only
161
+ }
162
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/ui/banner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ declare const ROWS = 9, COLS = 13;
2
+ type Caps = {
3
+ sixel: boolean;
4
+ cellH: number;
5
+ cellW: number;
6
+ };
7
+ export declare function capabilities(): Promise<Caps | null>;
8
+ /**
9
+ * Draw the logo, then climb back over it and set the wordmark beside it.
10
+ * DEC save/restore (ESC 7 / ESC 8) does NOT survive a sixel draw in Windows
11
+ * Terminal — the cursor lands near the bottom of the image. Cursor-up plus an
12
+ * absolute column (CSI n G) is what actually works.
13
+ */
14
+ export declare function lockup(caps: Caps, wordmark: string[], tagline: string, opts?: {
15
+ level?: number;
16
+ }): string;
17
+ export { ROWS as LOGO_ROWS, COLS as LOGO_COLS };
18
+ //# sourceMappingURL=graphics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphics.d.ts","sourceRoot":"","sources":["../../src/ui/graphics.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,IAAI,IAAI,EAAE,IAAI,KAAK,CAAC;AAM1B,KAAK,IAAI,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAkD7D,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAUzD;AASD;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5B,MAAM,CA6BR;AAED,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC"}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOGO_COLS = exports.LOGO_ROWS = void 0;
4
+ exports.capabilities = capabilities;
5
+ exports.lockup = lockup;
6
+ // scalebun/src/ui/graphics.ts
7
+ // Smooth logo via sixel, where the terminal supports it. Falls back to block art.
8
+ // Zero runtime deps. Payloads pre-generated by tools/gen-sixel.mjs.
9
+ const node_os_1 = require("node:os");
10
+ const node_path_1 = require("node:path");
11
+ const node_fs_1 = require("node:fs");
12
+ /** 9 rows tall, keyed by the terminal's cell height in px. ~5.7 KB total. */
13
+ const sixel_1 = require("./sixel");
14
+ const ROWS = 9, COLS = 13;
15
+ exports.LOGO_ROWS = ROWS;
16
+ exports.LOGO_COLS = COLS;
17
+ const GAP = 5, TOP = 2; // shared with the block-art path in banner.ts
18
+ const E = '\x1b';
19
+ const CACHE = (0, node_path_1.join)((0, node_os_1.homedir)(), '.scalebun', 'graphics.json');
20
+ const TTL = 7 * 24 * 3600 * 1000;
21
+ /**
22
+ * One round trip for everything: DA1 (feature list, 4 = sixel) and CSI 16 t
23
+ * (cell size). Env vars are useless here — cmd.exe inside Windows Terminal
24
+ * reports no TERM, no TERM_PROGRAM and no WT_SESSION, yet supports sixel.
25
+ */
26
+ function probe(ms = 300) {
27
+ return new Promise(resolve => {
28
+ if (!process.stdin.isTTY || !process.stdout.isTTY)
29
+ return resolve(null);
30
+ let buf = '';
31
+ const finish = () => {
32
+ clearTimeout(timer);
33
+ process.stdin.removeListener('data', onData);
34
+ try {
35
+ process.stdin.setRawMode(false);
36
+ }
37
+ catch { }
38
+ process.stdin.pause();
39
+ const da1 = buf.match(/\x1b\[\?([0-9;]+)c/);
40
+ const cell = buf.match(/\x1b\[6;(\d+);(\d+)t/);
41
+ resolve({
42
+ sixel: !!da1 && da1[1].split(';').includes('4'),
43
+ cellH: cell ? +cell[1] : 20,
44
+ cellW: cell ? +cell[2] : 10
45
+ });
46
+ };
47
+ const onData = (d) => {
48
+ buf += d.toString('binary');
49
+ if (/c/.test(buf) && /t/.test(buf))
50
+ finish();
51
+ };
52
+ const timer = setTimeout(finish, ms);
53
+ try {
54
+ process.stdin.setRawMode(true);
55
+ }
56
+ catch {
57
+ return resolve(null);
58
+ }
59
+ process.stdin.resume();
60
+ process.stdin.on('data', onData);
61
+ process.stdout.write(E + '[c' + E + '[16t');
62
+ });
63
+ }
64
+ function readCache() {
65
+ try {
66
+ const c = JSON.parse((0, node_fs_1.readFileSync)(CACHE, 'utf8'));
67
+ return Date.now() - c.at < TTL ? c.caps : null;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ function writeCache(caps) {
74
+ try {
75
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)((0, node_os_1.homedir)(), '.scalebun'), { recursive: true });
76
+ (0, node_fs_1.writeFileSync)(CACHE, JSON.stringify({ at: Date.now(), caps }));
77
+ }
78
+ catch { /* cache is an optimisation, never a requirement */ }
79
+ }
80
+ async function capabilities() {
81
+ const mode = process.env.SCALEBUN_GRAPHICS; // off | auto | refresh
82
+ if (mode === 'off')
83
+ return null;
84
+ if (mode !== 'refresh') {
85
+ const hit = readCache();
86
+ if (hit)
87
+ return hit;
88
+ }
89
+ const caps = await probe();
90
+ if (caps)
91
+ writeCache(caps);
92
+ return caps;
93
+ }
94
+ /** Pick the payload whose cell height is closest to this terminal's. */
95
+ function payload(cellH) {
96
+ const keys = Object.keys(sixel_1.SIXEL).map(Number);
97
+ const best = keys.reduce((a, b) => Math.abs(b - cellH) < Math.abs(a - cellH) ? b : a);
98
+ return sixel_1.SIXEL[String(best)];
99
+ }
100
+ /**
101
+ * Draw the logo, then climb back over it and set the wordmark beside it.
102
+ * DEC save/restore (ESC 7 / ESC 8) does NOT survive a sixel draw in Windows
103
+ * Terminal — the cursor lands near the bottom of the image. Cursor-up plus an
104
+ * absolute column (CSI n G) is what actually works.
105
+ */
106
+ function lockup(caps, wordmark, tagline, opts = {}) {
107
+ const img = payload(caps.cellH);
108
+ const level = opts.level ?? 3;
109
+ // Same indigo as the mark itself — #5046E5 — with the usual downshift.
110
+ const brand = level >= 3 ? E + '[38;2;80;70;229m'
111
+ : level === 2 ? E + '[38;5;62m'
112
+ : level === 1 ? E + '[95m' : '';
113
+ const dim = level ? E + '[90m' : '';
114
+ const R = level ? E + '[0m' : '';
115
+ // Match the block-art gutter exactly, so the wordmark sits in the same
116
+ // column whether the logo rendered as sixel or as blocks.
117
+ const gutter = Math.max(COLS, Math.ceil(img.w / caps.cellW)) + GAP;
118
+ // The mark's visual mass sits low (ears and arrow are open line, the head is
119
+ // solid), so geometric centring reads as the logo sagging. Dropping the text
120
+ // two rows lifts the logo optically. Rows 0-1 are the arrow and ear tips.
121
+ const top = TOP;
122
+ let s = img.d + E + '[' + ROWS + 'A';
123
+ for (let i = 0; i < ROWS; i++) {
124
+ const wi = i - top;
125
+ let text = '';
126
+ if (wi >= 0 && wi < wordmark.length)
127
+ text = brand + wordmark[wi] + R;
128
+ else if (wi === wordmark.length)
129
+ text = dim + tagline + R;
130
+ s += (text ? E + '[' + gutter + 'G' + text : '') + '\n';
131
+ }
132
+ return s;
133
+ }
134
+ //# sourceMappingURL=graphics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphics.js","sourceRoot":"","sources":["../../src/ui/graphics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const MARK: readonly string[];
2
+ export declare const MARK_W = 13;
3
+ export declare const MARK_H = 9;
4
+ //# sourceMappingURL=mark.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../src/ui/mark.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,EAAE,SAAS,MAAM,EAUjC,CAAC;AACF,eAAO,MAAM,MAAM,KAAK,CAAC;AACzB,eAAO,MAAM,MAAM,IAAI,CAAC"}
package/lib/ui/mark.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MARK_H = exports.MARK_W = exports.MARK = void 0;
4
+ /* eslint-disable */
5
+ // prettier-ignore
6
+ // GENERATED by tools/gen-mark.mjs from assets/scalebun-mark.svg — do not edit by hand.
7
+ // 13x9, arrowhead hand-hinted (see HINT in the generator)
8
+ exports.MARK = [
9
+ " ▄▄▄ ▄██",
10
+ "████▄ ████",
11
+ "██ ██ ▄██▀",
12
+ "▀████████▄",
13
+ " ████▀▀▀▀███",
14
+ "██▀ ▄▄▀██",
15
+ "██ ▀▀ ██",
16
+ "██▄ ▄▄▄▄██",
17
+ " ▀██████▀▀▀▀"
18
+ ];
19
+ exports.MARK_W = 13;
20
+ exports.MARK_H = 9;
21
+ //# sourceMappingURL=mark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mark.js","sourceRoot":"","sources":["../../src/ui/mark.ts"],"names":[],"mappings":";;;AAAA,oBAAoB;AACpB,kBAAkB;AAClB,uFAAuF;AACvF,0DAA0D;AAC7C,QAAA,IAAI,GAAsB;IACrC,cAAc;IACd,cAAc;IACd,aAAa;IACb,YAAY;IACZ,cAAc;IACd,eAAe;IACf,eAAe;IACf,eAAe;IACf,cAAc;CACf,CAAC;AACW,QAAA,MAAM,GAAG,EAAE,CAAC;AACZ,QAAA,MAAM,GAAG,CAAC,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The interactive home screen — arrow keys through the grouped commands.
3
+ *
4
+ * ── Why a menu and not just a prompt ────────────────────────────────────────
5
+ *
6
+ * A bare prompt only helps someone who already knows what to type, which is
7
+ * precisely the person who did not need an interactive mode. Printing all
8
+ * thirty commands instead solves discovery and destroys it in the same breath:
9
+ * a wall of cyan has no shape, so nothing stands out. Grouping and then
10
+ * revealing one group at a time keeps the whole surface reachable while never
11
+ * showing more than about five things at once.
12
+ *
13
+ * Typing still works, and works from the menu — any printable key opens the
14
+ * command line seeded with that character. So the menu is a floor, not a
15
+ * ceiling: it never stands between an experienced user and the thing they were
16
+ * going to type anyway.
17
+ *
18
+ * ── The frame must FIT ──────────────────────────────────────────────────────
19
+ *
20
+ * This is the whole ballgame, and getting it wrong is not a cosmetic bug.
21
+ * Logo, status box, project line, group header and the ten SETUP commands come
22
+ * to 32 lines; a normal terminal is 24 to 30. Overflow does not merely crop —
23
+ * the terminal scrolls to fit, so the next frame's `\x1b[H` (cursor home) lands
24
+ * at the top of the VIEWPORT rather than the top of the frame, and each redraw
25
+ * paints over a shifting target. Within a few keypresses the screen is a
26
+ * collage of half-frames, arrow keys appear to do nothing, and the session
27
+ * looks hung when it is in fact working perfectly.
28
+ *
29
+ * So the frame is budgeted against `stdout.rows` and the command list is
30
+ * windowed to whatever is left. The logo is never what gets sacrificed — it is
31
+ * the reason for coming back to this screen — so the list scrolls instead.
32
+ *
33
+ * Frames are composed in memory and written ONCE. Sequential console.log calls
34
+ * tear visibly: the terminal paints each line as it arrives, so an arrow key
35
+ * produces a flicker of half-drawn screen.
36
+ */
37
+ export type MenuChoice = {
38
+ kind: 'run';
39
+ argv: string[];
40
+ }
41
+ /** The user started typing; `seed` is the character that triggered it. */
42
+ | {
43
+ kind: 'type';
44
+ seed: string;
45
+ } | {
46
+ kind: 'quit';
47
+ };
48
+ export interface MenuDeps {
49
+ /**
50
+ * Splash art, rendered ONCE by the caller and reused for every frame.
51
+ * Detecting terminal capabilities means writing to stdin and waiting for a
52
+ * reply, which is impossible while the menu owns raw mode.
53
+ */
54
+ art: string;
55
+ /**
56
+ * A line that must not be dropped by the layout ladder — currently the
57
+ * "your session is running stale code" warning, which is worthless if it is
58
+ * the first thing sacrificed on a short terminal.
59
+ *
60
+ * A FUNCTION, not a string: the menu can sit open for a long time, and the
61
+ * condition it reports (an upgrade landing on disk) happens while it sits
62
+ * there. Passing a string would freeze the answer at the moment the menu was
63
+ * entered, so the warning would only appear after running an unrelated
64
+ * command — by which point the user has already hit the stale behaviour.
65
+ */
66
+ notice?: () => string | undefined;
67
+ }
68
+ /**
69
+ * Split one stdin chunk into individual keypresses.
70
+ *
71
+ * stdin delivers BYTES, not keys. Press two arrows faster than the event loop
72
+ * drains stdin — which is just "press them quickly" — and both arrive in a
73
+ * single chunk as `\x1b[B\x1b[B`. Comparing the whole chunk against a table of
74
+ * key sequences matches nothing, so the keys are silently dropped and the menu
75
+ * looks frozen. The same happens to a held-down arrow and to any paste.
76
+ *
77
+ * Escape sequences are ESC, an introducer (`[` for CSI, `O` for SS3), then
78
+ * parameter bytes up to a final byte in the 0x40-0x7E range. A lone ESC with
79
+ * nothing after it is the Escape key.
80
+ */
81
+ export declare function splitKeys(chunk: string): string[];
82
+ export interface FrameInput {
83
+ /** Terminal height. The frame is built to fit in `rows - 1`. */
84
+ rows: number;
85
+ art: string[];
86
+ status: string[];
87
+ /** Project line, stage hint — kept when they fit, dropped before the logo. */
88
+ extras: string[];
89
+ title: string[];
90
+ items: string[];
91
+ /** Index into `items` that must stay visible. */
92
+ active: number;
93
+ footer: string;
94
+ /** Always rendered, never traded away for space. */
95
+ notice?: string;
96
+ }
97
+ /**
98
+ * Compose one frame that fits.
99
+ *
100
+ * Pure, and exported, because the fit is the invariant that matters and it is
101
+ * invisible until it breaks: an overflowing frame scrolls the terminal, so the
102
+ * next redraw's cursor-home lands somewhere other than the top of the frame and
103
+ * the screen degrades into a collage of half-frames. That reads as a hung
104
+ * session, not as a layout bug, which is what makes it worth a test rather than
105
+ * an eyeball.
106
+ */
107
+ export declare function composeFrame(input: FrameInput): string[];
108
+ export declare function menu(deps: MenuDeps): Promise<MenuChoice>;
109
+ //# sourceMappingURL=menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../src/ui/menu.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;AACjC,0EAA0E;GACxE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,MAAM,WAAW,QAAQ;IACvB;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;CACnC;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBjD;AAyCD,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CA0DxD;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CA8JxD"}