@luxkit/cli 1.1.2 โ†’ 1.1.3

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/README.md CHANGED
@@ -16,15 +16,21 @@
16
16
 
17
17
  ---
18
18
 
19
- ### What is lux?
19
+ ### ๐Ÿ“Œ What is lux?
20
20
 
21
- `lux` is a CLI tool that sets up project lint configs and VSCode workspace settings with a single command โ€” saving you from repetitive configuration overhead and wasted tokens. It generates ESLint, Prettier, CSpell, Stylelint๏ผŒEditorConfig configs and VSCode settings from presets โ€” with smart merge and conflict resolution. Configurations can be customized to your needs.
21
+ `lux` is a CLI tool for modern development & the **AI era** that sets up project lint configs and VSCode workspace settings with a single command.
22
+
23
+ - ๐Ÿš€**One-click setup**: ESLint, Prettier, CSpell, Stylelint, EditorConfig, and VSCode workspace โ€” all in one command.
24
+ - ๐Ÿค–**AI Agent companion**: Built for Claude, Opencode and more! Use natural language (e.g. _"/lux configure a react lint template for my team"_) to let AI build and adjust custom presets for you.
25
+ - ๐Ÿ“ฆ**Framework presets**: Built-in presets for `web-vue`, `web-react`, `node`, and more.
26
+ - ๐ŸŽจ**Ultimate Freedom for Customization**: Tired of rigid one-size-fits-all encapsulated configurations? lux allows you to extract and fine-tune built-in presets, and also supports **fully custom private presets**. It perfectly balances out-of-the-box usability with the strong customization demands of team collaboration.
27
+ - ๐Ÿง **Safe project integration**: Smart conflict resolution and merge, auto-detects `bun`, `pnpm`, `npm`, `yarn` dependency trees.
22
28
 
23
29
  <div align="center">
24
30
  <img src="https://github.com/TTT1231/lux/blob/main/demo.gif?raw=true" alt="lux demo" width="640" />
25
31
  </div>
26
32
 
27
- ### Quick Start
33
+ ### โšกQuick Start
28
34
 
29
35
  ```bash
30
36
  # Install globally (pick your package manager)
@@ -45,21 +51,42 @@ lux vscode web-vue # Generate .vscode/settings.json + extensions.json (per
45
51
  # List available presets
46
52
  lux fmt list
47
53
  lux vscode list
54
+
55
+ # Next: customize your own lint preset (optional)
48
56
  ```
49
57
 
50
58
  <br />
51
59
 
52
- ### Custom Configuration
60
+ ### ๐ŸŽจCustomize Built-in Presets
61
+
62
+ ```bash
63
+ # Check if skill and presets are initialized (skip if already done)
64
+ lux init && lux init --preset
65
+
66
+ # Use an AI agent to customize a built-in preset (recommended)
67
+ # In an AI agent like Claude, just run:
68
+ /lux configure built-in preset web-react template to fit my development project style
69
+
70
+ # Or manually edit files under ~/.lux/preset/
71
+ # e.g. add a cspell script to web-react:
72
+ # "cspell":"cspell \"src/**/*\"" to ~/.lux/preset/fmt/web-react/package.json
73
+ ```
74
+
75
+ ### ๐ŸงฉFully Custom Presets
53
76
 
54
77
  ```bash
55
78
  # Check if skill and presets are initialized (skip if already done)
56
79
  lux init && lux init --preset
57
80
 
58
- # Use an agent to customize a preset
59
- /lux help me configure my web react lint template to fit my development project style
81
+ # Use an AI agent to create a fully custom preset (recommended)
82
+ # In an AI agent like Claude, just run:
83
+ /lux configure my formatting template <your-custom-fmt-preset-name> to fit my development project style
84
+
85
+ # Verify the preset is registered
86
+ lux fmt list
60
87
  ```
61
88
 
62
- ### CLI Commands
89
+ ### ๐Ÿ“–CLI Commands
63
90
 
64
91
  | Command | Description |
65
92
  | :-------------------------- | :---------------------------------------------------------------- |
@@ -80,7 +107,7 @@ lux init && lux init --preset
80
107
 
81
108
  <br />
82
109
 
83
- ### Options
110
+ ### โš™๏ธOptions
84
111
 
85
112
  ```bash
86
113
  lux fmt <preset> [options]
@@ -91,34 +118,49 @@ lux fmt <preset> [options]
91
118
  --stylelint Include Stylelint config generation (opt-in)
92
119
  --editorconfig Include EditorConfig config generation (opt-in)
93
120
  --reset Reset local preset and re-create from built-in defaults
121
+
122
+ lux vscode <preset> [options]
123
+
124
+ --force Force overwrite existing files
125
+ --dry-run Preview without writing files
126
+ --stylelint Include Stylelint settings and extension (opt-in)
127
+ --reset Reset local preset and re-create from built-in defaults
94
128
  ```
95
129
 
96
130
  <br />
97
131
 
98
- ### How It Works
132
+ ###๐Ÿ”ง How It Works
99
133
 
