speccrew 0.7.34 → 0.7.36

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.
@@ -54,7 +54,7 @@ Phase 4: API Contract Generation
54
54
  | ALL | ABORT ON FAILURE | If any skill invocation fails → STOP and report. Do NOT attempt to generate content manually as fallback |
55
55
  | ALL | SCRIPT ENFORCEMENT | All .checkpoints.json and WORKFLOW-PROGRESS.json updates via update-progress.js script. Manual JSON creation FORBIDDEN |
56
56
  | ALL | NAME LOCK | After Phase 2 Feature List is confirmed, feature_name is immutable. All Skills MUST use the exact parameter value for output filenames. Name translation or substitution is FORBIDDEN |
57
- | ALL | ANTI-SCRIPT | Agent MUST NOT create custom automation scripts. DO NOT generate helper scripts (.sh, .ps1, .js) for batch processing or progress checking. Use ONLY the standard update-progress.js commands in documented workflow order. |
57
+ | ALL | ANTI-SCRIPT | Agent MUST NOT create custom automation scripts. DO NOT generate helper scripts (.sh, .ps1, .js) for batch processing or progress checking. Use ONLY the standard update-progress.js commands in documented workflow order. If a required temp file (.tasks-temp.json) is missing, this indicates a workflow orchestration gap — follow the XML workflow's regeneration step, do NOT implement workarounds with ad-hoc commands. |
58
58
 
59
59
  ## MANDATORY WORKER ENFORCEMENT
60
60
 
@@ -742,7 +742,7 @@ Invoke API Contract skill directly:
742
742
  - `feature_spec_path`: Path to the Feature Spec document
743
743
  - `feature_id`: Feature ID (e.g., `F-CRM-01`)
744
744
  - `feature_type`: `Page+API` or `API-only`
745
- - `output_path`: `{iterations_dir}/{iteration}/02.feature-design/{feature_id}-{feature-name-slug}-api-contract.md`
745
+ - `output_path`: `{iterations_dir}/{iteration}/03.api-contract/{feature_id}-{feature-name-slug}-api-contract.md`
746
746
 
747
747
  **Note**: Both `Page+API` and `API-only` Features require API Contract documents.
748
748
 
@@ -756,15 +756,33 @@ If **2+ Feature Specs** in registry:
756
756
  > Worker will read the skill's workflow.agentflow.xml for its execution plan.
757
757
  > See: MANDATORY: Worker Dispatch Prompt Format section above.
758
758
 
759
+ ### Phase 4: API Contract — Task File Management
760
+
761
+ ⚠️ **CRITICAL: .tasks-temp.json Regeneration**
762
+
763
+ Phase 3 deletes `.tasks-temp.json` after init. Phase 4 MUST regenerate it before init:
764
+
765
+ 1. Read `{iteration_path}/02.feature-design/DISPATCH-PROGRESS.json` (Phase 3 results)
766
+ 2. Extract ALL task IDs from the tasks array
767
+ 3. Build flat JSON array: `[{"id":"F-M01-01"},{"id":"F-M01-02"},...]`
768
+ 4. Write to `{iteration_path}/03.api-contract/.tasks-temp.json`
769
+ 5. Run init: `node {workspace_path}/scripts/update-progress.js init --file {iteration_path}/03.api-contract/DISPATCH-PROGRESS.json --stage 02_feature_design_api_contract --tasks-file {iteration_path}/03.api-contract/.tasks-temp.json`
770
+ 6. Delete `.tasks-temp.json` after successful init
771
+
772
+ **DO NOT**:
773
+ - Run ad-hoc PowerShell/Bash commands to parse `.prd-feature-list.json`
774
+ - Create custom scripts to build task lists
775
+ - Skip the init step and manually edit DISPATCH-PROGRESS.json
776
+
759
777
  1. **Initialize DISPATCH-PROGRESS.json for API Contract stage**:
760
778
 
761
779
  > ⚠️ Use `--tasks-file` instead of `--tasks` to avoid PowerShell JSON parsing issues.
762
780
 
