frameshot-mcp 0.10.0 → 0.11.1
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/README.md +28 -2
- package/dist/{chunk-6OTGZDUU.js → chunk-RXVC5ZDW.js} +1 -1
- package/dist/{chunk-WACVDBUF.js → chunk-SP7UAIQL.js} +76 -32
- package/dist/cli.js +2 -2
- package/dist/index.js +32 -26
- package/dist/renderer.d.ts +2 -0
- package/dist/renderer.js +1 -1
- package/package.json +1 -1
- package/scripts/render-changed.mjs +9 -4
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Two lines. Auto-detects changed components. Posts before/after/diff screenshots
|
|
|
53
53
|
- uses: actions/checkout@v7
|
|
54
54
|
with:
|
|
55
55
|
fetch-depth: 0
|
|
56
|
-
- uses: kamegoro/frameshot@v0.
|
|
56
|
+
- uses: kamegoro/frameshot@v0.11.0
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
<p align="center">
|
|
@@ -70,7 +70,7 @@ Changed `.tsx`, `.jsx`, `.vue`, `.svelte`, `.astro`, `.mdx` files detected autom
|
|
|
70
70
|
<summary>Options</summary>
|
|
71
71
|
|
|
72
72
|
```yaml
|
|
73
|
-
- uses: kamegoro/frameshot@v0.
|
|
73
|
+
- uses: kamegoro/frameshot@v0.11.0
|
|
74
74
|
with:
|
|
75
75
|
paths: "./src/components/*.tsx" # default: auto-detect
|
|
76
76
|
extensions: ".jsx,.tsx,.vue" # default: .jsx,.tsx,.vue,.svelte,.astro,.mdx
|
|
@@ -95,6 +95,32 @@ render_file("src/components/Dashboard.tsx")
|
|
|
95
95
|
|
|
96
96
|
Resolves your project's real imports, Tailwind config, CSS Modules, and path aliases — not a CDN polyfill.
|
|
97
97
|
|
|
98
|
+
### Works out of the box with 16 frameworks
|
|
99
|
+
|
|
100
|
+
| Meta-frameworks | Core libraries |
|
|
101
|
+
|---|---|
|
|
102
|
+
| Next.js, Nuxt, SvelteKit, SolidStart | React, Vue, Svelte |
|
|
103
|
+
| Remix / React Router 7, Gatsby | Solid, Preact |
|
|
104
|
+
| Qwik, Astro, Vike | Lit / Web Components |
|
|
105
|
+
|
|
106
|
+
Auto-detected from `package.json`. No config needed for the common case. Framework-specific imports (`next/navigation`, `$app/stores`, `useLoaderData`, …) are stubbed automatically so components render in isolation.
|
|
107
|
+
|
|
108
|
+
### Mock API calls
|
|
109
|
+
|
|
110
|
+
Components that fetch data from `/api/...` render in their loaded state instead of showing a spinner:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
render_file({
|
|
114
|
+
path: "src/components/UserList.tsx",
|
|
115
|
+
mock: {
|
|
116
|
+
"/api/users": [{ id: 1, name: "Alice" }],
|
|
117
|
+
"/api/posts/*": { status: 200, body: { data: [] } },
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Pattern syntax: path (`/api/users`), glob (`**/api/*`), or full URL.
|
|
123
|
+
|
|
98
124
|
---
|
|
99
125
|
|
|
100
126
|
## Using with Claude
|
|
@@ -351,7 +351,7 @@ var ProjectDetector = class {
|
|
|
351
351
|
|
|
352
352
|
// src/infrastructure/vite-bundler.ts
|
|
353
353
|
import { existsSync as existsSync4 } from "fs";
|
|
354
|
-
import { createRequire } from "module";
|
|
354
|
+
import { createRequire as createRequire2 } from "module";
|
|
355
355
|
import { dirname as dirname2, join as join18, resolve as resolve2 } from "path";
|
|
356
356
|
import { fileURLToPath } from "url";
|
|
357
357
|
|
|
@@ -360,6 +360,7 @@ import { join as join3 } from "path";
|
|
|
360
360
|
|
|
361
361
|
// src/infrastructure/adapters/helpers.ts
|
|
362
362
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
363
|
+
import { createRequire } from "module";
|
|
363
364
|
import { join as join2 } from "path";
|
|
364
365
|
function hasDep(pkgPath, names) {
|
|
365
366
|
if (!existsSync2(pkgPath)) return false;
|
|
@@ -388,6 +389,20 @@ async function loadPlugin(pkg, fnName) {
|
|
|
388
389
|
}
|
|
389
390
|
return [];
|
|
390
391
|
}
|
|
392
|
+
async function loadPluginFromProject(projectRoot, pkg, fnName) {
|
|
393
|
+
try {
|
|
394
|
+
const require2 = createRequire(join2(projectRoot, "package.json"));
|
|
395
|
+
const resolvedPath = require2.resolve(pkg);
|
|
396
|
+
const mod = await import(`file://${resolvedPath}`);
|
|
397
|
+
const candidate = fnName ? mod[fnName] : mod.default ?? mod;
|
|
398
|
+
if (typeof candidate === "function") {
|
|
399
|
+
const result = candidate();
|
|
400
|
+
return Array.isArray(result) ? result : [result];
|
|
401
|
+
}
|
|
402
|
+
} catch {
|
|
403
|
+
}
|
|
404
|
+
return loadPlugin(pkg, fnName);
|
|
405
|
+
}
|
|
391
406
|
function loadReactPlugin() {
|
|
392
407
|
return loadPlugin("@vitejs/plugin-react");
|
|
393
408
|
}
|
|
@@ -417,13 +432,21 @@ var AstroAdapter = class {
|
|
|
417
432
|
if (hasInstalled(projectRoot, "react"))
|
|
418
433
|
plugins.push(...await loadReactPlugin());
|
|
419
434
|
if (hasInstalled(projectRoot, "vue"))
|
|
420
|
-
plugins.push(
|
|
435
|
+
plugins.push(
|
|
436
|
+
...await loadPluginFromProject(projectRoot, "@vitejs/plugin-vue")
|
|
437
|
+
);
|
|
421
438
|
if (hasInstalled(projectRoot, "svelte"))
|
|
422
439
|
plugins.push(
|
|
423
|
-
...await
|
|
440
|
+
...await loadPluginFromProject(
|
|
441
|
+
projectRoot,
|
|
442
|
+
"@sveltejs/vite-plugin-svelte",
|
|
443
|
+
"svelte"
|
|
444
|
+
)
|
|
424
445
|
);
|
|
425
446
|
if (hasInstalled(projectRoot, "solid-js"))
|
|
426
|
-
plugins.push(
|
|
447
|
+
plugins.push(
|
|
448
|
+
...await loadPluginFromProject(projectRoot, "vite-plugin-solid")
|
|
449
|
+
);
|
|
427
450
|
return plugins;
|
|
428
451
|
}
|
|
429
452
|
useFrameshotVite() {
|
|
@@ -482,15 +505,25 @@ var GenericAdapter = class {
|
|
|
482
505
|
if (hasInstalled(projectRoot, "react"))
|
|
483
506
|
plugins.push(...await loadReactPlugin());
|
|
484
507
|
if (hasInstalled(projectRoot, "vue"))
|
|
485
|
-
plugins.push(
|
|
508
|
+
plugins.push(
|
|
509
|
+
...await loadPluginFromProject(projectRoot, "@vitejs/plugin-vue")
|
|
510
|
+
);
|
|
486
511
|
if (hasInstalled(projectRoot, "svelte"))
|
|
487
512
|
plugins.push(
|
|
488
|
-
...await
|
|
513
|
+
...await loadPluginFromProject(
|
|
514
|
+
projectRoot,
|
|
515
|
+
"@sveltejs/vite-plugin-svelte",
|
|
516
|
+
"svelte"
|
|
517
|
+
)
|
|
489
518
|
);
|
|
490
519
|
if (hasInstalled(projectRoot, "solid-js"))
|
|
491
|
-
plugins.push(
|
|
520
|
+
plugins.push(
|
|
521
|
+
...await loadPluginFromProject(projectRoot, "vite-plugin-solid")
|
|
522
|
+
);
|
|
492
523
|
if (hasInstalled(projectRoot, "preact"))
|
|
493
|
-
plugins.push(
|
|
524
|
+
plugins.push(
|
|
525
|
+
...await loadPluginFromProject(projectRoot, "@preact/preset-vite")
|
|
526
|
+
);
|
|
494
527
|
return plugins;
|
|
495
528
|
}
|
|
496
529
|
useFrameshotVite() {
|
|
@@ -588,8 +621,8 @@ var NuxtAdapter = class {
|
|
|
588
621
|
getOptimizeDeps(_root) {
|
|
589
622
|
return ["vue"];
|
|
590
623
|
}
|
|
591
|
-
async getPlugins(
|
|
592
|
-
return
|
|
624
|
+
async getPlugins(root) {
|
|
625
|
+
return loadPluginFromProject(root, "@vitejs/plugin-vue");
|
|
593
626
|
}
|
|
594
627
|
useFrameshotVite() {
|
|
595
628
|
return true;
|
|
@@ -743,11 +776,15 @@ var SvelteAdapter = class {
|
|
|
743
776
|
getOptimizeDeps() {
|
|
744
777
|
return [];
|
|
745
778
|
}
|
|
746
|
-
async getPlugins(
|
|
747
|
-
return
|
|
779
|
+
async getPlugins(root) {
|
|
780
|
+
return loadPluginFromProject(
|
|
781
|
+
root,
|
|
782
|
+
"@sveltejs/vite-plugin-svelte",
|
|
783
|
+
"svelte"
|
|
784
|
+
);
|
|
748
785
|
}
|
|
749
|
-
useFrameshotVite() {
|
|
750
|
-
return
|
|
786
|
+
useFrameshotVite(projectRoot) {
|
|
787
|
+
return projectRoot ? !hasInstalled(projectRoot, "vite") : false;
|
|
751
788
|
}
|
|
752
789
|
skipProjectConfig() {
|
|
753
790
|
return true;
|
|
@@ -771,11 +808,15 @@ var SvelteKitAdapter = class {
|
|
|
771
808
|
getOptimizeDeps(_root) {
|
|
772
809
|
return [];
|
|
773
810
|
}
|
|
774
|
-
async getPlugins(
|
|
775
|
-
return
|
|
811
|
+
async getPlugins(root) {
|
|
812
|
+
return loadPluginFromProject(
|
|
813
|
+
root,
|
|
814
|
+
"@sveltejs/vite-plugin-svelte",
|
|
815
|
+
"svelte"
|
|
816
|
+
);
|
|
776
817
|
}
|
|
777
|
-
useFrameshotVite() {
|
|
778
|
-
return
|
|
818
|
+
useFrameshotVite(projectRoot) {
|
|
819
|
+
return projectRoot ? !hasInstalled(projectRoot, "vite") : false;
|
|
779
820
|
}
|
|
780
821
|
skipProjectConfig() {
|
|
781
822
|
return true;
|
|
@@ -861,8 +902,8 @@ var VueAdapter = class {
|
|
|
861
902
|
getOptimizeDeps() {
|
|
862
903
|
return ["vue"];
|
|
863
904
|
}
|
|
864
|
-
async getPlugins(
|
|
865
|
-
return
|
|
905
|
+
async getPlugins(root) {
|
|
906
|
+
return loadPluginFromProject(root, "@vitejs/plugin-vue");
|
|
866
907
|
}
|
|
867
908
|
useFrameshotVite() {
|
|
868
909
|
return true;
|
|
@@ -910,7 +951,7 @@ var ViteBundler = class {
|
|
|
910
951
|
const absPath = resolve2(filePath);
|
|
911
952
|
const project = options.projectRoot ? this.detector.detect(join18(options.projectRoot, "package.json")) : this.detector.detect(absPath);
|
|
912
953
|
const adapter = selectAdapter(project.root);
|
|
913
|
-
if (!project.hasVite && !adapter.useFrameshotVite()) {
|
|
954
|
+
if (!project.hasVite && !adapter.useFrameshotVite(project.root)) {
|
|
914
955
|
throw new Error(
|
|
915
956
|
`Vite not found in ${project.root}. Install vite: npm install -D vite`
|
|
916
957
|
);
|
|
@@ -988,9 +1029,10 @@ try {
|
|
|
988
1029
|
case "solid":
|
|
989
1030
|
return `${cssImport}
|
|
990
1031
|
import { render } from "solid-js/web";
|
|
1032
|
+
import { createComponent } from "solid-js";
|
|
991
1033
|
import Component from "${componentPath}";
|
|
992
1034
|
const props = ${propsJson};
|
|
993
|
-
render(() => Component
|
|
1035
|
+
render(() => createComponent(Component, props), document.getElementById("app"));
|
|
994
1036
|
`;
|
|
995
1037
|
case "preact":
|
|
996
1038
|
return `${cssImport}
|
|
@@ -1010,7 +1052,7 @@ document.getElementById("app").innerHTML = html;
|
|
|
1010
1052
|
async ensureServer(project, adapter) {
|
|
1011
1053
|
const existing = this.servers.get(project.root);
|
|
1012
1054
|
if (existing) return existing;
|
|
1013
|
-
const vite = adapter.useFrameshotVite() ? await this.importFrameshotVite() : await this.importVite(project.root);
|
|
1055
|
+
const vite = adapter.useFrameshotVite(project.root) ? await this.importFrameshotVite() : await this.importVite(project.root);
|
|
1014
1056
|
if (!vite) {
|
|
1015
1057
|
throw new Error(`Failed to import vite for ${project.root}`);
|
|
1016
1058
|
}
|
|
@@ -1108,7 +1150,7 @@ document.getElementById("app").innerHTML = html;
|
|
|
1108
1150
|
}
|
|
1109
1151
|
async importFrameshotVite() {
|
|
1110
1152
|
try {
|
|
1111
|
-
const requireFromHere =
|
|
1153
|
+
const requireFromHere = createRequire2(import.meta.url);
|
|
1112
1154
|
const vitePath = requireFromHere.resolve("vite");
|
|
1113
1155
|
const mod = await import(vitePath);
|
|
1114
1156
|
if (mod && typeof mod === "object" && "createServer" in mod) {
|
|
@@ -1127,7 +1169,7 @@ document.getElementById("app").innerHTML = html;
|
|
|
1127
1169
|
}
|
|
1128
1170
|
async importVite(projectRoot) {
|
|
1129
1171
|
try {
|
|
1130
|
-
const require2 =
|
|
1172
|
+
const require2 = createRequire2(join18(projectRoot, "package.json"));
|
|
1131
1173
|
const vitePath = require2.resolve("vite");
|
|
1132
1174
|
const mod = await import(vitePath);
|
|
1133
1175
|
if (mod && typeof mod === "object" && "createServer" in mod) {
|
|
@@ -1139,7 +1181,7 @@ document.getElementById("app").innerHTML = html;
|
|
|
1139
1181
|
}
|
|
1140
1182
|
hasPackage(projectRoot, name) {
|
|
1141
1183
|
try {
|
|
1142
|
-
const require2 =
|
|
1184
|
+
const require2 = createRequire2(join18(projectRoot, "package.json"));
|
|
1143
1185
|
require2.resolve(name);
|
|
1144
1186
|
return true;
|
|
1145
1187
|
} catch {
|
|
@@ -1475,12 +1517,12 @@ var RenderUseCase = class {
|
|
|
1475
1517
|
async renderFile(filePath, options = {}) {
|
|
1476
1518
|
const opts = this.resolveOptions(options);
|
|
1477
1519
|
const ext = extname2(filePath).toLowerCase();
|
|
1478
|
-
const
|
|
1520
|
+
const extFramework = EXT_TO_FRAMEWORK[ext] ?? "react";
|
|
1521
|
+
let fallbackReason;
|
|
1479
1522
|
if (this.viteBundler) {
|
|
1480
1523
|
try {
|
|
1481
1524
|
const { url } = await this.viteBundler.getUrl(filePath, {
|
|
1482
1525
|
props: options.props,
|
|
1483
|
-
framework,
|
|
1484
1526
|
projectRoot: options.projectRoot
|
|
1485
1527
|
});
|
|
1486
1528
|
const results2 = await Promise.all(
|
|
@@ -1488,16 +1530,18 @@ var RenderUseCase = class {
|
|
|
1488
1530
|
);
|
|
1489
1531
|
return { results: results2, mode: "vite" };
|
|
1490
1532
|
} catch (err) {
|
|
1491
|
-
|
|
1533
|
+
fallbackReason = err instanceof Error ? err.message : String(err);
|
|
1492
1534
|
process.stderr.write(
|
|
1493
|
-
`[frameshot] Vite pipeline failed (${
|
|
1535
|
+
`[frameshot] Vite pipeline failed (${fallbackReason}), falling back to CDN
|
|
1494
1536
|
`
|
|
1495
1537
|
);
|
|
1496
1538
|
}
|
|
1539
|
+
} else {
|
|
1540
|
+
fallbackReason = "Vite bundler not available";
|
|
1497
1541
|
}
|
|
1498
1542
|
const code = readFileSync3(filePath, "utf-8");
|
|
1499
|
-
const results = await this.render(code,
|
|
1500
|
-
return { results, mode: "cdn" };
|
|
1543
|
+
const results = await this.render(code, extFramework, options);
|
|
1544
|
+
return { results, mode: "cdn", fallbackReason };
|
|
1501
1545
|
}
|
|
1502
1546
|
async renderInteraction(code, framework, interactions, options = {}) {
|
|
1503
1547
|
const opts = this.resolveOptions(options);
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createContainer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RXVC5ZDW.js";
|
|
5
5
|
import {
|
|
6
6
|
EXT_TO_FRAMEWORK
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SP7UAIQL.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
10
10
|
import { mkdirSync } from "fs";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createContainer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RXVC5ZDW.js";
|
|
5
5
|
import {
|
|
6
6
|
DEVICE_PRESETS,
|
|
7
7
|
EXT_TO_FRAMEWORK,
|
|
8
8
|
__export
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SP7UAIQL.js";
|
|
10
10
|
|
|
11
11
|
// src/index.ts
|
|
12
12
|
import { execSync } from "child_process";
|
|
@@ -14907,19 +14907,25 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14907
14907
|
mock
|
|
14908
14908
|
}) => {
|
|
14909
14909
|
const start = performance.now();
|
|
14910
|
-
const { results, mode } = await useCase.renderFile(
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
14919
|
-
|
|
14910
|
+
const { results, mode, fallbackReason } = await useCase.renderFile(
|
|
14911
|
+
path,
|
|
14912
|
+
{
|
|
14913
|
+
props,
|
|
14914
|
+
viewport: { width, height },
|
|
14915
|
+
fullPage: true,
|
|
14916
|
+
engines: ["chromium"],
|
|
14917
|
+
darkMode,
|
|
14918
|
+
tailwindVersion,
|
|
14919
|
+
projectRoot,
|
|
14920
|
+
mock
|
|
14921
|
+
}
|
|
14922
|
+
);
|
|
14920
14923
|
const elapsed = Math.round(performance.now() - start);
|
|
14921
14924
|
const ext = extname(path).toLowerCase();
|
|
14922
14925
|
const framework = EXT_TO_FRAMEWORK[ext] ?? "react";
|
|
14926
|
+
const fallbackNote = mode === "cdn" && fallbackReason ? `
|
|
14927
|
+
\u2139\uFE0F Fell back to CDN pipeline: ${fallbackReason}
|
|
14928
|
+
Imports from node_modules may not resolve. To fix: install vite as a devDep and add a minimal vite.config.` : "";
|
|
14923
14929
|
const content = results.flatMap((r) => [
|
|
14924
14930
|
{
|
|
14925
14931
|
type: "image",
|
|
@@ -14930,7 +14936,7 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14930
14936
|
type: "text",
|
|
14931
14937
|
text: `[${mode}/${framework}] ${r.width}x${r.height} (${elapsed}ms)${r.consoleErrors.length ? `
|
|
14932
14938
|
\u26A0\uFE0F Console errors:
|
|
14933
|
-
${r.consoleErrors.join("\n")}` : ""}`
|
|
14939
|
+
${r.consoleErrors.join("\n")}` : ""}${fallbackNote}`
|
|
14934
14940
|
}
|
|
14935
14941
|
]);
|
|
14936
14942
|
return { content };
|
|
@@ -15569,21 +15575,9 @@ function registerAllTools(server2, useCases) {
|
|
|
15569
15575
|
|
|
15570
15576
|
// src/index.ts
|
|
15571
15577
|
var container = createContainer();
|
|
15572
|
-
async function ensureBrowser() {
|
|
15573
|
-
try {
|
|
15574
|
-
await container.pool.warmup(["chromium"]);
|
|
15575
|
-
} catch {
|
|
15576
|
-
try {
|
|
15577
|
-
execSync("npx playwright install chromium", { stdio: "pipe" });
|
|
15578
|
-
await container.pool.warmup(["chromium"]);
|
|
15579
|
-
} catch {
|
|
15580
|
-
}
|
|
15581
|
-
}
|
|
15582
|
-
}
|
|
15583
|
-
await ensureBrowser();
|
|
15584
15578
|
var server = new McpServer({
|
|
15585
15579
|
name: "frameshot",
|
|
15586
|
-
version: "0.
|
|
15580
|
+
version: "0.10.0"
|
|
15587
15581
|
});
|
|
15588
15582
|
registerAllTools(server, {
|
|
15589
15583
|
render: container.renderUseCase,
|
|
@@ -15596,6 +15590,18 @@ registerAllTools(server, {
|
|
|
15596
15590
|
});
|
|
15597
15591
|
var transport = new StdioServerTransport();
|
|
15598
15592
|
await server.connect(transport);
|
|
15593
|
+
void (async () => {
|
|
15594
|
+
try {
|
|
15595
|
+
await container.pool.warmup(["chromium"]);
|
|
15596
|
+
} catch {
|
|
15597
|
+
try {
|
|
15598
|
+
execSync("npx playwright install chromium", { stdio: "pipe" });
|
|
15599
|
+
await container.pool.warmup(["chromium"]).catch(() => {
|
|
15600
|
+
});
|
|
15601
|
+
} catch {
|
|
15602
|
+
}
|
|
15603
|
+
}
|
|
15604
|
+
})();
|
|
15599
15605
|
process.on("SIGINT", async () => {
|
|
15600
15606
|
await container.shutdown();
|
|
15601
15607
|
process.exit(0);
|
package/dist/renderer.d.ts
CHANGED
|
@@ -218,6 +218,8 @@ declare class RenderUseCase {
|
|
|
218
218
|
renderFile(filePath: string, options?: Partial<FileRenderOptions>): Promise<{
|
|
219
219
|
results: ScreenshotResult[];
|
|
220
220
|
mode: "vite" | "cdn";
|
|
221
|
+
/** If we fell back to CDN, the reason the Vite pipeline was skipped. */
|
|
222
|
+
fallbackReason?: string;
|
|
221
223
|
}>;
|
|
222
224
|
renderInteraction(code: string, framework: Framework, interactions: Interaction[], options?: Partial<RenderOptions>): Promise<{
|
|
223
225
|
image: string;
|
package/dist/renderer.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frameshot-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Zero-config visual testing for AI agents. Render project components with full Vite dependency resolution — no stories, no config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -259,12 +259,17 @@ async function main() {
|
|
|
259
259
|
try {
|
|
260
260
|
// Render current (after) version
|
|
261
261
|
console.log(` Rendering (after): ${filePath}`);
|
|
262
|
-
const {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
const {
|
|
263
|
+
results: afterResults,
|
|
264
|
+
mode,
|
|
265
|
+
fallbackReason,
|
|
266
|
+
} = await renderUseCase.renderFile(filePath, renderOpts);
|
|
266
267
|
const afterResult = afterResults[0];
|
|
267
268
|
|
|
269
|
+
if (mode === "cdn" && fallbackReason) {
|
|
270
|
+
console.log(` ℹ️ CDN fallback: ${fallbackReason}`);
|
|
271
|
+
}
|
|
272
|
+
|
|
268
273
|
const afterPath = join(outputDir, `${safeName}_after.png`);
|
|
269
274
|
writeFileSync(afterPath, Buffer.from(afterResult.image, "base64"));
|
|
270
275
|
|