100
134
  ```
101
- lux fmt web-vue
135
+ lux fmt <preset> [options]
102
136
  โ”‚
103
137
  โ–ผ
104
- Parse CLI args โ”€โ”€โ–บ Resolve preset (fuzzy match on typo)
138
+ Parse CLI args, validate project package.json
105
139
  โ”‚
106
140
  โ–ผ
107
- Local preset exists in ~/.lux/preset/?
141
+ Resolve preset type
108
142
  โ”‚
109
- โ”œโ”€โ”€ Yes โ”€โ”€โ–บ Copy files from local preset (editable, survives updates)
110
- โ””โ”€โ”€ No โ”€โ”€โ–บ Generate from built-in โ”€โ”€โ–บ Save to ~/.lux/preset/ for reuse
143
+ โ”œโ”€โ”€ Built-in preset โ”€โ”€โ–บ --reset? โ”€โ”€โ–บ Reset local copy
144
+ โ”‚ โ”‚
145
+ โ”‚ โ”œโ”€โ”€ Local copy exists (~/.lux/preset/)? โ”€โ”€โ–บ Apply from local
146
+ โ”‚ โ””โ”€โ”€ Not found โ”€โ”€โ–บ Generate from built-in โ”€โ”€โ–บ Save to ~/.lux/preset/ โ”€โ”€โ–บ Apply
147
+ โ”‚
148
+ โ”œโ”€โ”€ Custom preset (~/.lux/preset/fmt/<name>/) โ”€โ”€โ–บ Apply from local directory
149
+ โ”‚
150
+ โ””โ”€โ”€ Not found โ”€โ”€โ–บ Fuzzy match against all presets (built-in + custom), show error
151
+ โ”‚
152
+ โ–ผ
153
+ --stylelint / --editorconfig filtering (warns if custom preset lacks matching config)
111
154
  โ”‚
112
155
  โ–ผ
113
156
  For each config file:
114
157
  โ”‚
115
158
  โ”œโ”€โ”€ File not found? โ”€โ”€โ–บ Create
116
- โ”œโ”€โ”€ In neverOverwrite? โ”€โ”€โ–บ Skip
117
- โ”œโ”€โ”€ In forceOverwrite? โ”€โ”€โ–บ Overwrite
118
- โ””โ”€โ”€ Exists + --force? โ”€โ”€โ–บ Overwrite / Skip
159
+ โ”œโ”€โ”€ Exists + --force? โ”€โ”€โ–บ Overwrite
160
+ โ””โ”€โ”€ Exists? โ”€โ”€โ–บ Skip
119
161
  โ”‚
120
162
  โ–ผ
121
- Inject scripts into package.json (<pm> โ†’ bun run / pnpm run / ...)
163
+ Inject scripts into package.json (auto-detect bun / pnpm / npm / yarn)
122
164
  โ”‚
123
165
  โ–ผ
124
166
  Auto-install devDependencies (detects lockfile)
@@ -128,7 +170,11 @@ lux fmt web-vue
128
170
 
129
171
  ### ๐Ÿค Support
130
172
 
131
- If you have any questions or run into issues, feel free to [open an issue](https://github.com/TTT1231/lux/issues) on GitHub.
173
+ Found a bug, have a feature idea, or want to improve the code? Contributions are welcome!
174
+
175
+ - **Report bugs or request features**: [Open an issue](https://github.com/TTT1231/lux/issues) on GitHub.
176
+ - **Submit code**: [Pull Requests](https://github.com/TTT1231/lux/pulls) are very welcome!
177
+ - **Star us**: If this tool saved you even 5 minutes of config time, please give us a [โญ๏ธStar](https://github.com/TTT1231/lux)!
132
178
 
133
179
  <br />
134
180
 
package/README_Zh.md ADDED
@@ -0,0 +1,189 @@
1
+ <div align="center">
2
+
3
+ # lux
4
+
5
+ **ไธ€้”ฎ้กน็›ฎๆ ผๅผๅŒ– & VSCode ้…็ฝฎ CLI**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@luxkit/cli.svg)](https://www.npmjs.com/package/@luxkit/cli)
8
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-green.svg)](https://nodejs.org/)
9
+ [![License: ISC](https://img.shields.io/badge/license-ISC-purple.svg)](https://opensource.org/licenses/ISC)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-6.0-3178C6.svg)](https://www.typescriptlang.org/)
11
+ [![ESM Only](https://img.shields.io/badge/ESM-only-F7DF1E.svg)](https://nodejs.org/api/esm.html)
12
+
13
+ [English](./README.md) | **ไธญๆ–‡**
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ### ๐Ÿ“Œ ไธบไป€ไนˆ้€‰ๆ‹ฉ lux๏ผŸ
20
+
21
+ ๆฏๆฌกๆ–ฐๅปบ้กน็›ฎ้ƒฝ่ฆ่Šฑๅคง้‡ๆ—ถ้—ดๆŠ˜่…พไปฃ็ ่ง„่Œƒ้…็ฝฎ๏ผŸ`lux` ่ฎฉไฝ ๅฝปๅบ•ๅ‘Šๅˆซ่ฟ™ไธ€็—›็‚น๏ผไฝœไธบไธ€ๆฌพไธ“ไธบ็ŽฐไปฃๅŒ–ๅผ€ๅ‘ไธŽ **AI ๆ—ถไปฃ** ๆ‰“้€ ็š„ๅทฅ็จ‹ๅŒ–้…็ฝฎๅทฅๅ…ท๏ผŒๅช้œ€ไธ€ๆกๅ‘ฝไปคๅณๅฏไธบๆ‚จๆญๅฅฝ็ปไฝณ็š„ๅผ€ๅ‘ lint ๅŸบๅปบใ€‚
22
+
23
+ - ๐Ÿš€ **ไธ€้”ฎๆž้€Ÿ้…็ฝฎ**๏ผšๅ‘Šๅˆซ็น็็š„ๆ‰‹ๅŠจไพ่ต–ๅฎ‰่ฃ…๏ผŒไธ€ๅฅ—ๅ‘ฝไปค่‡ชๅŠจไธบไฝ ๆญๅฅฝ ESLintใ€Prettierใ€CSpellใ€Stylelintใ€EditorConfig ไปฅๅŠๅฎŒ็พŽ็š„ VSCode ๅทฅไฝœๅŒบไฝ“้ชŒใ€‚
24
+ - ๐Ÿค– **AI Agent ๆœ€ไฝณๆ‹ๆกฃ**๏ผšไธ“ไธบ Claudeใ€Opencode ๆ‰“้€ ็”Ÿๆ€๏ผๆŠ€่ƒฝ๏ผˆSkill๏ผ‰ไฝ“็ณป๏ผŒไฝ ๅฏไปฅ็›ดๆŽฅ็”จ่‡ช็„ถ่ฏญ่จ€๏ผˆๅฆ‚*"/lux ๅธฎๆˆ‘้…ไธ€ๅฅ—้€‚ๅˆๅ›ข้˜Ÿ็š„ react ไปฃ็ ่ง„่Œƒ"*๏ผ‰๏ผŒ่ฎฉ AI ๅธฎไฝ ๅ…จ่‡ชๅŠจๆž„ๅปบๅ’Œ่ฐƒๆ•ด่‡ชๅฎšไน‰้ข„่ฎพใ€‚
25
+ - ๐Ÿ“ฆ **ๆก†ๆžถๅผ€็ฎฑๅณ็”จ**๏ผšๅ†…็ฝฎๅœบๆ™ฏ้ข„่ฎพ๏ผš`web-vue`, `web-react`, `node`็ญ‰ใ€‚
26
+ - ๐ŸŽจ **้ซ˜ๅบฆ่‡ช็”ฑ็š„ไธ“ๅฑžๅฎšๅˆถ**๏ผšๅŽŒๅ€ฆไบ†ๆญปๆฟ็š„โ€œไธ€ๅˆ€ๅˆ‡โ€ๅฐ่ฃ…้…็ฝฎ๏ผŸ`lux` ๆ”ฏๆŒๆๅ–ๅ’Œๅพฎ่ฐƒๅ†…็ฝฎ้ข„่ฎพ๏ผŒๆ›ดๆ”ฏๆŒ**ๅฎŒๅ…จ่‡ชๅฎšไน‰็งๆœ‰้ข„่ฎพ**๏ผŒๅฎŒ็พŽๅ…ผ้กพๅผ€็ฎฑๅณ็”จไฝ“้ชŒไธŽๅ›ข้˜ŸๅผบๅฎšๅˆถๅŒ–ๅˆš้œ€ใ€‚
27
+ - ๐Ÿง  **้กน็›ฎๅฎ‰ๅ…จๆ— ็—›ๆŽฅๅ…ฅ**๏ผšๆ‹ฅๆœ‰ๆ™บ่ƒฝๅ†ฒ็ช่งฃๅ†ณไธŽๅˆ้…ๆœบๅˆถ๏ผŒ่‡ชๅŠจๆฃ€ๆต‹ `bun` `pnpm` `npm` `yarn` ไพ่ต–ๆ ‘๏ผŒๅฐ†้…็ฝฎๆณจๅ…ฅๅˆฐๅทฒๆœ‰้กน็›ฎไธญใ€‚
28
+
29
+ <div align="center">
30
+ <img src="https://github.com/TTT1231/lux/blob/main/demo.gif?raw=true" alt="lux ๆผ”็คบ" width="640" />
31
+ </div>
32
+
33
+ ## โšกๅฟซ้€Ÿๅผ€ๅง‹
34
+
35
+ ```bash
36
+ # ๅ…จๅฑ€ๅฎ‰่ฃ…๏ผˆ้€‰ๆ‹ฉไฝ ็š„ๅŒ…็ฎก็†ๅ™จ๏ผ‰
37
+ npm install -g @luxkit/cli
38
+
39
+ # ๅˆๅง‹ๅŒ– skill ๅ’Œ preset
40
+ lux init && lux init --preset
41
+
42
+ # lint ไฝฟ็”จ
43
+ lux fmt web-vue # ้…็ฝฎweb-vue lint๏ผŒ้…็ฝฎ ESLintใ€Prettierใ€CSpell
44
+ lux fmt web-vue --stylelint # ๅŒๆ—ถๅŒ…ๅซ Stylelint
45
+ lux fmt web-vue --editorconfig # ๅŒๆ—ถๅŒ…ๅซ EditorConfig
46
+
47
+ # vscode้…็ฝฎไฝฟ็”จ๏ผˆoption๏ผ‰
48
+ # ๅฆ‚ๆžœไฝ ๅ…จๅฑ€่‡ชๅฎšไน‰้…็ฝฎไบ†๏ผŒๅฏๅฟฝ่ง†
49
+ lux vscode web-vue #๏ผˆ้กน็›ฎๅ†…๏ผ‰ ็”Ÿๆˆ .vscode/settings.json + extensions.json
50
+
51
+ # ๆŸฅ็œ‹ๅฏ็”จ้ข„่ฎพ
52
+ lux fmt list
53
+ lux vscode list
54
+
55
+ # ไธ‹ไธ€ๆญฅ๏ผš่‡ชๅฎšไน‰ไฝ ่‡ชๅทฑ็š„lint้ข„่ฎพ๏ผˆๅฏ้€‰๏ผ‰
56
+ ```
57
+
58
+ <br />
59
+
60
+ ## ๐ŸŽจ ่‡ชๅฎšไน‰ๅ†…็ฝฎ้ข„่ฎพ
61
+
62
+ ```bash
63
+ # ๆฃ€ๆŸฅskillๅ’Œ้ข„่ฎพๆ˜ฏๅฆๅˆๅง‹ๅŒ–๏ผˆๅทฒๅˆๅง‹ๅŒ–๏ผŒ่ฏทๅฟฝ่ง†๏ผ‰
64
+ lux init && lux init --preset
65
+
66
+ # ไฝฟ็”จ ai agent ่ฟ›่กŒ่‡ชๅฎšไน‰ๅ†…็ฝฎ้ข„่ฎพ๏ผˆๆŽจ่๏ผ‰
67
+ # ๅœจai agentไพ‹ๅฆ‚claude๏ผŒ็›ดๆŽฅๆ‰ง่กŒไปฅไธ‹ๅณๅฏ
68
+ /lux ้…็ฝฎๅ†…็ฝฎ้ข„่ฎพ web-react ๆจกๆฟ๏ผŒ็ฌฆๅˆๆˆ‘็š„ๅผ€ๅ‘้กน็›ฎ้ฃŽๆ ผ
69
+
70
+ # ๅฆ‚ๆžœไฝ ไธๆƒณไฝฟ็”จ ai agent ๅฏ็›ดๆŽฅ็ผ–่พ‘ `~/.lux/preset/`ไธ‹็š„ๅ†…็ฝฎ้ข„่ฎพๆ–‡ไปถ
71
+ # ไพ‹ๅฆ‚ไฟฎๆ”น web-react ๅขžๅŠ cspell script
72
+ # "cspell":"cspell \"src/**/*\"" ๅˆฐ `~/.lux/preset/fmt/web-react/package.json` ๅณๅฏ
73
+ ```
74
+
75
+ ## ๐Ÿงฉ ๅฎŒๅ…จ่‡ชๅฎšไน‰้ข„่ฎพ
76
+
77
+ ๅฆ‚ๆžœไฝ ๆƒณๅฎŒๅ…จ่‡ชๅฎšไน‰่‡ชๅทฑ็š„ lint๏ผŒๆŒ‰็…งไปฅไธ‹ๆ–นๆณ•่ฟ›่กŒๅณๅฏ๏ผš
78
+
79
+ ```bash
80
+ # ๆฃ€ๆŸฅskillๅ’Œ้ข„่ฎพๆ˜ฏๅฆๅˆๅง‹ๅŒ–๏ผˆๅทฒๅˆๅง‹ๅŒ–๏ผŒ่ฏทๅฟฝ่ง†๏ผ‰
81
+ lux init && lux init --preset
82
+
83
+ # ไฝฟ็”จ ai agent ่ฟ›่กŒๅฎŒๅ…จ่‡ชๅฎšไน‰้ข„่ฎพ๏ผˆๆŽจ่๏ผ‰
84
+ # ๅœจai agentไพ‹ๅฆ‚claude๏ผŒ็›ดๆŽฅๆ‰ง่กŒไปฅไธ‹ๅณๅฏ
85
+ /lux ้…็ฝฎๆˆ‘็š„ๆ ผๅผๅŒ–ๆจกๆฟ<your-custom-fmt-preset-name>๏ผŒ็ฌฆๅˆๆˆ‘็š„ๅผ€ๅ‘้กน็›ฎ้ฃŽๆ ผ
86
+
87
+ # ๆฃ€ๆŸฅๆ˜ฏๅฆ้…็ฝฎๆˆๅŠŸ
88
+ lux fmt list
89
+ ```
90
+
91
+ ## ๐Ÿ“–ๅ‘ฝไปคๅ‚่€ƒ
92
+
93
+ | ๅ‘ฝไปค | ่ฏดๆ˜Ž |
94
+ | :-------------------------- | :----------------------------------------------------------- |
95
+ | `lux fmt <preset>` | lint ้…็ฝฎ |
96
+ | `lux fmt list` | ๅˆ—ๅ‡บ lint ๅฏ็”จ็š„้ข„่ฎพ |
97
+ | `lux vscode <preset>` | ้…็ฝฎ VSCode ่ฎพ็ฝฎ (้กน็›ฎๅ†…) |
98
+ | `lux vscode list` | ๅˆ—ๅ‡บๅฏ็”จ็š„ VSCode ้ข„่ฎพ |
99
+ | `lux init` | ๅˆๅง‹ๅŒ– skill |
100
+ | `lux init --preset` | ๅˆๅง‹ๅŒ–ๆ‰€ๆœ‰้ข„่ฎพ |
101
+ | `lux set <key=value> [...]` | ่ฎพ็ฝฎไปฃ็†็Žฏๅขƒๅ˜้‡๏ผˆๅฆ‚ `https_proxy="http://127.0.0.1:7890"`๏ผ‰ |
102
+ | `lux unset` | ๆธ…้™คๅ…จ้ƒจ็š„ไปฃ็†้…็ฝฎ |
103
+ | `lux show env` | ๆ˜พ็คบๅทฒ้…็ฝฎ็š„ไปฃ็†็Žฏๅขƒๅ˜้‡ |
104
+ | `lux vpn cmd` | ๅคๅˆถ CMD ไปฃ็†ๅ‘ฝไปคๅˆฐๅ‰ช่ดดๆฟ |
105
+ | `lux vpn pw` | ๅคๅˆถ PowerShell ไปฃ็†ๅ‘ฝไปคๅˆฐๅ‰ช่ดดๆฟ |
106
+ | `lux vpn bash` | ๅคๅˆถ Bash ไปฃ็†ๅ‘ฝไปคๅˆฐๅ‰ช่ดดๆฟ |
107
+ | `lux update` | ๆ›ดๆ–ฐ `@luxkit/cli` ๅˆฐๆœ€ๆ–ฐ็‰ˆๆœฌ |
108
+ | `lux update --check` | ไป…ๆฃ€ๆŸฅๆ˜ฏๅฆๆœ‰ๅฏ็”จๆ›ดๆ–ฐ๏ผŒไธๆ‰ง่กŒๅฎ‰่ฃ… |
109
+
110
+ <br />
111
+
112
+ ### โš™๏ธๅ‘ฝไปค้€‰้กน
113
+
114
+ ```bash
115
+ lux fmt <preset> [options]
116
+
117
+ --force ๅผบๅˆถ่ฆ†็›–ๅทฒๆœ‰ๆ–‡ไปถ
118
+ --no-install ่ทณ่ฟ‡ไพ่ต–ๅฎ‰่ฃ…
119
+ --dry-run ้ข„่งˆๆจกๅผ๏ผŒไธๅ†™ๅ…ฅๆ–‡ไปถ
120
+ --stylelint ๅŒ…ๅซ Stylelint ้…็ฝฎ๏ผˆๆŒ‰้œ€ๅฏ็”จ๏ผ‰
121
+ --editorconfig ๅŒ…ๅซ EditorConfig ็š„้…็ฝฎ๏ผˆๆŒ‰้œ€ๅฏ็”จ๏ผ‰
122
+ --reset ้‡็ฝฎๆœฌๅœฐ้ข„่ฎพ๏ผŒไปŽๅ†…็ฝฎ้ป˜่ฎคๅ€ผ้‡ๆ–ฐๅˆ›ๅปบ
123
+
124
+ lux vscode <preset> [options]
125
+
126
+ --force ๅผบๅˆถ่ฆ†็›–ๅทฒๆœ‰ๆ–‡ไปถ
127
+ --dry-run ้ข„่งˆๆจกๅผ๏ผŒไธๅ†™ๅ…ฅๆ–‡ไปถ
128
+ --stylelint ๅŒ…ๅซ Stylelint ่ฎพ็ฝฎๅ’Œๆ‰ฉๅฑ•๏ผˆๆŒ‰้œ€ๅฏ็”จ๏ผ‰
129
+ --reset ้‡็ฝฎๆœฌๅœฐ้ข„่ฎพ๏ผŒไปŽๅ†…็ฝฎ้ป˜่ฎคๅ€ผ้‡ๆ–ฐๅˆ›ๅปบ
130
+ ```
131
+
132
+ <br />
133
+
134
+ ## ๐Ÿ”งๅทฅไฝœๅŽŸ็†
135
+
136
+ ```
137
+ lux fmt <preset> [options]
138
+ โ”‚
139
+ โ–ผ
140
+ ่งฃๆž CLI ๅ‚ๆ•ฐ๏ผŒๆ ก้ชŒ้กน็›ฎ package.json
141
+ โ”‚
142
+ โ–ผ
143
+ ้ข„่ฎพ็ฑปๅž‹ๅˆคๆ–ญ
144
+ โ”‚
145
+ โ”œโ”€โ”€ ๅ†…็ฝฎ้ข„่ฎพ โ”€โ”€โ–บ --reset๏ผŸ โ”€โ”€โ–บ ้‡็ฝฎๆœฌๅœฐๅ‰ฏๆœฌ
146
+ โ”‚ โ”‚
147
+ โ”‚ โ”œโ”€โ”€ ๆœฌๅœฐๅ‰ฏๆœฌๅญ˜ๅœจ (~/.lux/preset/)๏ผŸ โ”€โ”€โ–บ ไปŽๆœฌๅœฐๅ‰ฏๆœฌๅบ”็”จ
148
+ โ”‚ โ””โ”€โ”€ ไธๅญ˜ๅœจ โ”€โ”€โ–บ ไปŽๅ†…็ฝฎ็”Ÿๆˆ โ”€โ”€โ–บ ไฟๅญ˜ๅˆฐ ~/.lux/preset/ โ”€โ”€โ–บ ๅบ”็”จ
149
+ โ”‚
150
+ โ”œโ”€โ”€ ่‡ชๅฎšไน‰้ข„่ฎพ (~/.lux/preset/fmt/<name>/) โ”€โ”€โ–บ ็›ดๆŽฅไปŽๆœฌๅœฐ็›ฎๅฝ•ๅบ”็”จ
151
+ โ”‚
152
+ โ””โ”€โ”€ ๆœชๆ‰พๅˆฐ โ”€โ”€โ–บ ๆจก็ณŠๅŒน้…ๆ‰€ๆœ‰ๅฏ็”จ้ข„่ฎพ๏ผˆๅ†…็ฝฎ + ่‡ชๅฎšไน‰๏ผ‰ๅนถๆŠฅ้”™
153
+ โ”‚
154
+ โ–ผ
155
+ --stylelint / --editorconfig ่ฟ‡ๆปค๏ผˆ่‡ชๅฎšไน‰้ข„่ฎพๆ— ๅฏนๅบ”้…็ฝฎๆ—ถ warning๏ผ‰
156
+ โ”‚
157
+ โ–ผ
158
+ ้ๅކๆฏไธช้…็ฝฎๆ–‡ไปถ๏ผš
159
+ โ”‚
160
+ โ”œโ”€โ”€ ๆ–‡ไปถไธๅญ˜ๅœจ๏ผŸ โ”€โ”€โ–บ ๅˆ›ๅปบ
161
+ โ”œโ”€โ”€ ๅทฒๅญ˜ๅœจ + --force๏ผŸ โ”€โ”€โ–บ ่ฆ†็›–
162
+ โ””โ”€โ”€ ๅทฒๅญ˜ๅœจ๏ผŸ โ”€โ”€โ–บ ่ทณ่ฟ‡
163
+ โ”‚
164
+ โ–ผ
165
+ ๆณจๅ…ฅ่„šๆœฌๅˆฐ package.json๏ผˆ่‡ชๅŠจๆฃ€ๆต‹ bun / pnpm / npm / yarn๏ผ‰
166
+ โ”‚
167
+ โ–ผ
168
+ ่‡ชๅŠจๅฎ‰่ฃ… devDependencies๏ผˆๆฃ€ๆต‹ lockfile ๅˆคๆ–ญๅŒ…็ฎก็†ๅ™จ๏ผ‰
169
+ ```
170
+
171
+ <br />
172
+
173
+ ## ๐Ÿค ๅ‚ไธŽ่ดก็ŒฎไธŽๆ”ฏๆŒ
174
+
175
+ ๅ‘็Žฐ Bugใ€ๆœ‰็ปๅฆ™็š„ๆ–ฐๅŠŸ่ƒฝๆƒณๆณ•๏ผŒๆˆ–่€…ๆƒณไบฒ่‡ชไธ‹ๅœบไผ˜ๅŒ–ไปฃ็ ๏ผŸๆˆ‘ไปฌๆžๅ…ถๆฌข่ฟŽไฝ ็š„ๅŠ ๅ…ฅ๏ผ
176
+
177
+ - ๐Ÿ› **ๆไบค Bug ๆˆ–้œ€ๆฑ‚**๏ผšไปปไฝ•็–‘้—ฎๆˆ–ๆ”น่ฟ›ๅปบ่ฎฎ๏ผŒๆฌข่ฟŽ้šๆ—ถๅœจ GitHub [ๆไบค Issue](https://github.com/TTT1231/lux/issues)ใ€‚
178
+ - ๐Ÿ›  **ๆไบคไปฃ็  (PR)**๏ผš้žๅธธๆฌข่ฟŽๅนถไธ”ๆœŸๅพ…ไฝ ๆไบค [PR](https://github.com/TTT1231/lux/pulls) ๆฅไธ€่ตทๅฎŒๅ–„่ฟ™ไธช้กน็›ฎ๏ผ
179
+ - โญ๏ธ **็‚น่ตžๆ”ฏๆŒ**๏ผšๅฆ‚ๆžœ่ฟ™ไธชๅทฅๅ…ทๅธฎไฝ ่Š‚็œไบ†ๅ“ชๆ€• 5 ๅˆ†้’Ÿ็š„้…็ฝฎๆ—ถ้—ด๏ผŒ่ฏทๅœจ GitHub ไธŠ็‚นไบฎไธ€ไธช [โญ๏ธStar](https://github.com/TTT1231/lux)๏ผ
180
+
181
+ <br />
182
+
183
+ ## ๐Ÿ“„ ่ฎธๅฏ่ฏ
184
+
185
+ [ISC](https://opensource.org/licenses/ISC) โ€” ๅฏ่‡ช็”ฑไฝฟ็”จใ€ไฟฎๆ”นๅ’Œๅˆ†ๅ‘ใ€‚
186
+
187
+ <br />
188
+
189
+ <p align="right"><a href="./README.md">โ† Switch to English</a></p>
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { program } from "commander";
6
6
  // src/commands/fmt.ts
7
7
  import fs3 from "fs";
8
8
  import path5 from "path";
9
+ import chalk2 from "chalk";
9
10
 
10
11
  // src/presets/fmt/electron-vue.ts
11
12
  var electronVueFmt = {
@@ -668,7 +669,6 @@ var logger = {
668
669
  };
669
670
 
670
671
  // src/utils/errors.ts
671
- import chalk2 from "chalk";
672
672
  var CliError = class extends Error {
673
673
  code;
674
674
  suggestion;
@@ -714,14 +714,6 @@ function levenshtein(a, b) {
714
714
  }
715
715
  function resolvePreset(presets, name) {
716
716
  const found = presets.find((p) => p.name === name);
717
- if (!found) {
718
- const err = new PresetNotFoundError(
719
- name,
720
- presets.map((p) => p.name)
721
- );
722
- console.error(chalk2.red(err.message));
723
- process.exit(1);
724
- }
725
717
  return found;
726
718
  }
727
719
 
@@ -1031,6 +1023,28 @@ function getLocalPresetDir(type, presetName) {
1031
1023
  function isValidPresetName(name) {
1032
1024
  return name.length > 0 && !name.includes("/") && !name.includes("\\") && !name.includes("..");
1033
1025
  }
1026
+ function listCustomPresets() {
1027
+ const fmtDir = path4.join(getLuxDir(), "preset", "fmt");
1028
+ if (!fs2.existsSync(fmtDir)) return [];
1029
+ const entries = fs2.readdirSync(fmtDir, { withFileTypes: true });
1030
+ const result = [];
1031
+ for (const entry of entries) {
1032
+ if (!entry.isDirectory()) continue;
1033
+ if (!isValidPresetName(entry.name)) continue;
1034
+ const pkgPath = path4.join(fmtDir, entry.name, "package.json");
1035
+ if (fs2.existsSync(pkgPath)) {
1036
+ result.push(entry.name);
1037
+ }
1038
+ }
1039
+ return result;
1040
+ }
1041
+ function isValidCustomPreset(name) {
1042
+ if (!isValidPresetName(name)) return false;
1043
+ const presetDir = path4.join(getLuxDir(), "preset", "fmt", name);
1044
+ if (!fs2.existsSync(presetDir)) return false;
1045
+ const pkgPath = path4.join(presetDir, "package.json");
1046
+ return fs2.existsSync(pkgPath);
1047
+ }
1034
1048
  function localPresetExists(type, presetName) {
1035
1049
  const dir = getLocalPresetDir(type, presetName);
1036
1050
  return fs2.existsSync(dir);
@@ -1244,11 +1258,13 @@ function mergeTemplateIntoProject(templatePkg, projectPkg, pm, opts, result) {
1244
1258
  if (templatePkg.scripts) {
1245
1259
  const existingScripts = merged.scripts ?? {};
1246
1260
  const newScripts = { ...existingScripts };
1247
- for (const [key, value] of Object.entries(templatePkg.scripts)) {
1248
- let resolved = value.replace(/<pm>/g, prefix);
1249
- if (opts.noStylelint) {
1250
- resolved = resolved.replace(/\s*&&\s*stylelint\s+"[^"]*".*/g, "");
1251
- }
1261
+ const filteredScripts = filterScripts(
1262
+ templatePkg.scripts,
1263
+ opts.noStylelint,
1264
+ opts.noEditorconfig
1265
+ );
1266
+ for (const [key, value] of Object.entries(filteredScripts)) {
1267
+ const resolved = value.replace(/<pm>/g, prefix);
1252
1268
  if (existingScripts[key] !== void 0 && !opts.force) {
1253
1269
  result.scriptsSkipped++;
1254
1270
  if (opts.dryRun) {
@@ -1283,6 +1299,42 @@ function filterStylelintSettings(settings) {
1283
1299
  }
1284
1300
  return filtered;
1285
1301
  }
1302
+ function filterScripts(scripts, noStylelint, noEditorconfig) {
1303
+ const filtered = {};
1304
+ for (const [key, value] of Object.entries(scripts)) {
1305
+ if (noStylelint && key.includes("stylelint")) continue;
1306
+ if (noEditorconfig && key.includes("editorconfig")) continue;
1307
+ let resolved = value;
1308
+ if (noStylelint) {
1309
+ resolved = resolved.replace(/\s*&&\s*stylelint\s+"[^"]*".*/g, "");
1310
+ }
1311
+ filtered[key] = resolved;
1312
+ }
1313
+ return filtered;
1314
+ }
1315
+ function detectPresetCapabilities(presetName) {
1316
+ const presetDir = path4.join(getLuxDir(), "preset", "fmt", presetName);
1317
+ const entries = fs2.readdirSync(presetDir);
1318
+ const hasStylelintFile = entries.some((f) => STYLELINT_FILES.has(f));
1319
+ const pkg = readJson(
1320
+ path4.join(presetDir, "package.json")
1321
+ );
1322
+ const hasStylelintDep = pkg?.devDependencies ? Object.keys(pkg.devDependencies).some((d) => isNotStylelintDep(d) === false) : false;
1323
+ const hasEditorconfigFile = entries.includes(EDITORCONFIG_FILE);
1324
+ const hasEditorconfigDep = pkg?.devDependencies ? Object.keys(pkg.devDependencies).some((d) => !isNotEditorconfigDep(d)) : false;
1325
+ return {
1326
+ hasStylelint: hasStylelintFile || hasStylelintDep,
1327
+ hasEditorconfig: hasEditorconfigFile || hasEditorconfigDep
1328
+ };
1329
+ }
1330
+ function isNotStylelintDep(dep) {
1331
+ if (dep.includes("stylelint")) return false;
1332
+ if (dep === "postcss-html" || dep === "postcss-scss") return false;
1333
+ return true;
1334
+ }
1335
+ function isNotEditorconfigDep(dep) {
1336
+ return !dep.includes("editorconfig");
1337
+ }
1286
1338
  function resolveLocalDeps(deps) {
1287
1339
  const packages = [];
1288
1340
  for (const [name, version] of Object.entries(deps)) {
@@ -1296,27 +1348,24 @@ function resolveLocalDeps(deps) {
1296
1348
  }
1297
1349
 
1298
1350
  // src/commands/fmt.ts
1299
- function filterStylelintScripts(scripts) {
1300
- const filtered = {};
1301
- for (const [key, value] of Object.entries(scripts)) {
1302
- filtered[key] = value.replace(/\s*&&\s*stylelint\s+"[^"]*".*/g, "");
1303
- }
1304
- return filtered;
1305
- }
1306
- function isNotStylelintDep(dep) {
1351
+ function isNotStylelintDep2(dep) {
1307
1352
  if (dep.includes("stylelint")) return false;
1308
1353
  if (dep === "postcss-html" || dep === "postcss-scss") return false;
1309
1354
  return true;
1310
1355
  }
1311
- function isNotEditorconfigDep(dep) {
1356
+ function isNotEditorconfigDep2(dep) {
1312
1357
  return !dep.includes("editorconfig");
1313
1358
  }
1314
1359
  function registerFmtCommand(program2) {
1315
1360
  const fmt = program2.command("fmt").description("Initialize formatting config with preset");
1316
1361
  fmt.argument("<preset>").option("-F, --force", "Force overwrite existing files").option("--no-install", "Skip dependency installation").option("--dry-run", "Preview without writing files").option("--stylelint", "Include Stylelint config generation").option("--editorconfig", "Include EditorConfig config generation").option("--reset", "Reset local preset and re-materialize from built-in").action(
1317
1362
  async (presetName, options) => {
1318
- const preset = resolvePreset(FMT_PRESETS, presetName);
1319
- if (!preset) return;
1363
+ const builtinPreset = FMT_PRESETS.find((p) => p.name === presetName);
1364
+ const isBuiltin = builtinPreset !== void 0;
1365
+ if (options.reset && !isBuiltin) {
1366
+ logger.warn(`"${presetName}" is a custom preset, --reset has no builtin to restore`);
1367
+ return;
1368
+ }
1320
1369
  const cwd = process.cwd();
1321
1370
  const pkgPath = path5.join(cwd, "package.json");
1322
1371
  if (fileExists(pkgPath)) {
@@ -1329,25 +1378,52 @@ function registerFmtCommand(program2) {
1329
1378
  return;
1330
1379
  }
1331
1380
  }
1332
- if (options.reset) {
1333
- resetLocalPreset("fmt", presetName);
1334
- }
1335
- const useLocal = localPresetExists("fmt", presetName);
1336
- if (useLocal) {
1381
+ if (isBuiltin) {
1382
+ if (options.reset) {
1383
+ resetLocalPreset("fmt", presetName);
1384
+ }
1385
+ const useLocal = localPresetExists("fmt", presetName);
1386
+ if (useLocal) {
1387
+ await executeLocalPath(cwd, presetName, options);
1388
+ } else {
1389
+ await executeBuiltinPath(cwd, presetName, builtinPreset, options);
1390
+ }
1391
+ } else if (isValidCustomPreset(presetName)) {
1337
1392
  await executeLocalPath(cwd, presetName, options);
1338
1393
  } else {
1339
- await executeBuiltinPath(cwd, presetName, preset, options);
1394
+ const builtinNames = new Set(FMT_PRESETS.map((p) => p.name));
1395
+ const customNames = listCustomPresets().filter((n) => !builtinNames.has(n));
1396
+ const allNames = [...builtinNames, ...customNames];
1397
+ const err = new PresetNotFoundError(presetName, allNames);
1398
+ logger.error(err.message);
1399
+ process.exitCode = 1;
1340
1400
  }
1341
1401
  }
1342
1402
  );
1343
1403
  fmt.command("list").description("List available fmt presets").action(() => {
1404
+ const builtinNames = new Set(FMT_PRESETS.map((p) => p.name));
1344
1405
  for (const p of FMT_PRESETS) {
1345
1406
  console.log(`${p.name.padEnd(12)} ${p.description}`);
1346
1407
  }
1408
+ const customs = listCustomPresets().filter((name) => !builtinNames.has(name));
1409
+ for (const name of customs) {
1410
+ console.log(`${name.padEnd(12)} ${chalk2.yellow("(custom)")}`);
1411
+ }
1347
1412
  });
1348
1413
  }
1349
1414
  async function executeLocalPath(cwd, presetName, options) {
1350
1415
  logger.log("Using local custom preset");
1416
+ const caps = detectPresetCapabilities(presetName);
1417
+ if (options.stylelint && !caps.hasStylelint) {
1418
+ logger.warn(
1419
+ "--stylelint has no effect: this custom preset has no stylelint config or dependencies"
1420
+ );
1421
+ }
1422
+ if (options.editorconfig && !caps.hasEditorconfig) {
1423
+ logger.warn(
1424
+ "--editorconfig has no effect: this custom preset has no editorconfig config or dependencies"
1425
+ );
1426
+ }
1351
1427
  const opts = {
1352
1428
  cwd,
1353
1429
  force: options.force ?? false,
@@ -1452,13 +1528,13 @@ async function executeBuiltinPath(cwd, presetName, preset, options) {
1452
1528
  warnMissingPackageJson(preset, options.install !== false);
1453
1529
  return;
1454
1530
  }
1455
- const scripts = opts.noStylelint && preset.scripts ? filterStylelintScripts(preset.scripts) : preset.scripts;
1531
+ const scripts = preset.scripts ? filterScripts(preset.scripts, opts.noStylelint, opts.noEditorconfig) : void 0;
1456
1532
  if (scripts) {
1457
1533
  await injectScripts(scripts, opts, pm);
1458
1534
  }
1459
1535
  if (!preset.dependencies?.dev) return;
1460
- const devDeps = opts.noStylelint ? preset.dependencies.dev.filter(isNotStylelintDep) : preset.dependencies.dev;
1461
- const finalDeps = opts.noEditorconfig ? devDeps.filter(isNotEditorconfigDep) : devDeps;
1536
+ const devDeps = opts.noStylelint ? preset.dependencies.dev.filter(isNotStylelintDep2) : preset.dependencies.dev;
1537
+ const finalDeps = opts.noEditorconfig ? devDeps.filter(isNotEditorconfigDep2) : devDeps;
1462
1538
  if (opts.dryRun) {
1463
1539
  logger.log(`[dry-run] Would add to package.json: ${finalDeps.join(", ")}`);
1464
1540
  return;
@@ -1488,8 +1564,8 @@ async function executeBuiltinPath(cwd, presetName, preset, options) {
1488
1564
  }
1489
1565
  function filterDeps(deps, noStylelint, noEditorconfig) {
1490
1566
  let filtered = deps;
1491
- if (noStylelint) filtered = filtered.filter(isNotStylelintDep);
1492
- if (noEditorconfig) filtered = filtered.filter(isNotEditorconfigDep);
1567
+ if (noStylelint) filtered = filtered.filter(isNotStylelintDep2);
1568
+ if (noEditorconfig) filtered = filtered.filter(isNotEditorconfigDep2);
1493
1569
  return filtered;
1494
1570
  }
1495
1571
  function logGenerationResult(result, dryRun) {
@@ -2676,7 +2752,15 @@ function registerVscodeCommand(program2) {
2676
2752
  vscode.argument("<preset>").option("-F, --force", "Force overwrite existing files").option("--dry-run", "Preview without writing files").option("--stylelint", "Include Stylelint settings and extension").option("--reset", "Reset local preset and re-materialize from built-in").action(
2677
2753
  async (presetName, options) => {
2678
2754
  const preset = resolvePreset(VSCODE_PRESETS, presetName);
2679
- if (!preset) return;
2755
+ if (!preset) {
2756
+ const err = new PresetNotFoundError(
2757
+ presetName,
2758
+ VSCODE_PRESETS.map((p) => p.name)
2759
+ );
2760
+ logger.error(err.message);
2761
+ process.exitCode = 1;
2762
+ return;
2763
+ }
2680
2764
  const cwd = process.cwd();
2681
2765
  if (options.reset) {
2682
2766
  resetLocalPreset("vscode", presetName);
@@ -1,20 +1,6 @@
1
1
  # Custom Preset Configuration
2
2
 
3
- > โš ๏ธ **Always use `lux init --preset` to initialize presets.** Running `lux fmt` / `lux vscode` directly generates config files in cwd and requires `package.json` โ€” only use in real project directories.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- lux init --preset # materialize all built-in presets to ~/.lux/preset/
9
- ```
10
-
11
- After materialization, edit files under `~/.lux/preset/<type>/<preset-name>/` to customize. Changes take effect on the next `lux fmt` / `lux vscode` run.
12
-
13
- `lux init --preset` can be run repeatedly โ€” each run overwrites with built-in defaults. To reset a single preset, use `lux fmt <name> --reset` or `lux vscode <name> --reset` (deletes local preset dir only; re-generated from built-in on next run).
14
-
15
- ## Storage Location
16
-
17
- `~/.lux/preset/` (i.e. `os.homedir()/.lux/preset/`). Override with `LUX_HOME` env var.
3
+ lux ้ข„่ฎพๅญ˜ๅ‚จๅœจ`~/.lux/preset/` (i.e. `os.homedir()/.lux/preset/`). Override with `LUX_HOME` env varใ€‚
18
4
 