763
781
  ```bash
764
- # Step 1: Write tasks JSON to temp file inside iteration directory
765
- # Create .tasks-temp.json with the task array content
782
+ # Step 1: Read Phase 3 DISPATCH-PROGRESS.json and extract all task IDs
783
+ # Build flat JSON array: [{"id":"F-XXX"},...] and write to .tasks-temp.json
766
784
  # Step 2: Initialize with --tasks-file
767
- node {update_progress_script} init --file {iterations_dir}/{iteration}/03.api-contract/DISPATCH-PROGRESS.json --stage 02_feature_design_api_contract --tasks-file {iterations_dir}/{iteration}/02.feature-design/.tasks-temp.json
785
+ node {update_progress_script} init --file {iterations_dir}/{iteration}/03.api-contract/DISPATCH-PROGRESS.json --stage 02_feature_design_api_contract --tasks-file {iterations_dir}/{iteration}/03.api-contract/.tasks-temp.json
768
786
  # Step 3: Delete .tasks-temp.json after successful init
769
787
  ```
770
788
 
@@ -782,7 +800,7 @@ If **2+ Feature Specs** in registry:
782
800
  - `feature_id`: Feature ID (e.g., `F-CRM-01`)
783
801
  - `feature_name`: Feature name — **MUST be the exact value from .checkpoints.json, used verbatim for output filename**
784
802
  - `feature_type`: `Page+API` or `API-only`
785
- - `output_path`: `{iterations_dir}/{iteration}/02.feature-design/{feature_id}-{feature-name-slug}-api-contract.md`
803
+ - `output_path`: `{iterations_dir}/{iteration}/03.api-contract/{feature_id}-{feature-name-slug}-api-contract.md`
786
804
 
787
805
  3. **Wait for batch completion**, update progress per worker:
788
806
  ```bash
@@ -846,7 +864,7 @@ After user confirms Joint Confirmation:
846
864
  node {update_progress_script} update-workflow \
847
865
  --file {iterations_dir}/{iteration}/WORKFLOW-PROGRESS.json \
848
866
  --stage 02_feature_design --status confirmed \
849
- --output "02.feature-design/F-CRM-01-customer-list-feature-spec.md,02.feature-design/F-CRM-01-customer-list-api-contract.md,..."
867
+ --output "02.feature-design/F-CRM-01-customer-list-feature-spec.md,03.api-contract/F-CRM-01-customer-list-api-contract.md,..."
850
868
  ```
851
869
 
852
870
  2. **Confirm Transition**:
@@ -858,7 +876,7 @@ After user confirms Joint Confirmation:
858
876
  | Deliverable | Path | Notes |
859
877
  |-------------|------|-------|
860
878
  | Feature Spec | `{iterations_dir}/{iteration}/02.feature-design/{feature-id}-{feature-name}-feature-spec.md` | One document per Feature |
861
- | API Contract | `{iterations_dir}/{iteration}/02.feature-design/{feature-id}-{feature-name}-api-contract.md` | One document per Feature |
879
+ | API Contract | `{iterations_dir}/{iteration}/03.api-contract/{feature-id}-{feature-name}-api-contract.md` | One document per Feature |
862
880
 
863
881
  ## Naming Convention
864
882
 
@@ -65,6 +65,13 @@ When executing design or document generation skills:
65
65
  - Only output brief block execution announcements
66
66
  - This is especially critical in batch mode where multiple Workers run simultaneously
67
67
 
68
+ ### FILE ENCODING
69
+
70
+ ALL file operations MUST use UTF-8 encoding explicitly:
71
+ - When creating files via tools: ensure UTF-8 (most IDE tools default to UTF-8)
72
+ - When writing via Node.js: always pass `'utf8'` as encoding parameter
73
+ - NEVER rely on system default encoding — Chinese Windows defaults to GBK which corrupts Unicode characters
74
+
68
75
  **FORBIDDEN output in conversation during design tasks:**
69
76
  - ASCII wireframes / UI prototypes
70
77
  - Mermaid diagrams (these go in the file only)
@@ -80,9 +80,9 @@ Complete definition for each API:
80
80
  1. **Read the template file**: `templates/API-CONTRACT-TEMPLATE.md`
