@lumiflora/fsdk 0.1.4 → 0.1.6

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
@@ -1,122 +1,107 @@
1
- # @lumiflora/fsdk
2
-
3
1
  Vue 3 前端项目脚手架 CLI 工具,快速创建包含最佳技术栈的项目骨架。
4
2
 
5
3
  ## 安装
6
4
 
7
5
  ```bash
6
+ # 方式一:本地开发模式
7
+ cd /path/to/fsdk
8
+ pnpm install
9
+ pnpm dev
10
+
11
+ # 方式二:全局安装(发布后)
12
+ pnpm build
8
13
  npm install -g @lumiflora/fsdk
9
14
  ```
10
15
 
11
- ## 快速开始
16
+ ## 使用命令
12
17
 
13
18
  ```bash
14
- # 交互式创建项目
15
- fsdk create
16
-
17
- # 指定参数创建
19
+ # 创建新项目
20
+ fsdk create my-project # 交互式创建
18
21
  fsdk create my-project --template full --package-manager pnpm
19
- ```
20
-
21
- ## 命令
22
22
 
23
- ### create - 创建新项目
23
+ # 添加页面
24
+ fsdk add-page --page-name user --router-path /user
24
25
 
25
- ```bash
26
- fsdk create [project-name] [options]
27
-
28
- Options:
29
- --template <name> 模板名称 (base|full) [default: base]
30
- --package-manager <pm> 包管理器 (npm|pnpm|yarn|bun) [default: pnpm]
31
- --eslint 启用 ESLint [default: true]
32
- --no-git 跳过 git 初始化
33
- --no-install 跳过依赖安装
34
- ```
26
+ # 添加组件
27
+ fsdk add-component --name Header --type common
35
28
 
36
- ### add-page - 添加页面
29
+ # 添加 Store
30
+ fsdk add-store --name user
37
31
 
38
- ```bash
39
- fsdk add-page [options]
32
+ # 校验配置和模板
33
+ fsdk validate
40
34
 
41
- Options:
42
- --page-name <name> 页面名称
43
- --router-path <path> 路由路径
44
- ```
35
+ # 预览模板
36
+ fsdk preview --port 3000
45
37
 
46
- ### add-component - 添加组件
38
+ # 生成并安装补全脚本
39
+ fsdk completion bash # 生成 bash 补全脚本
40
+ fsdk completion zsh # 生成 zsh 补全脚本
41
+ fsdk completion fish # 生成 fish 补全脚本
47
42
 
48
- ```bash
49
- fsdk add-component [options]
43
+ # 自动安装到 shell 配置文件(推荐)
44
+ fsdk completion bash --install
45
+ fsdk completion zsh --install
50
46
 
51
- Options:
52
- --name <name> 组件名称
53
- --type <type> 组件类型 (page|common|business) [default: common]
54
- --dir <dir> 子目录
47
+ # 查看帮助
48
+ fsdk --help
49
+ fsdk create --help
55
50
  ```
56
51
 
57
- ### add-store - 添加状态管理
52
+ ## Shell 补全
58
53
 
59
- ```bash
60
- fsdk add-store [options]
61
-
62
- Options:
63
- --name <name> Store 名称
64
- --type <type> Store 类型 (pinia|redux) [default: pinia]
65
- ```
54
+ fsdk 支持 bash、zsh 和 fish 的命令行补全。安装后,输入 `fsdk ` 后按 Tab 键可自动补全命令和选项。
66
55
 
67
- ### validate - 校验配置和模板
56
+ ### Bash(Linux / macOS)
68
57
 
69
58
  ```bash
70
- fsdk validate [options]
59
+ # 方式一:自动安装(推荐)
60
+ fsdk completion bash --install
61
+ source ~/.bashrc
71
62
 
72
- Options:
73
- --config 仅校验配置
74
- --templates 仅校验模板
75
- --strict 严格校验
63
+ # 方式二:手动安装
64
+ fsdk completion bash
65
+ echo 'source ~/.fsdk-completion.bash' >> ~/.bashrc
66
+ source ~/.bashrc
76
67
  ```
77
68
 
78
- ### preview - 预览模板
69
+ ### Zsh(macOS 默认)
79
70
 