19
5
  ```
20
6
  ~/.lux/preset/
@@ -22,46 +8,118 @@ After materialization, edit files under `~/.lux/preset/<type>/<preset-name>/` to
22
8
  โ””โ”€โ”€ vscode/ # vscode presets (same + go)
23
9
  ```
24
10
 
25
- ## File Reference
11
+ > โš ๏ธ **Always use `lux init --preset` to initialize all built-in presets.**ใ€‚
12
+
13
+ ## Built-in presets File Reference
26
14
 
27
15
  ### fmt preset
28
16
 
29
- | File | Description |
30
- | :--------------------- | :--------------------------------------------- |
31
- | `eslint.config.mjs` | ESLint flat config |
32
- | `.prettierrc` | Prettier JSON config |
33
- | `.prettierignore` | Prettier ignore rules |
34
- | `stylelint.config.mjs` | Stylelint config |
35
- | `.stylelintignore` | Stylelint ignore rules |
36
- | `cspell.json` | CSpell dictionary config |
37
- | `.editorconfig` | EditorConfig config |
38
- | `package.json` | Template with `devDependencies` and `scripts` |
17
+ | File | Description |
18
+ | :--------------------- | :-------------------------------------------- |
19
+ | `eslint.config.mjs` | ESLint flat config |
20
+ | `.prettierrc` | Prettier JSON config |
21
+ | `.prettierignore` | Prettier ignore rules |
22
+ | `stylelint.config.mjs` | Stylelint config |
23
+ | `.stylelintignore` | Stylelint ignore rules |
24
+ | `cspell.json` | CSpell dictionary config |
25
+ | `.editorconfig` | EditorConfig config |
26
+ | `package.json` | Template with `devDependencies` and `scripts` |
39
27
 