81
81
  2. **Replace top-level placeholders** (feature name, date, feature_id if provided, etc.)
82
82
  3. **Create the document** using `create_file`:
83
- - **新格式(当提供了 feature_id 时)**:`speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/{feature-id}-{feature-name}-api-contract.md`
83
+ - **新格式(当提供了 feature_id 时)**:`speccrew-workspace/iterations/{number}-{type}-{name}/03.api-contract/{feature-id}-{feature-name}-api-contract.md`
84
84
  - 示例:`F-CRM-01-customer-list-api-contract.md`
85
- - **旧格式(向后兼容,未提供 feature_id 时)**:`speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/[feature-name]-api-contract.md`
85
+ - **旧格式(向后兼容,未提供 feature_id 时)**:`speccrew-workspace/iterations/{number}-{type}-{name}/03.api-contract/[feature-name]-api-contract.md`
86
86
  - Content: Template with top-level placeholders replaced
87
87
  4. **Verify**: Document has complete section structure ready for filling
88
88
 
@@ -127,7 +127,7 @@ Feature 设计阶段交付物已准备就绪:
127
127
 
128
128
  📄 文档清单:
129
129
  - Feature Spec: speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/{feature-id}-{feature-name}-feature-spec.md
130
- - API Contract: speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/{feature-id}-{feature-name}-api-contract.md
130
+ - API Contract: speccrew-workspace/iterations/{number}-{type}-{name}/03.api-contract/{feature-id}-{feature-name}-api-contract.md
131
131
 
132
132
  请确认以下关键点:
133
133
  1. 当前 Feature 的技术方案是否可行?
