framer-export 5.0.0-beta.2 → 5.0.0-beta.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/index.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "framer-export",
18
- version: "5.0.0-beta.2",
18
+ version: "5.0.0-beta.3",
19
19
  description: "Export 25+ website platforms (Framer, Webflow, Wix, Shopify, Notion, WordPress, Squarespace, Ghost, and more) into a fully working local mirror. Downloads all assets, strips badges, rewrites URLs, and pretty-prints JS.",
20
20
  type: "module",
21
21
  main: "dist/cli/index.js",
@@ -1881,6 +1881,171 @@ var init_cooking = __esm({
1881
1881
  }
1882
1882
  });
1883
1883
 
1884
+ // src/cli/input.ts
1885
+ import { stdin } from "process";
1886
+ function parseInput(buffer) {
1887
+ const events = [];
1888
+ let i = 0;
1889
+ while (i < buffer.length) {
1890
+ const ch = buffer[i];
1891
+ if (ch === "") {
1892
+ events.push({ type: "key", name: "ctrl-c" });
1893
+ i++;
1894
+ continue;
1895
+ }
1896
+ if (ch === "\r" || ch === "\n") {
1897
+ events.push({ type: "key", name: "return" });
1898
+ i++;
1899
+ continue;
1900
+ }
1901
+ if (ch === " ") {
1902
+ events.push({ type: "key", name: "tab" });
1903
+ i++;
1904
+ continue;
1905
+ }
1906
+ if (ch === "\x7F" || ch === "\b") {
1907
+ events.push({ type: "key", name: "backspace" });
1908
+ i++;
1909
+ continue;
1910
+ }
1911
+ if (ch === ESC) {
1912
+ const rest = buffer.slice(i);
1913
+ if (rest.length === 1) {
1914
+ return { events, rest };
1915
+ }
1916
+ const next = rest[1];
1917
+ if (next === "[" || next === "O") {
1918
+ const sgr = rest.match(/^\x1B\[<(\d+);(\d+);(\d+)([mM])/);
1919
+ if (sgr) {
1920
+ const code = Number(sgr[1]);
1921
+ const x = Number(sgr[2]);
1922
+ const y = Number(sgr[3]);
1923
+ const release = sgr[4] === "m";
1924
+ if (code === 64) events.push({ type: "mouse", kind: "wheel-up", x, y });
1925
+ else if (code === 65) events.push({ type: "mouse", kind: "wheel-down", x, y });
1926
+ else if ((code & 32) === 32) events.push({ type: "mouse", kind: "move", x, y });
1927
+ else if (release) events.push({ type: "mouse", kind: "click", x, y });
1928
+ else events.push({ type: "mouse", kind: "press", x, y });
1929
+ i += sgr[0].length;
1930
+ continue;
1931
+ }
1932
+ if (/^\x1B\[<[\d;]*$/.test(rest)) {
1933
+ return { events, rest };
1934
+ }
1935
+ const legacy = rest.match(/^\x1B\[M([\s\S])([\s\S])([\s\S])/);
1936
+ if (legacy) {
1937
+ const code = legacy[1].charCodeAt(0) - 32;
1938
+ const x = legacy[2].charCodeAt(0) - 32;
1939
+ const y = legacy[3].charCodeAt(0) - 32;
1940
+ if (code === 64) events.push({ type: "mouse", kind: "wheel-up", x, y });
1941
+ else if (code === 65) events.push({ type: "mouse", kind: "wheel-down", x, y });
1942
+ else if ((code & 32) === 32) events.push({ type: "mouse", kind: "move", x, y });
1943
+ else if ((code & 3) === 3) events.push({ type: "mouse", kind: "click", x, y });
1944
+ else events.push({ type: "mouse", kind: "press", x, y });
1945
+ i += legacy[0].length;
1946
+ continue;
1947
+ }
1948
+ if (/^\x1B\[M[\s\S]{0,2}$/.test(rest)) {
1949
+ return { events, rest };
1950
+ }
1951
+ const arrow = rest.match(/^\x1B[[O]([ABCD])/);
1952
+ if (arrow) {
1953
+ const names = { A: "up", B: "down", C: "right", D: "left" };
1954
+ events.push({ type: "key", name: names[arrow[1]] });
1955
+ i += arrow[0].length;
1956
+ continue;
1957
+ }
1958
+ if (rest.startsWith("\x1B[3~")) {
1959
+ events.push({ type: "key", name: "delete" });
1960
+ i += 4;
1961
+ continue;
1962
+ }
1963
+ const csi = rest.match(/^\x1B\[[0-?]*[ -/]*[@-~]/);
1964
+ if (csi) {
1965
+ i += csi[0].length;
1966
+ continue;
1967
+ }
1968
+ if (/^\x1B\[[0-?]*[ -/]*$/.test(rest)) {
1969
+ return { events, rest };
1970
+ }
1971
+ if (rest.length === 2) {
1972
+ return { events, rest };
1973
+ }
1974
+ i += 2;
1975
+ continue;
1976
+ }
1977
+ i += 2;
1978
+ continue;
1979
+ }
1980
+ if (ch >= " ") {
1981
+ const code = buffer.codePointAt(i);
1982
+ const char = String.fromCodePoint(code);
1983
+ events.push({ type: "char", char });
1984
+ i += char.length;
1985
+ continue;
1986
+ }
1987
+ i++;
1988
+ }
1989
+ return { events, rest: "" };
1990
+ }
1991
+ var ESC, ESC_TIMEOUT_MS, RawInput;
1992
+ var init_input = __esm({
1993
+ "src/cli/input.ts"() {
1994
+ "use strict";
1995
+ ESC = "\x1B";
1996
+ ESC_TIMEOUT_MS = 40;
1997
+ RawInput = class {
1998
+ constructor(handler) {
1999
+ this.handler = handler;
2000
+ }
2001
+ handler;
2002
+ buffer = "";
2003
+ escTimer = null;
2004
+ active = false;
2005
+ onData = (chunk) => {
2006
+ this.buffer += chunk.toString("utf-8");
2007
+ this.drain();
2008
+ };
2009
+ start() {
2010
+ if (this.active) return;
2011
+ this.active = true;
2012
+ stdin.setRawMode(true);
2013
+ stdin.resume();
2014
+ stdin.on("data", this.onData);
2015
+ }
2016
+ stop() {
2017
+ if (!this.active) return;
2018
+ this.active = false;
2019
+ if (this.escTimer) clearTimeout(this.escTimer);
2020
+ this.escTimer = null;
2021
+ stdin.removeListener("data", this.onData);
2022
+ stdin.setRawMode(false);
2023
+ stdin.pause();
2024
+ }
2025
+ drain() {
2026
+ if (this.escTimer) {
2027
+ clearTimeout(this.escTimer);
2028
+ this.escTimer = null;
2029
+ }
2030
+ const { events, rest } = parseInput(this.buffer);
2031
+ this.buffer = rest;
2032
+ for (const event of events) {
2033
+ if (!this.active) return;
2034
+ this.handler(event);
2035
+ }
2036
+ if (rest === ESC) {
2037
+ this.escTimer = setTimeout(() => {
2038
+ if (this.buffer === ESC) {
2039
+ this.buffer = "";
2040
+ if (this.active) this.handler({ type: "key", name: "escape" });
2041
+ }
2042
+ }, ESC_TIMEOUT_MS);
2043
+ }
2044
+ }
2045
+ };
2046
+ }
2047
+ });
2048
+
1884
2049
  // src/cli/box.ts
1885
2050
  import chalk3 from "chalk";
1886
2051
  function maxWidth() {
@@ -1983,77 +2148,203 @@ var init_box = __esm({
1983
2148
  // src/cli/backdrop.ts
1984
2149
  import chalk4 from "chalk";
1985
2150
  import { stdout } from "process";
1986
- function hash(x, y, frame) {
1987
- let h = x * 374761393 + y * 668265263 + frame * 2246822519;
1988
- h = (h ^ h >> 13) * 1274126177;
1989
- h = h ^ h >> 16;
1990
- return Math.abs(h) % 1e3;
1991
- }
1992
- var GLYPHS, COLORS, FRAME_MS, DENSITY, Backdrop;
2151
+ function fract(v) {
2152
+ return v - Math.floor(v);
2153
+ }
2154
+ function hash11(n) {
2155
+ return fract(Math.sin(n) * 43758.5453);
2156
+ }
2157
+ function mix(a, b, t) {
2158
+ return a + (b - a) * t;
2159
+ }
2160
+ function vnoise(px, py, pz) {
2161
+ const ix = Math.floor(px);
2162
+ const iy = Math.floor(py);
2163
+ const iz = Math.floor(pz);
2164
+ const fx = px - ix;
2165
+ const fy = py - iy;
2166
+ const fz = pz - iz;
2167
+ const dot = (ox, oy, oz) => (ix + ox) * 1 + (iy + oy) * 57 + (iz + oz) * 113;
2168
+ const n000 = hash11(dot(0, 0, 0));
2169
+ const n100 = hash11(dot(1, 0, 0));
2170
+ const n010 = hash11(dot(0, 1, 0));
2171
+ const n110 = hash11(dot(1, 1, 0));
2172
+ const n001 = hash11(dot(0, 0, 1));
2173
+ const n101 = hash11(dot(1, 0, 1));
2174
+ const n011 = hash11(dot(0, 1, 1));
2175
+ const n111 = hash11(dot(1, 1, 1));
2176
+ const wx = fx * fx * fx * (fx * (fx * 6 - 15) + 10);
2177
+ const wy = fy * fy * fy * (fy * (fy * 6 - 15) + 10);
2178
+ const wz = fz * fz * fz * (fz * (fz * 6 - 15) + 10);
2179
+ const x00 = mix(n000, n100, wx);
2180
+ const x10 = mix(n010, n110, wx);
2181
+ const x01 = mix(n001, n101, wx);
2182
+ const x11 = mix(n011, n111, wx);
2183
+ const y0 = mix(x00, x10, wy);
2184
+ const y1 = mix(x01, x11, wy);
2185
+ return mix(y0, y1, wz) * 2 - 1;
2186
+ }
2187
+ function fbm2(ux, uy, t) {
2188
+ const px = ux * PATTERN_SCALE;
2189
+ const py = uy * PATTERN_SCALE;
2190
+ let amp = 1;
2191
+ let freq = 1;
2192
+ let sum = 1;
2193
+ for (let i = 0; i < FBM_OCTAVES; i++) {
2194
+ sum += amp * vnoise(px * freq, py * freq, t * freq);
2195
+ freq *= FBM_LACUNARITY;
2196
+ amp *= FBM_GAIN;
2197
+ }
2198
+ return sum * 0.5 + 0.5;
2199
+ }
2200
+ function bayer2exact(x, y) {
2201
+ const ax = Math.floor(x);
2202
+ const ay = Math.floor(y);
2203
+ return fract(ax / 2 + ay * ay * 0.75);
2204
+ }
2205
+ function bayer4(x, y) {
2206
+ return bayer2exact(0.5 * x, 0.5 * y) * 0.25 + bayer2exact(x, y);
2207
+ }
2208
+ function bayer8(x, y) {
2209
+ return bayer4(0.5 * x, 0.5 * y) * 0.25 + bayer2exact(x, y);
2210
+ }
2211
+ var FRAME_MS, FBM_OCTAVES, FBM_LACUNARITY, FBM_GAIN, PATTERN_SCALE, PATTERN_DENSITY, PIXEL_JITTER, SPEED, EDGE_FADE, RIPPLE_SPEED, RIPPLE_THICKNESS, RIPPLE_INTENSITY, MAX_CLICKS, DAMP_T, DAMP_R, CELL_PX, GLYPHS, COLORS, Backdrop;
1993
2212
  var init_backdrop = __esm({
1994
2213
  "src/cli/backdrop.ts"() {
1995
2214
  "use strict";
1996
- GLYPHS = ["\xB7", "\xB7", "\u2022", "\u25AA"];
1997
- COLORS = ["#3d332a", "#4a3b2d", "#584535", "#33302c"];
1998
- FRAME_MS = 160;
1999
- DENSITY = 28;
2215
+ FRAME_MS = 100;
2216
+ FBM_OCTAVES = 5;
2217
+ FBM_LACUNARITY = 1.25;
2218
+ FBM_GAIN = 1;
2219
+ PATTERN_SCALE = 3;
2220
+ PATTERN_DENSITY = 1.1;
2221
+ PIXEL_JITTER = 0.4;
2222
+ SPEED = 0.5;
2223
+ EDGE_FADE = 0.18;
2224
+ RIPPLE_SPEED = 0.4;
2225
+ RIPPLE_THICKNESS = 0.12;
2226
+ RIPPLE_INTENSITY = 1.4;
2227
+ MAX_CLICKS = 10;
2228
+ DAMP_T = 1;
2229
+ DAMP_R = 10;
2230
+ CELL_PX = 8;
2231
+ GLYPHS = ["\xB7", "\u2022", "\u25AA", "\u25CF"];
2232
+ COLORS = ["#54402f", "#6b4c37", "#82593d", "#8f6244"];
2000
2233
  Backdrop = class {
2001
2234
  timer = null;
2002
- frame = 0;
2003
- prev = [];
2235
+ disabled = false;
2004
2236
  exclude = null;
2237
+ prev = /* @__PURE__ */ new Map();
2238
+ clicks = [];
2239
+ clickIx = 0;
2240
+ timeOffset = Math.random() * 1e3;
2241
+ startedAt = Date.now();
2005
2242
  constructor() {
2006
- if (process.env.FRAMER_EXPORT_NO_BG) this.frame = -1;
2243
+ if (process.env.FRAMER_EXPORT_NO_BG) this.disabled = true;
2007
2244
  }
2008
2245
  setExclude(rect) {
2009
2246
  this.exclude = rect;
2010
2247
  }
2248
+ addClick(col, row2) {
2249
+ if (this.clicks.length < MAX_CLICKS) {
2250
+ this.clicks.push({ x: col, y: row2 * 2, time: this.now() });
2251
+ } else {
2252
+ this.clicks[this.clickIx] = { x: col, y: row2 * 2, time: this.now() };
2253
+ }
2254
+ this.clickIx = (this.clickIx + 1) % MAX_CLICKS;
2255
+ }
2011
2256
  start() {
2012
- if (this.frame === -1 || !stdout.isTTY || this.timer) return;
2257
+ if (this.disabled || !stdout.isTTY || this.timer) return;
2258
+ this.startedAt = Date.now();
2013
2259
  this.paint();
2014
2260
  this.timer = setInterval(() => this.paint(), FRAME_MS);
2015
2261
  }
2016
2262
  stop() {
2017
2263
  if (this.timer) clearInterval(this.timer);
2018
2264
  this.timer = null;
2019
- this.erasePrev();
2020
- this.prev = [];
2265
+ this.erase();
2266
+ }
2267
+ now() {
2268
+ return this.timeOffset + (Date.now() - this.startedAt) / 1e3 * SPEED;
2021
2269
  }
2022
2270
  inExclude(x, y) {
2023
2271
  const r = this.exclude;
2024
2272
  if (!r) return false;
2025
2273
  return y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width;
2026
2274
  }
2027
- erasePrev() {
2028
- if (this.prev.length === 0) return;
2275
+ erase() {
2276
+ if (this.prev.size === 0) return;
2277
+ const columns = stdout.columns || 80;
2029
2278
  let out = "";
2030
- for (const [x, y] of this.prev) {
2279
+ for (const key of this.prev.keys()) {
2280
+ const x = key % columns + 1;
2281
+ const y = Math.floor(key / columns) + 1;
2031
2282
  out += `\x1B[${y};${x}H `;
2032
2283
  }
2033
2284
  stdout.write(out);
2285
+ this.prev.clear();
2034
2286
  }
2035
2287
  paint() {
2036
2288
  const rows = stdout.rows || 24;
2037
2289
  const columns = stdout.columns || 80;
2038
- this.frame++;
2290
+ const resX = columns;
2291
+ const resY = rows * 2;
2292
+ const aspect = resX / resY;
2293
+ const t = this.now();
2294
+ const next = /* @__PURE__ */ new Map();
2039
2295
  let out = "";
2040
- for (const [x, y] of this.prev) {
2041
- if (!this.inExclude(x, y)) out += `\x1B[${y};${x}H `;
2042
- }
2043
- const next = [];
2044
- for (let y = 1; y <= rows; y += 2) {
2045
- for (let x = 1; x <= columns; x += 2) {
2046
- const h = hash(x, y, Math.floor(this.frame / 3) + Math.floor(x / 24) + Math.floor(y / 12));
2047
- if (h >= DENSITY) continue;
2048
- if (this.inExclude(x, y)) continue;
2049
- const glyph = GLYPHS[h % GLYPHS.length];
2050
- const color = COLORS[(h >> 2) % COLORS.length];
2051
- out += `\x1B[${y};${x}H${chalk4.hex(color)(glyph)}`;
2052
- next.push([x, y]);
2296
+ for (let row2 = 1; row2 <= rows; row2++) {
2297
+ const fy = row2 * 2 - resY * 0.5;
2298
+ for (let col = 1; col <= columns; col++) {
2299
+ if (this.inExclude(col, row2)) continue;
2300
+ const fx = col - resX * 0.5;
2301
+ const cellX = Math.floor(fx / CELL_PX) * CELL_PX;
2302
+ const cellY = Math.floor(fy / CELL_PX) * CELL_PX;
2303
+ const ux = cellX / resX * aspect;
2304
+ const uy = cellY / resY;
2305
+ let base = fbm2(ux, uy, t * 0.05);
2306
+ base = base * 0.5 - 0.65;
2307
+ let feed = base + (PATTERN_DENSITY - 0.5) * 0.3;
2308
+ for (const click of this.clicks) {
2309
+ const cux = (click.x - resX * 0.5 - CELL_PX * 0.5) / resX * aspect;
2310
+ const cuy = (click.y - resY * 0.5 - CELL_PX * 0.5) / resY;
2311
+ const dt = Math.max(t - click.time, 0);
2312
+ const r = Math.hypot(ux - cux, uy - cuy);
2313
+ const waveR = RIPPLE_SPEED * dt;
2314
+ const ring = Math.exp(-(((r - waveR) / RIPPLE_THICKNESS) ** 2));
2315
+ const atten = Math.exp(-DAMP_T * dt) * Math.exp(-DAMP_R * r);
2316
+ feed = Math.max(feed, ring * atten * RIPPLE_INTENSITY);
2317
+ }
2318
+ const bayer = bayer8(fx, fy) - 0.5;
2319
+ const bw = feed + bayer > 0.5 ? 1 : 0;
2320
+ if (!bw) continue;
2321
+ const h = fract(Math.sin(Math.floor(fx) * 127.1 + Math.floor(fy) * 311.7) * 43758.5453);
2322
+ const jitterScale = 1 + (h - 0.5) * PIXEL_JITTER;
2323
+ let coverage = bw * jitterScale;
2324
+ if (EDGE_FADE > 0) {
2325
+ const nx = col / columns;
2326
+ const ny = row2 / rows;
2327
+ const edge = Math.min(nx, ny, 1 - nx, 1 - ny);
2328
+ const fade = Math.min(1, Math.max(0, edge / EDGE_FADE));
2329
+ coverage *= fade * fade * (3 - 2 * fade);
2330
+ }
2331
+ if (coverage < 0.35) continue;
2332
+ const level = Math.min(3, Math.floor(h * 4));
2333
+ const key = (row2 - 1) * columns + (col - 1);
2334
+ next.set(key, level);
2335
+ if (this.prev.get(key) !== level) {
2336
+ out += `\x1B[${row2};${col}H${chalk4.hex(COLORS[level])(GLYPHS[level])}`;
2337
+ }
2338
+ this.prev.delete(key);
2053
2339
  }
2054
2340
  }
2341
+ for (const key of this.prev.keys()) {
2342
+ const x = key % columns + 1;
2343
+ const y = Math.floor(key / columns) + 1;
2344
+ if (!this.inExclude(x, y)) out += `\x1B[${y};${x}H `;
2345
+ }
2055
2346
  this.prev = next;
2056
- stdout.write(out);
2347
+ if (out) stdout.write(out);
2057
2348
  }
2058
2349
  };
2059
2350
  }
@@ -2062,7 +2353,7 @@ var init_backdrop = __esm({
2062
2353
  // src/cli/select.ts
2063
2354
  import readline from "readline";
2064
2355
  import chalk5 from "chalk";
2065
- import { stdin, stdout as stdout2 } from "process";
2356
+ import { stdin as stdin2, stdout as stdout2 } from "process";
2066
2357
  function panelRow(width, content = "") {
2067
2358
  const visible = stripAnsi(content).length;
2068
2359
  const pad = Math.max(0, width - visible);
@@ -2081,7 +2372,7 @@ function titleRow(width, title) {
2081
2372
  return chalk5.bgHex(THEME.panel)(left + " ".repeat(gap) + right);
2082
2373
  }
2083
2374
  async function select(question, options, defaultIndex = 0, config = {}) {
2084
- const isTTY = stdin.isTTY && stdout2.isTTY;
2375
+ const isTTY = stdin2.isTTY && stdout2.isTTY;
2085
2376
  if (!isTTY) {
2086
2377
  const flat = options.map((o) => o.heading ? { ...o, disabled: true } : o);
2087
2378
  return fallbackPrompt(question, flat, defaultIndex, config);
@@ -2089,7 +2380,7 @@ async function select(question, options, defaultIndex = 0, config = {}) {
2089
2380
  return arrowSelect(question, options, defaultIndex, config);
2090
2381
  }
2091
2382
  async function promptInput(question, defaultValue = "", config = {}) {
2092
- if (!stdin.isTTY || !stdout2.isTTY) {
2383
+ if (!stdin2.isTTY || !stdout2.isTTY) {
2093
2384
  return fallbackInput(question, defaultValue);
2094
2385
  }
2095
2386
  return fullscreenInput(question, defaultValue, config);
@@ -2098,22 +2389,33 @@ async function arrowSelect(question, options, defaultIndex, config) {
2098
2389
  const actions = config.actions ?? [];
2099
2390
  const headerLines = config.headerLines ?? [];
2100
2391
  const searchable = config.searchable === true;
2101
- const width = Math.max(50, Math.min(maxWidth(), 64));
2102
- const inner = width - 4;
2103
2392
  const hasActions = actions.length > 0;
2104
2393
  const headerCount = headerLines.length;
2105
- const rows = process.stdout.rows || 24;
2106
- const columns = process.stdout.columns || 80;
2107
2394
  const searchRows = searchable ? 1 : 0;
2108
2395
  const optionStartOffset = 3 + searchRows + headerCount + (headerCount > 0 ? 1 : 0);
2109
- const chromeLines = optionStartOffset + (hasActions ? 3 : 1) + 2;
2110
- const maxVisible = Math.max(4, rows - chromeLines);
2111
- const visibleCount = Math.min(options.length, maxVisible);
2112
- const actionLineOffset = optionStartOffset + visibleCount + 1;
2113
- const lineCount = actionLineOffset + (hasActions ? 2 : 1);
2114
- const panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
2115
- const panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
2116
- const footerRow = Math.min(rows, panelTopRow + lineCount + 1);
2396
+ let width = 0;
2397
+ let inner = 0;
2398
+ let visibleCount = 0;
2399
+ let actionLineOffset = 0;
2400
+ let lineCount = 0;
2401
+ let panelTopRow = 0;
2402
+ let panelLeftCol = 0;
2403
+ let footerRow = 0;
2404
+ const recomputeLayout = () => {
2405
+ width = Math.max(50, Math.min(maxWidth(), 64));
2406
+ inner = width - 4;
2407
+ const rows = process.stdout.rows || 24;
2408
+ const columns = process.stdout.columns || 80;
2409
+ const chromeLines = optionStartOffset + (hasActions ? 3 : 1) + 2;
2410
+ const maxVisible = Math.max(4, rows - chromeLines);
2411
+ visibleCount = Math.min(options.length, maxVisible);
2412
+ actionLineOffset = optionStartOffset + visibleCount + 1;
2413
+ lineCount = actionLineOffset + (hasActions ? 2 : 1);
2414
+ panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
2415
+ panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
2416
+ footerRow = Math.min(rows, panelTopRow + lineCount + 1);
2417
+ };
2418
+ recomputeLayout();
2117
2419
  return new Promise((resolve) => {
2118
2420
  let query = "";
2119
2421
  const buildView = () => {
@@ -2153,6 +2455,8 @@ async function arrowSelect(question, options, defaultIndex, config) {
2153
2455
  }
2154
2456
  let selectedAction = null;
2155
2457
  let scrollOffset = 0;
2458
+ let prevLines = [];
2459
+ let prevFooter = "";
2156
2460
  const move = (direction) => {
2157
2461
  let next = selected + direction;
2158
2462
  while (next >= 0 && next < view.length) {
@@ -2174,14 +2478,18 @@ async function arrowSelect(question, options, defaultIndex, config) {
2174
2478
  scrollOffset = Math.max(0, Math.min(scrollOffset, view.length - visibleCount));
2175
2479
  };
2176
2480
  const backdrop = new Backdrop();
2177
- backdrop.setExclude({
2178
- top: panelTopRow - 1,
2179
- left: panelLeftCol - 2,
2180
- width: width + 4,
2181
- height: lineCount + 3
2182
- });
2481
+ const syncBackdropExclude = () => {
2482
+ backdrop.setExclude({
2483
+ top: panelTopRow - 1,
2484
+ left: panelLeftCol - 2,
2485
+ width: width + 4,
2486
+ height: lineCount + 3
2487
+ });
2488
+ };
2489
+ syncBackdropExclude();
2183
2490
  const searchRow = () => {
2184
- const shown = query ? `${chalk5.hex(THEME.text)(query)}${chalk5.hex(THEME.primary)("\u258C")}` : ui.muted("type to search");
2491
+ const clipped = truncatePlain(query, Math.max(10, inner - 6));
2492
+ const shown = query ? `${chalk5.hex(THEME.text)(clipped)}${chalk5.hex(THEME.primary)("\u258C")}` : ui.muted("type to search");
2185
2493
  const content = ` ${chalk5.hex(THEME.text)("\u258F")} ${shown}`;
2186
2494
  const visible = stripAnsi(content).length;
2187
2495
  return chalk5.bgHex(THEME.element)(content + " ".repeat(Math.max(0, width - visible)));
@@ -2222,17 +2530,23 @@ async function arrowSelect(question, options, defaultIndex, config) {
2222
2530
  lines.push(panelRow(width, renderActions(actions, selectedAction)));
2223
2531
  lines.push(panelRow(width));
2224
2532
  }
2225
- lines.forEach((line, index) => writeAt(panelTopRow + index, panelLeftCol, line));
2226
- writeAt(
2227
- footerRow,
2228
- panelLeftCol,
2229
- centerText(
2230
- ui.muted(
2231
- config.footer || (searchable ? "type to search \u2191\u2193 move enter select esc close" : "\u2191\u2193 move enter select mouse click esc close")
2232
- ),
2233
- width
2234
- )
2533
+ const sameLength = prevLines.length === lines.length;
2534
+ lines.forEach((line, index) => {
2535
+ if (!sameLength || prevLines[index] !== line) {
2536
+ writeAt(panelTopRow + index, panelLeftCol, line);
2537
+ }
2538
+ });
2539
+ prevLines = lines;
2540
+ const footer = centerText(
2541
+ ui.muted(
2542
+ config.footer || (searchable ? "type to search \u2191\u2193 move enter select esc close" : "\u2191\u2193 move enter select mouse click esc close")
2543
+ ),
2544
+ width
2235
2545
  );
2546
+ if (footer !== prevFooter) {
2547
+ writeAt(footerRow, panelLeftCol, footer);
2548
+ prevFooter = footer;
2549
+ }
2236
2550
  };
2237
2551
  const refilter = () => {
2238
2552
  view = buildView();
@@ -2252,97 +2566,128 @@ async function arrowSelect(question, options, defaultIndex, config) {
2252
2566
  );
2253
2567
  resolve(value);
2254
2568
  };
2255
- const onMouseData = (chunk) => {
2256
- const mouse = parseMouseEvent(chunk);
2257
- if (!mouse) return;
2258
- if (mouse.kind === "wheel-up") {
2259
- move(-1);
2260
- render();
2261
- return;
2262
- }
2263
- if (mouse.kind === "wheel-down") {
2264
- move(1);
2265
- render();
2266
- return;
2267
- }
2268
- if (hasActions && mouse.y === panelTopRow + actionLineOffset) {
2269
- const actionIdx = actionIndexAtX(actions, mouse.x, panelLeftCol, inner);
2569
+ const hitOption = (x, y) => {
2570
+ const relative = y - panelTopRow - optionStartOffset;
2571
+ if (relative < 0 || relative >= visibleCount) return null;
2572
+ if (x < panelLeftCol || x >= panelLeftCol + width) return null;
2573
+ const pos = scrollOffset + relative;
2574
+ if (pos >= view.length || !selectableAt(pos)) return null;
2575
+ return pos;
2576
+ };
2577
+ const onMouse = (kind, x, y) => {
2578
+ if (kind === "click") backdrop.addClick(x, y);
2579
+ if (hasActions && y === panelTopRow + actionLineOffset) {
2580
+ const actionIdx = actionIndexAtX(actions, x, panelLeftCol, inner);
2270
2581
  if (actionIdx === null || actions[actionIdx].disabled) return;
2271
2582
  if (selectedAction !== actionIdx) {
2272
2583
  selectedAction = actionIdx;
2273
2584
  render();
2274
2585
  }
2275
- if (mouse.kind === "click") choose(actions[actionIdx].value);
2586
+ if (kind === "click") choose(actions[actionIdx].value);
2276
2587
  return;
2277
2588
  }
2278
- const relative = mouse.y - panelTopRow - optionStartOffset;
2279
- if (relative < 0 || relative >= visibleCount) return;
2280
- const pos = scrollOffset + relative;
2281
- if (pos >= view.length || !selectableAt(pos)) return;
2282
- if (selected !== pos) {
2589
+ const pos = hitOption(x, y);
2590
+ if (pos === null) {
2591
+ if (kind === "move" && selectedAction !== null) {
2592
+ selectedAction = null;
2593
+ render();
2594
+ }
2595
+ return;
2596
+ }
2597
+ if (selected !== pos || selectedAction !== null) {
2283
2598
  selected = pos;
2284
2599
  selectedAction = null;
2285
2600
  render();
2286
2601
  }
2287
- if (mouse.kind === "click") {
2288
- choose();
2602
+ if (kind === "click") choose();
2603
+ };
2604
+ const onEvent = (event) => {
2605
+ if (event.type === "mouse") {
2606
+ if (event.kind === "wheel-up") {
2607
+ move(-1);
2608
+ render();
2609
+ } else if (event.kind === "wheel-down") {
2610
+ move(1);
2611
+ render();
2612
+ } else {
2613
+ onMouse(event.kind, event.x, event.y);
2614
+ }
2615
+ return;
2616
+ }
2617
+ if (event.type === "key") {
2618
+ switch (event.name) {
2619
+ case "up":
2620
+ move(-1);
2621
+ selectedAction = null;
2622
+ render();
2623
+ return;
2624
+ case "down":
2625
+ move(1);
2626
+ selectedAction = null;
2627
+ render();
2628
+ return;
2629
+ case "tab":
2630
+ if (hasActions) {
2631
+ selectedAction = selectedAction === null ? 0 : null;
2632
+ render();
2633
+ }
2634
+ return;
2635
+ case "return":
2636
+ if (selectedAction !== null) choose(actions[selectedAction].value);
2637
+ else choose();
2638
+ return;
2639
+ case "ctrl-c":
2640
+ cleanup();
2641
+ process.exit(0);
2642
+ return;
2643
+ case "escape":
2644
+ if (searchable && query) {
2645
+ query = "";
2646
+ refilter();
2647
+ return;
2648
+ }
2649
+ cleanup();
2650
+ process.exit(0);
2651
+ return;
2652
+ case "backspace":
2653
+ if (searchable) {
2654
+ query = query.slice(0, -1);
2655
+ refilter();
2656
+ }
2657
+ return;
2658
+ default:
2659
+ return;
2660
+ }
2661
+ }
2662
+ if (event.type === "char" && searchable && query.length < 40) {
2663
+ query += cleanInputValue(event.char);
2664
+ refilter();
2289
2665
  }
2290
2666
  };
2667
+ const input = new RawInput(onEvent);
2668
+ const onResize = () => {
2669
+ recomputeLayout();
2670
+ syncBackdropExclude();
2671
+ prevLines = [];
2672
+ prevFooter = "";
2673
+ stdout2.write("\x1B[2J");
2674
+ render();
2675
+ };
2291
2676
  const cleanup = () => {
2292
2677
  backdrop.stop();
2678
+ stdout2.removeListener("resize", onResize);
2679
+ input.stop();
2293
2680
  leaveInteractiveScreen();
2294
- stdin.setRawMode(false);
2295
- stdin.removeListener("keypress", onKeypress);
2296
- stdin.removeListener("data", onMouseData);
2297
- stdin.pause();
2298
2681
  };
2299
- readline.emitKeypressEvents(stdin);
2300
- stdin.setRawMode(true);
2301
2682
  enterInteractiveScreen(true);
2302
2683
  render();
2303
2684
  backdrop.start();
2304
- const onKeypress = (str, key) => {
2305
- if (!key) return;
2306
- if (key.name === "up") {
2307
- move(-1);
2308
- selectedAction = null;
2309
- render();
2310
- } else if (key.name === "down") {
2311
- move(1);
2312
- selectedAction = null;
2313
- render();
2314
- } else if (key.name === "tab" && hasActions) {
2315
- selectedAction = selectedAction === null ? 0 : null;
2316
- render();
2317
- } else if (key.name === "return") {
2318
- if (selectedAction !== null) choose(actions[selectedAction].value);
2319
- else choose();
2320
- } else if (key.ctrl && key.name === "c") {
2321
- cleanup();
2322
- process.exit(0);
2323
- } else if (key.name === "escape") {
2324
- if (searchable && query) {
2325
- query = "";
2326
- refilter();
2327
- return;
2328
- }
2329
- cleanup();
2330
- process.exit(0);
2331
- } else if (searchable && key.name === "backspace") {
2332
- query = query.slice(0, -1);
2333
- refilter();
2334
- } else if (searchable && str && !key.ctrl && !key.meta && str >= " " && !isTerminalSequence(str, key)) {
2335
- query += cleanInputValue(str.replace(/[\r\n]/g, ""));
2336
- refilter();
2337
- }
2338
- };
2339
- stdin.resume();
2340
- stdin.on("data", onMouseData);
2341
- stdin.on("keypress", onKeypress);
2685
+ stdout2.on("resize", onResize);
2686
+ input.start();
2342
2687
  });
2343
2688
  }
2344
2689
  async function fallbackPrompt(question, options, defaultIndex, config) {
2345
- if (!stdin.isTTY) {
2690
+ if (!stdin2.isTTY) {
2346
2691
  const firstEnabled = options.findIndex((option) => !option.disabled);
2347
2692
  const enabledDefault = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
2348
2693
  const def = String(enabledDefault + 1);
@@ -2371,7 +2716,7 @@ async function fallbackPrompt(question, options, defaultIndex, config) {
2371
2716
  }
2372
2717
  }
2373
2718
  return new Promise((resolve) => {
2374
- const rl = readline.createInterface({ input: stdin, output: stdout2 });
2719
+ const rl = readline.createInterface({ input: stdin2, output: stdout2 });
2375
2720
  const firstEnabled = options.findIndex((option) => !option.disabled);
2376
2721
  const enabledDefault = options[defaultIndex]?.disabled ? firstEnabled : defaultIndex;
2377
2722
  printFallbackOptions(question, options, enabledDefault, config);
@@ -2421,24 +2766,37 @@ async function fallbackPrompt(question, options, defaultIndex, config) {
2421
2766
  }
2422
2767
  function fullscreenInput(question, defaultValue, config) {
2423
2768
  const headerLines = config.headerLines ?? [];
2424
- const width = Math.max(50, Math.min(maxWidth(), 64));
2425
- const inner = width - 4;
2426
2769
  const headerCount = headerLines.length;
2427
2770
  const lineCount = 3 + headerCount + (headerCount > 0 ? 1 : 0) + 2;
2428
- const rows = process.stdout.rows || 24;
2429
- const columns = process.stdout.columns || 80;
2430
- const panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
2431
- const panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
2432
- const footerRow = Math.min(rows, panelTopRow + lineCount + 1);
2771
+ let width = 0;
2772
+ let inner = 0;
2773
+ let panelTopRow = 0;
2774
+ let panelLeftCol = 0;
2775
+ let footerRow = 0;
2776
+ const recomputeLayout = () => {
2777
+ width = Math.max(50, Math.min(maxWidth(), 64));
2778
+ inner = width - 4;
2779
+ const rows = process.stdout.rows || 24;
2780
+ const columns = process.stdout.columns || 80;
2781
+ panelTopRow = Math.max(2, Math.floor((rows - lineCount) / 2) + 1);
2782
+ panelLeftCol = Math.max(1, Math.floor((columns - width) / 2) + 1);
2783
+ footerRow = Math.min(rows, panelTopRow + lineCount + 1);
2784
+ };
2785
+ recomputeLayout();
2433
2786
  return new Promise((resolve) => {
2434
2787
  let value = defaultValue;
2788
+ let prevLines = [];
2789
+ let prevFooter = "";
2435
2790
  const backdrop = new Backdrop();
2436
- backdrop.setExclude({
2437
- top: panelTopRow - 1,
2438
- left: panelLeftCol - 2,
2439
- width: width + 4,
2440
- height: lineCount + 3
2441
- });
2791
+ const syncBackdropExclude = () => {
2792
+ backdrop.setExclude({
2793
+ top: panelTopRow - 1,
2794
+ left: panelLeftCol - 2,
2795
+ width: width + 4,
2796
+ height: lineCount + 3
2797
+ });
2798
+ };
2799
+ syncBackdropExclude();
2442
2800
  const render = () => {
2443
2801
  const shown = value || "";
2444
2802
  const clipped = truncatePlain(shown, Math.max(12, inner - 6));
@@ -2457,67 +2815,86 @@ function fullscreenInput(question, defaultValue, config) {
2457
2815
  if (headerCount > 0) lines.push(panelRow(width));
2458
2816
  lines.push(inputRow);
2459
2817
  lines.push(panelRow(width));
2460
- lines.forEach((line, index) => writeAt(panelTopRow + index, panelLeftCol, line));
2461
- writeAt(
2462
- footerRow,
2463
- panelLeftCol,
2464
- centerText(ui.muted(config.footer || "type value enter confirm esc close"), width)
2818
+ const sameLength = prevLines.length === lines.length;
2819
+ lines.forEach((line, index) => {
2820
+ if (!sameLength || prevLines[index] !== line) {
2821
+ writeAt(panelTopRow + index, panelLeftCol, line);
2822
+ }
2823
+ });
2824
+ prevLines = lines;
2825
+ const footer = centerText(
2826
+ ui.muted(config.footer || "type value enter confirm esc close"),
2827
+ width
2465
2828
  );
2829
+ if (footer !== prevFooter) {
2830
+ writeAt(footerRow, panelLeftCol, footer);
2831
+ prevFooter = footer;
2832
+ }
2833
+ };
2834
+ const onResize = () => {
2835
+ recomputeLayout();
2836
+ syncBackdropExclude();
2837
+ prevLines = [];
2838
+ prevFooter = "";
2839
+ stdout2.write("\x1B[2J");
2840
+ render();
2466
2841
  };
2467
2842
  const cleanup = () => {
2468
2843
  backdrop.stop();
2844
+ stdout2.removeListener("resize", onResize);
2845
+ input.stop();
2469
2846
  leaveInteractiveScreen();
2470
- stdin.setRawMode(false);
2471
- stdin.removeListener("keypress", onKeypress);
2472
- stdin.pause();
2473
2847
  };
2474
2848
  const submit = () => {
2475
2849
  const output2 = cleanInputValue(value.trim() || defaultValue);
2476
2850
  cleanup();
2477
2851
  resolve(output2);
2478
2852
  };
2479
- const onKeypress = (str, key) => {
2480
- if (key.ctrl && key.name === "c" || key.name === "escape") {
2481
- cleanup();
2482
- process.exit(0);
2483
- }
2484
- if (key.name === "return") {
2485
- submit();
2486
- return;
2487
- }
2488
- if (key.name === "backspace") {
2489
- value = value.slice(0, -1);
2490
- render();
2491
- return;
2492
- }
2493
- if (key.name === "delete") {
2494
- value = "";
2495
- render();
2496
- return;
2853
+ const onEvent = (event) => {
2854
+ if (event.type === "key") {
2855
+ switch (event.name) {
2856
+ case "ctrl-c":
2857
+ case "escape":
2858
+ cleanup();
2859
+ process.exit(0);
2860
+ return;
2861
+ case "return":
2862
+ submit();
2863
+ return;
2864
+ case "backspace":
2865
+ value = value.slice(0, -1);
2866
+ render();
2867
+ return;
2868
+ case "delete":
2869
+ value = "";
2870
+ render();
2871
+ return;
2872
+ default:
2873
+ return;
2874
+ }
2497
2875
  }
2498
- if (str && !key.ctrl && !key.meta && str >= " " && !isTerminalSequence(str, key)) {
2499
- value += cleanInputValue(str.replace(/[\r\n]/g, ""));
2876
+ if (event.type === "char") {
2877
+ value += cleanInputValue(event.char);
2500
2878
  render();
2501
2879
  }
2502
2880
  };
2503
- readline.emitKeypressEvents(stdin);
2504
- stdin.setRawMode(true);
2881
+ const input = new RawInput(onEvent);
2505
2882
  enterInteractiveScreen(false);
2506
2883
  render();
2507
2884
  backdrop.start();
2508
- stdin.resume();
2509
- stdin.on("keypress", onKeypress);
2885
+ stdout2.on("resize", onResize);
2886
+ input.start();
2510
2887
  });
2511
2888
  }
2512
2889
  async function fallbackInput(question, defaultValue) {
2513
- if (!stdin.isTTY) {
2890
+ if (!stdin2.isTTY) {
2514
2891
  const suffix = defaultValue ? ui.muted(` (${defaultValue})`) : "";
2515
2892
  console.log(` ${ui.primary(">")} ${ui.text.bold(question)}${suffix}: `);
2516
2893
  const answer = await readPipedLine();
2517
2894
  return cleanInputValue(answer.trim() || defaultValue);
2518
2895
  }
2519
2896
  return new Promise((resolve) => {
2520
- const rl = readline.createInterface({ input: stdin, output: stdout2 });
2897
+ const rl = readline.createInterface({ input: stdin2, output: stdout2 });
2521
2898
  const suffix = defaultValue ? ui.muted(` (${defaultValue})`) : "";
2522
2899
  rl.question(` ${ui.primary(">")} ${ui.text.bold(question)}${suffix}: `, (answer) => {
2523
2900
  rl.close();
@@ -2550,14 +2927,14 @@ function readPipedLine() {
2550
2927
  if (!pipedLinesPromise) {
2551
2928
  pipedLinesPromise = new Promise((resolve) => {
2552
2929
  let data = "";
2553
- stdin.setEncoding("utf8");
2554
- stdin.on("data", (chunk) => {
2930
+ stdin2.setEncoding("utf8");
2931
+ stdin2.on("data", (chunk) => {
2555
2932
  data += chunk;
2556
2933
  });
2557
- stdin.on("end", () => {
2934
+ stdin2.on("end", () => {
2558
2935
  resolve(data.split(/\r?\n/));
2559
2936
  });
2560
- stdin.on("error", () => {
2937
+ stdin2.on("error", () => {
2561
2938
  resolve([]);
2562
2939
  });
2563
2940
  });
@@ -2586,21 +2963,32 @@ function labelForValue(value, options, actions) {
2586
2963
  options.find((option) => option.value === value)?.label || actions.find((action) => action.value === value)?.label || value
2587
2964
  );
2588
2965
  }
2966
+ function betaBadge() {
2967
+ return chalk5.bgHex(THEME.warning).hex(THEME.background).bold(" beta ");
2968
+ }
2969
+ function splitBetaLabel(plain) {
2970
+ if (plain.endsWith(BETA_SUFFIX)) {
2971
+ return { base: plain.slice(0, -BETA_SUFFIX.length).trimEnd(), beta: true };
2972
+ }
2973
+ return { base: plain, beta: false };
2974
+ }
2589
2975
  function renderOption(option, isSelected, isDefault, width, inner) {
2590
2976
  const plain = truncatePlain(stripAnsi(option.label), Math.max(10, inner - 2));
2591
2977
  if (option.heading) {
2592
2978
  return panelRow(width, ` ${ui.accent.bold(plain)}`);
2593
2979
  }
2980
+ const { base, beta } = splitBetaLabel(plain);
2594
2981
  if (isSelected && !option.disabled) {
2595
2982
  return selectedRow(width, ` ${isDefault ? "\u25CF" : " "} ${plain}`);
2596
2983
  }
2984
+ const badge = beta ? ` ${betaBadge()}` : "";
2597
2985
  if (option.disabled) {
2598
- return panelRow(width, ` ${ui.muted(plain)}`);
2986
+ return panelRow(width, ` ${ui.muted(base)}${badge}`);
2599
2987
  }
2600
2988
  if (isDefault) {
2601
- return panelRow(width, ` ${ui.primary("\u25CF")} ${ui.primary(plain)}`);
2989
+ return panelRow(width, ` ${ui.primary("\u25CF")} ${ui.primary(base)}${badge}`);
2602
2990
  }
2603
- return panelRow(width, ` ${ui.text(plain)}`);
2991
+ return panelRow(width, ` ${ui.text(base)}${badge}`);
2604
2992
  }
2605
2993
  function enterInteractiveScreen(enableMouse) {
2606
2994
  stdout2.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
@@ -2613,51 +3001,23 @@ function leaveInteractiveScreen() {
2613
3001
  "\x1B[?1003l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?25h\x1B[?1049l"
2614
3002
  );
2615
3003
  }
2616
- function parseMouseEvent(chunk) {
2617
- const text = chunk.toString("utf-8");
2618
- const match = text.match(/\x1B\[<(\d+);(\d+);(\d+)([mM])/);
2619
- if (!match) return parseLegacyMouseEvent(text);
2620
- const code = Number(match[1]);
2621
- const x = Number(match[2]);
2622
- const y = Number(match[3]);
2623
- const state2 = match[4];
2624
- if (code === 64) return { kind: "wheel-up", x, y };
2625
- if (code === 65) return { kind: "wheel-down", x, y };
2626
- if (state2 === "m") return { kind: "click", x, y };
2627
- if ((code & 32) === 32 || code === 35) return { kind: "hover", x, y };
2628
- if ((code & 3) === 0) return { kind: "hover", x, y };
2629
- return null;
2630
- }
2631
- function parseLegacyMouseEvent(text) {
2632
- const match = text.match(/\x1B\[M([\s\S])([\s\S])([\s\S])/);
2633
- if (!match) return null;
2634
- const code = match[1].charCodeAt(0) - 32;
2635
- const x = match[2].charCodeAt(0) - 32;
2636
- const y = match[3].charCodeAt(0) - 32;
2637
- if (code === 64) return { kind: "wheel-up", x, y };
2638
- if (code === 65) return { kind: "wheel-down", x, y };
2639
- if ((code & 3) === 3) return { kind: "click", x, y };
2640
- if ((code & 32) === 32) return { kind: "hover", x, y };
2641
- return { kind: "hover", x, y };
2642
- }
2643
3004
  function writeAt(row2, col, text) {
2644
3005
  stdout2.write(`\x1B[${row2};${col}H${text}`);
2645
3006
  }
2646
- function isTerminalSequence(str, key) {
2647
- return str.includes("\x1B") || !!key.sequence?.includes("\x1B") || /^(?:\d+;){2}\d+[mM]$/.test(str);
2648
- }
2649
3007
  function cleanInputValue(value) {
2650
3008
  return value.replace(/\x1B\[<\d+;\d+;\d+[mM]/g, "").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").replace(/(?:\d+;){2}\d+[mM]/g, "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
2651
3009
  }
2652
- var pipedLinesPromise, pipedLineIndex;
3010
+ var pipedLinesPromise, pipedLineIndex, BETA_SUFFIX;
2653
3011
  var init_select = __esm({
2654
3012
  "src/cli/select.ts"() {
2655
3013
  "use strict";
3014
+ init_input();
2656
3015
  init_box();
2657
3016
  init_backdrop();
2658
3017
  init_theme();
2659
3018
  pipedLinesPromise = null;
2660
3019
  pipedLineIndex = 0;
3020
+ BETA_SUFFIX = "[beta]";
2661
3021
  }
2662
3022
  });
2663
3023
 
@@ -2763,11 +3123,13 @@ var init_page = __esm({
2763
3123
  .badge-beta {
2764
3124
  font-size: 10px;
2765
3125
  font-weight: 700;
2766
- color: var(--warning);
2767
- border: 1px solid var(--warning);
3126
+ color: #131010;
3127
+ background: var(--warning);
2768
3128
  border-radius: 3px;
2769
- padding: 1px 5px;
2770
- letter-spacing: 0.04em;
3129
+ padding: 2px 7px;
3130
+ letter-spacing: 0.05em;
3131
+ text-transform: uppercase;
3132
+ box-shadow: 0 0 10px rgba(245, 167, 66, 0.35);
2771
3133
  }
2772
3134
  .search-wrap { max-width: 420px; margin-bottom: 1.6rem; }
2773
3135
  .card .hint { font-size: 12px; color: var(--muted); margin-top: 8px; opacity: 0; transition: opacity .15s ease; }
@@ -3687,12 +4049,12 @@ var init_asset_map = __esm({
3687
4049
  }
3688
4050
  let filename;
3689
4051
  const baseName = path.basename(pathname.split("?")[0]);
3690
- const hash2 = crypto.createHash("md5").update(urlStr).digest("hex").slice(0, 6);
4052
+ const hash = crypto.createHash("md5").update(urlStr).digest("hex").slice(0, 6);
3691
4053
  if (baseName && baseName.length > 1 && baseName !== "/") {
3692
4054
  const clean = baseName.replace(/[^a-zA-Z0-9._-]/g, "_");
3693
- filename = clean.includes(".") ? clean : `${clean}-${hash2}`;
4055
+ filename = clean.includes(".") ? clean : `${clean}-${hash}`;
3694
4056
  } else {
3695
- filename = `asset-${hash2}${ext || ""}`;
4057
+ filename = `asset-${hash}${ext || ""}`;
3696
4058
  }
3697
4059
  if (ext === ".mjs" || ext === ".js") {
3698
4060
  filename = baseName.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -5135,10 +5497,10 @@ var init_summary = __esm({
5135
5497
  // src/ai/prompt-assistant.ts
5136
5498
  import fs4 from "fs/promises";
5137
5499
  import path5 from "path";
5138
- import { stdin as stdin2, stdout as stdout4 } from "process";
5500
+ import { stdin as stdin3, stdout as stdout4 } from "process";
5139
5501
  import { spawn } from "child_process";
5140
5502
  async function runAiPromptAssistant(exporter) {
5141
- if (!stdin2.isTTY || !stdout4.isTTY) return;
5503
+ if (!stdin3.isTTY || !stdout4.isTTY) return;
5142
5504
  const serveCommand = buildServeCommand(exporter);
5143
5505
  const shouldConvert = await runExportCompletePrompt(exporter, serveCommand);
5144
5506
  if (!shouldConvert) return;
@@ -6195,7 +6557,7 @@ __export(setup_exports, {
6195
6557
  runSetup: () => runSetup
6196
6558
  });
6197
6559
  import readline2 from "readline/promises";
6198
- import { stdin as stdin3, stdout as stdout5 } from "process";
6560
+ import { stdin as stdin4, stdout as stdout5 } from "process";
6199
6561
  import path8 from "path";
6200
6562
  import { URL as URL5 } from "url";
6201
6563
  import chalk9 from "chalk";
@@ -6332,7 +6694,7 @@ async function runSetup(legacyMode = false) {
6332
6694
  });
6333
6695
  }
6334
6696
  async function runLegacySetup() {
6335
- const rl = readline2.createInterface({ input: stdin3, output: stdout5 });
6697
+ const rl = readline2.createInterface({ input: stdin4, output: stdout5 });
6336
6698
  const ask = async (question, defaultVal) => {
6337
6699
  const suffix = defaultVal ? chalk9.gray(` (${defaultVal})`) : "";
6338
6700
  const prompt = ` ${ui.primary("\u25CF")} ${ui.text.bold(question)}${suffix} ${ui.muted(">")} `;