40
28
  ### vscode preset
41
29
 
42
- | File | Description |
43
- | :---------------- | :-------------------------- |
44
- | `settings.json` | VSCode workspace settings |
30
+ | File | Description |
31
+ | :---------------- | :------------------------------- |
32
+ | `settings.json` | VSCode workspace settings |
45
33
  | `extensions.json` | VSCode extension recommendations |
46
34
 
47
- ## Template Placeholders (fmt preset)
35
+ ## Customize built-in presets
36
+
37
+ ```bash
38
+ lux init --preset # init all built-in presets
39
+ ```
40
+
41
+ After init, edit files under `~/.lux/preset/<type>/<preset-name>/` to customize๏ผŒไพ‹ๅฆ‚`package.json`ใ€`eslint.config.mjs`็ญ‰็ญ‰๏ผŒไนŸๅฏไปฅๅขžๅŠ ไฝ ่‡ชๅทฑ็š„ lint ๆ–‡ไปถไพ‹ๅฆ‚`your-file-lint-config`. Changes take effect on the next `lux fmt` / `lux vscode` run.
42
+
43
+ ๅฆ‚ๆžœไฝ ่‡ชๅฎšไน‰ๅ†…็ฝฎ้ข„่ฎพๆƒณ้‡็ฝฎ็š„ๆ—ถๅ€™๏ผŒๅฏไปฅ้‡ๆ–ฐๆ‰ง่กŒ`lux init --preset`ๅŽป่ฆ†็›–๏ผŒๆˆ–่€…ไฝฟ็”จ`lux fmt <name> --reset` ใ€`lux vscode <name> --reset` (deletes local preset dir only; re-generated from built-in on next run).
48
44
 
