framer-export 4.4.1 → 4.4.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 +219 -122
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
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: "4.4.
|
|
18
|
+
version: "4.4.3",
|
|
19
19
|
description: "Export any Framer, Webflow, or Wix site 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",
|
|
@@ -215,7 +215,8 @@ async function showLoadingIntro(version) {
|
|
|
215
215
|
const title = renderShinyText(`Framer Export v${version}`, frame, {
|
|
216
216
|
baseColor: "#969696",
|
|
217
217
|
shineColor: "#ffffff",
|
|
218
|
-
shineWidth: 18
|
|
218
|
+
shineWidth: 18,
|
|
219
|
+
speed: 1.2
|
|
219
220
|
});
|
|
220
221
|
const dots = ".".repeat(frame % 4).padEnd(3, " ");
|
|
221
222
|
process.stdout.write(
|
|
@@ -237,8 +238,9 @@ function renderShinyText(text, frame, options = {}) {
|
|
|
237
238
|
const baseColor = options.baseColor || "#808080";
|
|
238
239
|
const shineColor = options.shineColor || "#ffffff";
|
|
239
240
|
const shineWidth = options.shineWidth || SHINE_WIDTH;
|
|
241
|
+
const speed = options.speed ?? SHINE_SPEED;
|
|
240
242
|
const travel = text.length + shineWidth * 2;
|
|
241
|
-
const pos = frame *
|
|
243
|
+
const pos = frame * speed % travel - shineWidth;
|
|
242
244
|
const base = hexToRgb(baseColor);
|
|
243
245
|
const shine = hexToRgb(shineColor);
|
|
244
246
|
let result = "";
|
|
@@ -338,9 +340,66 @@ function maxWidth() {
|
|
|
338
340
|
return Math.min(process.stdout.columns || 80, 76);
|
|
339
341
|
}
|
|
340
342
|
function padRight(text, w) {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
343
|
+
const fitted = fitAnsi(text, w);
|
|
344
|
+
const visible = stripAnsi(fitted).length;
|
|
345
|
+
if (visible >= w) return fitted;
|
|
346
|
+
return fitted + " ".repeat(w - visible);
|
|
347
|
+
}
|
|
348
|
+
function fitAnsi(text, width) {
|
|
349
|
+
if (stripAnsi(text).length <= width) return text;
|
|
350
|
+
if (width <= 2) return ".".repeat(Math.max(0, width));
|
|
351
|
+
let out = "";
|
|
352
|
+
let visible = 0;
|
|
353
|
+
let i = 0;
|
|
354
|
+
const limit = width - 2;
|
|
355
|
+
while (i < text.length && visible < limit) {
|
|
356
|
+
if (text[i] === "\x1B") {
|
|
357
|
+
const match = text.slice(i).match(/^\x1B\[[0-9;]*[a-zA-Z]/);
|
|
358
|
+
if (match) {
|
|
359
|
+
out += match[0];
|
|
360
|
+
i += match[0].length;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
out += text[i];
|
|
365
|
+
visible++;
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
return out + "..\x1B[0m";
|
|
369
|
+
}
|
|
370
|
+
function fitValue(value, width) {
|
|
371
|
+
if (value.length <= width) return value;
|
|
372
|
+
const pathLike = value.includes("\\") || value.includes("/");
|
|
373
|
+
if (pathLike) {
|
|
374
|
+
const shortened = shortenPath(value, width);
|
|
375
|
+
if (shortened.length <= width) return shortened;
|
|
376
|
+
}
|
|
377
|
+
if (width <= 3) return ".".repeat(Math.max(0, width));
|
|
378
|
+
return value.slice(0, width - 2) + "..";
|
|
379
|
+
}
|
|
380
|
+
function shortenPath(value, width) {
|
|
381
|
+
if (width <= 12) {
|
|
382
|
+
return width <= 3 ? ".".repeat(Math.max(0, width)) : value.slice(0, width - 2) + "..";
|
|
383
|
+
}
|
|
384
|
+
const separator = value.includes("\\") ? "\\" : "/";
|
|
385
|
+
const parts = value.split(/[\\/]+/).filter(Boolean);
|
|
386
|
+
const prefix = value.startsWith(separator) ? separator : "";
|
|
387
|
+
const shortened = parts.map((part, index) => {
|
|
388
|
+
const isLast = index === parts.length - 1;
|
|
389
|
+
if (isLast) return part;
|
|
390
|
+
if (/^[A-Za-z]:$/.test(part)) return part;
|
|
391
|
+
return part.length > 5 ? part.slice(0, 3) + ".." : part;
|
|
392
|
+
}).join(separator);
|
|
393
|
+
const withPrefix = prefix + shortened;
|
|
394
|
+
if (withPrefix.length <= width) return withPrefix;
|
|
395
|
+
const last = parts.at(-1) || value;
|
|
396
|
+
const first = parts.slice(0, -1).map((part) => /^[A-Za-z]:$/.test(part) ? part : part.slice(0, 3) + "..");
|
|
397
|
+
const compact = prefix + [...first, last].join(separator);
|
|
398
|
+
if (compact.length <= width) return compact;
|
|
399
|
+
const tailSpace = Math.max(8, Math.floor(width * 0.45));
|
|
400
|
+
const headSpace = Math.max(0, width - tailSpace - 4);
|
|
401
|
+
const middle = compact.slice(0, headSpace) + separator + ".." + separator + compact.slice(-tailSpace);
|
|
402
|
+
return middle.length <= width ? middle : compact.slice(0, width - 2) + "..";
|
|
344
403
|
}
|
|
345
404
|
function boxTop(w) {
|
|
346
405
|
const inner = w - 4;
|
|
@@ -379,14 +438,10 @@ function panelSep(w) {
|
|
|
379
438
|
function boxRow(w, label, value) {
|
|
380
439
|
const inner = w - 4;
|
|
381
440
|
const labelPlain = stripAnsi(chalk3.bold(label));
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(truncated) + " ".repeat(Math.max(0, inner - labelPlain.length - 1 - truncated.length)) + ui.border(" \u2502");
|
|
387
|
-
}
|
|
388
|
-
const right = inner - labelPlain.length - 1 - value.length;
|
|
389
|
-
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(value) + " ".repeat(right) + ui.border(" \u2502");
|
|
441
|
+
const avail = Math.max(0, inner - labelPlain.length - 2);
|
|
442
|
+
const fittedValue = fitValue(value, avail);
|
|
443
|
+
const right = Math.max(0, inner - labelPlain.length - 2 - fittedValue.length);
|
|
444
|
+
return " " + ui.border("\u2502 ") + chalk3.bold(label) + ": " + ui.primary(fittedValue) + " ".repeat(right) + ui.border(" \u2502");
|
|
390
445
|
}
|
|
391
446
|
var init_box = __esm({
|
|
392
447
|
"src/cli/box.ts"() {
|
|
@@ -1603,12 +1658,13 @@ var init_template = __esm({
|
|
|
1603
1658
|
"src/server/template.ts"() {
|
|
1604
1659
|
"use strict";
|
|
1605
1660
|
SERVE_SCRIPT = `#!/usr/bin/env node
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1661
|
+
import http from 'node:http';
|
|
1662
|
+
import fs from 'node:fs';
|
|
1663
|
+
import path from 'node:path';
|
|
1664
|
+
import { fileURLToPath } from 'node:url';
|
|
1609
1665
|
|
|
1610
1666
|
const PORT = process.env.PORT || 3000;
|
|
1611
|
-
const ROOT =
|
|
1667
|
+
const ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
1612
1668
|
|
|
1613
1669
|
const MIME = {
|
|
1614
1670
|
'.html': 'text/html; charset=utf-8',
|
|
@@ -1679,37 +1735,53 @@ const ANSI = {
|
|
|
1679
1735
|
border: '\\x1b[38;2;72;72;72m',
|
|
1680
1736
|
success: '\\x1b[38;2;127;216;143m',
|
|
1681
1737
|
info: '\\x1b[38;2;86;182;194m',
|
|
1738
|
+
accent: '\\x1b[38;2;157;124;216m',
|
|
1739
|
+
warning: '\\x1b[38;2;245;167;66m',
|
|
1740
|
+
command: '\\x1b[38;2;255;192;159m',
|
|
1741
|
+
error: '\\x1b[38;2;224;108;117m',
|
|
1682
1742
|
};
|
|
1683
1743
|
|
|
1684
1744
|
function color(name, value) {
|
|
1685
1745
|
return ANSI[name] + value + ANSI.reset;
|
|
1686
1746
|
}
|
|
1687
1747
|
|
|
1688
|
-
function
|
|
1689
|
-
const text =
|
|
1690
|
-
|
|
1691
|
-
|
|
1748
|
+
function fitValue(value, width) {
|
|
1749
|
+
const text = String(value);
|
|
1750
|
+
if (text.length <= width) return text;
|
|
1751
|
+
if ((text.includes('\\\\') || text.includes('/')) && width > 12) {
|
|
1752
|
+
const separator = text.includes('\\\\') ? '\\\\' : '/';
|
|
1753
|
+
const prefix = text.startsWith(separator) ? separator : '';
|
|
1754
|
+
const parts = text.split(/[\\\\/]+/).filter(Boolean);
|
|
1755
|
+
const compact = prefix + parts.map((part, index) => {
|
|
1756
|
+
if (index === parts.length - 1) return part;
|
|
1757
|
+
if (/^[A-Za-z]:$/.test(part)) return part;
|
|
1758
|
+
return part.length > 5 ? part.slice(0, 3) + '..' : part;
|
|
1759
|
+
}).join(separator);
|
|
1760
|
+
if (compact.length <= width) return compact;
|
|
1761
|
+
const tail = Math.max(8, Math.floor(width * 0.45));
|
|
1762
|
+
const head = Math.max(0, width - tail - 4);
|
|
1763
|
+
return compact.slice(0, head) + separator + '..' + separator + compact.slice(-tail);
|
|
1764
|
+
}
|
|
1765
|
+
return width <= 3 ? '.'.repeat(Math.max(0, width)) : text.slice(0, width - 2) + '..';
|
|
1692
1766
|
}
|
|
1693
1767
|
|
|
1694
|
-
function
|
|
1695
|
-
const
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
'\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 ',
|
|
1702
|
-
];
|
|
1768
|
+
function frameLine(label, value, colorName = 'text') {
|
|
1769
|
+
const labelText = label.padEnd(10);
|
|
1770
|
+
const valueWidth = Math.max(0, 56 - labelText.length);
|
|
1771
|
+
const shown = fitValue(value, valueWidth);
|
|
1772
|
+
const pad = Math.max(0, 56 - labelText.length - shown.length);
|
|
1773
|
+
console.log(' ' + color('border', '\u2502 ') + color('muted', labelText) + color(colorName, shown) + ' '.repeat(pad) + color('border', ' \u2502'));
|
|
1774
|
+
}
|
|
1703
1775
|
|
|
1704
|
-
|
|
1705
|
-
for (const line of logo) console.log(' ' + color('primary', line));
|
|
1776
|
+
function drawServerUi() {
|
|
1706
1777
|
console.log('');
|
|
1707
1778
|
console.log(' ' + color('border', '\u256D\u2500' + '\u2500'.repeat(56) + '\u2500\u256E'));
|
|
1708
|
-
console.log(' ' + color('border', '\u2502 ') + color('text', ' Framer Export
|
|
1779
|
+
console.log(' ' + color('border', '\u2502 ') + color('text', ' Framer Export preview server') + ' '.repeat(26) + color('border', ' \u2502'));
|
|
1709
1780
|
console.log(' ' + color('border', '\u251C\u2500' + '\u2500'.repeat(56) + '\u2500\u2524'));
|
|
1710
|
-
frameLine('URL', 'http://localhost:' + PORT);
|
|
1711
|
-
frameLine('Root', ROOT);
|
|
1712
|
-
frameLine('
|
|
1781
|
+
frameLine('URL', 'http://localhost:' + PORT, 'primary');
|
|
1782
|
+
frameLine('Root', ROOT, 'soft');
|
|
1783
|
+
frameLine('Run', 'node serve.js', 'command');
|
|
1784
|
+
frameLine('Mode', 'static mirror + SPA fallback', 'accent');
|
|
1713
1785
|
console.log(' ' + color('border', '\u2570\u2500' + '\u2500'.repeat(56) + '\u2500\u256F'));
|
|
1714
1786
|
console.log('');
|
|
1715
1787
|
console.log(' ' + color('success', 'ready') + color('muted', ' press Ctrl+C to stop') + '\\n');
|
|
@@ -1717,9 +1789,14 @@ function drawServerUi() {
|
|
|
1717
1789
|
|
|
1718
1790
|
server.listen(PORT, () => {
|
|
1719
1791
|
const frames = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
|
|
1792
|
+
const steps = ['Preparing server', 'Checking exported files', 'Binding local port', 'Serving static mirror'];
|
|
1793
|
+
const stepColors = ['text', 'info', 'warning', 'success'];
|
|
1720
1794
|
let i = 0;
|
|
1721
1795
|
const timer = setInterval(() => {
|
|
1722
|
-
|
|
1796
|
+
const stepIndex = Math.min(steps.length - 1, Math.floor(i / 6));
|
|
1797
|
+
const step = steps[stepIndex];
|
|
1798
|
+
const dots = color('error', '.'.repeat(i % 4).padEnd(3, ' '));
|
|
1799
|
+
process.stdout.write('\\r\\x1B[2K ' + color('primary', frames[i % frames.length]) + ' ' + color(stepColors[stepIndex], step) + dots);
|
|
1723
1800
|
i++;
|
|
1724
1801
|
}, 80);
|
|
1725
1802
|
|
|
@@ -1727,7 +1804,7 @@ server.listen(PORT, () => {
|
|
|
1727
1804
|
clearInterval(timer);
|
|
1728
1805
|
process.stdout.write('\\r\\x1B[2K');
|
|
1729
1806
|
drawServerUi();
|
|
1730
|
-
},
|
|
1807
|
+
}, 1280);
|
|
1731
1808
|
});
|
|
1732
1809
|
`;
|
|
1733
1810
|
}
|
|
@@ -1893,8 +1970,13 @@ async function buildOutput(exporter) {
|
|
|
1893
1970
|
log("Writing index.html (" + (html.length / 1024).toFixed(1) + " KB)...");
|
|
1894
1971
|
await fs2.writeFile(path3.join(exporter.outDir, "index.html"), html);
|
|
1895
1972
|
success("index.html written");
|
|
1896
|
-
await fs2.writeFile(path3.join(exporter.outDir, "serve.
|
|
1897
|
-
log("serve.
|
|
1973
|
+
await fs2.writeFile(path3.join(exporter.outDir, "serve.js"), SERVE_SCRIPT);
|
|
1974
|
+
log("serve.js written");
|
|
1975
|
+
await fs2.writeFile(
|
|
1976
|
+
path3.join(exporter.outDir, "package.json"),
|
|
1977
|
+
JSON.stringify({ type: "module", scripts: { serve: "node serve.js" } }, null, 2) + "\n"
|
|
1978
|
+
);
|
|
1979
|
+
log("package.json written for serve.js");
|
|
1898
1980
|
success("Output build complete");
|
|
1899
1981
|
}
|
|
1900
1982
|
async function rewriteDownloadedFiles(exporter) {
|
|
@@ -2044,21 +2126,19 @@ async function printSummary(exporter) {
|
|
|
2044
2126
|
console.log(boxBot(w));
|
|
2045
2127
|
}
|
|
2046
2128
|
console.log("");
|
|
2047
|
-
const cdCmd = "cd " + path4.basename(exporter.outDir)
|
|
2129
|
+
const cdCmd = "cd " + path4.basename(exporter.outDir);
|
|
2130
|
+
const runCmd = "node serve.js";
|
|
2048
2131
|
if (!isSmall) {
|
|
2049
2132
|
console.log(boxTop(w));
|
|
2050
2133
|
console.log(boxLine(w, ui.text.bold(" To serve locally")));
|
|
2051
2134
|
console.log(boxSep(w));
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
const pad = Math.max(0, inner - cmdLen);
|
|
2055
|
-
console.log(
|
|
2056
|
-
" " + ui.border("\u2502 ") + G(cdCmd) + " ".repeat(pad) + ui.muted(" copy") + ui.border(" \u2502")
|
|
2057
|
-
);
|
|
2135
|
+
console.log(boxRow(w, "Open", cdCmd));
|
|
2136
|
+
console.log(boxRow(w, "Run", runCmd));
|
|
2058
2137
|
console.log(boxBot(w));
|
|
2059
2138
|
} else {
|
|
2060
2139
|
console.log(ui.text.bold(" To serve locally:"));
|
|
2061
2140
|
console.log(` ${G(cdCmd)}`);
|
|
2141
|
+
console.log(` ${G(runCmd)}`);
|
|
2062
2142
|
}
|
|
2063
2143
|
console.log("");
|
|
2064
2144
|
console.log(ui.muted(" note: must be served via HTTP for JS modules to work."));
|
|
@@ -2079,17 +2159,10 @@ import { stdin as stdin2, stdout as stdout2 } from "process";
|
|
|
2079
2159
|
import { spawn } from "child_process";
|
|
2080
2160
|
async function runAiPromptAssistant(exporter) {
|
|
2081
2161
|
if (!stdin2.isTTY || !stdout2.isTTY) return;
|
|
2082
|
-
|
|
2083
|
-
const
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
{ label: `${buttonLabel("Convert")} open AI prompt modal`, value: "convert" },
|
|
2087
|
-
{ label: `${buttonLabel("Skip")} finish export`, value: "skip" }
|
|
2088
|
-
],
|
|
2089
|
-
0
|
|
2090
|
-
);
|
|
2091
|
-
if (action === "skip") return;
|
|
2092
|
-
printAssistantModal("AI conversion prompt", [
|
|
2162
|
+
const serveCommand = buildServeCommand(exporter);
|
|
2163
|
+
const shouldConvert = await runExportCompletePrompt(exporter, serveCommand);
|
|
2164
|
+
if (!shouldConvert) return;
|
|
2165
|
+
printAssistantModal(`${ui.text.bold("AI conversion prompt")} ${ui.error("BETA")}`, [
|
|
2093
2166
|
"Choose a target stack, AI tool, and conversion situation.",
|
|
2094
2167
|
"Mouse clicks are supported in the terminal when available.",
|
|
2095
2168
|
"A detailed prompt file will be generated inside the export folder."
|
|
@@ -2118,16 +2191,8 @@ async function runAiPromptAssistant(exporter) {
|
|
|
2118
2191
|
const promptPath = path5.join(aiDir, `${aiTool.id}-${target.id}-${goal.id}-prompt.md`);
|
|
2119
2192
|
await fs4.mkdir(aiDir, { recursive: true });
|
|
2120
2193
|
await fs4.writeFile(promptPath, prompt, "utf-8");
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
"Prompt actions",
|
|
2124
|
-
[
|
|
2125
|
-
{ label: `${buttonLabel("Copy prompt")} clipboard`, value: "copy" },
|
|
2126
|
-
{ label: `${buttonLabel("Done")} keep file only`, value: "done" }
|
|
2127
|
-
],
|
|
2128
|
-
0
|
|
2129
|
-
);
|
|
2130
|
-
if (promptAction === "copy") {
|
|
2194
|
+
const copyPrompt = await runPromptReadyPrompt(promptPath, target, aiTool, goal);
|
|
2195
|
+
if (copyPrompt) {
|
|
2131
2196
|
try {
|
|
2132
2197
|
await copyToClipboard(prompt);
|
|
2133
2198
|
console.log(` ${ui.success("\u2713")} ${ui.text.bold("Prompt copied to clipboard")}
|
|
@@ -2185,27 +2250,97 @@ function centerText2(text, width) {
|
|
|
2185
2250
|
const left = Math.floor((width - visible) / 2);
|
|
2186
2251
|
return " ".repeat(left) + text + " ".repeat(width - visible - left);
|
|
2187
2252
|
}
|
|
2188
|
-
function
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2253
|
+
function buildServeCommand(exporter) {
|
|
2254
|
+
return `cd ${path5.basename(exporter.outDir)} && node serve.js`;
|
|
2255
|
+
}
|
|
2256
|
+
async function runExportCompletePrompt(exporter, serveCommand) {
|
|
2257
|
+
let copyServeCommand = true;
|
|
2258
|
+
while (true) {
|
|
2259
|
+
const action = await select(
|
|
2260
|
+
"Export complete",
|
|
2261
|
+
[
|
|
2262
|
+
{
|
|
2263
|
+
label: `${checkboxLabel(copyServeCommand)} Copy serve command when finishing`,
|
|
2264
|
+
value: "toggle-copy"
|
|
2265
|
+
},
|
|
2266
|
+
{
|
|
2267
|
+
label: `${buttonLabel("Convert to AI code")} ${ui.error("BETA")}`,
|
|
2268
|
+
value: "convert"
|
|
2269
|
+
},
|
|
2270
|
+
{ label: buttonLabel("Finish"), value: "finish" }
|
|
2271
|
+
],
|
|
2272
|
+
2,
|
|
2273
|
+
{
|
|
2274
|
+
headerLines: [
|
|
2275
|
+
`Output: ${path5.basename(exporter.outDir)}`,
|
|
2276
|
+
`Run: ${serveCommand}`,
|
|
2277
|
+
"Use Convert to open the AI conversion assistant."
|
|
2278
|
+
],
|
|
2279
|
+
footer: "enter select \xB7 checkbox toggles copy \xB7 mouse hover/click"
|
|
2280
|
+
}
|
|
2281
|
+
);
|
|
2282
|
+
if (action === "toggle-copy") {
|
|
2283
|
+
copyServeCommand = !copyServeCommand;
|
|
2284
|
+
continue;
|
|
2285
|
+
}
|
|
2286
|
+
if (action === "finish") {
|
|
2287
|
+
if (copyServeCommand) {
|
|
2288
|
+
try {
|
|
2289
|
+
await copyToClipboard(serveCommand);
|
|
2290
|
+
console.log(` ${ui.success("\u2713")} ${ui.text.bold("Serve command copied")}
|
|
2291
|
+
`);
|
|
2292
|
+
} catch (error) {
|
|
2293
|
+
console.log(
|
|
2294
|
+
` ${ui.warning("!")} ${ui.warning("Clipboard copy unavailable:")} ${ui.muted(error.message)}
|
|
2295
|
+
`
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
return true;
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
async function runPromptReadyPrompt(promptPath, target, aiTool, goal) {
|
|
2305
|
+
const relPath = path5.relative(process.cwd(), promptPath) || promptPath;
|
|
2306
|
+
let copyPrompt = false;
|
|
2307
|
+
while (true) {
|
|
2308
|
+
const action = await select(
|
|
2309
|
+
`AI Prompt Ready ${ui.error("BETA")}`,
|
|
2310
|
+
[
|
|
2311
|
+
{
|
|
2312
|
+
label: `${checkboxLabel(copyPrompt)} Copy prompt when finishing`,
|
|
2313
|
+
value: "toggle-copy"
|
|
2314
|
+
},
|
|
2315
|
+
{ label: buttonLabel("Finish"), value: "finish" }
|
|
2316
|
+
],
|
|
2317
|
+
1,
|
|
2318
|
+
{
|
|
2319
|
+
headerLines: [
|
|
2320
|
+
`Tool: ${aiTool.displayName}`,
|
|
2321
|
+
`Stack: ${target.label}`,
|
|
2322
|
+
`Mode: ${goal.label}`,
|
|
2323
|
+
`File: ${relPath}`
|
|
2324
|
+
],
|
|
2325
|
+
footer: "enter finish \xB7 checkbox toggles copy \xB7 mouse hover/click"
|
|
2326
|
+
}
|
|
2327
|
+
);
|
|
2328
|
+
if (action === "toggle-copy") {
|
|
2329
|
+
copyPrompt = !copyPrompt;
|
|
2330
|
+
continue;
|
|
2331
|
+
}
|
|
2332
|
+
return copyPrompt;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
function checkboxLabel(checked) {
|
|
2336
|
+
return checked ? ui.success("\u2611") : ui.muted("\u2610");
|
|
2202
2337
|
}
|
|
2203
2338
|
function printAssistantModal(title, lines) {
|
|
2204
2339
|
const w = maxWidth();
|
|
2205
2340
|
const inner = w - 4;
|
|
2206
2341
|
console.log("");
|
|
2207
2342
|
console.log(boxTop(w));
|
|
2208
|
-
console.log(boxLine(w, centerText2(`${ui.primary("\u25C6")} ${
|
|
2343
|
+
console.log(boxLine(w, centerText2(`${ui.primary("\u25C6")} ${title}`, inner)));
|
|
2209
2344
|
console.log(boxSep(w));
|
|
2210
2345
|
for (const line of lines) {
|
|
2211
2346
|
console.log(boxLine(w, centerText2(ui.muted(line), inner)));
|
|
@@ -2388,44 +2523,6 @@ function pipeToCommand(command, args, input) {
|
|
|
2388
2523
|
child.stdin?.end(input);
|
|
2389
2524
|
});
|
|
2390
2525
|
}
|
|
2391
|
-
function printPromptResult(promptPath, target, aiTool, goal) {
|
|
2392
|
-
const w = maxWidth();
|
|
2393
|
-
const isSmall = w < 50;
|
|
2394
|
-
const inner = w - 4;
|
|
2395
|
-
const relPath = path5.relative(process.cwd(), promptPath) || promptPath;
|
|
2396
|
-
console.log("");
|
|
2397
|
-
if (!isSmall) {
|
|
2398
|
-
console.log(boxTop(w));
|
|
2399
|
-
console.log(
|
|
2400
|
-
boxLine(
|
|
2401
|
-
w,
|
|
2402
|
-
centerText2(
|
|
2403
|
-
`${ui.success("\u2713")} ${ui.text.bold("AI Prompt Ready")} ${ui.muted("BETA")}`,
|
|
2404
|
-
inner
|
|
2405
|
-
)
|
|
2406
|
-
)
|
|
2407
|
-
);
|
|
2408
|
-
console.log(boxSep(w));
|
|
2409
|
-
console.log(
|
|
2410
|
-
boxLine(w, centerText2(`${ui.muted("Tool")} ${ui.primary(aiTool.displayName)}`, inner))
|
|
2411
|
-
);
|
|
2412
|
-
console.log(boxLine(w, centerText2(`${ui.muted("Stack")} ${ui.primary(target.label)}`, inner)));
|
|
2413
|
-
console.log(boxLine(w, centerText2(`${ui.muted("Mode")} ${ui.primary(goal.label)}`, inner)));
|
|
2414
|
-
console.log(boxLine(w, centerText2(`${ui.muted("File")} ${ui.primary(relPath)}`, inner)));
|
|
2415
|
-
console.log(boxSep(w));
|
|
2416
|
-
console.log(
|
|
2417
|
-
boxLine(w, centerText2(`${buttonLabel("Copy prompt")} ${buttonLabel("Done")}`, inner))
|
|
2418
|
-
);
|
|
2419
|
-
console.log(boxBot(w));
|
|
2420
|
-
} else {
|
|
2421
|
-
console.log(ui.text.bold(" AI Prompt Ready - BETA"));
|
|
2422
|
-
console.log(` Tool: ${ui.primary(aiTool.displayName)}`);
|
|
2423
|
-
console.log(` Stack: ${ui.primary(target.label)}`);
|
|
2424
|
-
console.log(` Situation: ${ui.primary(goal.label)}`);
|
|
2425
|
-
console.log(` File: ${ui.primary(relPath)}`);
|
|
2426
|
-
}
|
|
2427
|
-
console.log("");
|
|
2428
|
-
}
|
|
2429
2526
|
var IMPORTANT_DIRS, AI_TOOLS, TARGETS, GOALS;
|
|
2430
2527
|
var init_prompt_assistant = __esm({
|
|
2431
2528
|
"src/ai/prompt-assistant.ts"() {
|