@localsummer/incspec 0.2.2 → 0.2.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
@@ -160,7 +160,7 @@ AI 编程助手在处理复杂前端代码库时常常力不从心,因为 API
160
160
  | 工具 | 命令 |
161
161
  |------|------|
162
162
  | **Cursor** | `/incspec/inc-analyze`、`/incspec/inc-collect-req`、`/incspec/inc-collect-dep`、`/incspec/inc-design`、`/incspec/inc-apply`、`/incspec/inc-merge`、`/incspec/inc-archive` |
163
- | **Claude Code** | 使用 `inc-spec-skill` Skill |
163
+ | **Claude Code** | Cursor,使用相同的 `/incspec/inc-*` 命令 |
164
164
 
165
165
  </details>
166
166
 
@@ -226,8 +226,8 @@ incspec sync --all # 全部
226
226
 
227
227
  **设置完成后:**
228
228
  - 运行 `incspec status` 验证设置
229
- - Cursor 用户可直接触发 `/incspec/inc-*` 命令
230
- - Claude Code 用户可使用 `inc-spec-skill` Skill
229
+ - Cursor Claude Code 用户都可直接使用 `/incspec/inc-*` 命令
230
+ - 命令生成到 `.cursor/commands/incspec/` `.claude/commands/incspec/` 目录
231
231
 
232
232
  ### 创建你的第一个增量
233
233
 
