@wangs-ui/create-react-app 1.0.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/dist/bin.js +445 -0
- package/package.json +64 -0
- package/template/README.md +114 -0
- package/template/_gitignore +25 -0
- package/template/_npmrc +3 -0
- package/template/_pnpm-workspace.yaml +6 -0
- package/template/agents/AGENTS.md +59 -0
- package/template/agents/agents.mcp.json +8 -0
- package/template/agents/kilo.mcp.json +8 -0
- package/template/agents/mcp.json +8 -0
- package/template/agents/opencode.json +9 -0
- package/template/index.html +20 -0
- package/template/oxfmt.config.ts +3 -0
- package/template/oxlint.config.ts +3 -0
- package/template/package.json +48 -0
- package/template/public/wangs_ui_logo.png +0 -0
- package/template/src/App.tsx +26 -0
- package/template/src/components/AuthLayout.tsx +31 -0
- package/template/src/components/Footer.tsx +41 -0
- package/template/src/index.css +5 -0
- package/template/src/main.tsx +36 -0
- package/template/src/pages/Landing.tsx +321 -0
- package/template/src/pages/Login.tsx +151 -0
- package/template/src/pages/Register.tsx +166 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.app.json +27 -0
- package/template/tsconfig.json +4 -0
- package/template/tsconfig.node.json +24 -0
- package/template/vite.config.ts +21 -0
package/dist/bin.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process$1 from "node:process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { cancel, confirm, intro, isCancel, multiselect, outro, select, spinner, text } from "@clack/prompts";
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
import { installSkill, loadAllSkills } from "@wangs-ui/skills";
|
|
9
|
+
//#region src/utils/fs.ts
|
|
10
|
+
/**
|
|
11
|
+
* Recursively copy a template directory into the target directory,
|
|
12
|
+
* customizing project name and presets in text files.
|
|
13
|
+
*/
|
|
14
|
+
function copyProjectTemplate(options) {
|
|
15
|
+
const { srcDir, destDir, projectName, preset, ignore = [] } = options;
|
|
16
|
+
if (!fs.existsSync(srcDir)) return;
|
|
17
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
18
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (ignore.includes(entry.name)) continue;
|
|
21
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
22
|
+
let destName = entry.name;
|
|
23
|
+
if (destName === "_gitignore") destName = ".gitignore";
|
|
24
|
+
else if (destName === "_npmrc") destName = ".npmrc";
|
|
25
|
+
else if (destName === "_pnpm-workspace.yaml") destName = "pnpm-workspace.yaml";
|
|
26
|
+
const destPath = path.join(destDir, destName);
|
|
27
|
+
if (entry.isDirectory()) copyProjectTemplate({
|
|
28
|
+
srcDir: srcPath,
|
|
29
|
+
destDir: destPath,
|
|
30
|
+
projectName,
|
|
31
|
+
preset,
|
|
32
|
+
ignore
|
|
33
|
+
});
|
|
34
|
+
else {
|
|
35
|
+
if (/\.(png|jpe?g|gif|svg|ico|webp|avif|woff2?|eot|ttf|otf|lottie)$/i.test(srcPath)) {
|
|
36
|
+
fs.copyFileSync(srcPath, destPath);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
let content = fs.readFileSync(srcPath, "utf8");
|
|
40
|
+
if (destName === "package.json") {
|
|
41
|
+
content = content.replace(/"name":\s*"[^"]*"/, `"name": "${projectName}"`);
|
|
42
|
+
let cliVersion = "^1.0.50";
|
|
43
|
+
try {
|
|
44
|
+
const cliPackageJsonPath = path.resolve(__dirname, "../../package.json");
|
|
45
|
+
if (fs.existsSync(cliPackageJsonPath)) {
|
|
46
|
+
const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, "utf8"));
|
|
47
|
+
if (cliPackageJson.version) cliVersion = `^${cliPackageJson.version}`;
|
|
48
|
+
}
|
|
49
|
+
} catch {}
|
|
50
|
+
content = content.replace(/"workspace:\*"/g, `"${cliVersion}"`);
|
|
51
|
+
} else if (destName === "index.html") content = content.replace(/<title>.*<\/title>/, `<title>${projectName}</title>`);
|
|
52
|
+
else if (destName === "tsconfig.app.json") content = content.replace(/\s*"customConditions":\s*\["wangs-ui-dev"\],?\n?/, "\n");
|
|
53
|
+
else if (destName === "vite.config.ts") content = content.replace(/\s*resolve:\s*\{\s*conditions:\s*\['wangs-ui-dev'\],\s*\},?\n?/, "\n");
|
|
54
|
+
if (preset !== "blue") content = content.replace(/@wangs-ui\/react-presets\/blue/g, `@wangs-ui/react-presets/${preset}`).replace(/preset:\s*blue/g, `preset: ${preset}`).replace(/palette:\s*'blue'/g, `palette: '${preset}'`).replace(/import blue from/g, `import ${preset} from`);
|
|
55
|
+
fs.writeFileSync(destPath, content, "utf8");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/utils/git.ts
|
|
61
|
+
function initGitRepository(targetDir) {
|
|
62
|
+
try {
|
|
63
|
+
if (fs.existsSync(path.join(targetDir, ".git"))) return false;
|
|
64
|
+
try {
|
|
65
|
+
execSync("git init -b main", {
|
|
66
|
+
cwd: targetDir,
|
|
67
|
+
stdio: "ignore"
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
70
|
+
execSync("git init", {
|
|
71
|
+
cwd: targetDir,
|
|
72
|
+
stdio: "ignore"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
execSync("git add -A", {
|
|
80
|
+
cwd: targetDir,
|
|
81
|
+
stdio: "ignore"
|
|
82
|
+
});
|
|
83
|
+
let hasAuthor = true;
|
|
84
|
+
try {
|
|
85
|
+
execSync("git config user.name", {
|
|
86
|
+
cwd: targetDir,
|
|
87
|
+
stdio: "ignore"
|
|
88
|
+
});
|
|
89
|
+
} catch {
|
|
90
|
+
hasAuthor = false;
|
|
91
|
+
}
|
|
92
|
+
if (hasAuthor) execSync("git commit -m \"chore: initial commit from @wangs-ui/create-react-app\"", {
|
|
93
|
+
cwd: targetDir,
|
|
94
|
+
stdio: "ignore"
|
|
95
|
+
});
|
|
96
|
+
else execSync("git -c user.name=\"Wangs UI Scaffolder\" -c user.email=\"dev@wangs-ui.internal\" commit -m \"chore: initial commit from @wangs-ui/create-react-app\"", {
|
|
97
|
+
cwd: targetDir,
|
|
98
|
+
stdio: "ignore"
|
|
99
|
+
});
|
|
100
|
+
return true;
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/utils/mcpInstaller.ts
|
|
107
|
+
function setupAgentConfigurations(options) {
|
|
108
|
+
const { targetDir, templateDir, agents, skills } = options;
|
|
109
|
+
const configuredAgents = [];
|
|
110
|
+
const agentsTemplateDir = path.join(templateDir, "agents");
|
|
111
|
+
const agentsMdSrc = path.join(agentsTemplateDir, "AGENTS.md");
|
|
112
|
+
if (fs.existsSync(agentsMdSrc)) fs.copyFileSync(agentsMdSrc, path.join(targetDir, "AGENTS.md"));
|
|
113
|
+
if (agents.includes("claude")) {
|
|
114
|
+
const mcpSrc = path.join(agentsTemplateDir, "mcp.json");
|
|
115
|
+
const claudeMdSrc = path.join(agentsTemplateDir, "CLAUDE.md");
|
|
116
|
+
if (fs.existsSync(mcpSrc)) fs.copyFileSync(mcpSrc, path.join(targetDir, ".mcp.json"));
|
|
117
|
+
if (fs.existsSync(claudeMdSrc)) fs.copyFileSync(claudeMdSrc, path.join(targetDir, "CLAUDE.md"));
|
|
118
|
+
configuredAgents.push("Claude Code (.mcp.json, CLAUDE.md)");
|
|
119
|
+
}
|
|
120
|
+
if (agents.includes("opencode")) {
|
|
121
|
+
const opencodeSrc = path.join(agentsTemplateDir, "opencode.json");
|
|
122
|
+
const mcpSrc = path.join(agentsTemplateDir, "mcp.json");
|
|
123
|
+
if (fs.existsSync(opencodeSrc)) {
|
|
124
|
+
fs.copyFileSync(opencodeSrc, path.join(targetDir, "opencode.json"));
|
|
125
|
+
const dotOpencode = path.join(targetDir, ".opencode");
|
|
126
|
+
fs.mkdirSync(dotOpencode, { recursive: true });
|
|
127
|
+
fs.copyFileSync(opencodeSrc, path.join(dotOpencode, "mcp.json"));
|
|
128
|
+
}
|
|
129
|
+
if (fs.existsSync(mcpSrc) && !fs.existsSync(path.join(targetDir, ".mcp.json"))) fs.copyFileSync(mcpSrc, path.join(targetDir, ".mcp.json"));
|
|
130
|
+
configuredAgents.push("OpenCode (opencode.json, .opencode/mcp.json)");
|
|
131
|
+
}
|
|
132
|
+
if (agents.includes("kilo")) {
|
|
133
|
+
const kiloMcpSrc = path.join(agentsTemplateDir, "kilo.mcp.json");
|
|
134
|
+
if (fs.existsSync(kiloMcpSrc)) {
|
|
135
|
+
const dotKilo = path.join(targetDir, ".kilo");
|
|
136
|
+
fs.mkdirSync(dotKilo, { recursive: true });
|
|
137
|
+
fs.copyFileSync(kiloMcpSrc, path.join(dotKilo, "mcp.json"));
|
|
138
|
+
const dotVscode = path.join(targetDir, ".vscode");
|
|
139
|
+
fs.mkdirSync(dotVscode, { recursive: true });
|
|
140
|
+
fs.copyFileSync(kiloMcpSrc, path.join(dotVscode, "mcp.json"));
|
|
141
|
+
}
|
|
142
|
+
configuredAgents.push("Kilo (.kilo/mcp.json, .vscode/mcp.json)");
|
|
143
|
+
}
|
|
144
|
+
if (agents.includes("antigravity")) {
|
|
145
|
+
const agentsMcpSrc = path.join(agentsTemplateDir, "agents.mcp.json");
|
|
146
|
+
const dotAgents = path.join(targetDir, ".agents");
|
|
147
|
+
fs.mkdirSync(dotAgents, { recursive: true });
|
|
148
|
+
if (fs.existsSync(agentsMcpSrc)) fs.copyFileSync(agentsMcpSrc, path.join(dotAgents, "mcp_config.json"));
|
|
149
|
+
configuredAgents.push("Antigravity IDE & CLI (.agents/mcp_config.json)");
|
|
150
|
+
}
|
|
151
|
+
const allSkills = loadAllSkills();
|
|
152
|
+
const selectedSkills = skills !== void 0 ? allSkills.filter((s) => skills.includes(s.id)) : allSkills;
|
|
153
|
+
for (const skill of selectedSkills) installSkill(skill, targetDir);
|
|
154
|
+
if (selectedSkills.length > 0) configuredAgents.push(`Wangs UI Consumer Skills (${selectedSkills.map((s) => s.id).join(", ")})`);
|
|
155
|
+
return configuredAgents;
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/utils/packageManager.ts
|
|
159
|
+
function detectPackageManager() {
|
|
160
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
161
|
+
if (userAgent) {
|
|
162
|
+
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
163
|
+
if (userAgent.startsWith("bun")) return "bun";
|
|
164
|
+
if (userAgent.startsWith("yarn")) return "yarn";
|
|
165
|
+
if (userAgent.startsWith("npm")) return "npm";
|
|
166
|
+
}
|
|
167
|
+
return "pnpm";
|
|
168
|
+
}
|
|
169
|
+
function getInstallCommand(pm) {
|
|
170
|
+
switch (pm) {
|
|
171
|
+
case "pnpm": return "pnpm install";
|
|
172
|
+
case "bun": return "bun install";
|
|
173
|
+
case "yarn": return "yarn";
|
|
174
|
+
default: return "npm install";
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function getRunCommand(pm, script) {
|
|
178
|
+
switch (pm) {
|
|
179
|
+
case "pnpm": return `pnpm ${script}`;
|
|
180
|
+
case "bun": return `bun ${script}`;
|
|
181
|
+
case "yarn": return `yarn ${script}`;
|
|
182
|
+
default: return `npm run ${script}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/index.ts
|
|
187
|
+
var __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
188
|
+
function generateProject(options) {
|
|
189
|
+
const { projectName, targetDir, preset, agents, skills, git } = options;
|
|
190
|
+
let templateDir = path.resolve(__dirname$1, "../template");
|
|
191
|
+
if (!fs.existsSync(templateDir)) templateDir = path.resolve(__dirname$1, "template");
|
|
192
|
+
const s = spinner();
|
|
193
|
+
s.start(`Scaffolding Wangs UI React Application in ${path.basename(targetDir)}...`);
|
|
194
|
+
copyProjectTemplate({
|
|
195
|
+
srcDir: templateDir,
|
|
196
|
+
destDir: targetDir,
|
|
197
|
+
projectName,
|
|
198
|
+
preset,
|
|
199
|
+
ignore: [
|
|
200
|
+
"agents",
|
|
201
|
+
"node_modules",
|
|
202
|
+
"dist"
|
|
203
|
+
]
|
|
204
|
+
});
|
|
205
|
+
let configuredAgents = [];
|
|
206
|
+
if (agents.length > 0) configuredAgents = setupAgentConfigurations({
|
|
207
|
+
targetDir,
|
|
208
|
+
templateDir,
|
|
209
|
+
agents,
|
|
210
|
+
skills
|
|
211
|
+
});
|
|
212
|
+
let gitInitialized = false;
|
|
213
|
+
if (git !== false) gitInitialized = initGitRepository(targetDir);
|
|
214
|
+
s.stop("Project structure initialized.");
|
|
215
|
+
const pm = detectPackageManager();
|
|
216
|
+
const installCmd = getInstallCommand(pm);
|
|
217
|
+
const devCmd = getRunCommand(pm, "dev");
|
|
218
|
+
const lintCmd = getRunCommand(pm, "lint");
|
|
219
|
+
if (configuredAgents.length > 0 || gitInitialized) {
|
|
220
|
+
console.log("\n\x1B[1mâš™ Setup Highlights:\x1B[0m");
|
|
221
|
+
if (gitInitialized) console.log(" \x1B[32m✔\x1B[0m Git repository initialized (initial commit created)");
|
|
222
|
+
for (const agent of configuredAgents) console.log(` \x1b[32m✔\x1b[0m ${agent}`);
|
|
223
|
+
}
|
|
224
|
+
outro(`\x1b[32m✨ Project created successfully!\x1b[0m\n\n\x1b[1mNext steps:\x1b[0m\n ${targetDir === process.cwd() ? "" : `cd ${path.relative(process.cwd(), targetDir)}\n `}${installCmd}\n ${devCmd}\n ${lintCmd} \x1b[2m(runs Oxlint)\x1b[0m`);
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/prompts.ts
|
|
228
|
+
var VALID_PRESETS = [
|
|
229
|
+
"blue",
|
|
230
|
+
"emerald",
|
|
231
|
+
"crimson",
|
|
232
|
+
"carbon"
|
|
233
|
+
];
|
|
234
|
+
async function promptUser(initialOptions) {
|
|
235
|
+
let { projectName, preset, agents, skills, git } = initialOptions;
|
|
236
|
+
const allSkills = loadAllSkills();
|
|
237
|
+
if (initialOptions.yes) return {
|
|
238
|
+
projectName: projectName || "my-wangs-app",
|
|
239
|
+
preset: preset || "blue",
|
|
240
|
+
agents: agents || [
|
|
241
|
+
"antigravity",
|
|
242
|
+
"opencode",
|
|
243
|
+
"claude",
|
|
244
|
+
"kilo"
|
|
245
|
+
],
|
|
246
|
+
skills: skills || allSkills.map((s) => s.id),
|
|
247
|
+
git: git !== void 0 ? git : true
|
|
248
|
+
};
|
|
249
|
+
intro(`\x1b[36m🚀 Wangs UI React App Scaffolder\x1b[0m [2m(v1.0.1)[0m`);
|
|
250
|
+
if (!projectName) {
|
|
251
|
+
const nameResponse = await text({
|
|
252
|
+
message: "What is your project name?",
|
|
253
|
+
placeholder: "my-wangs-app",
|
|
254
|
+
defaultValue: "my-wangs-app",
|
|
255
|
+
validate: (value) => {
|
|
256
|
+
if (value && value.trim().length > 0) {
|
|
257
|
+
if (/[<>:"/\\|?*]/.test(value.trim())) return "Project name contains invalid characters";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
if (isCancel(nameResponse)) {
|
|
262
|
+
cancel("Project scaffolding cancelled.");
|
|
263
|
+
process$1.exit(0);
|
|
264
|
+
}
|
|
265
|
+
projectName = (nameResponse ? nameResponse.trim() : "") || "my-wangs-app";
|
|
266
|
+
}
|
|
267
|
+
if (!preset) {
|
|
268
|
+
const presetResponse = await select({
|
|
269
|
+
message: "Select a Wangs UI Design Preset:",
|
|
270
|
+
options: [
|
|
271
|
+
{
|
|
272
|
+
value: "blue",
|
|
273
|
+
label: "Blue",
|
|
274
|
+
hint: "Default & Recommended Theme Preset (Ocean Blue)"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
value: "emerald",
|
|
278
|
+
label: "Emerald",
|
|
279
|
+
hint: "Fresh & Modern Theme Preset (Green / Teal)"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
value: "crimson",
|
|
283
|
+
label: "Crimson",
|
|
284
|
+
hint: "Bold & Elegant Theme Preset (Deep Red)"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
value: "carbon",
|
|
288
|
+
label: "Carbon",
|
|
289
|
+
hint: "Neutral & High-Contrast Theme Preset (Monochrome / Slate)"
|
|
290
|
+
}
|
|
291
|
+
],
|
|
292
|
+
initialValue: "blue"
|
|
293
|
+
});
|
|
294
|
+
if (isCancel(presetResponse)) {
|
|
295
|
+
cancel("Project scaffolding cancelled.");
|
|
296
|
+
process$1.exit(0);
|
|
297
|
+
}
|
|
298
|
+
preset = presetResponse;
|
|
299
|
+
}
|
|
300
|
+
if (!agents) {
|
|
301
|
+
const agentsResponse = await multiselect({
|
|
302
|
+
message: "Select AI Agent configurations to include: (Space to select/deselect, Enter to submit)",
|
|
303
|
+
options: [
|
|
304
|
+
{
|
|
305
|
+
value: "antigravity",
|
|
306
|
+
label: "Google Antigravity IDE",
|
|
307
|
+
hint: ".agents/skills + MCP rules"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
value: "opencode",
|
|
311
|
+
label: "OpenCode",
|
|
312
|
+
hint: "opencode.json MCP tooling"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
value: "claude",
|
|
316
|
+
label: "Claude Code",
|
|
317
|
+
hint: "CLAUDE.md developer instructions"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
value: "kilo",
|
|
321
|
+
label: "Kilo Code",
|
|
322
|
+
hint: ".kilo MCP config"
|
|
323
|
+
}
|
|
324
|
+
],
|
|
325
|
+
required: false
|
|
326
|
+
});
|
|
327
|
+
if (isCancel(agentsResponse)) {
|
|
328
|
+
cancel("Project scaffolding cancelled.");
|
|
329
|
+
process$1.exit(0);
|
|
330
|
+
}
|
|
331
|
+
agents = agentsResponse;
|
|
332
|
+
}
|
|
333
|
+
if (!skills && agents.length > 0 && allSkills.length > 0) {
|
|
334
|
+
const skillsResponse = await multiselect({
|
|
335
|
+
message: "Select Wangs UI AI Skills to install: (Space to select/deselect, Enter to submit)",
|
|
336
|
+
options: allSkills.map((s) => ({
|
|
337
|
+
value: s.id,
|
|
338
|
+
label: s.id,
|
|
339
|
+
hint: s.description
|
|
340
|
+
})),
|
|
341
|
+
initialValues: allSkills.map((s) => s.id),
|
|
342
|
+
required: false
|
|
343
|
+
});
|
|
344
|
+
if (isCancel(skillsResponse)) {
|
|
345
|
+
cancel("Project scaffolding cancelled.");
|
|
346
|
+
process$1.exit(0);
|
|
347
|
+
}
|
|
348
|
+
skills = skillsResponse;
|
|
349
|
+
}
|
|
350
|
+
if (git === void 0) {
|
|
351
|
+
const gitResponse = await confirm({
|
|
352
|
+
message: "Initialize a new git repository and create initial commit?",
|
|
353
|
+
initialValue: true
|
|
354
|
+
});
|
|
355
|
+
if (isCancel(gitResponse)) {
|
|
356
|
+
cancel("Project scaffolding cancelled.");
|
|
357
|
+
process$1.exit(0);
|
|
358
|
+
}
|
|
359
|
+
git = Boolean(gitResponse);
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
projectName,
|
|
363
|
+
preset,
|
|
364
|
+
agents,
|
|
365
|
+
skills: skills || (agents.length > 0 ? allSkills.map((s) => s.id) : []),
|
|
366
|
+
git: Boolean(git)
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region bin.ts
|
|
371
|
+
async function main() {
|
|
372
|
+
const args = process$1.argv.slice(2);
|
|
373
|
+
const options = {};
|
|
374
|
+
for (let i = 0; i < args.length; i++) {
|
|
375
|
+
const arg = args[i];
|
|
376
|
+
if (arg === "-y" || arg === "--yes") options.yes = true;
|
|
377
|
+
else if (arg.startsWith("--preset=")) {
|
|
378
|
+
const val = arg.split("=")[1];
|
|
379
|
+
if (VALID_PRESETS.includes(val)) options.preset = val;
|
|
380
|
+
} else if (arg === "--preset" && args[i + 1]) {
|
|
381
|
+
const val = args[++i];
|
|
382
|
+
if (VALID_PRESETS.includes(val)) options.preset = val;
|
|
383
|
+
} else if (arg.startsWith("--agent=") || arg.startsWith("--agents=")) {
|
|
384
|
+
const val = arg.split("=")[1];
|
|
385
|
+
if (val === "all") options.agents = [
|
|
386
|
+
"kilo",
|
|
387
|
+
"opencode",
|
|
388
|
+
"claude",
|
|
389
|
+
"antigravity"
|
|
390
|
+
];
|
|
391
|
+
else if (val === "none") options.agents = [];
|
|
392
|
+
else options.agents = val.split(",").filter((a) => [
|
|
393
|
+
"kilo",
|
|
394
|
+
"opencode",
|
|
395
|
+
"claude",
|
|
396
|
+
"antigravity"
|
|
397
|
+
].includes(a));
|
|
398
|
+
} else if ((arg === "--agent" || arg === "--agents") && args[i + 1]) {
|
|
399
|
+
const val = args[++i];
|
|
400
|
+
if (val === "all") options.agents = [
|
|
401
|
+
"kilo",
|
|
402
|
+
"opencode",
|
|
403
|
+
"claude",
|
|
404
|
+
"antigravity"
|
|
405
|
+
];
|
|
406
|
+
else if (val === "none") options.agents = [];
|
|
407
|
+
else options.agents = val.split(",").filter((a) => [
|
|
408
|
+
"kilo",
|
|
409
|
+
"opencode",
|
|
410
|
+
"claude",
|
|
411
|
+
"antigravity"
|
|
412
|
+
].includes(a));
|
|
413
|
+
} else if (arg.startsWith("--skill=") || arg.startsWith("--skills=")) {
|
|
414
|
+
const val = arg.split("=")[1];
|
|
415
|
+
if (val === "all") options.skills = void 0;
|
|
416
|
+
else if (val === "none") options.skills = [];
|
|
417
|
+
else options.skills = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
418
|
+
} else if ((arg === "--skill" || arg === "--skills") && args[i + 1]) {
|
|
419
|
+
const val = args[++i];
|
|
420
|
+
if (val === "all") options.skills = void 0;
|
|
421
|
+
else if (val === "none") options.skills = [];
|
|
422
|
+
else options.skills = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
423
|
+
} else if (arg === "--git" || arg === "--git=true") options.git = true;
|
|
424
|
+
else if (arg === "--no-git" || arg === "--git=false") options.git = false;
|
|
425
|
+
else if (!arg.startsWith("-") && !options.projectName) options.projectName = arg;
|
|
426
|
+
}
|
|
427
|
+
const { projectName, preset, agents, skills, git } = await promptUser(options);
|
|
428
|
+
const targetDir = path.resolve(process$1.cwd(), projectName);
|
|
429
|
+
generateProject({
|
|
430
|
+
projectName: path.basename(targetDir),
|
|
431
|
+
targetDir,
|
|
432
|
+
preset,
|
|
433
|
+
agents,
|
|
434
|
+
skills,
|
|
435
|
+
git
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
await main();
|
|
440
|
+
} catch (err) {
|
|
441
|
+
console.error("\x1B[31mError during project creation:\x1B[0m", err);
|
|
442
|
+
process$1.exit(1);
|
|
443
|
+
}
|
|
444
|
+
//#endregion
|
|
445
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wangs-ui/create-react-app",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Scaffold a modern React app with Wangs UI, Vite 8, Oxlint, Oxfmt, and AI Agent MCP integration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"antigravity",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"create-react-app",
|
|
9
|
+
"kilo",
|
|
10
|
+
"mcp",
|
|
11
|
+
"opencode",
|
|
12
|
+
"oxfmt",
|
|
13
|
+
"oxlint",
|
|
14
|
+
"react",
|
|
15
|
+
"vite",
|
|
16
|
+
"wangs-ui"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/fewangsit/wangs-ui-react",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Wangsit FE Developer",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/fewangsit/wangs-ui-react.git",
|
|
24
|
+
"directory": "packages/create-react-app"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"create-react-app": "dist/bin.js",
|
|
28
|
+
"create-wangs-app": "dist/bin.js",
|
|
29
|
+
"create-wangs-ui-react-app": "dist/bin.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"template/index.html",
|
|
34
|
+
"template/package.json",
|
|
35
|
+
"template/oxfmt.config.ts",
|
|
36
|
+
"template/oxlint.config.ts",
|
|
37
|
+
"template/tsconfig.json",
|
|
38
|
+
"template/tsconfig.app.json",
|
|
39
|
+
"template/tsconfig.node.json",
|
|
40
|
+
"template/vite.config.ts",
|
|
41
|
+
"template/_gitignore",
|
|
42
|
+
"template/_npmrc",
|
|
43
|
+
"template/_pnpm-workspace.yaml",
|
|
44
|
+
"template/src",
|
|
45
|
+
"template/agents",
|
|
46
|
+
"template/README.md",
|
|
47
|
+
"template/public"
|
|
48
|
+
],
|
|
49
|
+
"type": "module",
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"registry": "https://registry.npmjs.org/"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@clack/prompts": "^1.7.0",
|
|
56
|
+
"@wangs-ui/skills": "1.0.1"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "vite build",
|
|
61
|
+
"check:publint": "publint",
|
|
62
|
+
"check:attw": "attw --pack ."
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Wangs UI React Application
|
|
2
|
+
|
|
3
|
+
A modern enterprise React application built with **Wangs UI Design System**, Vite 8, Tailwind CSS v4, Oxlint, and pre-configured AI Agent MCP workflows.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Getting Started
|
|
8
|
+
|
|
9
|
+
### 1. Install Dependencies
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Available Scripts
|
|
16
|
+
|
|
17
|
+
| Command | Description |
|
|
18
|
+
| :------------- | :------------------------------------------ |
|
|
19
|
+
| `pnpm dev` | Start the local development server with HMR |
|
|
20
|
+
| `pnpm build` | Build optimized production bundle |
|
|
21
|
+
| `pnpm preview` | Preview production build locally |
|
|
22
|
+
| `pnpm lint` | Lint codebase with fast Oxlint |
|
|
23
|
+
| `pnpm fmt` | Format codebase with Oxfmt |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🎨 Working with Wangs UI
|
|
28
|
+
|
|
29
|
+
### 1. Modular Subpath Imports
|
|
30
|
+
|
|
31
|
+
Always import primitive components and icons via their subpaths to ensure optimal tree-shaking:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// Primitives
|
|
35
|
+
import Button from '@wangs-ui/react-core/primitive/button';
|
|
36
|
+
import Card from '@wangs-ui/react-core/primitive/card';
|
|
37
|
+
import InputText from '@wangs-ui/react-core/primitive/inputtext';
|
|
38
|
+
import DataTable, { Column } from '@wangs-ui/react-core/primitive/datatable';
|
|
39
|
+
|
|
40
|
+
// Icons
|
|
41
|
+
import { SearchLine, AddLine, DeleteBin6Line } from '@wangs-ui/react-icons';
|
|
42
|
+
|
|
43
|
+
// Form & Internationalization
|
|
44
|
+
import { Form, Field } from '@wangs-ui/react-core';
|
|
45
|
+
import { useFormControl } from '@wangs-ui/form';
|
|
46
|
+
import { useI18n } from '@wangs-ui/react-i18n';
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Strict Primitive Rule
|
|
50
|
+
|
|
51
|
+
Never write unstyled raw HTML elements (`<button>`, `<input>`, `<table>`, `<dialog>`). Always use the corresponding Wangs UI primitive component.
|
|
52
|
+
|
|
53
|
+
### 3. Internationalization (`useI18n`)
|
|
54
|
+
|
|
55
|
+
Never hardcode user-facing text strings in JSX. Always wrap UI labels, button text, table headers, and error messages in `t()`:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
const { t } = useI18n();
|
|
59
|
+
|
|
60
|
+
return <Button label={t('Save Changes')} severity="primary" />;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🤖 AI Agent & MCP Integration
|
|
66
|
+
|
|
67
|
+
This project comes pre-configured with **`@wangs-ui/mcp`** for leading AI agents:
|
|
68
|
+
|
|
69
|
+
- **Antigravity IDE & CLI**: `.agents/mcp_config.json`
|
|
70
|
+
- **Claude Code**: `.mcp.json` & `CLAUDE.md`
|
|
71
|
+
- **OpenCode**: `opencode.json` & `.opencode/mcp.json`
|
|
72
|
+
- **Kilo**: `.kilo/mcp.json` & `.vscode/mcp.json`
|
|
73
|
+
|
|
74
|
+
The MCP server provides live access to:
|
|
75
|
+
|
|
76
|
+
1. **Component Documentation & Types**: `get-documentation({ id: "button" })`
|
|
77
|
+
2. **Component Stories & Variants**: `get-documentation-for-story({ id: "button", storyName: "Primary" })`
|
|
78
|
+
3. **Knowledge Graph Queries**: `query_graph({ query: "DataTable" })`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📦 Managing AI Agent Skills (`@wangs-ui/skills`)
|
|
83
|
+
|
|
84
|
+
Skills provide high-level workflows and recipes for AI agents (form management, data grids, modal dialogs, i18n formatting). You can install, update, or remove skills independently using the CLI:
|
|
85
|
+
|
|
86
|
+
### List Available Skills
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx @wangs-ui/skills list
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Install Specific Skills
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Interactive selection
|
|
96
|
+
npx @wangs-ui/skills add
|
|
97
|
+
|
|
98
|
+
# Direct install
|
|
99
|
+
npx @wangs-ui/skills add create-form data-table dialog-modal
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Update Installed Skills
|
|
103
|
+
|
|
104
|
+
To update all skills in your project to the latest definitions:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx @wangs-ui/skills update
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Remove a Skill
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npx @wangs-ui/skills remove create-form
|
|
114
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
!.vscode/mcp.json
|
|
19
|
+
.idea
|
|
20
|
+
.DS_Store
|
|
21
|
+
*.suo
|
|
22
|
+
*.ntvs*
|
|
23
|
+
*.njsproj
|
|
24
|
+
*.sln
|
|
25
|
+
*.sw?
|
package/template/_npmrc
ADDED