@matteoaliano/forest-ui 0.2.0 → 0.2.2
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/bin/sync.mjs +83 -42
- package/dist/chunk-C3OBHPIS.mjs +1806 -0
- package/dist/chunk-C3OBHPIS.mjs.map +1 -0
- package/dist/index-BHSAMOHR.d.mts +525 -0
- package/dist/index-BHSAMOHR.d.ts +525 -0
- package/dist/index.d.mts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +1539 -980
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -8
- package/dist/index.mjs.map +1 -1
- package/dist/theme.d.mts +2 -1
- package/dist/theme.d.ts +2 -1
- package/dist/theme.js +1499 -976
- package/dist/theme.js.map +1 -1
- package/dist/theme.mjs +1 -1
- package/{FOREST_AI_GUIDELINES.md → guidelines/FOREST_AI_GUIDELINES.md} +60 -8
- package/guidelines/FOREST_DEV_GUIDELINES.md +14 -0
- package/guidelines/themes/FOREST_THEME_DEFAULT.md +14 -0
- package/package.json +5 -2
- package/dist/chunk-2HGULC2Q.mjs +0 -1302
- package/dist/chunk-2HGULC2Q.mjs.map +0 -1
- package/dist/index-CSXrXG9V.d.mts +0 -233
- package/dist/index-CSXrXG9V.d.ts +0 -233
package/bin/sync.mjs
CHANGED
|
@@ -3,38 +3,72 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* forest-ui sync
|
|
5
5
|
*
|
|
6
|
-
* Copies
|
|
6
|
+
* Copies guideline files into the AI-tool config directories
|
|
7
7
|
* of the consuming project so coding assistants automatically follow
|
|
8
8
|
* Forest UI conventions.
|
|
9
9
|
*
|
|
10
10
|
* Supported targets:
|
|
11
|
-
* .claude
|
|
12
|
-
* .cursor/rules
|
|
11
|
+
* .claude/<name>.md — Claude Code
|
|
12
|
+
* .cursor/rules/<name>.mdc — Cursor
|
|
13
|
+
*
|
|
14
|
+
* Guideline categories:
|
|
15
|
+
* - FOREST_AI_GUIDELINES.md — Design system components, tokens, patterns
|
|
16
|
+
* - FOREST_DEV_GUIDELINES.md — Development best practices
|
|
17
|
+
* - themes/FOREST_THEME_<NAME>.md — Theme-specific guidelines (auto-discovered)
|
|
13
18
|
*/
|
|
14
19
|
|
|
15
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
16
|
-
import { resolve, dirname } from "node:path";
|
|
20
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync } from "node:fs";
|
|
21
|
+
import { resolve, dirname, basename } from "node:path";
|
|
17
22
|
import { fileURLToPath } from "node:url";
|
|
18
23
|
|
|
19
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
25
|
const __dirname = dirname(__filename);
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
const
|
|
27
|
+
const guidelinesDir = resolve(__dirname, "..", "guidelines");
|
|
28
|
+
const themesDir = resolve(guidelinesDir, "themes");
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
// Static guideline entries
|
|
31
|
+
const staticEntries = [
|
|
32
|
+
{
|
|
33
|
+
source: resolve(guidelinesDir, "FOREST_AI_GUIDELINES.md"),
|
|
34
|
+
claudeName: "forest-ui.md",
|
|
35
|
+
cursorName: "forest-ui.mdc",
|
|
36
|
+
cursorDescription: "Forest UI Design System guidelines — components, tokens, and patterns",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
source: resolve(guidelinesDir, "FOREST_DEV_GUIDELINES.md"),
|
|
40
|
+
claudeName: "forest-dev.md",
|
|
41
|
+
cursorName: "forest-dev.mdc",
|
|
42
|
+
cursorDescription: "Forest UI development best practices",
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
// Auto-discover theme files from guidelines/themes/
|
|
47
|
+
function discoverThemeEntries() {
|
|
48
|
+
if (!existsSync(themesDir)) return [];
|
|
49
|
+
|
|
50
|
+
return readdirSync(themesDir)
|
|
51
|
+
.filter((f) => /^FOREST_THEME_\w+\.md$/.test(f))
|
|
52
|
+
.map((f) => {
|
|
53
|
+
const themeName = f
|
|
54
|
+
.replace(/^FOREST_THEME_/, "")
|
|
55
|
+
.replace(/\.md$/, "")
|
|
56
|
+
.toLowerCase();
|
|
29
57
|
|
|
30
|
-
|
|
58
|
+
return {
|
|
59
|
+
source: resolve(themesDir, f),
|
|
60
|
+
claudeName: `forest-theme-${themeName}.md`,
|
|
61
|
+
cursorName: `forest-theme-${themeName}.mdc`,
|
|
62
|
+
cursorDescription: `Forest UI theme guidelines — ${themeName}`,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
31
66
|
|
|
32
67
|
// Find the consuming project root (walk up until we find package.json)
|
|
33
68
|
function findProjectRoot(startDir) {
|
|
34
69
|
let dir = startDir;
|
|
35
70
|
while (dir !== dirname(dir)) {
|
|
36
71
|
if (existsSync(resolve(dir, "package.json"))) {
|
|
37
|
-
// Skip if this is the forest-ui package itself
|
|
38
72
|
try {
|
|
39
73
|
const pkg = JSON.parse(readFileSync(resolve(dir, "package.json"), "utf-8"));
|
|
40
74
|
if (pkg.name !== "@matteoaliano/forest-ui") return dir;
|
|
@@ -48,44 +82,51 @@ function findProjectRoot(startDir) {
|
|
|
48
82
|
}
|
|
49
83
|
|
|
50
84
|
const projectRoot = findProjectRoot(process.cwd());
|
|
51
|
-
|
|
52
|
-
// Define sync targets
|
|
53
|
-
const targets = [
|
|
54
|
-
{
|
|
55
|
-
name: "Claude Code",
|
|
56
|
-
dir: resolve(projectRoot, ".claude"),
|
|
57
|
-
file: "forest-ui.md",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: "Cursor",
|
|
61
|
-
dir: resolve(projectRoot, ".cursor", "rules"),
|
|
62
|
-
file: "forest-ui.mdc",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
85
|
+
const entries = [...staticEntries, ...discoverThemeEntries()];
|
|
65
86
|
|
|
66
87
|
console.log(`\n🌲 Forest UI — Syncing AI guidelines\n`);
|
|
67
|
-
console.log(` Project root: ${projectRoot}
|
|
88
|
+
console.log(` Project root: ${projectRoot}`);
|
|
89
|
+
console.log(` Found ${entries.length} guideline file(s)\n`);
|
|
68
90
|
|
|
69
91
|
let synced = 0;
|
|
92
|
+
let total = 0;
|
|
93
|
+
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
if (!existsSync(entry.source)) {
|
|
96
|
+
console.log(` ⚠️ ${basename(entry.source)} — not found, skipping`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
70
99
|
|
|
71
|
-
|
|
100
|
+
const content = readFileSync(entry.source, "utf-8");
|
|
101
|
+
|
|
102
|
+
// Claude Code target
|
|
103
|
+
const claudeDir = resolve(projectRoot, ".claude");
|
|
104
|
+
const claudePath = resolve(claudeDir, entry.claudeName);
|
|
105
|
+
total++;
|
|
72
106
|
try {
|
|
73
|
-
mkdirSync(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
guidelines;
|
|
81
|
-
}
|
|
107
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
108
|
+
writeFileSync(claudePath, content, "utf-8");
|
|
109
|
+
console.log(` ✅ Claude Code → .claude/${entry.claudeName}`);
|
|
110
|
+
synced++;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.log(` ⚠️ Claude Code — .claude/${entry.claudeName} skipped (${err.message})`);
|
|
113
|
+
}
|
|
82
114
|
|
|
83
|
-
|
|
84
|
-
|
|
115
|
+
// Cursor target
|
|
116
|
+
const cursorDir = resolve(projectRoot, ".cursor", "rules");
|
|
117
|
+
const cursorPath = resolve(cursorDir, entry.cursorName);
|
|
118
|
+
total++;
|
|
119
|
+
try {
|
|
120
|
+
mkdirSync(cursorDir, { recursive: true });
|
|
121
|
+
const cursorContent =
|
|
122
|
+
`---\ndescription: ${entry.cursorDescription}\nglobs: **/*.{ts,tsx,js,jsx}\nalwaysApply: false\n---\n\n` +
|
|
123
|
+
content;
|
|
124
|
+
writeFileSync(cursorPath, cursorContent, "utf-8");
|
|
125
|
+
console.log(` ✅ Cursor → .cursor/rules/${entry.cursorName}`);
|
|
85
126
|
synced++;
|
|
86
127
|
} catch (err) {
|
|
87
|
-
console.log(` ⚠️
|
|
128
|
+
console.log(` ⚠️ Cursor — .cursor/rules/${entry.cursorName} skipped (${err.message})`);
|
|
88
129
|
}
|
|
89
130
|
}
|
|
90
131
|
|
|
91
|
-
console.log(`\n Synced
|
|
132
|
+
console.log(`\n Synced ${synced}/${total} targets.\n`);
|