49
- | Placeholder | Replaced with |
50
- | :---------- | :------------ |
51
- | `<pm>` | Package manager prefix (`bun run` / `pnpm run` / `npm run`) |
52
- | `<lockfile>` | Project lockfile name (`bun.lock` / `pnpm-lock.yaml` etc.) |
53
- | `"<latest>"` | Resolved to latest version at install time, or pin like `"3.3.0"` |
45
+ ## Customize your own presets
54
46
 
55
- ## Workflow
47
+ ### fmt
56
48
 
49
+ Create a directory under `~/.lux/preset/fmt/<your-fmt-preset-name>/` with config files and a `package.json`:
50
+
51
+ ```bash
52
+ # 1. Create the preset directory
53
+ mkdir -p ~/.lux/preset/fmt/[your-custom-fmt-preset-name]
54
+
55
+ # 2. Add config files (pick what you need)
56
+ # Required: package.json (with devDependencies/dependencies and/or scripts)
57
+ # Optional: eslint.config.mjs, .prettierrc, .prettierignore,
58
+ # stylelint.config.mjs, .stylelintignore,
59
+ # cspell.json, .editorconfig , etc....
60
+ ```
61
+
62
+ Minimum `package.json` example:
63
+
64
+ ```json
65
+ {
66
+ "devDependencies": {
67
+ "eslint": "<latest>",
68
+ "prettier": "<latest>"
69
+ },
70
+ "scripts": {
71
+ "lint": "<pm> eslint .",
72
+ "lint:fix": "<pm> eslint . --fix --cache --cache-location node_modules/.cache/.eslintcache",
73
+ "cspell": "<pm> cspell \"**\""
74
+ }
75
+ }
76
+ ```
77
+
78
+ Then ๆ‰ง่กŒ`lux fmt list`ๆฃ€ๆŸฅๆ˜ฏๅฆ็”Ÿๆ•ˆโ€”โ€”่ฟ™ไธช`<your-fmt-preset-name>` ๆ˜ฏๅฆๅ‡บ็Žฐๅœจๅ…ถไธญใ€‚
79
+
80
+ ```bash
81
+ lux fmt <your-fmt-preset-name> # applies your custom preset
82
+ lux fmt <your-fmt-preset-name> --force # overwrite existing config files
83
+ lux fmt <your-fmt-preset-name> --dry-run # preview without writing
84
+ lux fmt <your-fmt-preset-name> --stylelint # applies your custom preset (includes stylelint config)
57
85
  ```