@@ -146,7 +146,7 @@ Feature 设计阶段交付物已准备就绪:
146
146
  ```
147
147
  Feature design phase deliverables are ready:
148
148
  - Feature Spec: speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/[feature-name]-feature-spec.md
149
- - API Contract: speccrew-workspace/iterations/{number}-{type}-{name}/02.feature-design/[feature-name]-api-contract.md
149
+ - API Contract: speccrew-workspace/iterations/{number}-{type}-{name}/03.api-contract/[feature-name]-api-contract.md
150
150
 
151
151
  Please confirm the following key points:
152
152
  1. Is the overall technical solution feasible?
@@ -249,7 +249,7 @@ Update `WORKFLOW-PROGRESS.json` to reflect current feature/module status.
249
249
  "confirmed_at": "{current_timestamp}",
250
250
  "outputs": [
251
251
  "02.feature-design/{feature-id}-{feature-name}-feature-spec.md",
252
- "02.feature-design/{feature-id}-{feature-name}-api-contract.md"
252
+ "03.api-contract/${feature_id}-${feature_name}-api-contract.md"
253
253
  ]
254
254
  }
255
255
  }
@@ -274,7 +274,7 @@ Update `WORKFLOW-PROGRESS.json` to reflect current feature/module status.
274
274
  "confirmed_at": "{current_timestamp}",
275
275
  "outputs": [
276
276
  "02.feature-design/[feature-name]-feature-spec.md",
277
- "02.feature-design/[feature-name]-api-contract.md"
277
+ "03.api-contract/${feature_name}-api-contract.md"
278
278
  ]
279
279
  }
280
280
  }
@@ -81,21 +81,21 @@
81
81
  - {Feature ID} → ${feature_id}
82
82
  - {Date} → current date
83
83
  </field>
84
- <field name="output_path">${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md</field>
85
- <field name="fallback_path">${iteration_path}/02.feature-design/${feature_name}-api-contract.md</field>
84
+ <field name="output_path">${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md</field>
85
+ <field name="fallback_path">${iteration_path}/03.api-contract/${feature_name}-api-contract.md</field>
86
86
  <field name="output" var="document_created"/>
87
87
  </block>
88
88
 
89
89
  <!-- Checkpoint: Verify document created -->
90
90
  <block type="checkpoint" id="CP1" name="document-created" desc="Verify API contract document created">
91
- <field name="file" value="${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md"/>
92
- <field name="verify" value="file_exists(${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md)"/>
91
+ <field name="file" value="${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md"/>
92
+ <field name="verify" value="file_exists(${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md)"/>
93
93
  </block>
94
94
 
95
95
  <!-- Step 4b: Fill API List Overview Section -->
96
96
  <block type="task" id="B5" action="edit-file" desc="Fill API List Overview section">
97
- <field name="path">${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md</field>
98
- <field name="fallback_path">${iteration_path}/02.feature-design/${feature_name}-api-contract.md</field>
97
+ <field name="path">${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md</field>
98
+ <field name="fallback_path">${iteration_path}/03.api-contract/${feature_name}-api-contract.md</field>
99
99
  <field name="operation">search_replace</field>
100
100
  <field name="search">## API List Overview
101
101
 
@@ -123,8 +123,8 @@ ${api_list.table}</field>
123
123
  </block>
124
124
 
125
125
  <block type="task" id="B7" action="edit-file" desc="Fill API contract section">
126
- <field name="path">${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md</field>
127
- <field name="fallback_path">${iteration_path}/02.feature-design/${feature_name}-api-contract.md</field>
126
+ <field name="path">${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md</field>
127
+ <field name="fallback_path">${iteration_path}/03.api-contract/${feature_name}-api-contract.md</field>
128
128
  <field name="operation">search_replace</field>
129
129
  <field name="search">### ${api.name}
130
130
 
@@ -137,8 +137,8 @@ ${api_contract_details.content}</field>
137
137
 
138
138
  <!-- Step 6: Fill Error Code Summary -->
139
139
  <block type="task" id="B8" action="edit-file" desc="Fill Error Code Summary section">
140
- <field name="path">${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md</field>
141
- <field name="fallback_path">${iteration_path}/02.feature-design/${feature_name}-api-contract.md</field>
140
+ <field name="path">${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md</field>
141
+ <field name="fallback_path">${iteration_path}/03.api-contract/${feature_name}-api-contract.md</field>
142
142
  <field name="operation">search_replace</field>
143
143
  <field name="search">## Error Code Summary
144
144
 
@@ -161,7 +161,7 @@ Feature Name: ${feature_name}
161
161
 
162
162
  Documents:
163
163
  - Feature Spec: ${iteration_path}/02.feature-design/${feature_id}-${feature_name}-feature-spec.md
164
- - API Contract: ${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md
164
+ - API Contract: ${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md
165
165
 
166
166
  Please confirm:
167
167
  1. Is the technical solution feasible?
@@ -175,7 +175,7 @@ After confirmation, API Contract becomes the sole baseline for frontend-backend
175
175
  <block type="event" id="E2" action="confirm" title="Feature Design Confirmation" type="yesno" desc="Request user confirmation">
176
176
  <field name="preview">Feature design phase deliverables ready:
177
177
  - Feature Spec: ${iteration_path}/02.feature-design/${feature_name}-feature-spec.md
178
- - API Contract: ${iteration_path}/02.feature-design/${feature_name}-api-contract.md
178
+ - API Contract: ${iteration_path}/03.api-contract/${feature_name}-api-contract.md
179
179
 
180
180
  Please confirm:
181
181
  1. Is the overall technical solution feasible?
@@ -197,12 +197,12 @@ After confirmation, API Contract becomes the sole baseline for frontend-backend
197
197
  <block type="gateway" id="G4" mode="exclusive" desc="Update progress based on mode">
198
198
  <branch test="${feature_id} != null" name="Feature mode">
199
199
  <block type="task" id="B10" action="run-script" desc="Update workflow progress for feature">
200
- <field name="command">node "${workspace_path}/scripts/update-progress.js" update-task --file "${iteration_path}/WORKFLOW-PROGRESS.json" --task-id "${feature_id}" --status confirmed --outputs '["02.feature-design/${feature_id}-${feature_name}-feature-spec.md","02.feature-design/${feature_id}-${feature_name}-api-contract.md"]'</field>
200
+ <field name="command">node "${workspace_path}/scripts/update-progress.js" update-task --file "${iteration_path}/WORKFLOW-PROGRESS.json" --task-id "${feature_id}" --status confirmed --outputs '["02.feature-design/${feature_id}-${feature_name}-feature-spec.md","03.api-contract/${feature_id}-${feature_name}-api-contract.md"]'</field>
201
201
  </block>
202
202
  </branch>
203
203
  <branch default="true" name="Module mode">
204
204
  <block type="task" id="B11" action="run-script" desc="Update workflow progress for module">
205
- <field name="command">node "${workspace_path}/scripts/update-progress.js" update-stage --file "${iteration_path}/WORKFLOW-PROGRESS.json" --stage 02_feature_design --status confirmed --outputs '["02.feature-design/${feature_name}-feature-spec.md","02.feature-design/${feature_name}-api-contract.md"]'</field>
205
+ <field name="command">node "${workspace_path}/scripts/update-progress.js" update-stage --file "${iteration_path}/WORKFLOW-PROGRESS.json" --stage 02_feature_design --status confirmed --outputs '["02.feature-design/${feature_name}-feature-spec.md","03.api-contract/${feature_name}-api-contract.md"]'</field>
206
206
  </block>
207
207
  </branch>
208
208
  </block>
@@ -213,7 +213,7 @@ After confirmation, API Contract becomes the sole baseline for frontend-backend
213
213
  Output Results
214
214
  ============================================================ -->
215
215
  <block type="output" id="O1" desc="Workflow output results">
216
- <field name="api_contract_path" value="${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md" type="string" desc="Path to generated API contract"/>
216
+ <field name="api_contract_path" value="${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md" type="string" desc="Path to generated API contract"/>
217
217
  <field name="feature_spec_path" value="${iteration_path}/02.feature-design/${feature_id}-${feature_name}-feature-spec.md" type="string" desc="Path to Feature Spec"/>
218
218
  <field name="api_count" from="${api_list.count}" type="number" desc="Number of APIs documented"/>
219
219
  <field name="confirmation_status" value="confirmed" type="string" desc="User confirmation status"/>
@@ -341,7 +341,7 @@
341
341
  feature_id: ${feature_list.modules[0].features[0].feature_id}
342
342
  feature_name: ${feature_list.modules[0].features[0].feature_name}
343
343
  feature_type: ${feature_list.modules[0].features[0].feature_type}
344
- output_path: ${iteration_path}/02.feature-design/${feature_id}-${feature_name}-api-contract.md
344
+ output_path: ${iteration_path}/03.api-contract/${feature_id}-${feature_name}-api-contract.md
345
345
  </field>
346
346
  <field name="output" var="api_contract_result"/>
347
347
  </block>
@@ -355,9 +355,15 @@
355
355
  <field name="text">DO NOT invoke speccrew-fd-api-contract directly</field>
356
356
  </block>
357
357
 
358
+ <!-- Phase 4.1a: Regenerate tasks file from Phase 3 completed features -->
359
+ <block type="task" id="P4-B1c" action="analyze" status="pending" desc="Build API Contract task list from Phase 3 DISPATCH-PROGRESS.json">
360
+ <field name="text">Read ${iteration_path}/02.feature-design/DISPATCH-PROGRESS.json. Extract all task IDs (regardless of status). Build a flat JSON array: [{"id":"F-M01-01"},{"id":"F-M01-02"},...]. Write this array to ${iteration_path}/03.api-contract/.tasks-temp.json</field>
361
+ <field name="output" var="api_contract_tasks_file"/>
362
+ </block>
363
+
358
364
  <!-- Initialize DISPATCH-PROGRESS.json for API Contract stage -->
359
365
  <block type="task" id="P4-B2" action="run-script" status="pending" desc="Initialize API contract dispatch">
360
- <field name="command">node ${workspace_root}/scripts/update-progress.js init --file ${iteration_path}/03.api-contract/DISPATCH-PROGRESS.json --stage 02_feature_design_api_contract --tasks-file ${iteration_path}/02.feature-design/.tasks-temp.json</field>
366
+ <field name="command">node ${workspace_root}/scripts/update-progress.js init --file ${iteration_path}/03.api-contract/DISPATCH-PROGRESS.json --stage 02_feature_design_api_contract --tasks-file ${iteration_path}/03.api-contract/.tasks-temp.json</field>
361
367
  </block>
362
368
 
363
369
  <!-- MANDATORY: Dispatch prompt must contain ONLY skill path + context data parameters.
@@ -376,7 +382,7 @@
376
382
  feature_id: ${item.feature_id}
377
383
  feature_name: ${item.feature_name}
378
384
  feature_type: ${item.feature_type}
379
- output_path: ${iteration_path}/02.feature-design/${item.feature_id}-${item.feature_name}-api-contract.md
385
+ output_path: ${iteration_path}/03.api-contract/${item.feature_id}-${item.feature_name}-api-contract.md
380
386
  </field>
381
387
  </block>
382
388
 
@@ -201,6 +201,14 @@ IF verification fails:
201
201
  > **Purpose:** Separate feature data from dispatch plan into dedicated `.prd-feature-list.json` file.
202
202
  > Each Sub-PRD Worker writes its module's features upon completion.
203
203
 
204
+ > **CRITICAL: UTF-8 Encoding**
205
+ >
206
+ > When writing ANY file (JSON, Markdown, or other text files), you MUST ensure UTF-8 encoding:
207
+ > - Use `create_file` tool (which defaults to UTF-8) for file creation
208
+ > - If using Node.js scripts: `fs.writeFileSync(path, content, 'utf8')`
209
+ > - NEVER rely on system default encoding (may be GBK on Chinese Windows)
210
+ > - This applies to ALL output files including `.prd-feature-list.json`
211
+
204
212
  ### 5.1 Determine Feature List File Path
205
213
 
206
214
  ```