80
71
  ```bash
81
- fsdk preview [options]
82
-
83
- Options:
84
- --port <port> 端口号 [default: 3000]
85
- --host <host> 主机地址 [default: localhost]
86
- --open 打开浏览器
87
- --template <name> 模板名称
72
+ # 方式一:自动安装(推荐)
73
+ fsdk completion zsh --install
74
+ source ~/.zshrc
75
+
76
+ # 方式二:手动安装
77
+ fsdk completion zsh
78
+ # 添加以下内容到 ~/.zshrc:
79
+ # fpath=("$HOME/.zsh/completion" $fpath)
80
+ # autoload -U compinit && compinit
81
+ source ~/.zshrc
88
82
  ```
89
83
 
90
- ### sync-template - 同步模板文件
91
-
92
- ```bash
93
- fsdk sync-template [options]
94
-
95
- Options:
96
- --template <name> 模板名称
97
- --force 强制同步
98
- ```
84
+ > **注意**:如果使用 Oh My Zsh,可以将补全文件复制到 `~/.oh-my-zsh/completions/` 目录:
85
+ > ```bash
86
+ > mkdir -p ~/.oh-my-zsh/completions
87
+ > fsdk completion zsh --output ~/.oh-my-zsh/completions/_fsdk
88
+ > exec zsh
89
+ > ```
99
90
 
100
- ### completion - 生成 Shell 补全
91
+ ### Fish
101
92
 
102
93
  ```bash
103
- fsdk completion [shell] [options]
104
-
105
- Options:
106
- --install 自动安装到 shell 配置
107
-
108
- # 示例
109
- fsdk completion --install # 自动配置当前 shell
110
- fsdk completion zsh --install
111
- fsdk completion bash --install
94
+ fsdk completion fish
95
+ # 补全文件自动生成到 ~/.config/fish/completions/fsdk.fish
96
+ # 重启 fish 或打开新终端即可生效
112
97
  ```
113
98
 
114
99
  ## 模板
115
100
 
116
101
  | 模板 | 说明 |
117
102
  |------|------|
103
+ | `full` | Vue 3.5 + Vite 6 + Element Plus + Pinia + Vue Router + SCSS |
118
104
  | `base` | Vue 3.5 + Vite 6 基础版 |
119
- | `full` | Vue 3.5 + Vite 6 + Element Plus + Pinia + Vue Router + SCSS + ESLint |
120
105
 
121
106
  ## 技术栈
122
107
 
@@ -129,22 +114,3 @@ fsdk completion bash --install
129
114
  | Vite | ^6.0.0 | 构建工具 |
130
115
  | TypeScript | ~5.6.0 | 类型系统 |
131
116
  | ESLint | ^9.0.0 | 代码检查 |