@@ -223,9 +223,9 @@ export async function analyzeCommand(ctx) {
223
223
  print('');
224
224
  print(colorize(` /incspec/inc-analyze ${sourcePath} --module=${moduleName}`, colors.bold, colors.white));
225
225
  print('');
226
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
226
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
227
227
  print('');
228
- print(colorize(` 请分析 ${sourcePath} 的代码流程,生成基线报告到 ${path.join(projectRoot, INCSPEC_DIR, DIRS.baselines)}`, colors.dim));
228
+ print(colorize(` /incspec/inc-analyze ${sourcePath} --module=${moduleName}`, colors.bold, colors.white));
229
229
  print('');
230
230
  printInfo(`完成后运行 'incspec status' 查看进度`);
231
231
  print('');
@@ -159,9 +159,9 @@ export async function applyCommand(ctx) {
159
159
  print('');
160
160
  print(colorize(` /incspec/inc-apply ${inputPath}`, colors.bold, colors.white));
161
161
  print('');
162
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
162
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
163
163
  print('');
164
- print(colorize(` 请按照 ${inputPath} 的增量设计,应用代码变更到 ${path.join(projectRoot, sourceDir)}`, colors.dim));
164
+ print(colorize(` /incspec/inc-apply ${inputPath}`, colors.bold, colors.white));
165
165
  print('');
166
166
  print(colorize('该命令将:', colors.dim));
167
167
  print(colorize(' 1. 解析增量设计文件中的变更计划', colors.dim));
@@ -76,9 +76,9 @@ export async function collectDepCommand(ctx) {
76
76
  print('');
77
77
  print(colorize(` /incspec/inc-collect-dep`, colors.bold, colors.white));
78
78
  print('');
79
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
79
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
80
80
  print('');
81
- print(colorize(` 请收集 UI 依赖,生成依赖报告到 ${path.join(projectRoot, INCSPEC_DIR, DIRS.requirements)}`, colors.dim));
81
+ print(colorize(` /incspec/inc-collect-dep`, colors.bold, colors.white));
82
82
  print('');
83
83
  print(colorize('该命令将交互式采集 6 维度 UI 依赖:', colors.dim));
84
84
  print(colorize(' - UI组件库 (Arco/Antd)', colors.dim));
@@ -71,9 +71,9 @@ export async function collectReqCommand(ctx) {
71
71
  print('');
72
72
  print(colorize(` /incspec/inc-collect-req`, colors.bold, colors.white));
73
73
  print('');
74
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
74
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
75
75
  print('');
76
- print(colorize(` 请收集需求,生成结构化需求表格到 ${path.join(projectRoot, INCSPEC_DIR, DIRS.requirements)}`, colors.dim));
76
+ print(colorize(` /incspec/inc-collect-req`, colors.bold, colors.white));
77
77
  print('');
78
78
  print(colorize('该命令将交互式收集需求,生成 5 列结构化表格:', colors.dim));
79
79
  print(colorize(' | 新增/修改功能 | 涉及UI组件 | 触发条件 | 影响的核心状态 | 预期数据流向 |', colors.dim));
@@ -116,13 +116,9 @@ export async function designCommand(ctx) {
116
116
  print('');
117
117
  print(colorize(` /incspec/inc-design --feature=${featureName}`, colors.bold, colors.white));
118
118
  print('');
119
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
119
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
120
120
  print('');
121
- const baselinePath = path.join(projectRoot, INCSPEC_DIR, DIRS.baselines, latestBaseline);
122
- const reqPath = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'structured-requirements.md');
123
- const depPath = path.join(projectRoot, INCSPEC_DIR, DIRS.requirements, 'ui-dependencies.md');
124
- const outDir = path.join(projectRoot, INCSPEC_DIR, DIRS.increments);
125
- print(colorize(` 请基于基线 ${latestBaseline} 和需求/依赖文件,设计增量方案到 ${outDir}`, colors.dim));
121
+ print(colorize(` /incspec/inc-design --feature=${featureName}`, colors.bold, colors.white));
126
122
  print('');
127
123
  print(colorize('该命令将生成包含 7 大模块的增量设计蓝图:', colors.dim));
128
124
  print(colorize(' 1. 一句话摘要', colors.dim));
package/commands/help.mjs CHANGED
@@ -137,7 +137,7 @@ const COMMANDS = {
137
137
  description: '同步集成到 IDE/AI 工具 (Cursor, Claude Code)',
138
138
  options: [
139
139
  ['--cursor', '仅同步 Cursor 命令'],
140
- ['--claude', '仅同步 Claude Code Skill'],
140
+ ['--claude', '仅同步 Claude Code 命令'],
141
141
  ['--all', '同步所有目标'],
142
142
  ['--project', '同步到当前目录'],
143
143
  ['--global', '同步到全局目录'],
@@ -146,10 +146,9 @@ export async function mergeCommand(ctx) {
146
146
  print('');
147
147
  print(colorize(` /incspec/inc-merge ${incrementPath}`, colors.bold, colors.white));
148
148
  print('');
149
- print(colorize('或在 Claude Code 中使用 inc-spec-skill 技能:', colors.cyan));
149
+ print(colorize('或在 Claude Code 中使用斜杠命令:', colors.cyan));
150
150
  print('');
151
- const outDir = path.join(projectRoot, INCSPEC_DIR, DIRS.baselines);
152
- print(colorize(` 请将 ${incrementPath} 的增量合并到基线 ${outDir}`, colors.dim));
151
+ print(colorize(` /incspec/inc-merge ${incrementPath}`, colors.bold, colors.white));
153
152
  print('');
154
153
  print(colorize('该命令将:', colors.dim));
155
154
  print(colorize(' 1. 解析增量设计文件中的时序图和依赖图', colors.dim));
package/commands/sync.mjs CHANGED
@@ -3,13 +3,10 @@
3
3
  */
4
4
 
5
5
  import {
6
- syncToProject as syncCursorToProject,
7
- syncToGlobal as syncCursorToGlobal,
8
- } from '../lib/cursor.mjs';
9
- import {
10
- syncToProjectClaude,
11
- syncToGlobalClaude,
12
- } from '../lib/claude.mjs';
6
+ syncToProject,
7
+ syncToGlobal,
8
+ getIDEConfig,
9
+ } from '../lib/ide-sync.mjs';
13
10
  import {
14
11
  colors,
15
12
  colorize,
@@ -110,14 +107,15 @@ async function syncCursor(ctx) {
110
107
  } else if (options.global) {
111
108
  syncTarget = 'global';
112
109
  } else {
110
+ const config = getIDEConfig('cursor');
113
111
  const choices = [
114
112
  {
115
- name: `当前目录 (${cwd}/.cursor/commands/incspec/)`,
113
+ name: `当前目录 (${cwd}/${config.projectDir}/)`,
116
114
  value: 'project',
117
115
  description: colorize('仅对当前目录生效', colors.blue),
118
116
  },
119
117
  {
120
- name: '全局目录 (~/.cursor/commands/incspec/)',
118
+ name: `全局目录 (${config.globalDir}/)`,
121
119
  value: 'global',
122
120
  description: colorize('对所有项目生效', colors.blue),
123
121
  },
@@ -131,12 +129,14 @@ async function syncCursor(ctx) {
131
129
 
132
130
  // Execute sync
133
131
  if (syncTarget === 'project') {
134
- const count = syncCursorToProject(cwd);
135
- printSuccess(`Cursor: 已同步 ${count} 个命令到 .cursor/commands/incspec/`);
132
+ const count = syncToProject('cursor', cwd);
133
+ const config = getIDEConfig('cursor');
134
+ printSuccess(`Cursor: 已同步 ${count} 个命令到 ${config.projectDir}/`);
136
135
  printCursorCommands();
137
136
  } else if (syncTarget === 'global') {
138
- const count = syncCursorToGlobal();
139
- printSuccess(`Cursor: 已同步 ${count} 个命令到 ~/.cursor/commands/incspec/`);
137
+ const count = syncToGlobal('cursor');
138
+ const config = getIDEConfig('cursor');
139
+ printSuccess(`Cursor: 已同步 ${count} 个命令到 ${config.globalDir}/`);
140
140
  printCursorCommands();
141
141
  }
142
142
  }
@@ -161,13 +161,13 @@ function printCursorCommands() {
161
161
  }
162
162
 
163
163
  /**
164
- * Sync Claude Code skill
164
+ * Sync Claude Code commands
165
165
  * @param {Object} ctx
166
166
  */
167
167
  async function syncClaude(ctx) {
168
168
  const { cwd, options } = ctx;
169
169
 
170
- print(colorize('=== Claude Code Skill 同步 ===', colors.bold));
170
+ print(colorize('=== Claude Code 命令同步 ===', colors.bold));
171
171
  print('');
172
172
 
173
173
  // Determine sync target
@@ -178,14 +178,15 @@ async function syncClaude(ctx) {
178
178
  } else if (options.global) {
179
179
  syncTarget = 'global';
180
180
  } else {
181
+ const config = getIDEConfig('claude');
181
182
  const choices = [
182
183
  {
183
- name: `当前目录 (${cwd}/.claude/skills/inc-spec-skill/)`,
184
+ name: `当前目录 (${cwd}/${config.projectDir}/)`,
184
185
  value: 'project',
185
186
  description: colorize('仅对当前目录生效', colors.blue),
186
187
  },
187
188
  {
188
- name: '全局目录 (~/.claude/skills/inc-spec-skill/)',
189
+ name: `全局目录 (${config.globalDir}/)`,
189
190
  value: 'global',
190
191
  description: colorize('对所有项目生效(推荐)', colors.blue),
191
192
  },
@@ -199,12 +200,33 @@ async function syncClaude(ctx) {
199
200
 
200
201
  // Execute sync
201
202
  if (syncTarget === 'project') {
202
- const { count } = syncToProjectClaude(cwd);
203
- printSuccess(`Claude Code: 已同步 ${count} 个文件到 .claude/skills/inc-spec-skill/`);
204
- print(colorize(' 包含: SKILL.md + references/', colors.dim));
203
+ const count = syncToProject('claude', cwd);
204
+ const config = getIDEConfig('claude');
205
+ printSuccess(`Claude Code: 已同步 ${count} 个命令到 ${config.projectDir}/`);
206
+ printClaudeCommands();
205
207
  } else if (syncTarget === 'global') {
206
- const { count } = syncToGlobalClaude();
207
- printSuccess(`Claude Code: 已同步 ${count} 个文件到 ~/.claude/skills/inc-spec-skill/`);
208
- print(colorize(' 包含: SKILL.md + references/', colors.dim));
208
+ const count = syncToGlobal('claude');
209
+ const config = getIDEConfig('claude');
210
+ printSuccess(`Claude Code: 已同步 ${count} 个命令到 ${config.globalDir}/`);
211
+ printClaudeCommands();
209
212
  }
210
213
  }
214
+
215
+ /**
216
+ * Print Claude commands list
217
+ */
218
+ function printClaudeCommands() {
219
+ print('');
220
+ print(colorize('已创建的命令:', colors.bold));
221
+ print(colorize(' /incspec/inc-analyze 步骤1: 分析代码流程', colors.dim));
222
+ print(colorize(' /incspec/inc-collect-req 步骤2: 收集结构化需求', colors.dim));
223
+ print(colorize(' /incspec/inc-collect-dep 步骤3: UI依赖采集', colors.dim));
224
+ print(colorize(' /incspec/inc-design 步骤4: 增量设计', colors.dim));
225
+ print(colorize(' /incspec/inc-apply 步骤5: 应用代码变更', colors.dim));
226
+ print(colorize(' /incspec/inc-merge 步骤6: 合并到基线', colors.dim));
227
+ print(colorize(' /incspec/inc-archive 归档规范文件', colors.dim));
228
+ print(colorize(' /incspec/inc-status 查看工作流状态', colors.dim));
229
+ print(colorize(' /incspec/inc-help 显示帮助', colors.dim));
230
+ print('');
231
+ printInfo('请重启 Claude Code 以加载新命令。');
232
+ }
@@ -1,31 +1,43 @@
1
1
  /**
2
- * Cursor integration utilities
3
- * - Generate Cursor slash commands
4
- * - Sync to project or global
2
+ * Unified IDE integration utilities
3
+ * - Generate IDE slash commands from templates
4
+ * - Support multiple IDEs through configuration
5
5
  */
6
6
 
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import * as os from 'os';
10
10
  import { fileURLToPath } from 'url';
11
- import { INCSPEC_DIR, DIRS } from './config.mjs';
12
-
13
- /** Cursor commands directory */
14
- const CURSOR_COMMANDS_DIR = '.cursor/commands/incspec';
15
-
16
- /** Global Cursor commands directory */
17
- const GLOBAL_CURSOR_DIR = path.join(os.homedir(), '.cursor', 'commands', 'incspec');
18
-
19
- /** Claude commands source directory (user local) */
20
- const CLAUDE_COMMANDS_DIR = path.join(os.homedir(), '.claude', 'commands', 'ai-increment');
11
+ import { INCSPEC_DIR } from './config.mjs';
21
12
 
22
13
  /** Built-in templates directory */
23
14
  const TEMPLATES_DIR = fileURLToPath(new URL('../templates/commands', import.meta.url));
24
15
 
25
16
  /**
26
- * Command mapping from Claude to Cursor
17
+ * IDE-specific configurations
18
+ */
19
+ const IDE_CONFIGS = {
20
+ cursor: {
21
+ name: 'Cursor',
22
+ projectDir: '.cursor/commands/incspec',
23
+ globalDir: path.join(os.homedir(), '.cursor', 'commands', 'incspec'),
24
+ fallbackDirs: [
25
+ // Support old ai-incremental-coding commands for backward compatibility
26
+ path.join(os.homedir(), '.claude', 'commands', 'ai-increment'),
27
+ ],
28
+ },
29
+ claude: {
30
+ name: 'Claude Code',
31
+ projectDir: '.claude/commands/incspec',
32
+ globalDir: path.join(os.homedir(), '.claude', 'commands', 'incspec'),
33
+ fallbackDirs: [],
34
+ },
35
+ };
36
+
37
+ /**
38
+ * Command mapping (shared across all IDEs)
27
39
  */
28
- const COMMAND_MAP = [
40
+ export const COMMAND_MAP = [
29
41
  {
30
42
  source: 'analyze-codeflow.md',
31
43
  target: 'inc-analyze.md',
@@ -78,80 +90,38 @@ const COMMAND_MAP = [
78
90
  ];
79
91
 
80
92
  /**
81
- * Generate Cursor command content
82
- * Templates already contain complete Cursor command format with CLI sync instructions,
83
- * so we just pass through the source content directly.
84
- * @param {Object} cmd - Command definition
85
- * @param {string} sourceContent - Original template content (already complete)
86
- * @param {string} projectRoot - Project root path (optional, unused)
87
- * @returns {string}
88
- */
89
- function generateCursorCommand(cmd, sourceContent, projectRoot = null) {
90
- // Templates are already complete Cursor commands, pass through directly
91
- return sourceContent;
92
- }
93
-
94
- /**
95
- * Get source file path with fallback to user local commands
93
+ * Get source file path with optional fallback directories
96
94
  * @param {string} fileName - Source file name
95
+ * @param {Array<string>} fallbackDirs - Optional fallback directories to search
97
96
  * @returns {string|null} Path to source file or null if not found
98
97
  */
99
- function getSourcePath(fileName) {
98
+ function getSourcePath(fileName, fallbackDirs = []) {
100
99
  // Try built-in templates first (preferred)
101
100
  const templatePath = path.join(TEMPLATES_DIR, fileName);
102
101
  if (fs.existsSync(templatePath)) {
103
102
  return templatePath;
104
103
  }
105
104
 
106
- // Fallback to user local Claude commands
107
- const claudePath = path.join(CLAUDE_COMMANDS_DIR, fileName);
108
- if (fs.existsSync(claudePath)) {
109
- return claudePath;
105
+ // Try fallback directories
106
+ for (const dir of fallbackDirs) {
107
+ const fallbackPath = path.join(dir, fileName);
108
+ if (fs.existsSync(fallbackPath)) {
109
+ return fallbackPath;
110
+ }
110
111
  }
111
112
 
112
113
  return null;
113
114
  }
114
115
 
115
116
  /**
116
- * Generate all Cursor commands
117
- * @param {string} projectRoot - Optional project root for customization
117
+ * Generate utility commands content
118
118
  * @returns {Array<{name: string, content: string}>}
119
119
  */
120
- export function generateCursorCommands(projectRoot = null) {
121
- const commands = [];
122
-
123
- for (const cmd of COMMAND_MAP) {
124
- const sourcePath = getSourcePath(cmd.source);
125
-
126
- let content;
127
- if (sourcePath) {
128
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
129
- content = generateCursorCommand(cmd, sourceContent, projectRoot);
130
- } else {
131
- // Generate placeholder if source doesn't exist
132
- content = `---
133
- description: ${cmd.description}
134
- ---
135
-
136
- # ${cmd.label}
137
-
138
- > 源命令文件不存在: ${cmd.source}
139
- > 请确保已正确安装 incspec-cli 或 ai-incremental-coding 技能。
140
-
141
- 请参考 incspec 文档手动执行此步骤。
142
- `;
143
- }
144
-
145
- commands.push({
146
- name: cmd.target,
147
- content,
148
- });
149
- }
150
-
151
- // Add utility commands
152
- commands.push({
153
- name: 'inc-status.md',
154
- content: `---
120
+ function generateUtilityCommands() {
121
+ return [
122
+ {
123
+ name: 'inc-status.md',
124
+ content: `---
155
125
  description: [incspec] 查看当前工作流状态
156
126
  ---
157
127
 
@@ -169,11 +139,10 @@ incspec status
169
139
  cat ${INCSPEC_DIR}/WORKFLOW.md
170
140
  \`\`\`
171
141
  `,
172
- });
173
-
174
- commands.push({
175
- name: 'inc-help.md',
176
- content: `---
142
+ },
143
+ {
144
+ name: 'inc-help.md',
145
+ content: `---
177
146
  description: [incspec] 显示帮助信息
178
147
  ---
179
148
 
@@ -225,25 +194,79 @@ ${INCSPEC_DIR}/
225
194
  └── archives/ # 历史归档 (YYYY-MM/{module}/)
226
195
  \`\`\`
227
196
  `,
228
- });
197
+ },
198
+ ];
199
+ }
200
+
201
+ /**
202
+ * Generate all IDE commands
203
+ * @param {string} ide - IDE type ('cursor' or 'claude')
204
+ * @param {Object} options - Additional options
205
+ * @param {string} options.projectRoot - Optional project root for customization
206
+ * @returns {Array<{name: string, content: string}>}
207
+ */
208
+ export function generateCommands(ide, { projectRoot = null } = {}) {
209
+ const config = IDE_CONFIGS[ide];
210
+ if (!config) {
211
+ throw new Error(`Unknown IDE: ${ide}`);
212
+ }
213
+
214
+ const commands = [];
215
+
216
+ // Generate workflow commands
217
+ for (const cmd of COMMAND_MAP) {
218
+ const sourcePath = getSourcePath(cmd.source, config.fallbackDirs);
219
+
220
+ let content;
221
+ if (sourcePath) {
222
+ content = fs.readFileSync(sourcePath, 'utf-8');
223
+ } else {
224
+ // Generate placeholder if source doesn't exist
225
+ content = `---
226
+ description: ${cmd.description}
227
+ ---
228
+
229
+ # ${cmd.label}
230
+
231
+ > 源命令文件不存在: ${cmd.source}
232
+ > 请确保已正确安装 incspec-cli。
233
+
234
+ 请参考 incspec 文档手动执行此步骤。
235
+ `;
236
+ }
237
+
238
+ commands.push({
239
+ name: cmd.target,
240
+ content,
241
+ });
242
+ }
243
+
244
+ // Add utility commands
245
+ commands.push(...generateUtilityCommands());
229
246
 
230
247
  return commands;
231
248
  }
232
249
 
233
250
  /**
234
251
  * Sync commands to project directory
235
- * @param {string} projectRoot
252
+ * @param {string} ide - IDE type ('cursor' or 'claude')
253
+ * @param {string} projectRoot - Project root path
236
254
  * @returns {number} Number of files written
237
255
  */
238
- export function syncToProject(projectRoot) {
239
- const targetDir = path.join(projectRoot, CURSOR_COMMANDS_DIR);
256
+ export function syncToProject(ide, projectRoot) {
257
+ const config = IDE_CONFIGS[ide];
258
+ if (!config) {
259
+ throw new Error(`Unknown IDE: ${ide}`);
260
+ }
261
+
262
+ const targetDir = path.join(projectRoot, config.projectDir);
240
263
 
241
264
  // Create directory
242
265
  if (!fs.existsSync(targetDir)) {
243
266
  fs.mkdirSync(targetDir, { recursive: true });
244
267
  }
245
268
 
246
- const commands = generateCursorCommands(projectRoot);
269
+ const commands = generateCommands(ide, { projectRoot });
247
270
 
248
271
  for (const cmd of commands) {
249
272
  const filePath = path.join(targetDir, cmd.name);
@@ -254,19 +277,27 @@ export function syncToProject(projectRoot) {
254
277
  }
255
278
 
256
279
  /**
257
- * Sync commands to global Cursor directory
280
+ * Sync commands to global directory
281
+ * @param {string} ide - IDE type ('cursor' or 'claude')
258
282
  * @returns {number} Number of files written
259
283
  */
260
- export function syncToGlobal() {
284
+ export function syncToGlobal(ide) {
285
+ const config = IDE_CONFIGS[ide];
286
+ if (!config) {
287
+ throw new Error(`Unknown IDE: ${ide}`);
288
+ }
289
+
290
+ const targetDir = config.globalDir;
291
+
261
292
  // Create directory
262
- if (!fs.existsSync(GLOBAL_CURSOR_DIR)) {
263
- fs.mkdirSync(GLOBAL_CURSOR_DIR, { recursive: true });
293
+ if (!fs.existsSync(targetDir)) {
294
+ fs.mkdirSync(targetDir, { recursive: true });
264
295
  }
265
296
 
266
- const commands = generateCursorCommands();
297
+ const commands = generateCommands(ide);
267
298
 
268
299
  for (const cmd of commands) {
269
- const filePath = path.join(GLOBAL_CURSOR_DIR, cmd.name);
300
+ const filePath = path.join(targetDir, cmd.name);
270
301
  fs.writeFileSync(filePath, cmd.content, 'utf-8');
271
302
  }
272
303
 
@@ -274,16 +305,43 @@ export function syncToGlobal() {
274
305
  }
275
306
 
276
307
  /**
277
- * Check if Cursor commands exist
278
- * @param {string} projectRoot
308
+ * Check if IDE commands exist
309
+ * @param {string} ide - IDE type ('cursor' or 'claude')
310
+ * @param {string} projectRoot - Project root path
279
311
  * @returns {{project: boolean, global: boolean}}
280
312
  */
281
- export function checkCursorCommands(projectRoot) {
282
- const projectDir = path.join(projectRoot, CURSOR_COMMANDS_DIR);
283
- const globalDir = GLOBAL_CURSOR_DIR;
313
+ export function checkCommands(ide, projectRoot) {
314
+ const config = IDE_CONFIGS[ide];
315
+ if (!config) {
316
+ throw new Error(`Unknown IDE: ${ide}`);
317
+ }
318
+
319
+ const projectDir = path.join(projectRoot, config.projectDir);
320
+ const globalDir = config.globalDir;
284
321
 
285
322
  return {
286
323
  project: fs.existsSync(projectDir) && fs.readdirSync(projectDir).length > 0,
287
324
  global: fs.existsSync(globalDir) && fs.readdirSync(globalDir).length > 0,
288
325
  };
289
326
  }
327
+
328
+ /**
329
+ * Get IDE configuration
330
+ * @param {string} ide - IDE type ('cursor' or 'claude')
331
+ * @returns {Object} IDE configuration
332
+ */
333
+ export function getIDEConfig(ide) {
334
+ const config = IDE_CONFIGS[ide];
335
+ if (!config) {
336
+ throw new Error(`Unknown IDE: ${ide}`);
337
+ }
338
+ return config;
339
+ }
340
+
341
+ /**
342
+ * Get list of supported IDEs
343
+ * @returns {Array<string>}
344
+ */
345
+ export function getSupportedIDEs() {
346
+ return Object.keys(IDE_CONFIGS);
347
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localsummer/incspec",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "面向 AI 编程助手的增量规范驱动开发工具",
5
5
  "bin": {
6
6
  "incspec": "index.mjs"