@@ -190,6 +190,7 @@
190
190
 
191
191
  <block type="task" id="B17" action="write-file" desc="Update feature list file">
192
192
  <field name="path" value="${feature_list_path}"/>
193
+ <field name="encoding">utf8</field>
193
194
  <field name="merge">true</field>
194
195
  <field name="entry" value="${feature_list_entry}"/>
195
196
  <field name="output" var="feature_list_updated"/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speccrew",
3
- "version": "0.7.34",
3
+ "version": "0.7.36",
4
4
  "description": "Spec-Driven Development toolkit for AI-powered IDEs",
5
5
  "author": "charlesmu99",
6
6
  "repository": {
@@ -65,6 +65,14 @@
65
65
  * --features-dir <dir> Directory containing features-*.json files (required)
66
66
  * --force Overwrite existing file
67
67
  *
68
+ * 8. sync - Sync task status with actual output files
69
+ * node update-progress.js sync --file <path> --dir <dir> --suffix <suffix> [--strict]
70
+ * Options:
71
+ * --file <path> Progress file path (required)
72
+ * --dir <path> Output directory absolute path (required)
73
+ * --suffix <suffix> File suffix to match, e.g., -api-contract.md (required)
74
+ * --strict Also mark completed tasks as pending if file is missing
75
+ *
68
76
  * Output Format:
69
77
  * Success: {"success": true, "message": "...", "data": {...}}
70
78
  * Failure: {"success": false, "error": "..."} (output to stderr, exit code 1)
@@ -254,7 +262,10 @@ function parseArgs() {
254
262
  featuresDir: null,
255
263
  platforms: null,
256
264
  force: false,
257
- metadata: null
265
+ metadata: null,
266
+ dir: null,
267
+ suffix: null,
268
+ strict: false
258
269
  };
259
270
 
260
271
  // First argument is the command
@@ -363,6 +374,18 @@ function parseArgs() {
363
374
  case '-Metadata':
364
375
  result.metadata = args[++i];
365
376
  break;
377
+ case '--dir':
378
+ case '-Dir':
379
+ result.dir = args[++i];
380
+ break;
381
+ case '--suffix':
382
+ case '-Suffix':
383
+ result.suffix = args[++i];
384
+ break;
385
+ case '--strict':
386
+ case '-Strict':
387
+ result.strict = true;
388
+ break;
366
389
  }
367
390
  }
