@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.
@@ -16,7 +16,7 @@
16
16
  font-size: 12px;
17
17
  }
18
18
  </style>
19
- <script type="module" crossorigin src="/panel/assets/index-CGc6ZuTL.js"></script>
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);
@@ -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
- console.error("[ghost-cache] Failed to write cache:", err);
78
+ // ignore write errors
79
79
  }
80
80
  }
81
81
 
@@ -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';
@@ -62,13 +62,12 @@ export async function loadStoryArgTypes(
62
62
  result[componentName] = meta.argTypes;
63
63
  }
64
64
  } catch (err) {
65
- console.error(`[storybook] Failed to import ${importPath}:`, err);
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
 
@@ -407,8 +407,24 @@ export class TailwindV3Adapter implements TailwindAdapter {
407
407
  pathToFileURL(req.resolve("tailwindcss/resolveConfig")).href
408
408
  )
409
409
  ).default;
410
- const userConfig = (await import(pathToFileURL(configPath).href))
411
- .default;
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
 
@@ -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
- resolved = req.resolve(id, { paths: [base || cwd] });
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
- const result = await compile('@import "tailwindcss";', {
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
  }
@@ -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;