claude-sdlc 1.0.5 → 1.0.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.
Files changed (2) hide show
  1. package/lib/installer.js +65 -7
  2. package/package.json +1 -1
package/lib/installer.js CHANGED
@@ -112,6 +112,46 @@ function mergeSettings(existing, template) {
112
112
  return result;
113
113
  }
114
114
 
115
+ /**
116
+ * 从 CLAUDE.md 中提取 YAML 状态块(```yaml ... ``` 包裹的 SDLC 项目状态)
117
+ */
118
+ function extractYamlState(content) {
119
+ const match = content.match(/```yaml\n# === SDLC 项目状态 ===\n[\s\S]*?```/);
120
+ return match ? match[0] : null;
121
+ }
122
+
123
+ /**
124
+ * 判断 YAML 状态块是否有实际项目数据(非空白模板)
125
+ */
126
+ function hasActiveState(yamlBlock) {
127
+ if (!yamlBlock) return false;
128
+ // 检查 current_phase 是否不是 P0
129
+ if (/current_phase:\s*P[1-6]/.test(yamlBlock)) return true;
130
+ // 检查 task_description 是否非空
131
+ if (/task_description:\s*"[^"]+"/.test(yamlBlock)) return true;
132
+ // 检查 modified_files 是否有内容
133
+ if (/modified_files:\s*\n\s*-/.test(yamlBlock)) return true;
134
+ // 检查 prd 是否有实际条目(非注释)
135
+ if (/prd:\s*\n\s*-\s*id:/.test(yamlBlock)) return true;
136
+ return false;
137
+ }
138
+
139
+ /**
140
+ * 合并 CLAUDE.md — 更新模板指令,保留用户的 YAML 状态块
141
+ */
142
+ function mergeClaudeMd(existingContent, templateContent) {
143
+ const existingState = extractYamlState(existingContent);
144
+ const templateState = extractYamlState(templateContent);
145
+
146
+ if (!existingState || !templateState) {
147
+ // 格式不匹配,无法合并,返回模板
148
+ return templateContent;
149
+ }
150
+
151
+ // 用旧的状态块替换新模板中的空白状态块
152
+ return templateContent.replace(templateState, existingState);
153
+ }
154
+
115
155
  function copyFilesQuiet(srcDir, destDir, ext) {
116
156
  if (!fs.existsSync(srcDir)) return [];
117
157
  const files = fs.readdirSync(srcDir).filter(f => f.endsWith(ext));
@@ -151,13 +191,31 @@ function install(targetDir) {
151
191
  console.log(` ${SYM.arrow} 目标 ${BOLD}${targetDir}${RESET}`);
152
192
  blank();
153
193
 
154
- // Step 1: CLAUDE.md
194
+ // Step 1: CLAUDE.md(智能合并:更新模板指令,保留项目状态)
155
195
  step(1, STEPS, '安装核心控制文件');
156
- fs.copyFileSync(
157
- path.join(templateDir, 'CLAUDE.md'),
158
- path.join(targetDir, 'CLAUDE.md')
159
- );
160
- fileLog(SYM.check, 'CLAUDE.md');
196
+ const targetClaudeMd = path.join(targetDir, 'CLAUDE.md');
197
+ const templateClaudeMd = path.join(templateDir, 'CLAUDE.md');
198
+ const templateContent = fs.readFileSync(templateClaudeMd, 'utf-8');
199
+
200
+ if (fs.existsSync(targetClaudeMd)) {
201
+ const existingContent = fs.readFileSync(targetClaudeMd, 'utf-8');
202
+ const existingState = extractYamlState(existingContent);
203
+
204
+ if (hasActiveState(existingState)) {
205
+ // 有活跃项目状态 → 更新指令模板,保留状态块
206
+ const merged = mergeClaudeMd(existingContent, templateContent);
207
+ fs.writeFileSync(targetClaudeMd, merged, 'utf-8');
208
+ fileLog(SYM.check, `CLAUDE.md ${DIM}(升级模板,保留项目状态)${RESET}`);
209
+ } else {
210
+ // 状态为空(P0)→ 直接覆盖
211
+ fs.writeFileSync(targetClaudeMd, templateContent, 'utf-8');
212
+ fileLog(SYM.check, 'CLAUDE.md');
213
+ }
214
+ } else {
215
+ // 首次安装
216
+ fs.writeFileSync(targetClaudeMd, templateContent, 'utf-8');
217
+ fileLog(SYM.check, 'CLAUDE.md');
218
+ }
161
219
 
162
220
  // Step 2: 目录结构
163
221
  step(2, STEPS, '创建目录结构');
@@ -340,4 +398,4 @@ function uninstall(targetDir) {
340
398
  blank();
341
399
  }
342
400
 
343
- module.exports = { install, uninstall, mergeSettings };
401
+ module.exports = { install, uninstall, mergeSettings, extractYamlState, hasActiveState, mergeClaudeMd };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-sdlc",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "让 Claude Code 严格按 SDLC 规范开发 — 一条命令安装",
5
5
  "bin": {
6
6
  "claude-sdlc": "./bin/cli.js"