132
-
133
- ## 开发
134
-
135
- ```bash
136
- # 本地开发
137
- cd packages/cli
138
- pnpm install
139
- pnpm dev
140
-
141
- # 构建
142
- pnpm build
143
-
144
- # 类型检查
145
- pnpm typecheck
146
- ```
147
-
148
- ## License
149
-
150
- MIT
@@ -1 +1 @@
1
- {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAoLD,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BvF"}
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA8KD,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCvF"}
@@ -45,14 +45,11 @@ _fsdk_completion() {
45
45
 
46
46
  complete -F _fsdk_completion fsdk
47
47
  `;
48
- const ZSH_COMPLETION = `#fsdk completion
49
- autoload -Uz compinit
50
- compinit 2>/dev/null
48
+ const ZSH_COMPLETION = `#compdef fsdk
51
49
 
52
- # Define the completion function
53
50
  _fsdk() {
54
- local -a _fsdk_cmds
55
- _fsdk_cmds=(
51
+ local -a commands
52
+ commands=(
56
53
  'create:Create a new application'
57
54
  'add-page:Add a new page'
58
55
  'add-component:Add a new component'
@@ -70,7 +67,7 @@ _fsdk() {
70
67
 
71
68
  case "$state" in
72
69
  command)
73
- _describe 'command' _fsdk_cmds
70
+ _describe 'command' commands
74
71
  ;;
75
72
  args)
76
73
  case $words[1] in
@@ -126,9 +123,6 @@ _fsdk() {
126
123
  ;;
127
124
  esac
128
125
  }
129
-
130
- # Register the completion function for fsdk command
131
- compdef _fsdk fsdk
132
126
  `;
133
127
  const FISH_COMPLETION = `# fish completion for fsdk
134
128
 
@@ -192,7 +186,13 @@ export async function generateCompletion(options = {}) {
192
186
  await installToShellRc(shell, outputPath);
193
187
  }
194
188
  else if (!install) {
195
- if (shell !== 'fish') {
189
+ if (shell === 'zsh') {
190
+ const completionDir = path.dirname(outputPath);
191
+ logger.info(`Add the following lines to your ~/.zshrc:`);
192
+ logger.info(` fpath=("${completionDir}" $fpath)`);
193
+ logger.info(` autoload -U compinit && compinit`);
194
+ }
195
+ else if (shell !== 'fish') {
196
196
  logger.info(`Add the following line to your shell configuration:`);
197
197
  logger.info(` source ${outputPath}`);
198
198
  }
@@ -210,12 +210,16 @@ export async function generateCompletion(options = {}) {
210
210
  async function installToShellRc(shell, completionPath) {
211
211
  const home = process.env.HOME || '';
212
212
  let rcFile = '';
213
- let sourceLine = `source ${completionPath}`;
213
+ let sourceLine = '';
214
214
  if (shell === 'bash') {
215
215
  rcFile = path.resolve(home, '.bashrc');
216
+ sourceLine = `source ${completionPath}`;
216
217
  }
217
218
  else if (shell === 'zsh') {
218
219
  rcFile = path.resolve(home, '.zshrc');
220
+ // For zsh, add to fpath and compinit
221
+ const completionDir = path.dirname(completionPath);
222
+ sourceLine = `# Add fsdk completion to fpath\nfpath=("${completionDir}" $fpath)\nautoload -U compinit && compinit`;
219
223
  }
220
224
  else {
221
225
  logger.warning(`--install is not supported for fish shell yet`);
@@ -226,12 +230,12 @@ async function installToShellRc(shell, completionPath) {
226
230
  if (await fs.pathExists(rcFile)) {
227
231
  rcContent = await fs.readFile(rcFile, 'utf-8');
228
232
  }
229
- const pattern = shell === 'bash' ? /\.fsdk-completion/ : 'fsdk-completion';
233
+ const pattern = shell === 'bash' ? /\.fsdk-completion/ : 'fsdk completion';
230
234
  if (rcContent.includes(pattern)) {
231
235
  logger.info(`Completion already installed in ${rcFile}`);
232
236
  return;
233
237
  }
234
- await fs.appendFile(rcFile, `\n# fsdk completion\n${sourceLine}\n`);
238
+ await fs.appendFile(rcFile, `\n# ${shell} fsdk completion\n${sourceLine}\n`);
235
239
  logger.success(`Completion installed to ${rcFile}`);
236
240
  logger.info(`Run "source ${rcFile}" or restart your shell to apply`);
237
241
  }
@@ -254,7 +258,8 @@ function getDefaultOutputPath(shell) {
254
258
  case 'bash':
255
259
  return path.resolve(home, '.fsdk-completion.bash');
256
260
  case 'zsh':
257
- return path.resolve(home, '.fsdk-completion.zsh');
261
+ // zsh completion must be in fpath directory with _command name
262
+ return path.resolve(home, '.zsh', 'completion', '_fsdk');
258
263
  case 'fish':
259
264
  return path.resolve(home, '.config', 'fish', 'completions', 'fsdk.fish');
260
265
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import { createRequire } from 'module';
4
+ import fs from 'fs';
5
5
  import cac from 'cac';
6
6
  import { logger, enableDebugMode, resolveCwd } from './utils/index.js';
7
7
  import { configLoader, pluginSystem } from './core/index.js';
@@ -12,9 +12,9 @@ import { createApp, addPage, addComponent, addStore, syncTemplate, validate, pre
12
12
  const cliEntryPath = fileURLToPath(import.meta.url);
13
13
  const cliRoot = path.dirname(path.dirname(cliEntryPath));
14
14
  global.__cliRoot = cliRoot;
15
- // Create require for reading package.json in ES module
16
- const require = createRequire(import.meta.url);
17
- const pkg = require('../../package.json');
15
+ // Read package.json to get version
16
+ const pkgPath = path.join(cliRoot, 'package.json');
17
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
18
18
  const cli = cac('fsdk');
19
19
  cli
20
20
  .version(pkg.version)
package/package.json CHANGED
@@ -1,18 +1,21 @@
1
1
  {
2
2
  "name": "@lumiflora/fsdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {
7
7
  "fsdk": "dist/index.js"
8
8
  },
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "scripts/postinstall.js",
12
+ "README.md"
11
13
  ],
12
14
  "scripts": {
13
15
  "dev": "tsx src/index.ts",
14
16
  "build": "tsc && node scripts/fix-bin.js",
15
- "typecheck": "tsc --noEmit"
17
+ "typecheck": "tsc --noEmit",
18
+ "postinstall": "node scripts/postinstall.js"
16
19
  },
17
20
  "dependencies": {
18
21
  "cac": "^6.7.14",
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync } from 'fs';
4
+ import { readFileSync, writeFileSync } from 'fs';
5
+ import path from 'path';
6
+
7
+ const detectShell = () => {
8
+ const shell = process.env.SHELL || '';
9
+ if (shell.includes('zsh')) return 'zsh';
10
+ if (shell.includes('fish')) return 'fish';
11
+ return 'bash';
12
+ };
13
+
14
+ const generateCompletion = (shell) => {
15
+ if (shell === 'bash') {
16
+ return `#!/bin/bash
17
+ # fsdk bash completion
18
+
19
+ _fsdk_completion() {
20
+ local cur prev opts
21
+ COMPREPLY=()
22
+ cur="\${COMP_WORDS[COMP_CWORD]}"
23
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
24
+ opts="create add-page add-component add-store sync-template validate preview completion"
25
+ case "\${prev}" in
26
+ create)
27
+ opts="--template --package-manager --eslint --no-git --no-install"
28
+ ;;
29
+ add-page)
30
+ opts="--router-path --page-name"
31
+ ;;
32
+ add-component)
33
+ opts="--type --name --dir"
34
+ ;;
35
+ add-store)
36
+ opts="--type --name"
37
+ ;;
38
+ sync-template)
39
+ opts="--template --force"
40
+ ;;
41
+ validate)
42
+ opts="--config --templates --strict"
43
+ ;;
44
+ preview)
45
+ opts="--port --host --open --template"
46
+ ;;
47
+ completion)
48
+ opts="bash zsh fish"
49
+ ;;
50
+ esac
51
+ COMPREPLY=($(compgen -W "\${opts}" -- "\${cur}"))
52
+ return 0
53
+ }
54
+ complete -F _fsdk_completion fsdk`;
55
+ }
56
+
57
+ if (shell === 'zsh') {
58
+ return `#compdef fsdk
59
+
60
+ _fsdk() {
61
+ local -a commands
62
+ commands=(
63
+ 'create:Create a new application'
64
+ 'add-page:Add a new page'
65
+ 'add-component:Add a new component'
66
+ 'add-store:Add a new store'
67
+ 'sync-template:Sync template files'
68
+ 'validate:Validate configuration and templates'
69
+ 'preview:Preview template'
70
+ 'completion:Generate shell completion script'
71
+ )
72
+ _arguments -C \
73
+ '1: :->command' \
74
+ '2: :->args' \
75
+ '*: :->rest'
76
+ case "$state" in
77
+ command)
78
+ _describe 'command' commands
79
+ ;;
80
+ args)
81
+ case $words[1] in
82
+ create)
83
+ _arguments -s \
84
+ '--template[Template name]' \
85
+ '--package-manager[Package manager: npm|pnpm|yarn|bun]' \
86
+ '--eslint[Enable ESLint]' \
87
+ '--no-git[Skip git initialization]' \
88
+ '--no-install[Skip dependency installation]'
89
+ ;;
90
+ add-page)
91
+ _arguments -s \
92
+ '--router-path[Router path]' \
93
+ '--page-name[Page name]'
94
+ ;;
95
+ add-component)
96
+ _arguments -s \
97
+ '--type[Component type: page|common|business]' \
98
+ '--name[Component name]' \
99
+ '--dir[Subdirectory]'
100
+ ;;
101
+ add-store)
102
+ _arguments -s \
103
+ '--type[Store type: pinia|redux]' \
104
+ '--name[Store name]'
105
+ ;;
106
+ sync-template)
107
+ _arguments -s \
108
+ '--template[Template name]' \
109
+ '--force[Force sync]'
110
+ ;;
111
+ validate)
112
+ _arguments -s \
113
+ '--config[Validate config only]' \
114
+ '--templates[Validate templates only]' \
115
+ '--strict[Strict validation]'
116
+ ;;
117
+ preview)
118
+ _arguments -s \
119
+ '--port[Port number]' \
120
+ '--host[Host address]' \
121
+ '--open[Open browser]' \
122
+ '--template[Template name]'
123
+ ;;
124
+ completion)
125
+ _arguments -s \
126
+ 'bash:Generate bash completion' \
127
+ 'zsh:Generate zsh completion' \
128
+ 'fish:Generate fish completion'
129
+ ;;
130
+ esac
131
+ ;;
132
+ esac
133
+ }`;
134
+ }
135
+
136
+ if (shell === 'fish') {
137
+ return `# fish completion for fsdk
138
+
139
+ complete -c fsdk -n '__fish_use_subcommand' -a 'create' -d 'Create a new application'
140
+ complete -c fsdk -n '__fish_use_subcommand' -a 'add-page' -d 'Add a new page'
141
+ complete -c fsdk -n '__fish_use_subcommand' -a 'add-component' -d 'Add a new component'
142
+ complete -c fsdk -n '__fish_use_subcommand' -a 'add-store' -d 'Add a new store'
143
+ complete -c fsdk -n '__fish_use_subcommand' -a 'sync-template' -d 'Sync template files'
144
+ complete -c fsdk -n '__fish_use_subcommand' -a 'validate' -d 'Validate configuration and templates'
145
+ complete -c fsdk -n '__fish_use_subcommand' -a 'preview' -d 'Preview template'
146
+ complete -c fsdk -n '__fish_use_subcommand' -a 'completion' -d 'Generate shell completion script'
147
+
148
+ complete -c fsdk -n '__fish_seen_subcommand_from create' -l template -d 'Template name'
149
+ complete -c fsdk -n '__fish_seen_subcommand_from create' -l package-manager -d 'Package manager' -a 'npm pnpm yarn bun'
150
+ complete -c fsdk -n '__fish_seen_subcommand_from create' -l eslint -d 'Enable ESLint'
151
+ complete -c fsdk -n '__fish_seen_subcommand_from create' -l no-git -d 'Skip git initialization'
152
+ complete -c fsdk -n '__fish_seen_subcommand_from create' -l no-install -d 'Skip dependency installation'
153
+
154
+ complete -c fsdk -n '__fish_seen_subcommand_from add-page' -l router-path -d 'Router path'
155
+ complete -c fsdk -n '__fish_seen_subcommand_from add-page' -l page-name -d 'Page name'
156
+
157
+ complete -c fsdk -n '__fish_seen_subcommand_from add-component' -l type -d 'Component type' -a 'page common business'
158
+ complete -c fsdk -n '__fish_seen_subcommand_from add-component' -l name -d 'Component name'
159
+ complete -c fsdk -n '__fish_seen_subcommand_from add-component' -l dir -d 'Subdirectory'
160
+
161
+ complete -c fsdk -n '__fish_seen_subcommand_from add-store' -l type -d 'Store type' -a 'pinia redux'
162
+ complete -c fsdk -n '__fish_seen_subcommand_from add-store' -l name -d 'Store name'
163
+
164
+ complete -c fsdk -n '__fish_seen_subcommand_from sync-template' -l template -d 'Template name'
165
+ complete -c fsdk -n '__fish_seen_subcommand_from sync-template' -l force -d 'Force sync'
166
+
167
+ complete -c fsdk -n '__fish_seen_subcommand_from validate' -l config -d 'Validate config only'
168
+ complete -c fsdk -n '__fish_seen_subcommand_from validate' -l templates -d 'Validate templates only'
169
+ complete -c fsdk -n '__fish_seen_subcommand_from validate' -l strict -d 'Strict validation'
170
+
171
+ complete -c fsdk -n '__fish_seen_subcommand_from preview' -l port -d 'Port number'
172
+ complete -c fsdk -n '__fish_seen_subcommand_from preview' -l host -d 'Host address'
173
+ complete -c fsdk -n '__fish_seen_subcommand_from preview' -l open -d 'Open browser'
174
+ complete -c fsdk -n '__fish_seen_subcommand_from preview' -l template -d 'Template name'`;
175
+ }
176
+ };
177
+
178
+ const installCompletion = () => {
179
+ const shell = detectShell();
180
+ const home = process.env.HOME || process.env.USERPROFILE || '';
181
+ let rcFile = '';
182
+ let completionFile = '';
183
+ let configLine = '';
184
+
185
+ if (shell === 'bash') {
186
+ rcFile = path.resolve(home, '.bashrc');
187
+ completionFile = path.resolve(home, '.fsdk-completion.bash');
188
+ configLine = 'source ~/.fsdk-completion.bash';
189
+ } else if (shell === 'zsh') {
190
+ rcFile = path.resolve(home, '.zshrc');
191
+ completionFile = path.resolve(home, '.zsh', 'completion', '_fsdk');
192
+ configLine = 'fpath=("~/.zsh/completion" $fpath)';
193
+ } else if (shell === 'fish') {
194
+ rcFile = path.resolve(home, '.config', 'fish', 'config.fish');
195
+ completionFile = path.resolve(home, '.config', 'fish', 'completions', 'fsdk.fish');
196
+ configLine = '';
197
+ }
198
+
199
+ // 生成补全文件
200
+ try {
201
+ const content = generateCompletion(shell);
202
+ writeFileSync(completionFile, content, 'utf-8');
203
+ if (shell === 'bash') {
204
+ import('fs').then(fs => { fs.chmodSync(completionFile, 0o755); });
205
+ }
206
+ } catch (err) {
207
+ console.error('Failed to write completion file:', err.message);
208
+ process.exit(1);
209
+ }
210
+
211
+ // Fish 不需要额外配置
212
+ if (shell === 'fish') {
213
+ console.log('✓ fsdk completion installed to', completionFile);
214
+ console.log(' Restart your fish shell or open a new terminal to apply');
215
+ return;
216
+ }
217
+
218
+ // 读取现有配置
219
+ let rcContent = '';
220
+ if (existsSync(rcFile)) {
221
+ rcContent = readFileSync(rcFile, 'utf-8');
222
+ }
223
+
224
+ // 先检测原始内容是否已有有效配置
225
+ const alreadyHasValidConfig = (shell === 'bash' && rcContent.includes('source ~/.fsdk-completion.bash')) ||
226
+ (shell === 'zsh' && /fpath=.*\.zsh\/completion/.test(rcContent));
227
+
228
+ if (alreadyHasValidConfig) {
229
+ console.log('✓ fsdk completion already configured in', rcFile);
230
+ return;
231
+ }
232
+
233
+ // 清理旧的 fsdk completion 配置
234
+ const lines = rcContent.split('\n');
235
+ const newLines = [];
236
+ let skipLines = false;
237
+ for (const line of lines) {
238
+ if (line.includes('# fsdk completion') || line.includes('# zsh fsdk completion') || line.includes('# bash fsdk completion')) {
239
+ skipLines = true;
240
+ continue;
241
+ }
242
+ if (skipLines) {
243
+ if (line.trim() === '') {
244
+ skipLines = false;
245
+ }
246
+ continue;
247
+ }
248
+ newLines.push(line);
249
+ }
250
+
251
+ const newContent = newLines.join('\n');
252
+
253
+ // 检查是否已有 compinit(使用原始 rcContent)
254
+ const alreadyHasCompinit = rcContent.includes('autoload -U compinit');
255
+
256
+ // 决定添加什么配置
257
+ let configToAdd = '';
258
+ if (shell === 'zsh' && alreadyHasCompinit) {
259
+ // 已有 compinit,只添加 fpath
260
+ configToAdd = '# zsh fsdk completion\n' + configLine + '\n';
261
+ } else if (configLine) {
262
+ configToAdd = `# ${shell} fsdk completion\n${configLine}\n`;
263
+ }
264
+
265
+ // 写入新配置
266
+ writeFileSync(rcFile, (newContent ? newContent + '\n' : '') + configToAdd, 'utf-8');
267
+ console.log('✓ fsdk completion installed to', rcFile);
268
+ console.log(' Run "source', rcFile, '" or restart your shell to apply');
269
+ };
270
+
271
+ installCompletion();