specflow-cc 1.22.0 → 1.22.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,12 @@ All notable changes to SpecFlow will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.22.1] - 2026-05-20
9
+
10
+ ### Fixed
11
+
12
+ - `todo next-id` now scans `.specflow/specs/` and `.specflow/archive/` for `source: TODO-XXX` frontmatter entries, preventing reissue of retired IDs. Previously, a TODO file deleted during promotion to a spec could have its ID reassigned to an unrelated new TODO, leaving downstream `/sf:plan` unable to operate on the new TODO (it rejects the ID as "already promoted").
13
+
8
14
  ## [1.22.0] - 2026-05-19
9
15
 
10
16
  ### Added
package/bin/lib/todo.cjs CHANGED
@@ -183,6 +183,8 @@ function cmdTodoList(cwd, raw, { showAll } = {}) {
183
183
  * Scans:
184
184
  * 1. .specflow/todos/TODO-*.md filenames using fs.readdirSync() + JS regex
185
185
  * 2. .specflow/todos/TODO.md for legacy IDs using fs.readFileSync() + /TODO-(\d+)/g
186
+ * 3. .specflow/specs/*.md and .specflow/archive/*.md for `source: TODO-XXX`
187
+ * frontmatter entries (retired IDs from promoted TODOs).
186
188
  *
187
189
  * NOTE: Does NOT use grep -oP (GNU-only, unavailable on macOS).
188
190
  *
@@ -222,6 +224,31 @@ function cmdTodoNextId(cwd, raw) {
222
224
  // file may not exist — skip
223
225
  }
224
226
 
227
+ // Scan promoted-spec frontmatter for retired TODO IDs.
228
+ // On promotion, the source TODO file is deleted; the only surviving
229
+ // record is `source: TODO-XXX` in the spec's frontmatter. Without this
230
+ // scan, next-id can reissue a retired ID and downstream `/sf:plan` will
231
+ // reject the new TODO because the archive still records the old promotion.
232
+ for (const sub of ['specs', 'archive']) {
233
+ const dir = path.join(cwd, '.specflow', sub);
234
+ let files;
235
+ try {
236
+ files = fs.readdirSync(dir).filter(f => f.endsWith('.md'));
237
+ } catch (e) { continue; }
238
+ for (const file of files) {
239
+ let content;
240
+ try {
241
+ content = fs.readFileSync(path.join(dir, file), 'utf8');
242
+ } catch (e) { continue; }
243
+ const regex = /(?:^|\n)source:\s*TODO-(\d+)/g;
244
+ let match;
245
+ while ((match = regex.exec(content)) !== null) {
246
+ const num = parseInt(match[1], 10);
247
+ if (num > maxNum) maxNum = num;
248
+ }
249
+ }
250
+ }
251
+
225
252
  const nextNumber = maxNum + 1;
226
253
  const nextId = 'TODO-' + String(nextNumber).padStart(3, '0');
227
254
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specflow-cc",
3
- "version": "1.22.0",
3
+ "version": "1.22.1",
4
4
  "description": "Spec-driven development system for Claude Code — quality-first workflow with explicit audit cycles",
5
5
  "bin": {
6
6
  "specflow-cc": "bin/install.js"