@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 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 (v1.0.1)`);
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?
@@ -0,0 +1,3 @@
1
+ @fewangsit:registry=http://192.168.1.102:4873/
2
+ @wangs-ui:registry=http://192.168.1.102:4873/
3
+ minimum-release-age=0
@@ -0,0 +1,6 @@
1
+ allowBuilds:
2
+ '@swc/core': true
3
+ core-js: true
4
+ esbuild: true
5
+
6
+ minimumReleaseAge: 0