@bitovi/vybit 0.11.2 → 0.11.4
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 +17 -4
- package/overlay/dist/overlay.js +78 -52
- package/package.json +1 -1
- package/panel/dist/assets/{DesignMode-Ch-krWhx.js → DesignMode-Dz9Ji12J.js} +1 -1
- package/panel/dist/assets/{index-CGc6ZuTL.js → index-B1KqavJw.js} +13 -13
- package/panel/dist/index.html +1 -1
- package/server/app.ts +0 -5
- package/server/ghost-cache.ts +1 -1
- package/server/mcp-tools.ts +0 -8
- package/server/queue.ts +0 -1
- package/server/storybook.ts +1 -5
- package/server/tailwind-v3.ts +18 -2
- package/server/tailwind-v4.ts +95 -14
- package/server/tailwind.ts +0 -1
- package/storybook-addon/preview-v10.ts +0 -2
- package/storybook-addon/preview.ts +0 -2
package/panel/dist/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
font-size: 12px;
|
|
17
17
|
}
|
|
18
18
|
</style>
|
|
19
|
-
<script type="module" crossorigin src="/panel/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/panel/assets/index-B1KqavJw.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/panel/assets/index-BdUOBofL.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
package/server/app.ts
CHANGED
|
@@ -53,17 +53,12 @@ export function createApp(packageRoot: string, storybookUrl: string | null = nul
|
|
|
53
53
|
|
|
54
54
|
app.post("/css", express.json(), async (req, res) => {
|
|
55
55
|
const { classes } = req.body as { classes?: unknown };
|
|
56
|
-
console.error("[http] POST /css — requested classes:", classes);
|
|
57
56
|
if (!Array.isArray(classes) || classes.some((c) => typeof c !== "string")) {
|
|
58
|
-
console.error("[http] POST /css — invalid request body");
|
|
59
57
|
res.status(400).json({ error: "classes must be an array of strings" });
|
|
60
58
|
return;
|
|
61
59
|
}
|
|
62
60
|
try {
|
|
63
61
|
const css = await generateCssForClasses(classes as string[]);
|
|
64
|
-
console.error(`[http] POST /css — generated ${css.length} chars for [${classes.join(', ')}]`);
|
|
65
|
-
if (css.length < 500) console.error("[http] POST /css — full CSS:", css);
|
|
66
|
-
else console.error("[http] POST /css — CSS preview:", css.substring(0, 300), "...");
|
|
67
62
|
res.json({ css });
|
|
68
63
|
} catch (err) {
|
|
69
64
|
const message = err instanceof Error ? err.message : String(err);
|
package/server/ghost-cache.ts
CHANGED
|
@@ -75,7 +75,7 @@ function flushToDisk(): void {
|
|
|
75
75
|
const data: CacheFile = { entries: Array.from(cache.values()) };
|
|
76
76
|
fs.writeFileSync(filePath, JSON.stringify(data), "utf-8");
|
|
77
77
|
} catch (err) {
|
|
78
|
-
|
|
78
|
+
// ignore write errors
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
package/server/mcp-tools.ts
CHANGED
|
@@ -243,7 +243,6 @@ function waitForCommitted(
|
|
|
243
243
|
}, KEEPALIVE_INTERVAL_MS);
|
|
244
244
|
|
|
245
245
|
const onAbort = () => {
|
|
246
|
-
console.log('[mcp] waitForCommitted: abort signal fired — client disconnected');
|
|
247
246
|
clearInterval(keepalive);
|
|
248
247
|
unsubscribe();
|
|
249
248
|
// Notify the panel that no agent is waiting anymore
|
|
@@ -255,7 +254,6 @@ function waitForCommitted(
|
|
|
255
254
|
const unsubscribe = onCommitted(() => {
|
|
256
255
|
const next = getNextCommitted();
|
|
257
256
|
if (next) {
|
|
258
|
-
console.log(`[mcp] waitForCommitted: resolved with commit ${next.id}`);
|
|
259
257
|
clearInterval(keepalive);
|
|
260
258
|
extra?.signal?.removeEventListener?.("abort", onAbort);
|
|
261
259
|
resolve(next);
|
|
@@ -293,7 +291,6 @@ export function registerMcpTools(mcp: McpServer, deps: McpToolDeps): void {
|
|
|
293
291
|
"Use implement_next_change instead if you want guided implementation with auto-looping.",
|
|
294
292
|
async (_extra) => {
|
|
295
293
|
const extra = _extra as any;
|
|
296
|
-
console.log('[mcp] get_next_change called');
|
|
297
294
|
|
|
298
295
|
const reclaimed = reclaimImplementingCommits();
|
|
299
296
|
if (reclaimed > 0) broadcastPatchUpdate();
|
|
@@ -304,11 +301,9 @@ export function registerMcpTools(mcp: McpServer, deps: McpToolDeps): void {
|
|
|
304
301
|
}
|
|
305
302
|
|
|
306
303
|
if (extra?.signal?.aborted) {
|
|
307
|
-
console.log('[mcp] get_next_change: signal aborted after waitForCommitted — skipping markCommitImplementing');
|
|
308
304
|
throw new Error('Cancelled');
|
|
309
305
|
}
|
|
310
306
|
|
|
311
|
-
console.log(`[mcp] get_next_change: marking commit ${commit.id} as implementing`);
|
|
312
307
|
markCommitImplementing(commit.id);
|
|
313
308
|
broadcastPatchUpdate();
|
|
314
309
|
|
|
@@ -332,7 +327,6 @@ export function registerMcpTools(mcp: McpServer, deps: McpToolDeps): void {
|
|
|
332
327
|
"The agent MUST keep calling this tool in a loop until explicitly stopped by the user.",
|
|
333
328
|
async (_extra) => {
|
|
334
329
|
const extra = _extra as any;
|
|
335
|
-
console.log('[mcp] implement_next_change called');
|
|
336
330
|
|
|
337
331
|
const reclaimed = reclaimImplementingCommits();
|
|
338
332
|
if (reclaimed > 0) broadcastPatchUpdate();
|
|
@@ -343,11 +337,9 @@ export function registerMcpTools(mcp: McpServer, deps: McpToolDeps): void {
|
|
|
343
337
|
}
|
|
344
338
|
|
|
345
339
|
if (extra?.signal?.aborted) {
|
|
346
|
-
console.log('[mcp] implement_next_change: signal aborted after waitForCommitted — skipping markCommitImplementing');
|
|
347
340
|
throw new Error('Cancelled');
|
|
348
341
|
}
|
|
349
342
|
|
|
350
|
-
console.log(`[mcp] implement_next_change: marking commit ${commit.id} as implementing`);
|
|
351
343
|
markCommitImplementing(commit.id);
|
|
352
344
|
broadcastPatchUpdate();
|
|
353
345
|
|
package/server/queue.ts
CHANGED
|
@@ -112,7 +112,6 @@ export function reclaimImplementingCommits(): number {
|
|
|
112
112
|
let count = 0;
|
|
113
113
|
for (const commit of commits) {
|
|
114
114
|
if (commit.status === 'implementing') {
|
|
115
|
-
console.log(`[queue] Reclaiming orphaned implementing commit ${commit.id} → committed`);
|
|
116
115
|
commit.status = 'committed';
|
|
117
116
|
for (const p of commit.patches) {
|
|
118
117
|
if (p.status === 'implementing') p.status = 'committed';
|
package/server/storybook.ts
CHANGED
|
@@ -62,13 +62,12 @@ export async function loadStoryArgTypes(
|
|
|
62
62
|
result[componentName] = meta.argTypes;
|
|
63
63
|
}
|
|
64
64
|
} catch (err) {
|
|
65
|
-
|
|
65
|
+
// ignore import errors
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
return result;
|
|
70
70
|
} catch (err) {
|
|
71
|
-
console.error('[storybook] loadStoryArgTypes failed:', err);
|
|
72
71
|
return {};
|
|
73
72
|
}
|
|
74
73
|
}
|
|
@@ -81,19 +80,16 @@ export async function loadStoryArgTypes(
|
|
|
81
80
|
*/
|
|
82
81
|
export async function detectStorybookUrl(): Promise<string | null> {
|
|
83
82
|
if (process.env.STORYBOOK_URL) {
|
|
84
|
-
console.error(`[storybook] Using STORYBOOK_URL=${process.env.STORYBOOK_URL} (from env)`);
|
|
85
83
|
return process.env.STORYBOOK_URL;
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
for (const port of SCAN_PORTS) {
|
|
89
87
|
const url = `http://localhost:${port}`;
|
|
90
88
|
if (await probeStorybookUrl(url)) {
|
|
91
|
-
console.error(`[storybook] Auto-detected at ${url}`);
|
|
92
89
|
return url;
|
|
93
90
|
}
|
|
94
91
|
}
|
|
95
92
|
|
|
96
|
-
console.error('[storybook] Not detected — Draw tab will show "Start Storybook" prompt');
|
|
97
93
|
return null;
|
|
98
94
|
}
|
|
99
95
|
|
package/server/tailwind-v3.ts
CHANGED
|
@@ -407,8 +407,24 @@ export class TailwindV3Adapter implements TailwindAdapter {
|
|
|
407
407
|
pathToFileURL(req.resolve("tailwindcss/resolveConfig")).href
|
|
408
408
|
)
|
|
409
409
|
).default;
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
|
|
411
|
+
// Inject a global `require` so ESM config files that call require()
|
|
412
|
+
// (e.g. `plugins: [require('tailwindcss-animate')]`) don't fail.
|
|
413
|
+
const hadRequire = "require" in globalThis;
|
|
414
|
+
const prevRequire = (globalThis as any).require;
|
|
415
|
+
(globalThis as any).require = req;
|
|
416
|
+
let userConfig: any;
|
|
417
|
+
try {
|
|
418
|
+
userConfig = (await import(pathToFileURL(configPath).href))
|
|
419
|
+
.default;
|
|
420
|
+
} finally {
|
|
421
|
+
if (hadRequire) {
|
|
422
|
+
(globalThis as any).require = prevRequire;
|
|
423
|
+
} else {
|
|
424
|
+
delete (globalThis as any).require;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
412
428
|
const full = resolveConfig(userConfig);
|
|
413
429
|
const theme = full.theme ?? {};
|
|
414
430
|
|
package/server/tailwind-v4.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Tailwind v4 adapter — uses compile() / build() from the target project's tailwindcss v4.
|
|
2
2
|
|
|
3
|
-
import { readFileSync } from "fs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import { dirname, resolve } from "path";
|
|
5
|
+
import { dirname, resolve, join } from "path";
|
|
6
6
|
import { pathToFileURL } from "url";
|
|
7
7
|
import type {
|
|
8
8
|
TailwindAdapter,
|
|
@@ -41,7 +41,18 @@ function makeLoadStylesheet(cwd: string) {
|
|
|
41
41
|
if (id === "tailwindcss") {
|
|
42
42
|
resolved = req.resolve("tailwindcss/index.css");
|
|
43
43
|
} else {
|
|
44
|
-
|
|
44
|
+
// Try resolving from node_modules first, then as a file path
|
|
45
|
+
try {
|
|
46
|
+
resolved = req.resolve(id, { paths: [base || cwd] });
|
|
47
|
+
} catch {
|
|
48
|
+
// If module resolution fails, try as a direct file path
|
|
49
|
+
const candidate = resolve(base || cwd, id);
|
|
50
|
+
if (existsSync(candidate)) {
|
|
51
|
+
resolved = candidate;
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error(`Cannot resolve stylesheet: ${id} from ${base || cwd}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
45
56
|
}
|
|
46
57
|
return {
|
|
47
58
|
content: readFileSync(resolved, "utf8"),
|
|
@@ -50,8 +61,60 @@ function makeLoadStylesheet(cwd: string) {
|
|
|
50
61
|
};
|
|
51
62
|
}
|
|
52
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Find the project's CSS entry point that contains Tailwind directives.
|
|
66
|
+
* Looks for common CSS files that include @import "tailwindcss" or @theme blocks.
|
|
67
|
+
*/
|
|
68
|
+
function findProjectCssEntry(cwd: string): string | null {
|
|
69
|
+
const candidates = [
|
|
70
|
+
"src/index.css",
|
|
71
|
+
"src/app.css",
|
|
72
|
+
"src/globals.css",
|
|
73
|
+
"src/global.css",
|
|
74
|
+
"src/styles.css",
|
|
75
|
+
"src/style.css",
|
|
76
|
+
"src/main.css",
|
|
77
|
+
"app/globals.css",
|
|
78
|
+
"app/global.css",
|
|
79
|
+
"styles/globals.css",
|
|
80
|
+
"styles/global.css",
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
for (const candidate of candidates) {
|
|
84
|
+
const fullPath = join(cwd, candidate);
|
|
85
|
+
if (existsSync(fullPath)) {
|
|
86
|
+
const content = readFileSync(fullPath, "utf8");
|
|
87
|
+
// Check if it imports tailwindcss (v4 style) or has @theme blocks
|
|
88
|
+
if (content.includes("tailwindcss") || content.includes("@theme")) {
|
|
89
|
+
|
|
90
|
+
return fullPath;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Fallback: scan src/ for any .css file that imports tailwindcss
|
|
96
|
+
const srcDir = join(cwd, "src");
|
|
97
|
+
if (existsSync(srcDir)) {
|
|
98
|
+
try {
|
|
99
|
+
const files = readdirSync(srcDir).filter(f => f.endsWith(".css"));
|
|
100
|
+
for (const file of files) {
|
|
101
|
+
const fullPath = join(srcDir, file);
|
|
102
|
+
const content = readFileSync(fullPath, "utf8");
|
|
103
|
+
if (content.includes("tailwindcss") || content.includes("@theme")) {
|
|
104
|
+
|
|
105
|
+
return fullPath;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch { /* ignore read errors */ }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
53
114
|
/**
|
|
54
115
|
* Initialize the Tailwind v4 compiler for the target project.
|
|
116
|
+
* Tries to use the project's actual CSS entry point (which may contain @theme blocks
|
|
117
|
+
* with custom colors) instead of bare @import "tailwindcss".
|
|
55
118
|
*/
|
|
56
119
|
async function getCompiler(): Promise<{
|
|
57
120
|
build: (classes: string[]) => string;
|
|
@@ -61,14 +124,25 @@ async function getCompiler(): Promise<{
|
|
|
61
124
|
const cwd = process.cwd();
|
|
62
125
|
const compile = await getCompile();
|
|
63
126
|
|
|
64
|
-
|
|
127
|
+
// Try to use the project's CSS entry point for custom theme support
|
|
128
|
+
const cssEntryPath = findProjectCssEntry(cwd);
|
|
129
|
+
let inputCss: string;
|
|
130
|
+
let base: string;
|
|
131
|
+
|
|
132
|
+
if (cssEntryPath) {
|
|
133
|
+
inputCss = readFileSync(cssEntryPath, "utf8");
|
|
134
|
+
base = dirname(cssEntryPath);
|
|
135
|
+
} else {
|
|
136
|
+
inputCss = '@import "tailwindcss";';
|
|
137
|
+
base = cwd;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const result = await compile(inputCss, {
|
|
65
141
|
loadStylesheet: makeLoadStylesheet(cwd),
|
|
142
|
+
base,
|
|
66
143
|
});
|
|
67
144
|
|
|
68
145
|
compilerCache = result;
|
|
69
|
-
console.error(
|
|
70
|
-
"[tailwind] Initialized Tailwind v4 compiler from target project",
|
|
71
|
-
);
|
|
72
146
|
return result;
|
|
73
147
|
}
|
|
74
148
|
|
|
@@ -217,7 +291,21 @@ export class TailwindV4Adapter implements TailwindAdapter {
|
|
|
217
291
|
const css = compiler.build(probeClasses);
|
|
218
292
|
|
|
219
293
|
// --- Colors (extracted from CSS custom properties) ---
|
|
294
|
+
// In v4, --color-* vars are emitted in the base layer for all theme colors,
|
|
295
|
+
// including custom ones from @theme blocks.
|
|
220
296
|
const colorVars = extractVars(css, "color");
|
|
297
|
+
|
|
298
|
+
// Also try building with zero classes to get just the theme layer vars
|
|
299
|
+
// (some custom colors may only appear in the theme layer, not triggered by probes)
|
|
300
|
+
const baseCss = compiler.build([]);
|
|
301
|
+
const baseColorVars = extractVars(baseCss, "color");
|
|
302
|
+
// Merge base vars into colorVars (base vars are the ground truth)
|
|
303
|
+
for (const [name, value] of baseColorVars) {
|
|
304
|
+
if (!colorVars.has(name)) {
|
|
305
|
+
colorVars.set(name, value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
221
309
|
const colors: Record<string, unknown> = {};
|
|
222
310
|
for (const [name, value] of colorVars) {
|
|
223
311
|
const dashIdx = name.lastIndexOf("-");
|
|
@@ -259,19 +347,12 @@ export class TailwindV4Adapter implements TailwindAdapter {
|
|
|
259
347
|
fontWeight,
|
|
260
348
|
borderRadius,
|
|
261
349
|
};
|
|
262
|
-
console.error("[tailwind] v4 resolved theme:", {
|
|
263
|
-
colors: Object.keys(colors).length + " entries",
|
|
264
|
-
spacing: Object.keys(spacing).length + " entries",
|
|
265
|
-
});
|
|
266
350
|
return result;
|
|
267
351
|
}
|
|
268
352
|
|
|
269
353
|
async generateCssForClasses(classes: string[]): Promise<string> {
|
|
270
|
-
console.error(`[tailwind-v4] Generating CSS for classes:`, classes);
|
|
271
354
|
const compiler = await getCompiler();
|
|
272
355
|
const css = compiler.build(classes);
|
|
273
|
-
console.error(`[tailwind-v4] Generated ${css.length} chars`);
|
|
274
|
-
if (css.length < 500) console.error(`[tailwind-v4] Full CSS:`, css);
|
|
275
356
|
return css;
|
|
276
357
|
}
|
|
277
358
|
}
|
package/server/tailwind.ts
CHANGED
|
@@ -32,7 +32,6 @@ async function getAdapter(): Promise<TailwindAdapter> {
|
|
|
32
32
|
const { TailwindV4Adapter } = await import("./tailwind-v4.js");
|
|
33
33
|
adapterCache = new TailwindV4Adapter();
|
|
34
34
|
}
|
|
35
|
-
console.error(`[tailwind] Using Tailwind v${version} adapter`);
|
|
36
35
|
return adapterCache;
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -8,10 +8,8 @@ export const decorators = [
|
|
|
8
8
|
context.parameters?.vybit?.serverUrl ?? 'http://localhost:3333';
|
|
9
9
|
|
|
10
10
|
if (!injected) {
|
|
11
|
-
console.log('[vybit-addon] Injecting overlay script from', serverUrl);
|
|
12
11
|
const script = document.createElement('script');
|
|
13
12
|
script.src = `${serverUrl}/overlay.js`;
|
|
14
|
-
script.onload = () => console.log('[vybit-addon] overlay.js loaded successfully');
|
|
15
13
|
script.onerror = (err) => console.error('[vybit-addon] overlay.js FAILED to load', err);
|
|
16
14
|
document.head.appendChild(script);
|
|
17
15
|
injected = true;
|
|
@@ -8,10 +8,8 @@ export const decorators = [
|
|
|
8
8
|
context.parameters?.vybit?.serverUrl ?? 'http://localhost:3333';
|
|
9
9
|
|
|
10
10
|
if (!injected) {
|
|
11
|
-
console.log('[vybit-addon] Injecting overlay script from', serverUrl);
|
|
12
11
|
const script = document.createElement('script');
|
|
13
12
|
script.src = `${serverUrl}/overlay.js`;
|
|
14
|
-
script.onload = () => console.log('[vybit-addon] overlay.js loaded successfully');
|
|
15
13
|
script.onerror = (err) => console.error('[vybit-addon] overlay.js FAILED to load', err);
|
|
16
14
|
document.head.appendChild(script);
|
|
17
15
|
injected = true;
|