58
- lux init --preset
59
- โ†’ materialize all built-in presets to ~/.lux/preset/ (no cwd writes)
60
86
 
61
- lux fmt web-vue (in target project)
62
- โ†’ local preset exists โ†’ use local version (with custom edits)
63
- โ†’ local preset missing โ†’ generate from built-in + materialize (also writes to cwd)
87
+ Notes:
88
+
89
+ - `lux fmt list` shows custom presets after built-in ones, marked with `(custom)`
90
+ - `lux fmt <name> --reset` warns and aborts for custom presets โ€” there is no built-in source to restore
91
+ - Unknown preset names fuzzy-match against all available presets (builtin + custom combined)
92
+ - `lux fmt` returns exit code **1** when a preset is not found (safe for CI/CD)
93
+ - `lux fmt <name> --stylelint/--editorconfig` warns when the flag has no effect (preset has no matching config or dependencies)
94
+
95
+ ### vscode
96
+
97
+ Custom vscode presets are not yet supported. To customize VSCode settings, use the built-in preset customization flow:
98
+
99
+ ```bash
100
+ lux init --preset # materialize built-in presets
101
+ # Edit files under ~/.lux/preset/vscode/<preset-name>/
102
+ # - settings.json (VSCode workspace settings)
103
+ # - extensions.json (extension recommendations)
104
+ lux vscode web-vue # applies your customized preset
105
+ ```
64
106
 
