adspecs 0.1.28 → 0.1.29

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.
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "adspecs",
12
12
  "description": "AI Coding研发协同开发插件",
13
- "version": "0.1.28",
13
+ "version": "0.1.29",
14
14
  "source": "./",
15
15
  "author": {
16
16
  "name": "Qingwen Chen",
@@ -2,7 +2,7 @@
2
2
  "name": "adspecs",
3
3
  "displayName": "adspecs AI Plugin",
4
4
  "description": "AI first工程规范驱动开发插件",
5
- "version": "0.1.28",
5
+ "version": "0.1.29",
6
6
  "author": {
7
7
  "name": "Qingwen Chen",
8
8
  "email": "cqinwn@qq.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "adspecs",
3
3
  "displayName": "adspecs AI 工程规范驱动开发插件",
4
- "version": "0.1.28",
4
+ "version": "0.1.29",
5
5
  "description": "AI-first specification-driven development plugin for ECP platform full-lifecycle development",
6
6
  "descriptionZh": "AI优先的工程规范驱动开发插件,覆盖需求分析、PRD、系统设计、任务拆解、TDD、代码评审、Wiki同步全流程",
7
7
  "author": {
package/INSTALL.md CHANGED
@@ -181,14 +181,41 @@ claude plugins update adspecs --scope project
181
181
 
182
182
  ---
183
183
 
184
- ## 跨平台环境变量
184
+ ## 跨平台支持
185
185
 
186
- adspecs hooks 支持通过环境变量控制平台行为:
186
+ ### 平台自动检测
187
+
188
+ adspecs 通过 `hooks/platform.js` 模块自动检测运行环境,无需手动配置:
189
+
190
+ | 检测方式 | 说明 |
191
+ |----------|------|
192
+ | `ADSPECS_PLATFORM` 环境变量 | 显式指定平台(优先级最高) |
193
+ | `CLAUDE_PLUGIN_ROOT` 环境变量 | Claude Code 自动注入 |
194
+ | `QODER_PLUGIN_ROOT` 环境变量 | Qoder 自动注入 |
195
+
196
+ ### 环境变量
187
197
 
188
198
  | 环境变量 | 说明 | 可选值 |
189
199
  |----------|------|--------|
190
200
  | `ADSPECS_PLATFORM` | 显式指定运行平台 | `claude` / `qoder` |
191
201
  | `CLAUDE_PLUGIN_ROOT` | Claude Code 注入的插件根路径 | 自动 |
192
- | `QODER_PLUGIN_ROOT` | Qoder 注入的插件根路径(如适用) | 自动 |
202
+ | `QODER_PLUGIN_ROOT` | Qoder 注入的插件根路径 | 自动 |
193
203
 
194
204
  通常无需手动设置,平台会自动注入。若 hooks 执行异常,可尝试设置 `ADSPECS_PLATFORM=qoder`。
205
+
206
+ ### Hooks 系统
207
+
208
+ adspecs 的 hooks 脚本(`hooks/*.js`)已适配双平台,通过统一的 `platform.js` 模块获取:
209
+
210
+ - 平台类型(`claude` / `qoder`)
211
+ - 状态目录(`.claude/` / `.qoder/`)
212
+ - 工具输出文件路径
213
+
214
+ hooks 配置位于 `hooks/hooks.json`,支持以下事件:
215
+
216
+ | 事件 | 说明 |
217
+ |------|------|
218
+ | `SessionStart` | 会话启动时注入上下文 |
219
+ | `PreCompact` | 上下文压缩前保存提醒 |
220
+ | `PostToolUse` | 文件变更后追踪队列 |
221
+ | `Stop` | 会话结束时建议操作 |
package/README.md CHANGED
@@ -2,20 +2,24 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/adspecs)](https://www.npmjs.com/package/adspecs)
4
4
  [![npm downloads](https://img.shields.io/npm/dt/adspecs)](https://www.npmjs.com/package/adspecs)
5
+ [![Platform](https://img.shields.io/badge/platform-Claude%20Code%20%7C%20Qoder-blueviolet)](#安装)
5
6
 
6
7
  ---
7
8
 
8
9
  ## 简介
9
10
 
10
- AdSpecs 是一个基于 Claude Code AI 工程研发协同插件,提供:
11
+ AdSpecs 是一个支持 **Claude Code** **Qoder** 双平台的 AI 工程研发协同插件,提供:
11
12
 
12
13
  - **21 个 Skill**(Slash 命令) — 覆盖需求分析、架构规划、系统设计、任务拆解、单元测试、代码审查、文档导出、Wiki 同步
13
14
  - **CLI 工具** — `adspecs init` 一键脚手架、`adspecs plugin install` 插件注册、`adspecs doctor` 环境检查
14
15
  - **21 个标准文档模板** — 需求 / 设计 / 任务 / 测试 / 评审 / 架构全覆盖
15
- - **多技术栈参考** — ECP Java 后端、Vue 3 前端、Ant Design React 前端、Python 后端等 11 套参考工程
16
+ - **多技术栈参考** — Java 后端、Vue 3 前端、Ant Design React 前端、Python 后端等 11 套参考工程
17
+ - **双平台支持** — 原生兼容 Claude Code 和 Qoder,自动检测运行环境
16
18
  - **npm 分发** — `npm install -g adspecs` 即装即用
17
19
 
18
- 本插件需配合 [`superpowers`](https://github.com/anthropics/claude-plugins-official) 插件(提供 TDD、子代理驱动开发等通用 Skill)一起使用。
20
+ > **平台依赖说明**:
21
+ > - **Claude Code**:需配合 [`superpowers`](https://github.com/anthropics/claude-plugins-official) 插件(提供 TDD、子代理驱动开发等通用 Skill)一起使用
22
+ > - **Qoder**:adspecs 的 Skills 可独立运行,无需额外依赖
19
23
 
20
24
  ---
21
25
 
@@ -344,12 +348,25 @@ Skill 支持通过 `.adspecs/paths.json` 自定义输出目录:
344
348
 
345
349
  详细安装说明见 [INSTALL.md](./INSTALL.md)。
346
350
 
351
+ ### Claude Code
352
+
353
+ ```bash
354
+ npm install -g adspecs
355
+ adspecs plugin install # 用户级(默认)
356
+ adspecs plugin install --scope project # 项目级
357
+ ```
358
+
359
+ ### Qoder
360
+
347
361
  ```bash
348
- # 安装
349
362
  npm install -g adspecs
350
- adspecs plugin install # 用户级(默认)
351
- adspecs plugin install --scope project # 项目级
363
+ adspecs plugin install --platform qoder # 用户级
364
+ adspecs plugin install --platform qoder --scope project # 项目级
365
+ ```
366
+
367
+ ### 通用命令
352
368
 
369
+ ```bash
353
370
  # 升级
354
371
  npm install -g adspecs@latest
355
372
 
@@ -363,15 +380,20 @@ adspecs plugin uninstall --scope project
363
380
  ## 常见问题
364
381
 
365
382
  **Q1:adspecs 与 superpowers 的关系?**
366
- adspecs 提供领域专属 Skill(需求、设计、模板、规范),superpowers 提供通用 AI 工程 Skill(TDD、子代理、调试)。两者分工协作,**编码阶段必须同时安装**。
383
+ adspecs 提供领域专属 Skill(需求、设计、模板、规范),superpowers 提供通用 AI 工程 Skill(TDD、子代理、调试)。
384
+ - **Claude Code**:两者分工协作,编码阶段必须同时安装
385
+ - **Qoder**:adspecs 可独立运行,无需 superpowers
367
386
 
368
387
  **Q2:用户级和项目级安装可以共存吗?**
369
388
  可以,项目级优先于用户级(就近原则)。个人开发选用户级,团队协作选项目级。
370
389
 
371
- **Q3:安装后 Skill 未生效?**
390
+ **Q3:Claude Code 和 Qoder 可以同时使用吗?**
391
+ 可以。adspecs 通过 `.claude-plugin/` 和 `.qoder-plugin/` 分别提供两个平台的插件配置,互不干扰。使用 `--platform` 参数指定目标平台即可。
392
+
393
+ **Q4:安装后 Skill 未生效?**
372
394
  1. 执行 `/plugins` 查看 adspecs 是否在已加载列表
373
- 2. 重启 Claude Code
374
- 3. 检查安装 scope 对应的目录是否存在
395
+ 2. 重启 Claude Code 或 Qoder
396
+ 3. 检查安装 scope 对应的目录是否存在(`.claude-plugin/` 或 `.qoder-plugin/`)
375
397
 
376
398
  **Q4:如何升级?**
377
399
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adspecs",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "AI first 工程规范驱动开发插件 — 支持 npm 安装和 CLI 初始化",
5
5
  "bin": {
6
6
  "adspecs": "bin/adspecs.js"
@@ -3,6 +3,7 @@
3
3
  const { execSync } = require('child_process');
4
4
  const path = require('path');
5
5
  const fs = require('fs');
6
+ const os = require('os');
6
7
  const chalk = require('chalk');
7
8
 
8
9
  /**
@@ -91,8 +92,9 @@ exports.install = async function install(options) {
91
92
 
92
93
  /**
93
94
  * Qoder 平台安装
94
- * Qoder 通过 .qoder-plugin/plugin.json 自动发现插件,
95
- * 安装即确保插件目录可被 Qoder 访问。
95
+ * 自动注册到 Qoder 插件系统:
96
+ * - 用户级:创建 junction 链接 + 写入注册表 + 启用插件
97
+ * - 项目级:在项目目录创建 .qoder-plugin 链接
96
98
  */
97
99
  async function installForQoder(pluginName, scope) {
98
100
  const qoderManifest = path.join(PLUGIN_DIR, '.qoder-plugin', 'plugin.json');
@@ -101,64 +103,238 @@ async function installForQoder(pluginName, scope) {
101
103
  }
102
104
 
103
105
  if (scope === 'project') {
104
- // 项目级:在当前项目创建 .qoder-plugin 符号链接或复制
105
- const targetDir = path.join(process.cwd(), '.qoder-plugin');
106
- if (fs.existsSync(targetDir)) {
107
- console.log(chalk.yellow(' ⏭ 当前项目已存在 .qoder-plugin/,跳过'));
108
- } else {
109
- try {
110
- // 尝试创建符号链接(节省空间)
111
- fs.symlinkSync(
112
- path.join(PLUGIN_DIR, '.qoder-plugin'),
113
- targetDir,
114
- 'junction' // Windows 使用 junction
115
- );
116
- console.log(chalk.green(' ✅ 已创建 .qoder-plugin 符号链接'));
117
- } catch (_err) {
118
- // 符号链接失败,复制清单文件
119
- fs.mkdirSync(targetDir, { recursive: true });
120
- fs.copyFileSync(qoderManifest, path.join(targetDir, 'plugin.json'));
121
- console.log(chalk.green(' ✅ 已复制 .qoder-plugin/plugin.json 到项目'));
122
- }
106
+ await installQoderProject(pluginName, qoderManifest);
107
+ } else {
108
+ await installQoderUser(pluginName, qoderManifest);
109
+ }
110
+
111
+ console.log('');
112
+ console.log(chalk.green.bold(`✅ adspecs 插件已配置到 Qoder (scope=${scope})`));
113
+ console.log('');
114
+ printSkillList();
115
+ }
116
+
117
+ /**
118
+ * Qoder 用户级安装 — 自动注册到 ~/.qoder/plugins/
119
+ */
120
+ async function installQoderUser(pluginName, qoderManifest) {
121
+ const qoderHome = path.join(os.homedir(), '.qoder');
122
+ const pluginsDir = path.join(qoderHome, 'plugins');
123
+ const cacheDir = path.join(pluginsDir, 'cache', 'local');
124
+ const linkPath = path.join(cacheDir, pluginName);
125
+ const registryKey = `${pluginName}@local`;
126
+
127
+ console.log(chalk.gray(' → Qoder 用户级插件自动注册...'));
128
+ console.log('');
129
+
130
+ // 1. 确保目录结构存在
131
+ fs.mkdirSync(cacheDir, { recursive: true });
132
+
133
+ // 2. 创建 junction 链接(已存在则先移除重建,确保指向最新路径)
134
+ if (fs.existsSync(linkPath)) {
135
+ try {
136
+ fs.rmSync(linkPath, { recursive: true, force: true });
137
+ } catch (_err) {
138
+ // junction 可能无法用 rmSync 删除,尝试 unlink
139
+ try { fs.unlinkSync(linkPath); } catch (_e) { /* ignore */ }
123
140
  }
141
+ }
124
142
 
125
- // 确保 skills 可被访问
126
- const targetSkills = path.join(process.cwd(), 'skills');
127
- if (!fs.existsSync(targetSkills)) {
128
- try {
129
- fs.symlinkSync(path.join(PLUGIN_DIR, 'skills'), targetSkills, 'junction');
130
- console.log(chalk.green(' ✅ 已创建 skills/ 符号链接'));
131
- } catch (_err) {
132
- console.log(chalk.yellow(' ⚠ skills/ 链接创建失败,请手动确保 Qoder 可访问插件 skills 目录'));
133
- }
143
+ try {
144
+ fs.symlinkSync(PLUGIN_DIR, linkPath, 'junction');
145
+ console.log(chalk.green(` ✅ 已创建插件链接: ${linkPath}`));
146
+ console.log(chalk.gray(` ${PLUGIN_DIR}`));
147
+ } catch (err) {
148
+ // junction 创建失败(权限不足等),回退为复制关键文件
149
+ console.log(chalk.yellow(` ⚠ 链接创建失败(${err.message}),回退为文件复制...`));
150
+ fs.mkdirSync(linkPath, { recursive: true });
151
+ copyDirRecursive(PLUGIN_DIR, linkPath, [
152
+ 'node_modules', '.git', '.claude', 'assets'
153
+ ]);
154
+ console.log(chalk.green(` ✅ 已复制插件文件到: ${linkPath}`));
155
+ }
156
+
157
+ // 3. 读取插件版本
158
+ const pluginJson = JSON.parse(fs.readFileSync(qoderManifest, 'utf8'));
159
+ const version = pluginJson.version || '0.0.0';
160
+ const now = new Date().toISOString();
161
+
162
+ // 4. 写入 installed_plugins_v2.json
163
+ const v2Path = path.join(pluginsDir, 'installed_plugins_v2.json');
164
+ let v2Data = { version: 2, plugins: {} };
165
+ if (fs.existsSync(v2Path)) {
166
+ try { v2Data = JSON.parse(fs.readFileSync(v2Path, 'utf8')); } catch (_e) { /* use default */ }
167
+ }
168
+ if (!v2Data.plugins) v2Data.plugins = {};
169
+
170
+ v2Data.plugins[registryKey] = [{
171
+ scope: 'user',
172
+ installPath: linkPath,
173
+ version: version,
174
+ source: 'local',
175
+ installedAt: (v2Data.plugins[registryKey] && v2Data.plugins[registryKey][0] && v2Data.plugins[registryKey][0].installedAt) || now,
176
+ lastUpdated: now,
177
+ enabled: true
178
+ }];
179
+
180
+ fs.writeFileSync(v2Path, JSON.stringify(v2Data, null, 2) + '\n', 'utf8');
181
+ console.log(chalk.green(' ✅ 已写入插件注册表 (installed_plugins_v2.json)'));
182
+
183
+ // 5. 写入 installed_plugins.json(v1 兼容)
184
+ const v1Path = path.join(pluginsDir, 'installed_plugins.json');
185
+ let v1Data = { plugins: {} };
186
+ if (fs.existsSync(v1Path)) {
187
+ try { v1Data = JSON.parse(fs.readFileSync(v1Path, 'utf8')); } catch (_e) { /* use default */ }
188
+ }
189
+ if (!v1Data.plugins) v1Data.plugins = {};
190
+
191
+ v1Data.plugins[registryKey] = { installPath: linkPath };
192
+
193
+ fs.writeFileSync(v1Path, JSON.stringify(v1Data, null, 2) + '\n', 'utf8');
194
+ console.log(chalk.green(' ✅ 已写入插件注册表 (installed_plugins.json)'));
195
+
196
+ // 6. 在 settings.json 中启用插件
197
+ const settingsPath = path.join(qoderHome, 'settings.json');
198
+ let settings = {};
199
+ if (fs.existsSync(settingsPath)) {
200
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (_e) { /* use default */ }
201
+ }
202
+ if (!settings.enabledPlugins) settings.enabledPlugins = {};
203
+
204
+ settings.enabledPlugins[registryKey] = true;
205
+
206
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
207
+ console.log(chalk.green(' ✅ 已在 settings.json 中启用插件'));
208
+
209
+ console.log('');
210
+ console.log(chalk.gray(' 请重启 Qoder 使插件生效。'));
211
+ }
212
+
213
+ /**
214
+ * Qoder 项目级安装
215
+ */
216
+ async function installQoderProject(pluginName, qoderManifest) {
217
+ // 项目级:在当前项目创建 .qoder-plugin 符号链接或复制
218
+ const targetDir = path.join(process.cwd(), '.qoder-plugin');
219
+ if (fs.existsSync(targetDir)) {
220
+ console.log(chalk.yellow(' ⏭ 当前项目已存在 .qoder-plugin/,跳过'));
221
+ } else {
222
+ try {
223
+ fs.symlinkSync(
224
+ path.join(PLUGIN_DIR, '.qoder-plugin'),
225
+ targetDir,
226
+ 'junction'
227
+ );
228
+ console.log(chalk.green(' ✅ 已创建 .qoder-plugin 符号链接'));
229
+ } catch (_err) {
230
+ fs.mkdirSync(targetDir, { recursive: true });
231
+ fs.copyFileSync(qoderManifest, path.join(targetDir, 'plugin.json'));
232
+ console.log(chalk.green(' ✅ 已复制 .qoder-plugin/plugin.json 到项目'));
233
+ }
234
+ }
235
+
236
+ // 确保 skills 可被访问
237
+ const targetSkills = path.join(process.cwd(), 'skills');
238
+ if (!fs.existsSync(targetSkills)) {
239
+ try {
240
+ fs.symlinkSync(path.join(PLUGIN_DIR, 'skills'), targetSkills, 'junction');
241
+ console.log(chalk.green(' ✅ 已创建 skills/ 符号链接'));
242
+ } catch (_err) {
243
+ console.log(chalk.yellow(' ⚠ skills/ 链接创建失败,请手动确保 Qoder 可访问插件 skills 目录'));
134
244
  }
245
+ }
135
246
 
136
- // 确保 hooks 可被访问
137
- const targetHooks = path.join(process.cwd(), 'hooks');
138
- if (!fs.existsSync(targetHooks)) {
139
- try {
140
- fs.symlinkSync(path.join(PLUGIN_DIR, 'hooks'), targetHooks, 'junction');
141
- console.log(chalk.green(' ✅ 已创建 hooks/ 符号链接'));
142
- } catch (_err) {
143
- console.log(chalk.yellow(' ⚠ hooks/ 链接创建失败,请手动确保 Qoder 可访问插件 hooks 目录'));
144
- }
247
+ // 确保 hooks 可被访问
248
+ const targetHooks = path.join(process.cwd(), 'hooks');
249
+ if (!fs.existsSync(targetHooks)) {
250
+ try {
251
+ fs.symlinkSync(path.join(PLUGIN_DIR, 'hooks'), targetHooks, 'junction');
252
+ console.log(chalk.green(' ✅ 已创建 hooks/ 符号链接'));
253
+ } catch (_err) {
254
+ console.log(chalk.yellow(' ⚠ hooks/ 链接创建失败,请手动确保 Qoder 可访问插件 hooks 目录'));
255
+ }
256
+ }
257
+ }
258
+
259
+ /**
260
+ * 递归复制目录(排除指定目录名)
261
+ */
262
+ function copyDirRecursive(src, dest, excludeDirs) {
263
+ fs.mkdirSync(dest, { recursive: true });
264
+ const entries = fs.readdirSync(src, { withFileTypes: true });
265
+ for (const entry of entries) {
266
+ if (excludeDirs && excludeDirs.includes(entry.name)) continue;
267
+ const srcPath = path.join(src, entry.name);
268
+ const destPath = path.join(dest, entry.name);
269
+ if (entry.isDirectory()) {
270
+ copyDirRecursive(srcPath, destPath, excludeDirs);
271
+ } else {
272
+ fs.copyFileSync(srcPath, destPath);
273
+ }
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Qoder 用户级卸载 — 移除链接 + 注册表条目 + 启用配置
279
+ */
280
+ function uninstallQoderUser(pluginName) {
281
+ const qoderHome = path.join(os.homedir(), '.qoder');
282
+ const pluginsDir = path.join(qoderHome, 'plugins');
283
+ const linkPath = path.join(pluginsDir, 'cache', 'local', pluginName);
284
+ const registryKey = `${pluginName}@local`;
285
+
286
+ // 1. 移除 junction 链接 / 复制的目录
287
+ if (fs.existsSync(linkPath)) {
288
+ try {
289
+ fs.rmSync(linkPath, { recursive: true, force: true });
290
+ console.log(chalk.green(` ✅ 已移除插件目录: ${linkPath}`));
291
+ } catch (err) {
292
+ console.log(chalk.yellow(` ⚠ 移除插件目录失败: ${err.message}`));
145
293
  }
146
294
  } else {
147
- // 用户级:输出指引
148
- console.log(chalk.gray(' → Qoder 用户级插件安装...'));
149
- console.log('');
150
- console.log(chalk.green(' ✅ Qoder 插件清单已就绪: ' + qoderManifest));
151
- console.log('');
152
- console.log(' Qoder 用户级安装方式:');
153
- console.log(' 1. 将本插件目录路径添加到 Qoder 插件搜索路径');
154
- console.log(' 2. 或在 Qoder 设置中配置插件目录指向: ' + PLUGIN_DIR);
155
- console.log(' 3. 重启 Qoder 使插件生效');
295
+ console.log(chalk.yellow(' ⏭ 插件目录不存在,跳过'));
156
296
  }
157
297
 
158
- console.log('');
159
- console.log(chalk.green.bold(`✅ adspecs 插件已配置到 Qoder (scope=${scope})`));
160
- console.log('');
161
- printSkillList();
298
+ // 2. 从 installed_plugins_v2.json 移除
299
+ const v2Path = path.join(pluginsDir, 'installed_plugins_v2.json');
300
+ if (fs.existsSync(v2Path)) {
301
+ try {
302
+ const v2Data = JSON.parse(fs.readFileSync(v2Path, 'utf8'));
303
+ if (v2Data.plugins && v2Data.plugins[registryKey]) {
304
+ delete v2Data.plugins[registryKey];
305
+ fs.writeFileSync(v2Path, JSON.stringify(v2Data, null, 2) + '\n', 'utf8');
306
+ console.log(chalk.green(' ✅ 已从注册表移除 (installed_plugins_v2.json)'));
307
+ }
308
+ } catch (_err) { /* ignore */ }
309
+ }
310
+
311
+ // 3. 从 installed_plugins.json 移除
312
+ const v1Path = path.join(pluginsDir, 'installed_plugins.json');
313
+ if (fs.existsSync(v1Path)) {
314
+ try {
315
+ const v1Data = JSON.parse(fs.readFileSync(v1Path, 'utf8'));
316
+ if (v1Data.plugins && v1Data.plugins[registryKey]) {
317
+ delete v1Data.plugins[registryKey];
318
+ fs.writeFileSync(v1Path, JSON.stringify(v1Data, null, 2) + '\n', 'utf8');
319
+ console.log(chalk.green(' ✅ 已从注册表移除 (installed_plugins.json)'));
320
+ }
321
+ } catch (_err) { /* ignore */ }
322
+ }
323
+
324
+ // 4. 从 settings.json 禁用
325
+ const settingsPath = path.join(qoderHome, 'settings.json');
326
+ if (fs.existsSync(settingsPath)) {
327
+ try {
328
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
329
+ if (settings.enabledPlugins && settings.enabledPlugins[registryKey] !== undefined) {
330
+ delete settings.enabledPlugins[registryKey];
331
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
332
+ console.log(chalk.green(' ✅ 已从 settings.json 移除启用配置'));
333
+ }
334
+ } catch (_err) { /* ignore */ }
335
+ }
336
+
337
+ console.log(chalk.gray(' 请重启 Qoder 使变更生效。'));
162
338
  }
163
339
 
164
340
  /**
@@ -262,8 +438,8 @@ exports.uninstall = async function uninstall(options) {
262
438
  console.log('');
263
439
 
264
440
  if (platform === 'qoder') {
265
- // Qoder 卸载:移除项目级链接
266
441
  if (scope === 'project') {
442
+ // Qoder 项目级卸载:移除项目链接
267
443
  const targetDir = path.join(process.cwd(), '.qoder-plugin');
268
444
  if (fs.existsSync(targetDir)) {
269
445
  try {
@@ -276,7 +452,8 @@ exports.uninstall = async function uninstall(options) {
276
452
  console.log(chalk.yellow(' ⏭ 项目未安装 .qoder-plugin/,无需卸载'));
277
453
  }
278
454
  } else {
279
- console.log(chalk.yellow(' 用户级卸载请从 Qoder 插件设置中移除本插件路径'));
455
+ // Qoder 用户级卸载:移除链接 + 注册表 + 启用配置
456
+ uninstallQoderUser(pluginName);
280
457
  }
281
458
  console.log('');
282
459
  console.log(chalk.green(`✅ ${pluginName} 已从 Qoder 卸载 (scope=${scope})`));