speccrew 0.6.10 → 0.6.12

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.
@@ -15,7 +15,7 @@ const {
15
15
  } = require('../utils');
16
16
  const { resolveIDE, transformAgentForIDE, transformSkillForIDE } = require('../ide-adapters');
17
17
 
18
- // 解析命令行参数
18
+ // Parse command line arguments
19
19
  function parseArgs() {
20
20
  const args = process.argv.slice(2);
21
21
  let ide = null;
@@ -30,7 +30,7 @@ function parseArgs() {
30
30
  return { ide };
31
31
  }
32
32
 
33
- // 检查 Node.js 版本 >= 16
33
+ // Check Node.js version >= 16
34
34
  function checkNodeVersion() {
35
35
  const version = process.version;
36
36
  const major = parseInt(version.slice(1).split('.')[0], 10);
@@ -39,7 +39,7 @@ function checkNodeVersion() {
39
39
  }
40
40
  }
41
41
 
42
- // 进度显示辅助函数
42
+ // Progress display helper functions
43
43
  function printProgress(step, total, message) {
44
44
  process.stdout.write(`[${step}/${total}] ${message}... `);
45
45
  }
@@ -48,12 +48,12 @@ function printDone() {
48
48
  console.log('done');
49
49
  }
50
50
 
51
- // 获取 npm 包根目录
51
+ // Get npm package root directory
52
52
  function getPackageRoot() {
53
53
  return path.resolve(__dirname, '..', '..');
54
54
  }
55
55
 
56
- // 复制 agentsspeccrew-* 前缀文件,总是覆盖)
56
+ // Copy agents (speccrew-* prefixed files, always overwrite)
57
57
  function copyAgents(sourceDir, destDir, ideConfig) {
58
58
  if (!fs.existsSync(sourceDir)) return { copied: 0, skipped: 0 };
59
59
 
@@ -70,7 +70,7 @@ function copyAgents(sourceDir, destDir, ideConfig) {
70
70
  const srcPath = path.join(sourceDir, entry.name);
71
71
  const destPath = path.join(destDir, entry.name);
72
72
 
73
- // 如果 IDE 需要转换 frontmatter 且是 .md 文件
73
+ // If IDE needs frontmatter transformation and is .md file
74
74
  if (ideConfig && ideConfig.transformFrontmatter && entry.name.endsWith('.md')) {
75
75
  const originalContent = fs.readFileSync(srcPath, 'utf8');
76
76
  const transformedContent = transformAgentForIDE(originalContent, ideConfig);
@@ -84,7 +84,7 @@ function copyAgents(sourceDir, destDir, ideConfig) {
84
84
  return { copied, skipped };
85
85
  }
86
86
 
87
- // 复制 skillsspeccrew-* 前缀目录,递归复制,总是覆盖)
87
+ // Copy skills (speccrew-* prefixed directories, recursive copy, always overwrite)
88
88
  function copySkills(sourceDir, destDir, ideConfig) {
89
89
  if (!fs.existsSync(sourceDir)) return { copied: 0, skipped: 0 };
90
90
 
@@ -101,14 +101,14 @@ function copySkills(sourceDir, destDir, ideConfig) {
101
101
  const destPath = path.join(destDir, entry.name);
102
102
 
103
103
  if (entry.isDirectory()) {
104
- // 构建 contentTransform 回调:只对 SKILL.md 文件转化
104
+ // Build contentTransform callback: only transform SKILL.md files
105
105
  let contentTransform = null;
106
106
  if (ideConfig && ideConfig.transformFrontmatter) {
107
107
  contentTransform = (content, fileName, filePath) => {
108
108
  if (fileName === 'SKILL.md') {
109
109
  return transformSkillForIDE(content, ideConfig);
110
110
  }
111
- // 其他文件返回 null,表示按原方式复制
111
+ // Other files return null, indicating copy as-is
112
112
  return null;
113
113
  };
114
114
  }
@@ -124,7 +124,7 @@ function copySkills(sourceDir, destDir, ideConfig) {
124
124
  return { copied, skipped };
125
125
  }
126
126
 
127
- // 创建 workspace 目录结构
127
+ // Create workspace directory structure
128
128
  function createWorkspaceStructure(workspaceDir) {
129
129
  const dirs = [
130
130
  'iterations',
@@ -143,7 +143,7 @@ function createWorkspaceStructure(workspaceDir) {
143
143
  ensureDirectories(workspaceDir, dirs);
144
144
  }
145
145
 
146
- // 复制 workspace 模板(仅复制不存在的文件)
146
+ // Copy workspace template (only copy non-existent files)
147
147
  function copyWorkspaceTemplate(templateDir, workspaceDir) {
148
148
  if (!fs.existsSync(templateDir)) return { copied: 0, skipped: 0 };
149
149
 
@@ -169,7 +169,7 @@ function copyWorkspaceTemplate(templateDir, workspaceDir) {
169
169
  }
170
170
  }
171
171
 
172
- // 遍历 workspace-template 下的所有一级子目录并复制
172
+ // Iterate over all first-level subdirectories in workspace-template and copy
173
173
  const entries = fs.readdirSync(templateDir, { withFileTypes: true });
174
174
  for (const entry of entries) {
175
175
  if (entry.isDirectory()) {
@@ -183,11 +183,11 @@ function copyWorkspaceTemplate(templateDir, workspaceDir) {
183
183
  return { copied, skipped };
184
184
  }
185
185
 
186
- // 复制文档文件(仅复制不存在的文件)
186
+ // Copy documentation files (only copy non-existent files)
187
187
  function copyDocs(packageRoot, workspaceDir) {
188
188
  let copied = 0;
189
189
 
190
- // 复制 GETTING-STARTED*.md workspace/docs/
190
+ // Copy GETTING-STARTED*.md to workspace/docs/
191
191
  const docsSourceDir = path.join(packageRoot, 'docs');
192
192
  const docsDestDir = path.join(workspaceDir, 'docs');
193
193
 
@@ -206,7 +206,7 @@ function copyDocs(packageRoot, workspaceDir) {
206
206
  }
207
207
  }
208
208
 
209
- // 复制 README*.md workspace/
209
+ // Copy README*.md to workspace/
210
210
  const entries = fs.readdirSync(packageRoot, { withFileTypes: true });
211
211
  for (const entry of entries) {
212
212
  if (entry.name.startsWith('README') && entry.name.endsWith('.md')) {
@@ -223,7 +223,7 @@ function copyDocs(packageRoot, workspaceDir) {
223
223
  return { copied };
224
224
  }
225
225
 
226
- // 迁移旧的 .speccrewrc workspace 目录
226
+ // Migrate old .speccrewrc to workspace directory
227
227
  function migrateOldSpeccrewRC(projectRoot, workspaceDir) {
228
228
  const oldRcPath = path.join(projectRoot, '.speccrewrc');
229
229
  const newRcPath = path.join(workspaceDir, '.speccrewrc');
@@ -235,7 +235,7 @@ function migrateOldSpeccrewRC(projectRoot, workspaceDir) {
235
235
  return false;
236
236
  }
237
237
 
238
- // 统计 agents skills 数量
238
+ // Count agents and skills
239
239
  function countAgentsAndSkills(sourceRoot) {
240
240
  let agentCount = 0;
241
241
  let skillCount = 0;
@@ -256,7 +256,7 @@ function countAgentsAndSkills(sourceRoot) {
256
256
  return { agentCount, skillCount };
257
257
  }
258
258
 
259
- // 询问用户确认
259
+ // Ask user for confirmation
260
260
  function askConfirm(message) {
261
261
  return new Promise((resolve) => {
262
262
  const rl = readline.createInterface({
@@ -272,7 +272,7 @@ function askConfirm(message) {
272
272
  });
273
273
  }
274
274
 
275
- // 核心安装逻辑
275
+ // Core installation logic
276
276
  async function runInit(options = {}) {
277
277
  const {
278
278
  projectRoot = process.cwd(),
@@ -284,22 +284,22 @@ async function runInit(options = {}) {
284
284
  const log = silent ? () => {} : console.log;
285
285
 
286
286
  try {
287
- // 1. 检查 Node.js 版本
287
+ // 1. Check Node.js version
288
288
  checkNodeVersion();
289
289
 
290
- // 2. 确定源文件路径
290
+ // 2. Determine source file paths
291
291
  const sourceRoot = getSourceRoot();
292
292
  const packageRoot = getPackageRoot();
293
293
 
294
- // 3. 解析 IDE
294
+ // 3. Resolve IDE
295
295
  if (!silent) printProgress(1, 5, 'Detecting IDE environment');
296
296
  const ideConfigs = resolveIDE(projectRoot, ideArg);
297
297
  if (!silent) printDone();
298
298
 
299
- // 4. 统计 agents skills 数量
299
+ // 4. Count agents and skills
300
300
  const { agentCount, skillCount } = countAgentsAndSkills(sourceRoot);
301
301
 
302
- // 5. 显示安装摘要并确认
302
+ // 5. Show installation summary and confirm
303
303
  const version = getPackageVersion();
304
304
  const workspaceDir = path.join(projectRoot, 'speccrew-workspace');
305
305
 
@@ -323,10 +323,10 @@ async function runInit(options = {}) {
323
323
  log('');
324
324
  }
325
325
 
326
- // 6. 迁移旧的 .speccrewrc(如果存在)
326
+ // 6. Migrate old .speccrewrc (if exists)
327
327
  migrateOldSpeccrewRC(projectRoot, workspaceDir);
328
328
 
329
- // 统计信息
329
+ // Statistics
330
330
  const stats = {
331
331
  ides: [],
332
332
  totalAgents: 0,
@@ -335,7 +335,7 @@ async function runInit(options = {}) {
335
335
  docsInstalled: 0,
336
336
  };
337
337
 
338
- // 7. 复制 agents skills
338
+ // 7. Copy agents and skills
339
339
  if (!silent) printProgress(2, 5, `Installing agents (${agentCount})`);
340
340
  for (const ideConfig of ideConfigs) {
341
341
  const agentsSourceDir = path.join(sourceRoot, 'agents');
@@ -363,28 +363,28 @@ async function runInit(options = {}) {
363
363
  }
364
364
  if (!silent) printDone();
365
365
 
366
- // 8. 复制 skills(显示进度)
366
+ // 8. Copy skills (show progress)
367
367
  if (!silent) printProgress(3, 5, `Installing skills (${skillCount})`);
368
- // skills 已经在上面复制完成,这里只是显示进度
368
+ // Skills already copied above, just showing progress here
369
369
  if (!silent) printDone();
370
370
 
371
- // 9. 创建 speccrew-workspace 目录结构
371
+ // 9. Create speccrew-workspace directory structure
372
372
  if (!silent) printProgress(4, 5, 'Creating workspace structure');
373
373
  createWorkspaceStructure(workspaceDir);
374
374
  stats.workspaceCreated = true;
375
375
  if (!silent) printDone();
376
376
 
377
- // 10. 复制 workspace 模板
377
+ // 10. Copy workspace template
378
378
  const templateDir = getWorkspaceTemplatePath();
379
379
  copyWorkspaceTemplate(templateDir, workspaceDir);
380
380
 
381
- // 11. 复制文档
381
+ // 11. Copy documentation
382
382
  if (!silent) printProgress(5, 5, 'Installing documentation');
383
383
  const docsResult = copyDocs(packageRoot, workspaceDir);
384
384
  stats.docsInstalled = docsResult.copied;
385
385
  if (!silent) printDone();
386
386
 
387
- // 12. 写入 .speccrewrc workspace 目录
387
+ // 12. Write .speccrewrc to workspace directory
388
388
  const rcConfig = {
389
389
  ide: ideConfigs.length === 1 ? ideConfigs[0].id : ideConfigs.map(c => c.id),
390
390
  version: version,
@@ -392,7 +392,7 @@ async function runInit(options = {}) {
392
392
  };
393
393
  writeSpeccrewRC(workspaceDir, rcConfig);
394
394
 
395
- // 13. 输出安装摘要
395
+ // 13. Output installation summary
396
396
  if (!silent) {
397
397
  log(`\nSpecCrew v${version} installed successfully!\n`);
398
398
 
@@ -442,7 +442,7 @@ async function runInit(options = {}) {
442
442
  }
443
443
  }
444
444
 
445
- // CLI 入口
445
+ // CLI entry point
446
446
  function run() {
447
447
  const { ide: cliIdeArg } = parseArgs();
448
448
 
@@ -3,7 +3,7 @@ const path = require('path');
3
3
  const { readSpeccrewRC, getPackageVersion, isSpeccrewFile } = require('../utils');
4
4
 
5
5
  function run(projectRoot, args) {
6
- // 检查是否已初始化
6
+ // Check if initialized
7
7
  const rc = readSpeccrewRC(projectRoot);
8
8
  if (!rc) {
9
9
  console.log('SpecCrew is not initialized in this project.');
@@ -25,7 +25,7 @@ function run(projectRoot, args) {
25
25
 
26
26
  console.log(`SpecCrew v${version} | IDE: ${ideDisplay} (${ideDirs.join(', ')})\n`);
27
27
 
28
- // 收集所有 agents skills
28
+ // Collect all agents and skills
29
29
  const speccrewAgents = new Set();
30
30
  const speccrewSkills = new Set();
31
31
  const userAgents = new Set();
@@ -35,7 +35,7 @@ function run(projectRoot, args) {
35
35
  const ideConfig = getIDEConfig(ideId);
36
36
  if (!ideConfig) continue;
37
37
 
38
- // 扫描 agents
38
+ // Scan agents
39
39
  const agentsDir = path.join(projectRoot, ideConfig.agentsDir);
40
40
  if (fs.existsSync(agentsDir)) {
41
41
  const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
@@ -49,7 +49,7 @@ function run(projectRoot, args) {
49
49
  }
50
50
  }
51
51
 
52
- // 扫描 skills
52
+ // Scan skills
53
53
  const skillsDir = path.join(projectRoot, ideConfig.skillsDir);
54
54
  if (fs.existsSync(skillsDir)) {
55
55
  const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
@@ -64,7 +64,7 @@ function run(projectRoot, args) {
64
64
  }
65
65
  }
66
66
 
67
- // 输出 Agents
67
+ // Output Agents
68
68
  const sortedAgents = Array.from(speccrewAgents).sort();
69
69
  console.log(`Agents (${sortedAgents.length}):`);
70
70
  for (const agent of sortedAgents) {
@@ -72,7 +72,7 @@ function run(projectRoot, args) {
72
72
  }
73
73
  console.log('');
74
74
 
75
- // 输出 Skills
75
+ // Output Skills
76
76
  const sortedSkills = Array.from(speccrewSkills).sort();
77
77
  console.log(`Skills (${sortedSkills.length}):`);
78
78
  for (const skill of sortedSkills) {
@@ -80,7 +80,7 @@ function run(projectRoot, args) {
80
80
  }
81
81
  console.log('');
82
82
 
83
- // 输出用户自定义内容
83
+ // Output user-defined content
84
84
  const allUserDefined = [...Array.from(userAgents), ...Array.from(userSkills)].sort();
85
85
  if (allUserDefined.length > 0) {
86
86
  console.log('User-defined:');
@@ -92,7 +92,7 @@ function run(projectRoot, args) {
92
92
  return true;
93
93
  }
94
94
 
95
- // 获取 IDE 配置(简化版,避免循环依赖)
95
+ // Get IDE config (simplified version, avoid circular dependency)
96
96
  function getIDEConfig(ideId) {
97
97
  const configs = {
98
98
  qoder: {
@@ -4,16 +4,16 @@ const readline = require('readline');
4
4
  const { readSpeccrewRC, isSpeccrewFile, removeDirRecursive } = require('../utils');
5
5
 
6
6
  function run(projectRoot, args) {
7
- // 检查是否已初始化(兼容新旧两个路径)
7
+ // Check if initialized (compatible with both old and new paths)
8
8
  let rc = readSpeccrewRC(projectRoot);
9
9
  const newRcPath = path.join(projectRoot, 'speccrew-workspace', '.speccrewrc');
10
10
 
11
- // 如果旧路径没有配置文件,检查新路径
11
+ // If config not found at old path, check new path
12
12
  if (!rc && fs.existsSync(newRcPath)) {
13
13
  try {
14
14
  rc = JSON.parse(fs.readFileSync(newRcPath, 'utf8'));
15
15
  } catch (e) {
16
- // 忽略解析错误
16
+ // Ignore parse errors
17
17
  }
18
18
  }
19
19
 
@@ -25,10 +25,10 @@ function run(projectRoot, args) {
25
25
 
26
26
  const isAll = args.includes('--all');
27
27
 
28
- // 获取 IDE 配置
28
+ // Get IDE configuration
29
29
  const ides = rc.ide ? (Array.isArray(rc.ide) ? rc.ide : [rc.ide]) : [];
30
30
 
31
- // 扫描将要删除的内容(不实际删除)
31
+ // Scan content to be deleted (don't actually delete yet)
32
32
  let totalAgents = 0;
33
33
  let totalSkills = 0;
34
34
  const idePaths = [];
@@ -40,7 +40,7 @@ function run(projectRoot, args) {
40
40
  let agentCount = 0;
41
41
  let skillCount = 0;
42
42
 
43
- // 统计 agents
43
+ // Count agents
44
44
  const agentsDir = path.join(projectRoot, ideConfig.agentsDir);
45
45
  if (fs.existsSync(agentsDir)) {
46
46
  const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
@@ -51,7 +51,7 @@ function run(projectRoot, args) {
51
51
  }
52
52
  }
53
53
 
54
- // 统计 skills
54
+ // Count skills
55
55
  const skillsDir = path.join(projectRoot, ideConfig.skillsDir);
56
56
  if (fs.existsSync(skillsDir)) {
57
57
  const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
@@ -67,17 +67,17 @@ function run(projectRoot, args) {
67
67
  idePaths.push({ ideConfig, agentCount, skillCount });
68
68
  }
69
69
 
70
- // 检查配置文件是否存在(新路径和旧路径)
70
+ // Check if config file exists (new and old paths)
71
71
  const oldRcPath = path.join(projectRoot, '.speccrewrc');
72
72
  const hasNewRc = fs.existsSync(newRcPath);
73
73
  const hasOldRc = fs.existsSync(oldRcPath);
74
74
  const hasRcFile = hasNewRc || hasOldRc;
75
75
 
76
- // 检查 workspace 是否存在
76
+ // Check if workspace exists
77
77
  const workspaceDir = path.join(projectRoot, 'speccrew-workspace');
78
78
  const hasWorkspace = fs.existsSync(workspaceDir);
79
79
 
80
- // 显示将要删除的内容
80
+ // Display content to be deleted
81
81
  console.log('SpecCrew Uninstall\n');
82
82
  console.log('The following will be removed:');
83
83
 
@@ -99,7 +99,7 @@ function run(projectRoot, args) {
99
99
  console.log('\nWARNING: This will permanently delete your workspace data!');
100
100
  }
101
101
 
102
- // 询问用户确认
102
+ // Ask user for confirmation
103
103
  const rl = readline.createInterface({
104
104
  input: process.stdin,
105
105
  output: process.stdout
@@ -117,7 +117,7 @@ function run(projectRoot, args) {
117
117
  return;
118
118
  }
119
119
 
120
- // 执行卸载
120
+ // Execute uninstall
121
121
  const result = performUninstall(projectRoot, idePaths, isAll, hasOldRc);
122
122
  resolve(result);
123
123
  });
@@ -128,11 +128,11 @@ function performUninstall(projectRoot, idePaths, isAll, hasOldRc) {
128
128
  let removedAgents = 0;
129
129
  let removedSkills = 0;
130
130
 
131
- // 计算总步骤数
131
+ // Calculate total steps
132
132
  const totalSteps = isAll ? 4 : 3;
133
133
  let currentStep = 0;
134
134
 
135
- // 删除 agents
135
+ // Delete agents
136
136
  currentStep++;
137
137
  process.stdout.write(`[${currentStep}/${totalSteps}] Removing agents... `);
138
138
  for (const { ideConfig } of idePaths) {
@@ -154,7 +154,7 @@ function performUninstall(projectRoot, idePaths, isAll, hasOldRc) {
154
154
  }
155
155
  console.log(`done (${removedAgents} removed)`);
156
156
 
157
- // 删除 skills
157
+ // Delete skills
158
158
  currentStep++;
159
159
  process.stdout.write(`[${currentStep}/${totalSteps}] Removing skills... `);
160
160
  for (const { ideConfig } of idePaths) {
@@ -176,17 +176,17 @@ function performUninstall(projectRoot, idePaths, isAll, hasOldRc) {
176
176
  }
177
177
  console.log(`done (${removedSkills} removed)`);
178
178
 
179
- // 删除配置文件
179
+ // Delete config files
180
180
  currentStep++;
181
181
  process.stdout.write(`[${currentStep}/${totalSteps}] Removing configuration... `);
182
182
 
183
- // 删除新路径的配置文件
183
+ // Delete config file at new path
184
184
  const newRcPath = path.join(projectRoot, 'speccrew-workspace', '.speccrewrc');
185
185
  if (fs.existsSync(newRcPath)) {
186
186
  fs.unlinkSync(newRcPath);
187
187
  }
188
188
 
189
- // 兼容处理:删除旧路径的配置文件
189
+ // Compatibility: Delete config file at old path
190
190
  const oldRcPath = path.join(projectRoot, '.speccrewrc');
191
191
  if (fs.existsSync(oldRcPath)) {
192
192
  fs.unlinkSync(oldRcPath);
@@ -194,7 +194,7 @@ function performUninstall(projectRoot, idePaths, isAll, hasOldRc) {
194
194
 
195
195
  console.log('done');
196
196
 
197
- // 如果 --all,删除 workspace
197
+ // If --all, delete workspace
198
198
  if (isAll) {
199
199
  currentStep++;
200
200
  process.stdout.write(`[${currentStep}/${totalSteps}] Removing workspace... `);
@@ -213,7 +213,7 @@ function performUninstall(projectRoot, idePaths, isAll, hasOldRc) {
213
213
  return true;
214
214
  }
215
215
 
216
- // 获取 IDE 配置(简化版,避免循环依赖)
216
+ // Get IDE config (simplified version, avoid circular dependency)
217
217
  function getIDEConfig(ideId) {
218
218
  const configs = {
219
219
  qoder: {