65
- lux vscode web-vue (in target project)
66
- โ†’ same as above
107
+ ## Fmt presets ยท package.json rules
108
+
109
+ `devDependencies` ๅ’Œ `dependencies` ๆœ€ๆ–ฐ็‰ˆๆœฌๅ ไฝไฝฟ็”จ`<latest>`๏ผŒ็‰นๅฎš็‰ˆๆœฌ้™คๅค–ใ€‚่ฟ˜ๆœ‰่ฟ™ไธช`scripts`ๅฆ‚ๆžœไธ็กฎๅฎšๅŒ…็ฎก็†ๅ™จๅฐฑ็”จๅ ไฝ็ฌฆ`<pm>`่ฎฉ lux ่‡ชๅŠจๆฃ€ๆต‹ใ€‚
110
+
111
+ ```jsonc
112
+ {
113
+ "devDependencies": {
114
+ // ๆœ€ๆ–ฐ็‰ˆๆœฌ
115
+ "prettier": "<latest>",
116
+ // ๅ›บๅฎš็‰ˆๆœฌ
117
+ "cspell": "10.0.0",
118
+ },
119
+ "scripts": {
120
+ "lint": "<pm> eslint .",
121
+ "lint:fix": "<pm> eslint . --fix --cache --cache-location node_modules/.cache/.eslintcache",
122
+ "cspell": "<pm> cspell \"**\"",
123
+ },
124
+ }
67
125
  ```