368
391
 
@@ -1039,6 +1062,186 @@ function cmdInitKnowledgeTasks(args) {
1039
1062
  }
1040
1063
  }
1041
1064
 
1065
+ /**
1066
+ * Command: sync - Sync task status with actual output files
1067
+ * Scans directory for files matching suffix, extracts task IDs from filenames,
1068
+ * and updates task status accordingly.
1069
+ */
1070
+ function cmdSync(args) {
1071
+ if (!args.file) { outputError('--file is required'); process.exit(1); }
1072
+ if (!args.dir) { outputError('--dir is required'); process.exit(1); }
1073
+ if (!args.suffix) { outputError('--suffix is required'); process.exit(1); }
1074
+
1075
+ const filePath = path.resolve(args.file);
1076
+ const dirPath = path.resolve(args.dir);
1077
+
1078
+ let lockPath = null;
1079
+
1080
+ try {
1081
+ lockPath = acquireLock(filePath);
1082
+
1083
+ const data = readJsonFile(filePath);
1084
+ if (!data || !data.tasks) { outputError('Invalid progress file'); process.exit(1); }
1085
+
1086
+ // Check if directory exists
1087
+ if (!fs.existsSync(dirPath)) {
1088
+ outputError(`Directory not found: ${dirPath}`);
1089
+ }
1090
+
1091
+ // Scan directory for matching files
1092
+ const files = fs.readdirSync(dirPath).filter(f => f.endsWith(args.suffix));
1093
+
1094
+ // Extract task IDs from filenames
1095
+ // Format: {task-id}-{feature-name}{suffix}
1096
+ // task-id pattern: F-Mxx-xx (starts with F-, contains module and feature number)
1097
+ const fileTaskIds = new Set();
1098
+ const fileMap = {};
1099
+ for (const file of files) {
1100
+ // Extract task ID: match F-M followed by digits, dash, digits
1101
+ const match = file.match(/^(F-M\d+-\d+)/);
1102
+ if (match) {
1103
+ fileTaskIds.add(match[1]);
1104
+ fileMap[match[1]] = file;
1105
+ }
1106
+ }
1107
+
1108
+ let synced = 0;
1109
+ let alreadyCorrect = 0;
1110
+ let missing = 0;
1111
+ const now = getTimestamp();
1112
+
1113
+ for (const task of data.tasks) {
1114
+ const taskId = task.id;
1115
+ if (fileTaskIds.has(taskId)) {
1116
+ if (task.status !== 'completed') {
1117
+ task.status = 'completed';
1118
+ task.output = fileMap[taskId];
1119
+ task.completed_at = now;
1120
+ task.updated_at = now;
1121
+ synced++;
1122
+ } else {
1123
+ alreadyCorrect++;
1124
+ }
1125
+ } else {
1126
+ if (task.status === 'completed' && args.strict) {
1127
+ task.status = 'pending';
1128
+ delete task.output;
1129
+ delete task.completed_at;
1130
+ task.updated_at = now;
1131
+ missing++;
1132
+ }
1133
+ }
1134
+ }
1135
+
1136
+ // Recalculate counts
1137
+ data.counts = calculateCounts(data.tasks);
1138
+ data.updated_at = now;
1139
+
1140
+ // Atomic write
1141
+ atomicWriteJson(filePath, data);
1142
+
1143
+ outputSuccess('Sync completed', {
1144
+ scanned_files: files.length,
1145
+ synced: synced,
1146
+ already_correct: alreadyCorrect,
1147
+ missing_files: missing,
1148
+ counts: data.counts
1149
+ });
1150
+ } finally {
1151
+ if (lockPath) releaseLock(lockPath);
1152
+ }
1153
+ }
1154
+
1155
+ /**
1156
+ * Command: sync - Sync task status with actual output files
1157
+ * Scans directory for files matching suffix, extracts task IDs from filenames,
1158
+ * and updates task status accordingly.
1159
+ */
1160
+ function cmdSync(args) {
1161
+ if (!args.file) { outputError('--file is required'); process.exit(1); }
1162
+ if (!args.dir) { outputError('--dir is required'); process.exit(1); }
1163
+ if (!args.suffix) { outputError('--suffix is required'); process.exit(1); }
1164
+
1165
+ const filePath = path.resolve(args.file);
1166
+ const dirPath = path.resolve(args.dir);
1167
+
1168
+ let lockPath = null;
1169
+
1170
+ try {
1171
+ lockPath = acquireLock(filePath);
1172
+
1173
+ const data = readJsonFile(filePath);
1174
+ if (!data || !data.tasks) { outputError('Invalid progress file'); process.exit(1); }
1175
+
1176
+ // Check if directory exists
1177
+ if (!fs.existsSync(dirPath)) {
1178
+ outputError(`Directory not found: ${dirPath}`);
1179
+ }
1180
+
1181
+ // Scan directory for matching files
1182
+ const files = fs.readdirSync(dirPath).filter(f => f.endsWith(args.suffix));
1183
+
1184
+ // Extract task IDs from filenames
1185
+ // Format: {task-id}-{feature-name}{suffix}
1186
+ // task-id pattern: F-Mxx-xx (starts with F-, contains module and feature number)
1187
+ const fileTaskIds = new Set();
1188
+ const fileMap = {};
1189
+ for (const file of files) {
1190
+ // Extract task ID: match F-M followed by digits, dash, digits
1191
+ const match = file.match(/^(F-M\d+-\d+)/);
1192
+ if (match) {
1193
+ fileTaskIds.add(match[1]);
1194
+ fileMap[match[1]] = file;
1195
+ }
1196
+ }
1197
+
1198
+ let synced = 0;
1199
+ let alreadyCorrect = 0;
1200
+ let missing = 0;
1201
+ const now = getTimestamp();
1202
+
1203
+ for (const task of data.tasks) {
1204
+ const taskId = task.id;
1205
+ if (fileTaskIds.has(taskId)) {
1206
+ if (task.status !== 'completed') {
1207
+ task.status = 'completed';
1208
+ task.output = fileMap[taskId];
1209
+ task.completed_at = now;
1210
+ task.updated_at = now;
1211
+ synced++;
1212
+ } else {
1213
+ alreadyCorrect++;
1214
+ }
1215
+ } else {
1216
+ if (task.status === 'completed' && args.strict) {
1217
+ task.status = 'pending';
1218
+ delete task.output;
1219
+ delete task.completed_at;
1220
+ task.updated_at = now;
1221
+ missing++;
1222
+ }
1223
+ }
1224
+ }
1225
+
1226
+ // Recalculate counts
1227
+ data.counts = calculateCounts(data.tasks);
1228
+ data.updated_at = now;
1229
+
1230
+ // Atomic write
1231
+ atomicWriteJson(filePath, data);
1232
+
1233
+ outputSuccess('Sync completed', {
1234
+ scanned_files: files.length,
1235
+ synced: synced,
1236
+ already_correct: alreadyCorrect,
1237
+ missing_files: missing,
1238
+ counts: data.counts
1239
+ });
1240
+ } finally {
1241
+ if (lockPath) releaseLock(lockPath);
1242
+ }
1243
+ }
1244
+
1042
1245
  /**
1043
1246
  * Command: init-tasks - Scan feature-design directory to generate task list
1044
1247
  */
@@ -1207,6 +1410,7 @@ function main() {
1207
1410
  console.error(' update-workflow Update a workflow stage status');
1208
1411
  console.error(' init-tasks Generate tasks from feature-spec files');
1209
1412
  console.error(' init-knowledge-tasks Generate knowledge initialization tasks from matcher results');
1413
+ console.error(' sync Sync task status with actual output files');
1210
1414
  console.error('');
1211
1415
  console.error('Run "node update-progress.js <command> --help" for more information.');
1212
1416
  process.exit(1);
@@ -1239,6 +1443,9 @@ function main() {
1239
1443
  case 'init-knowledge-tasks':
1240
1444
  cmdInitKnowledgeTasks(args);
1241
1445
  break;
1446
+ case 'sync':
1447
+ cmdSync(args);
1448
+ break;
1242
1449
  default:
1243
1450
  outputError(`Unknown command: ${args.command}`);
1244
1451
  }