paintoliver 0.1.0
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/LICENSE +21 -0
- package/README.md +207 -0
- package/dist/analyzer/index.d.ts +20 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +387 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +436 -0
- package/dist/cli.js.map +1 -0
- package/dist/contrast/index.d.ts +88 -0
- package/dist/contrast/index.d.ts.map +1 -0
- package/dist/contrast/index.js +314 -0
- package/dist/contrast/index.js.map +1 -0
- package/dist/paintoliver.bundle.js +14530 -0
- package/dist/reporter/index.d.ts +43 -0
- package/dist/reporter/index.d.ts.map +1 -0
- package/dist/reporter/index.js +235 -0
- package/dist/reporter/index.js.map +1 -0
- package/dist/transformer/css-var-transformer.d.ts +46 -0
- package/dist/transformer/css-var-transformer.d.ts.map +1 -0
- package/dist/transformer/css-var-transformer.js +422 -0
- package/dist/transformer/css-var-transformer.js.map +1 -0
- package/dist/transformer/index.d.ts +17 -0
- package/dist/transformer/index.d.ts.map +1 -0
- package/dist/transformer/index.js +213 -0
- package/dist/transformer/index.js.map +1 -0
- package/dist/transformer/tailwind-transformer.d.ts +47 -0
- package/dist/transformer/tailwind-transformer.d.ts.map +1 -0
- package/dist/transformer/tailwind-transformer.js +402 -0
- package/dist/transformer/tailwind-transformer.js.map +1 -0
- package/dist/utils/backup.d.ts +41 -0
- package/dist/utils/backup.d.ts.map +1 -0
- package/dist/utils/backup.js +125 -0
- package/dist/utils/backup.js.map +1 -0
- package/dist/vibes/definitions/brutalist.d.ts +11 -0
- package/dist/vibes/definitions/brutalist.d.ts.map +1 -0
- package/dist/vibes/definitions/brutalist.js +203 -0
- package/dist/vibes/definitions/brutalist.js.map +1 -0
- package/dist/vibes/definitions/corporate.d.ts +12 -0
- package/dist/vibes/definitions/corporate.d.ts.map +1 -0
- package/dist/vibes/definitions/corporate.js +212 -0
- package/dist/vibes/definitions/corporate.js.map +1 -0
- package/dist/vibes/definitions/glassmorphism.d.ts +20 -0
- package/dist/vibes/definitions/glassmorphism.d.ts.map +1 -0
- package/dist/vibes/definitions/glassmorphism.js +217 -0
- package/dist/vibes/definitions/glassmorphism.js.map +1 -0
- package/dist/vibes/definitions/kinetic-terminal.d.ts +20 -0
- package/dist/vibes/definitions/kinetic-terminal.d.ts.map +1 -0
- package/dist/vibes/definitions/kinetic-terminal.js +242 -0
- package/dist/vibes/definitions/kinetic-terminal.js.map +1 -0
- package/dist/vibes/definitions/minimal.d.ts +11 -0
- package/dist/vibes/definitions/minimal.d.ts.map +1 -0
- package/dist/vibes/definitions/minimal.js +167 -0
- package/dist/vibes/definitions/minimal.js.map +1 -0
- package/dist/vibes/definitions/windows-xp.d.ts +12 -0
- package/dist/vibes/definitions/windows-xp.d.ts.map +1 -0
- package/dist/vibes/definitions/windows-xp.js +229 -0
- package/dist/vibes/definitions/windows-xp.js.map +1 -0
- package/dist/vibes/registry.d.ts +25 -0
- package/dist/vibes/registry.d.ts.map +1 -0
- package/dist/vibes/registry.js +52 -0
- package/dist/vibes/registry.js.map +1 -0
- package/dist/vibes/types.d.ts +428 -0
- package/dist/vibes/types.d.ts.map +1 -0
- package/dist/vibes/types.js +12 -0
- package/dist/vibes/types.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sakshya Sharma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# FrontEnd Agent
|
|
2
|
+
|
|
3
|
+
> Apply consistent visual vibes to front-end codebases — safely, predictably, and in seconds.
|
|
4
|
+
|
|
5
|
+
FrontEnd Agent transforms the visual styling of an existing project to match a selected design "vibe" — without touching business logic, component structure, or application behavior.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g paintoliver
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# See what's available
|
|
21
|
+
paintoliver list
|
|
22
|
+
|
|
23
|
+
# Preview changes without writing anything (always a good first step)
|
|
24
|
+
paintoliver apply minimal ./your-project --dry-run
|
|
25
|
+
|
|
26
|
+
# Apply a vibe
|
|
27
|
+
paintoliver apply kinetic-terminal ./your-project
|
|
28
|
+
|
|
29
|
+
# Didn't like it? Restore the backup that was created automatically
|
|
30
|
+
paintoliver restore ./your-project
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What is a Vibe?
|
|
36
|
+
|
|
37
|
+
A vibe is a fully portable definition of a visual language: colors, typography, spacing, border radius, shadows, and motion — structured as data, not instructions. Every vibe ships with both light and dark mode variants. The same vibe applied to the same project always produces the same result.
|
|
38
|
+
|
|
39
|
+
**Built-in vibes:**
|
|
40
|
+
|
|
41
|
+
| Vibe | Character | Base mode |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `kinetic-terminal` | High-contrast cyberpunk. Cyan/magenta on near-black. Neon glow. | Dark |
|
|
44
|
+
| `minimal` | Maximum whitespace. Barely-there borders. Swiss typography. | Light |
|
|
45
|
+
| `brutalist` | Black borders. Heavy type. Zero decoration. Raw structure. | Light |
|
|
46
|
+
| `corporate` | Electric blue. Precise grid. Trustworthy and legible. | Light |
|
|
47
|
+
| `glassmorphism` | Frosted glass surfaces. Violet gradients. Translucent layers. | Dark |
|
|
48
|
+
| `windows-xp` | Skeuomorphic chrome. Gradients and bevels. Warm cream surfaces. | Light |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
### `apply`
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
paintoliver apply <vibe> [path]
|
|
58
|
+
paintoliver apply [path] # prompts for vibe if omitted
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Flag | Default | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `--dry-run` | off | Preview all changes without writing any files |
|
|
64
|
+
| `--backup` | on | Create a timestamped backup before modifying |
|
|
65
|
+
| `--no-backup` | — | Skip backup creation |
|
|
66
|
+
| `--watch` | off | Re-apply automatically when CSS files change |
|
|
67
|
+
| `--fix-contrast` | off | Auto-fix any WCAG AA contrast failures |
|
|
68
|
+
| `--no-contrast` | off | Skip contrast checking entirely |
|
|
69
|
+
| `--fonts` | off | Inject a Google Fonts `@import` for the vibe's typefaces |
|
|
70
|
+
| `--verbose` | off | Show before/after values for every change |
|
|
71
|
+
| `--report <path>` | — | Write a machine-readable JSON report |
|
|
72
|
+
|
|
73
|
+
### `analyze`
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
paintoliver analyze [path]
|
|
77
|
+
paintoliver analyze [path] --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Scans a project and reports its styling system, detected CSS variables, entry points, and theme mode. Read-only — no files are modified.
|
|
81
|
+
|
|
82
|
+
### `list`
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
paintoliver list
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Lists all available vibes with descriptions and tags.
|
|
89
|
+
|
|
90
|
+
### `list-backups`
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
paintoliver list-backups [path]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Shows all backups for a project with timestamps and ages.
|
|
97
|
+
|
|
98
|
+
### `restore`
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
paintoliver restore [path]
|
|
102
|
+
paintoliver restore [path] --backup-id 2026-04-08T12-00-00
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Restores files from the most recent backup, or a specific one by ID.
|
|
106
|
+
|
|
107
|
+
### `clear-overrides`
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
paintoliver clear-overrides [path]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Removes any persisted contrast overrides from `.paintoliver.json`, reverting to the vibe's original colors on the next apply.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## How It Works
|
|
118
|
+
|
|
119
|
+
### 1. Analyze
|
|
120
|
+
Scans the project to detect the styling system (Tailwind v3/v4, CSS modules, SCSS, plain CSS), find CSS entry points, extract custom property names, and detect the project's theme mode.
|
|
121
|
+
|
|
122
|
+
### 2. Backup
|
|
123
|
+
Copies every file that will be modified into `.paintoliver-backup/<timestamp>/` before any writes happen.
|
|
124
|
+
|
|
125
|
+
### 3. Transform
|
|
126
|
+
- **Tailwind projects** — updates `tailwind.config.js` color/font/radius sections or injects a `@theme` block (v4)
|
|
127
|
+
- **CSS/SCSS files** — rewrites custom property values that map to semantic vibe tokens, correctly handling separate dark-mode and light-mode selector blocks
|
|
128
|
+
- **Token-less projects** — injects a complete token block into the primary CSS entry point, including base, `@media (prefers-color-scheme)`, and `.dark/.light` class selector blocks
|
|
129
|
+
|
|
130
|
+
### 4. Contrast check
|
|
131
|
+
After transformation, runs WCAG 2.2 AA checks on the applied palette (4.5:1 for text, 3.0:1 for UI components). Failures can be auto-fixed or reviewed interactively. Fixes are saved to `.paintoliver.json` and reapplied on every subsequent run.
|
|
132
|
+
|
|
133
|
+
### 5. Report
|
|
134
|
+
Every change is printed with a confidence indicator. Low-confidence rewrites are flagged for review. A full JSON report can be written for code review.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Safety
|
|
139
|
+
|
|
140
|
+
- **Backups by default** — a timestamped copy of all modified files is saved before any writes
|
|
141
|
+
- **Dry run mode** — preview every change before it happens
|
|
142
|
+
- **Confidence scoring** — CSS variables that can't be confidently mapped to a semantic token are left untouched
|
|
143
|
+
- **No deletions** — no files, variables, or classes are ever removed
|
|
144
|
+
- **Fails safely** — files that can't be processed confidently are skipped and reported, not errored
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Dark and Light Mode
|
|
149
|
+
|
|
150
|
+
Every vibe defines a base mode and an override for the opposite mode. When a token block is injected into a project, three blocks are written:
|
|
151
|
+
|
|
152
|
+
```css
|
|
153
|
+
/* Base (default mode) */
|
|
154
|
+
:root { --primary: #00F0FF; ... }
|
|
155
|
+
|
|
156
|
+
/* System preference */
|
|
157
|
+
@media (prefers-color-scheme: light) {
|
|
158
|
+
:root:not(.dark):not([data-theme="dark"]) { --primary: #008A96; ... }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* Explicit class (Next.js next-themes, Tailwind darkMode: 'class', etc.) */
|
|
162
|
+
.light, [data-theme="light"] { --primary: #008A96; ... }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Only tokens that differ between modes are listed in the override blocks — everything else inherits from `:root`.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Watch Mode
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
paintoliver apply kinetic-terminal ./your-app --watch
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Watches for changes to CSS and config files and re-applies the vibe automatically with a 350ms debounce. Useful during active design iteration. No backup is created on re-applies.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Adding a Custom Vibe
|
|
180
|
+
|
|
181
|
+
1. Create `src/vibes/definitions/my-vibe.ts` exporting a `Vibe` object
|
|
182
|
+
2. Add its ID to the `VibeId` union in `src/vibes/types.ts`
|
|
183
|
+
3. Import and register it in `src/vibes/registry.ts`
|
|
184
|
+
|
|
185
|
+
That's it. The CLI, analyzer, transformer, and reporter pick it up automatically.
|
|
186
|
+
|
|
187
|
+
Refer to any existing vibe in `src/vibes/definitions/` as a template, and `src/vibes/types.ts` for the full interface.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Supported Projects
|
|
192
|
+
|
|
193
|
+
| Stack | Support |
|
|
194
|
+
|---|---|
|
|
195
|
+
| React + Tailwind v4 | Full |
|
|
196
|
+
| React + Tailwind v3 | Full |
|
|
197
|
+
| React + CSS Modules | CSS custom properties |
|
|
198
|
+
| React + plain CSS/SCSS | CSS custom properties |
|
|
199
|
+
| Next.js | Full (same as React above) |
|
|
200
|
+
| Vue / Svelte | CSS-level transforms only |
|
|
201
|
+
| styled-components / Emotion | CSS custom properties only |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Requirements
|
|
206
|
+
|
|
207
|
+
- Node.js ≥ 18
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Inspects a front-end project directory and produces a ProjectAnalysis:
|
|
5
|
+
* a structured description of what styling system is in use, which files
|
|
6
|
+
* are relevant to visual styling, and what design tokens already exist.
|
|
7
|
+
*
|
|
8
|
+
* The analyzer is conservative — it only reports what it can confirm.
|
|
9
|
+
* If it cannot determine something, it leaves the field as "unknown"
|
|
10
|
+
* rather than guessing.
|
|
11
|
+
*/
|
|
12
|
+
import type { ProjectAnalysis } from "../vibes/types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Analyze a project directory and return a structured ProjectAnalysis.
|
|
15
|
+
*
|
|
16
|
+
* This is the entry point for all project inspection work.
|
|
17
|
+
* The analysis is read-only — no files are modified.
|
|
18
|
+
*/
|
|
19
|
+
export declare function analyzeProject(rootPath: string, exclude?: string[]): Promise<ProjectAnalysis>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,mBAAmB,CAAC;AAqZ3B;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAM,EAAO,GACrB,OAAO,CAAC,eAAe,CAAC,CAqC1B"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Inspects a front-end project directory and produces a ProjectAnalysis:
|
|
5
|
+
* a structured description of what styling system is in use, which files
|
|
6
|
+
* are relevant to visual styling, and what design tokens already exist.
|
|
7
|
+
*
|
|
8
|
+
* The analyzer is conservative — it only reports what it can confirm.
|
|
9
|
+
* If it cannot determine something, it leaves the field as "unknown"
|
|
10
|
+
* rather than guessing.
|
|
11
|
+
*/
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import { glob } from "fast-glob";
|
|
15
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
16
|
+
const CSS_CUSTOM_PROP_RE = /--[\w-]+(?=\s*:)/g;
|
|
17
|
+
const TAILWIND_CLASS_TOKENS = /class(?:Name)?=["'`]([^"'`]+)["'`]/g;
|
|
18
|
+
const TAILWIND_CN_CALL = /cn\(([^)]+)\)/g;
|
|
19
|
+
// Files and directories the analyzer should always skip
|
|
20
|
+
const ALWAYS_EXCLUDE = [
|
|
21
|
+
"**/node_modules/**",
|
|
22
|
+
"**/.git/**",
|
|
23
|
+
"**/dist/**",
|
|
24
|
+
"**/build/**",
|
|
25
|
+
"**/.next/**",
|
|
26
|
+
"**/.nuxt/**",
|
|
27
|
+
"**/out/**",
|
|
28
|
+
"**/.cache/**",
|
|
29
|
+
"**/coverage/**",
|
|
30
|
+
"**/*.min.css",
|
|
31
|
+
"**/*.min.js",
|
|
32
|
+
];
|
|
33
|
+
// ─── Framework Detection ──────────────────────────────────────────────────────
|
|
34
|
+
function detectFramework(rootPath) {
|
|
35
|
+
const pkg = readJsonSafe(path.join(rootPath, "package.json"));
|
|
36
|
+
if (!pkg)
|
|
37
|
+
return "unknown";
|
|
38
|
+
const deps = {
|
|
39
|
+
...(pkg.dependencies ?? {}),
|
|
40
|
+
...(pkg.devDependencies ?? {}),
|
|
41
|
+
};
|
|
42
|
+
if ("next" in deps)
|
|
43
|
+
return "next";
|
|
44
|
+
if ("@angular/core" in deps)
|
|
45
|
+
return "angular";
|
|
46
|
+
if ("svelte" in deps)
|
|
47
|
+
return "svelte";
|
|
48
|
+
if ("vue" in deps)
|
|
49
|
+
return "vue";
|
|
50
|
+
if ("react" in deps && "vite" in deps)
|
|
51
|
+
return "vite-react";
|
|
52
|
+
if ("react" in deps)
|
|
53
|
+
return "react";
|
|
54
|
+
// Check for plain HTML (no package.json deps or index.html at root)
|
|
55
|
+
if (fs.existsSync(path.join(rootPath, "index.html")))
|
|
56
|
+
return "plain-html";
|
|
57
|
+
return "unknown";
|
|
58
|
+
}
|
|
59
|
+
// ─── Styling System Detection ─────────────────────────────────────────────────
|
|
60
|
+
function detectStylingSystem(rootPath) {
|
|
61
|
+
const pkg = readJsonSafe(path.join(rootPath, "package.json"));
|
|
62
|
+
const deps = pkg
|
|
63
|
+
? {
|
|
64
|
+
...(pkg.dependencies ?? {}),
|
|
65
|
+
...(pkg.devDependencies ?? {}),
|
|
66
|
+
}
|
|
67
|
+
: {};
|
|
68
|
+
// Check for CSS-in-JS
|
|
69
|
+
if ("@emotion/react" in deps || "@emotion/styled" in deps)
|
|
70
|
+
return { system: "emotion" };
|
|
71
|
+
if ("styled-components" in deps)
|
|
72
|
+
return { system: "styled-components" };
|
|
73
|
+
if ("@vanilla-extract/css" in deps)
|
|
74
|
+
return { system: "vanilla-extract" };
|
|
75
|
+
// Check for Tailwind
|
|
76
|
+
const tailwindVersion = deps["tailwindcss"];
|
|
77
|
+
if (tailwindVersion) {
|
|
78
|
+
const configPath = findTailwindConfig(rootPath);
|
|
79
|
+
const isV4 = tailwindVersion.startsWith("^4") || tailwindVersion.startsWith("4");
|
|
80
|
+
return {
|
|
81
|
+
system: isV4 ? "tailwind-v4" : "tailwind-v3",
|
|
82
|
+
tailwindConfigPath: configPath ?? undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Check for SCSS/Sass
|
|
86
|
+
if ("sass" in deps || "node-sass" in deps) {
|
|
87
|
+
return { system: hasSassFiles(rootPath, "scss") ? "scss" : "sass" };
|
|
88
|
+
}
|
|
89
|
+
// CSS Modules — detected by file pattern, not deps
|
|
90
|
+
if (hasCSSModuleFiles(rootPath))
|
|
91
|
+
return { system: "css-modules" };
|
|
92
|
+
// Plain CSS fallback
|
|
93
|
+
return { system: "plain-css" };
|
|
94
|
+
}
|
|
95
|
+
function findTailwindConfig(rootPath) {
|
|
96
|
+
const candidates = [
|
|
97
|
+
"tailwind.config.js",
|
|
98
|
+
"tailwind.config.ts",
|
|
99
|
+
"tailwind.config.mjs",
|
|
100
|
+
"tailwind.config.cjs",
|
|
101
|
+
];
|
|
102
|
+
for (const c of candidates) {
|
|
103
|
+
const full = path.join(rootPath, c);
|
|
104
|
+
if (fs.existsSync(full))
|
|
105
|
+
return full;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function hasSassFiles(rootPath, ext) {
|
|
110
|
+
try {
|
|
111
|
+
const files = glob.sync(`**/*.${ext}`, {
|
|
112
|
+
cwd: rootPath,
|
|
113
|
+
ignore: ALWAYS_EXCLUDE,
|
|
114
|
+
absolute: false,
|
|
115
|
+
});
|
|
116
|
+
return files.length > 0;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function hasCSSModuleFiles(rootPath) {
|
|
123
|
+
try {
|
|
124
|
+
const files = glob.sync("**/*.module.css", {
|
|
125
|
+
cwd: rootPath,
|
|
126
|
+
ignore: ALWAYS_EXCLUDE,
|
|
127
|
+
absolute: false,
|
|
128
|
+
});
|
|
129
|
+
return files.length > 0;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ─── File Discovery ───────────────────────────────────────────────────────────
|
|
136
|
+
async function discoverRelevantFiles(rootPath, exclude) {
|
|
137
|
+
const ignore = [...ALWAYS_EXCLUDE, ...exclude];
|
|
138
|
+
const detectedFiles = [];
|
|
139
|
+
// CSS-family files
|
|
140
|
+
const cssFiles = await glob(["**/*.css", "**/*.scss", "**/*.sass"], {
|
|
141
|
+
cwd: rootPath,
|
|
142
|
+
ignore,
|
|
143
|
+
absolute: true,
|
|
144
|
+
stats: true,
|
|
145
|
+
});
|
|
146
|
+
for (const entry of cssFiles) {
|
|
147
|
+
const filePath = entry.path;
|
|
148
|
+
const relativePath = path.relative(rootPath, filePath);
|
|
149
|
+
const ext = path.extname(filePath).slice(1);
|
|
150
|
+
const isModule = relativePath.includes(".module.");
|
|
151
|
+
const isEntry = relativePath.includes("global") ||
|
|
152
|
+
relativePath.includes("index") ||
|
|
153
|
+
relativePath.includes("main") ||
|
|
154
|
+
relativePath.includes("app") ||
|
|
155
|
+
relativePath.includes("base") ||
|
|
156
|
+
relativePath.includes("reset");
|
|
157
|
+
const content = readFileSafe(filePath);
|
|
158
|
+
const cssCustomProperties = content
|
|
159
|
+
? Array.from(new Set(content.match(CSS_CUSTOM_PROP_RE) ?? []))
|
|
160
|
+
: [];
|
|
161
|
+
const stat = entry.stats ?? fs.statSync(filePath);
|
|
162
|
+
detectedFiles.push({
|
|
163
|
+
path: filePath,
|
|
164
|
+
relativePath,
|
|
165
|
+
type: isModule ? "css" : ext === "css" ? "css" : ext,
|
|
166
|
+
isEntryPoint: isEntry && !isModule,
|
|
167
|
+
cssCustomProperties,
|
|
168
|
+
sizeBytes: stat.size,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// Tailwind config files
|
|
172
|
+
const tailwindConfigs = await glob(["tailwind.config.{js,ts,mjs,cjs}", "postcss.config.{js,ts,mjs,cjs}"], { cwd: rootPath, ignore, absolute: true });
|
|
173
|
+
for (const filePath of tailwindConfigs) {
|
|
174
|
+
const stat = fs.statSync(filePath);
|
|
175
|
+
detectedFiles.push({
|
|
176
|
+
path: filePath,
|
|
177
|
+
relativePath: path.relative(rootPath, filePath),
|
|
178
|
+
type: "tailwind-config",
|
|
179
|
+
isEntryPoint: true,
|
|
180
|
+
sizeBytes: stat.size,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// Component files (React/Vue/Svelte)
|
|
184
|
+
const componentFiles = await glob(["**/*.{tsx,jsx,vue,svelte}", "**/*.{ts,js}"], {
|
|
185
|
+
cwd: rootPath,
|
|
186
|
+
ignore: [
|
|
187
|
+
...ignore,
|
|
188
|
+
"**/*.test.*",
|
|
189
|
+
"**/*.spec.*",
|
|
190
|
+
"**/*.stories.*",
|
|
191
|
+
"**/*.d.ts",
|
|
192
|
+
"**/vite.config.*",
|
|
193
|
+
"**/next.config.*",
|
|
194
|
+
"**/webpack.config.*",
|
|
195
|
+
],
|
|
196
|
+
absolute: true,
|
|
197
|
+
stats: true,
|
|
198
|
+
});
|
|
199
|
+
for (const entry of componentFiles) {
|
|
200
|
+
// stats:true returns Entry objects — pull the plain path string out
|
|
201
|
+
const filePath = entry.path;
|
|
202
|
+
const relativePath = path.relative(rootPath, filePath);
|
|
203
|
+
const stat = entry.stats ?? fs.statSync(filePath);
|
|
204
|
+
if (stat.size > 200_000)
|
|
205
|
+
continue;
|
|
206
|
+
const content = readFileSafe(filePath);
|
|
207
|
+
if (!content)
|
|
208
|
+
continue;
|
|
209
|
+
// Only include if it contains className/class references
|
|
210
|
+
const hasStyling = content.includes("className") ||
|
|
211
|
+
content.includes(' class=') ||
|
|
212
|
+
content.includes("styles.") ||
|
|
213
|
+
content.includes("css`") ||
|
|
214
|
+
content.includes("styled.");
|
|
215
|
+
if (!hasStyling)
|
|
216
|
+
continue;
|
|
217
|
+
const tailwindClasses = extractTailwindClasses(content);
|
|
218
|
+
detectedFiles.push({
|
|
219
|
+
path: filePath,
|
|
220
|
+
relativePath,
|
|
221
|
+
type: "component",
|
|
222
|
+
isEntryPoint: false,
|
|
223
|
+
tailwindClasses,
|
|
224
|
+
sizeBytes: stat.size,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return detectedFiles;
|
|
228
|
+
}
|
|
229
|
+
function extractTailwindClasses(content) {
|
|
230
|
+
const classes = new Set();
|
|
231
|
+
// Match className="..." and class="..."
|
|
232
|
+
let match;
|
|
233
|
+
const classRe = new RegExp(TAILWIND_CLASS_TOKENS.source, "g");
|
|
234
|
+
while ((match = classRe.exec(content)) !== null) {
|
|
235
|
+
const raw = match[1];
|
|
236
|
+
for (const cls of raw.split(/\s+/)) {
|
|
237
|
+
if (cls)
|
|
238
|
+
classes.add(cls);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Match cn(...) calls
|
|
242
|
+
const cnRe = new RegExp(TAILWIND_CN_CALL.source, "g");
|
|
243
|
+
while ((match = cnRe.exec(content)) !== null) {
|
|
244
|
+
const raw = match[1];
|
|
245
|
+
// Extract quoted strings inside cn()
|
|
246
|
+
const quoted = raw.match(/"([^"]+)"|'([^']+)'/g) ?? [];
|
|
247
|
+
for (const q of quoted) {
|
|
248
|
+
const inner = q.slice(1, -1);
|
|
249
|
+
for (const cls of inner.split(/\s+/)) {
|
|
250
|
+
if (cls)
|
|
251
|
+
classes.add(cls);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return Array.from(classes);
|
|
256
|
+
}
|
|
257
|
+
// ─── CSS Entry Point Detection ────────────────────────────────────────────────
|
|
258
|
+
function findCSSEntryPoints(files) {
|
|
259
|
+
return files
|
|
260
|
+
.filter((f) => (f.type === "css" || f.type === "scss" || f.type === "sass") && f.isEntryPoint)
|
|
261
|
+
.map((f) => f.path);
|
|
262
|
+
}
|
|
263
|
+
// ─── CSS Custom Property Aggregation ─────────────────────────────────────────
|
|
264
|
+
function aggregateCSSVars(files) {
|
|
265
|
+
const all = new Set();
|
|
266
|
+
for (const f of files) {
|
|
267
|
+
for (const v of f.cssCustomProperties ?? []) {
|
|
268
|
+
all.add(v);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return Array.from(all).sort();
|
|
272
|
+
}
|
|
273
|
+
// ─── Theme Mode Detection ─────────────────────────────────────────────────────
|
|
274
|
+
function detectThemeMode(files) {
|
|
275
|
+
let hasLight = false;
|
|
276
|
+
let hasDark = false;
|
|
277
|
+
for (const f of files) {
|
|
278
|
+
if (f.type !== "css" && f.type !== "scss" && f.type !== "sass")
|
|
279
|
+
continue;
|
|
280
|
+
const content = readFileSafe(f.path) ?? "";
|
|
281
|
+
if (content.includes("prefers-color-scheme: dark") || content.includes(".dark ")) {
|
|
282
|
+
hasDark = true;
|
|
283
|
+
}
|
|
284
|
+
if (content.includes("prefers-color-scheme: light") || content.includes(".light ")) {
|
|
285
|
+
hasLight = true;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (hasLight && hasDark)
|
|
289
|
+
return "both";
|
|
290
|
+
if (hasDark)
|
|
291
|
+
return "dark";
|
|
292
|
+
return "light";
|
|
293
|
+
}
|
|
294
|
+
// ─── Token File Detection ─────────────────────────────────────────────────────
|
|
295
|
+
function detectTokenFile(files) {
|
|
296
|
+
return files.some((f) => {
|
|
297
|
+
const name = path.basename(f.path).toLowerCase();
|
|
298
|
+
return (name.includes("token") ||
|
|
299
|
+
name.includes("variable") ||
|
|
300
|
+
name.includes("design-system") ||
|
|
301
|
+
name.includes("theme"));
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// ─── Warnings ─────────────────────────────────────────────────────────────────
|
|
305
|
+
function buildWarnings(stylingSystem, framework, files) {
|
|
306
|
+
const warnings = [];
|
|
307
|
+
if (stylingSystem === "styled-components") {
|
|
308
|
+
warnings.push("styled-components detected: CSS-in-JS transforms are limited. " +
|
|
309
|
+
"The agent will update CSS custom properties but cannot rewrite styled() templates.");
|
|
310
|
+
}
|
|
311
|
+
if (stylingSystem === "emotion") {
|
|
312
|
+
warnings.push("Emotion detected: CSS-in-JS transforms are limited. " +
|
|
313
|
+
"The agent will update CSS custom properties where possible.");
|
|
314
|
+
}
|
|
315
|
+
if (stylingSystem === "vanilla-extract") {
|
|
316
|
+
warnings.push("vanilla-extract detected: transforms will target generated CSS output files only.");
|
|
317
|
+
}
|
|
318
|
+
if (framework === "unknown") {
|
|
319
|
+
warnings.push("Framework could not be determined. The agent will operate in generic CSS mode.");
|
|
320
|
+
}
|
|
321
|
+
if (stylingSystem === "unknown") {
|
|
322
|
+
warnings.push("Styling system could not be determined. The agent will scan for CSS files only.");
|
|
323
|
+
}
|
|
324
|
+
const largeFiles = files.filter((f) => f.sizeBytes > 100_000);
|
|
325
|
+
if (largeFiles.length > 0) {
|
|
326
|
+
warnings.push(`${largeFiles.length} large file(s) detected (>100KB). ` +
|
|
327
|
+
"These will be analyzed but changes will be conservative.");
|
|
328
|
+
}
|
|
329
|
+
return warnings;
|
|
330
|
+
}
|
|
331
|
+
// ─── Utilities ─────────────────────────────────────────────────────────────────
|
|
332
|
+
function readFileSafe(filePath) {
|
|
333
|
+
try {
|
|
334
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function readJsonSafe(filePath) {
|
|
341
|
+
try {
|
|
342
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
349
|
+
/**
|
|
350
|
+
* Analyze a project directory and return a structured ProjectAnalysis.
|
|
351
|
+
*
|
|
352
|
+
* This is the entry point for all project inspection work.
|
|
353
|
+
* The analysis is read-only — no files are modified.
|
|
354
|
+
*/
|
|
355
|
+
export async function analyzeProject(rootPath, exclude = []) {
|
|
356
|
+
if (!fs.existsSync(rootPath)) {
|
|
357
|
+
throw new Error(`Project root does not exist: ${rootPath}`);
|
|
358
|
+
}
|
|
359
|
+
const resolvedRoot = path.resolve(rootPath);
|
|
360
|
+
// Parallel detection — these don't depend on each other
|
|
361
|
+
const [framework, stylingDetection] = await Promise.all([
|
|
362
|
+
Promise.resolve(detectFramework(resolvedRoot)),
|
|
363
|
+
Promise.resolve(detectStylingSystem(resolvedRoot)),
|
|
364
|
+
]);
|
|
365
|
+
const { system: stylingSystem, tailwindConfigPath } = stylingDetection;
|
|
366
|
+
// File discovery — needs styling system to be known first
|
|
367
|
+
const relevantFiles = await discoverRelevantFiles(resolvedRoot, exclude);
|
|
368
|
+
const cssEntryPoints = findCSSEntryPoints(relevantFiles);
|
|
369
|
+
const detectedCSSVars = aggregateCSSVars(relevantFiles);
|
|
370
|
+
const themeMode = detectThemeMode(relevantFiles);
|
|
371
|
+
const hasTokenFile = detectTokenFile(relevantFiles);
|
|
372
|
+
const warnings = buildWarnings(stylingSystem, framework, relevantFiles);
|
|
373
|
+
return {
|
|
374
|
+
rootPath: resolvedRoot,
|
|
375
|
+
framework,
|
|
376
|
+
stylingSystem,
|
|
377
|
+
relevantFiles,
|
|
378
|
+
detectedCSSVars,
|
|
379
|
+
tailwindConfigPath: tailwindConfigPath ?? undefined,
|
|
380
|
+
cssEntryPoints,
|
|
381
|
+
hasTokenFile,
|
|
382
|
+
themeMode,
|
|
383
|
+
warnings,
|
|
384
|
+
analyzedAt: new Date().toISOString(),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"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"}
|