@@ -15,25 +15,28 @@ lux fmt list
15
15
  - `--no-install` โ€” write deps to package.json but skip install
16
16
  - `--reset` โ€” reset local preset, re-materialize from built-in defaults
17
17
 
18
- Presets: `web-vue` `web-react` `electron-vue` `uniapp` `node` `nest`
18
+ `lux fmt list` Built-in presets first, custom presets last, marked with **custom**.
19
+
20
+ built-in presets: `web-vue` `web-react` `electron-vue` `uniapp` `node` `nest`
19
21
 
20
22
  ## vscode โ€” generate editor settings
21
23
 
22
24
  ```bash
23
- lux vscode <preset> [--dry-run]
25
+ lux vscode <preset> [--dry-run] [--stylelint]
24
26
  lux vscode list
25
27
  ```
26
28
 
27
29
  - `--force` โ€” overwrite existing settings (default: skip)
28
30
  - `--dry-run` โ€” preview what would be generated, write nothing
31
+ - `--stylelint` โ€” Include Stylelint settings and extension
29
32
  - `--reset` โ€” reset local preset, re-materialize from built-in defaults
30
33
 
31
- Presets: `web-vue` `web-react` `electron-vue` `uniapp` `node` `nest` `go`
34
+ built-in presets: `web-vue` `web-react` `electron-vue` `uniapp` `node` `nest` `go`
32
35
 
33
36
  ## init โ€” initialize skills or presets
34
37
 
35
38
  ```bash
36
- lux init # interactively select AI tool, copy skill files to project
39
+ lux init # interactively select AI tool, copy skill files to AI Agent
37
40
  lux init --preset # materialize all built-in presets to ~/.lux/preset/ (no cwd writes, no package.json required)
38
41
  ```
39
42
 
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@luxkit/cli",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "One-click project formatting & VSCode config CLI",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "lux": "dist/index.js"
8
8
  },
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "README_Zh.md"
11
12
  ],
12
13
  "publishConfig": {
13
14
  "access": "public"
@@ -21,7 +22,8 @@
21
22
  "prepublishOnly": "cross-env NODE_ENV=production bun run build",
22
23
  "test": "vitest run",
23
24
  "test:watch": "vitest",
24
- "test:coverage": "vitest run --coverage"
25
+ "test:coverage": "vitest run --coverage",
26
+ "code:check": "bun run lint && bun run format:check"
25
27
  },
26
28
  "keywords": [
27
29
  "cli",