speccrew 0.6.14 → 0.6.15

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.
@@ -408,6 +408,12 @@ No knowledge base exists. A lightweight feature inventory scan is triggered to d
408
408
  > 🛑 **MANDATORY -- Path C -> Path B Sequence**:
409
409
  > After init-features completes (features-*.json generated), you MUST immediately execute Path B:
410
410
  >
411
+ > **Path B Recovery Check**:
412
+ > Before starting Step 1, check if `{workspace_path}/knowledges/bizs/DISPATCH-PROGRESS.json` exists:
413
+ > - If exists with pending tasks → resume from Step 3 (skip Step 1 and Step 1.5)
414
+ > - If exists with all completed → skip to Step 5 (Update Features Status)
415
+ > - If not exists → start from Step 1
416
+ >
411
417
  > **Path B Step 1: Module Matching**
412
418
  > Dispatch Worker with `speccrew-pm-module-matcher` skill to match requirement features against the generated features inventory.
413
419
  >
@@ -422,6 +428,26 @@ No knowledge base exists. A lightweight feature inventory scan is triggered to d
422
428
  > requirement_summary: <brief summary of user's requirement>
423
429
  > ```
424
430
  >
431
+ > **Path B Step 1.5: Initialize Knowledge Dispatch Progress**
432
+ >
433
+ > Save the matcher Worker's output to a temporary file:
434
+ > - File path: `{workspace_path}/knowledges/bizs/.matcher-result.json`
435
+ > - Content: The matcher's full JSON output (matched modules with platform_id, module_name, confidence)
436
+ >
437
+ > Run the dispatch progress initialization script:
438
+ > ```bash
439
+ > node "{update_progress_script}" init-knowledge-tasks `
440
+ > --file "{workspace_path}/knowledges/bizs/DISPATCH-PROGRESS.json" `
441
+ > --matcher-result "{workspace_path}/knowledges/bizs/.matcher-result.json" `
442
+ > --features-dir "{workspace_path}/knowledges/bizs"
443
+ > ```
444
+ >
445
+ > Verify the DISPATCH-PROGRESS.json was created successfully and log the total task count.
446
+ >
447
+ > 🛑 **HARD GATE — DISPATCH-PROGRESS.json MUST exist before proceeding**
448
+ > DO NOT proceed to Step 2 until DISPATCH-PROGRESS.json is created and contains tasks.
449
+ > If the script fails, diagnose the error and retry. DO NOT skip this step.
450
+ >
425
451
  > 🛑 **CRITICAL GATE — DO NOT SKIP Steps 2-5**:
426
452
  > After matcher completes, you MUST execute Steps 2-5 to deep-initialize the matched modules' knowledge base.
427
453
  > DO NOT jump to Phase 2 (Complexity Assessment) or Phase 3 (Requirement Clarification) until ALL Steps complete.
@@ -455,33 +481,70 @@ No knowledge base exists. A lightweight feature inventory scan is triggered to d
455
481
  >
456
482
  > Wait for ALL module-initializer Workers to complete. Collect all task plan JSON outputs.
457
483
  >
458
- > **Path B Step 3: Execute Feature Analysis**
459
- > Based on the task plans from Step 2, dispatch Worker for EACH pending feature.
484
+ > **Path B Step 3: Execute Feature Analysis (Dispatch-Tracked)**
460
485
  >
461
- > For backend features: dispatch Worker with `speccrew-knowledge-bizs-api-analyze` skill
462
- > For web/mobile/desktop features: dispatch Worker with `speccrew-knowledge-bizs-ui-analyze` skill
486
+ > ⚠️ **MANDATORY RULES FOR THIS STEP:**
487
+ > 1. MUST dispatch Workers for ALL tasks with status "pending" in DISPATCH-PROGRESS.json
488
+ > 2. DO NOT skip any pending task — the matcher already determined relevance
489
+ > 3. DO NOT stop mid-way to ask user for options (A/B/C) — execute ALL tasks
490
+ > 4. After each Worker completes, update task status via script
463
491
  >
464
- > **Agent Tool Invocation for each feature**:
465
- > ```
466
- > Use the Agent tool to invoke speccrew-task-worker:
467
- > - agent: speccrew-task-worker
468
- > - task: Execute {analyzer_skill} for feature "{fileName}"
469
- > - context:
470
- > skill: {analyzer_skill}
471
- > fileName: {task.fileName}
472
- > sourcePath: {source_path}/{task.sourcePath}
473
- > documentPath: {workspace_path}/{task.documentPath}
474
- > module: {task.module}
475
- > analyzed: false
476
- > platform_type: {task.platform_type}
477
- > platform_subtype: {task.platform_subtype}
478
- > tech_stack: {task.tech_stack}
479
- > language: {language}
480
- > completed_dir: {sync_state_bizs_dir}/completed
481
- > sourceFile: features-{platform_id}.json
482
- > ```
492
+ > **Recovery Check**: Read `{workspace_path}/knowledges/bizs/DISPATCH-PROGRESS.json`:
493
+ > - If tasks with `status: "completed"` exist, skip them (resuming from interruption)
494
+ > - Only dispatch tasks with `status: "pending"`
495
+ > - Log: "Resuming: {completed_count} completed, {pending_count} remaining"
496
+ >
497
+ > **Dispatch Loop**:
498
+ > For each task in DISPATCH-PROGRESS.json where status == "pending":
499
+ >
500
+ > 1. Dispatch `speccrew-task-worker` with:
501
+ > - **skill**: `{task.analyzer_skill}` (e.g., `speccrew-knowledge-bizs-api-analyze` or `speccrew-knowledge-bizs-ui-analyze`)
502
+ > - **context**: All task fields (module, platform_id, fileName, sourcePath, etc.)
503
+ >
504
+ > **Agent Tool Invocation**:
505
+ > ```
506
+ > Use the Agent tool to invoke speccrew-task-worker:
507
+ > - agent: speccrew-task-worker
508
+ > - task: Execute {task.analyzer_skill} for feature "{task.fileName}"
509
+ > - context:
510
+ > skill: {task.analyzer_skill}
511
+ > fileName: {task.fileName}
512
+ > sourcePath: {source_path}/{task.sourcePath}
513
+ > documentPath: {workspace_path}/{task.documentPath}
514
+ > module: {task.module}
515
+ > platform_id: {task.platform_id}
516
+ > platform_type: {task.platform_type}
517
+ > platform_subtype: {task.platform_subtype}
518
+ > tech_stack: {task.tech_stack}
519
+ > language: {language}
520
+ > completed_dir: {sync_state_bizs_dir}/completed
521
+ > sourceFile: features-{task.platform_id}.json
522
+ > ```
523
+ >
524
+ > 2. After Worker completes successfully, update progress:
525
+ > ```bash
526
+ > node "{update_progress_script}" update-task `
527
+ > --file "{workspace_path}/knowledges/bizs/DISPATCH-PROGRESS.json" `
528
+ > --task-id "{task.id}" `
529
+ > --status completed
530
+ > ```
531
+ >
532
+ > 3. If Worker fails, update status to "failed" and continue with next task:
533
+ > ```bash
534
+ > node "{update_progress_script}" update-task `
535
+ > --file "{workspace_path}/knowledges/bizs/DISPATCH-PROGRESS.json" `
536
+ > --task-id "{task.id}" `
537
+ > --status failed
538
+ > ```
539
+ >
540
+ > **Completion Check**: After all dispatches complete, read DISPATCH-PROGRESS.json:
541
+ > - If all tasks are "completed" → proceed to Step 4
542
+ > - If some tasks "failed" → log failures and proceed (do not block on failures)
483
543
  >
484
- > Wait for ALL analyze Workers to complete.
544
+ > 🛑 **CONTINUOUS EXECUTION DO NOT INTERRUPT**
545
+ > Process ALL pending tasks without stopping for user confirmation.
546
+ > The scope was already determined by the matcher in Step 1.
547
+ > Asking "do you want to continue?" mid-way is FORBIDDEN.
485
548
  >
486
549
  > **Path B Step 4: Generate Module Summaries**
487
550
  > For each matched module, dispatch Worker with `speccrew-knowledge-module-summarize` skill:
@@ -503,6 +566,7 @@ No knowledge base exists. A lightweight feature inventory scan is triggered to d
503
566
  >
504
567
  > 🛑 **Path B Completion Check**:
505
568
  > Before proceeding to Phase 2, verify:
569
+ > - [ ] Step 1.5 completed: DISPATCH-PROGRESS.json created with all tasks
506
570
  > - [ ] Step 2 completed: task plan JSON generated for each matched module
507
571
  > - [ ] Step 3 completed: analyze Workers dispatched and completed for ALL pending features
508
572
  > - [ ] Step 4 completed: module-summarize Workers completed for ALL matched modules
@@ -52,6 +52,7 @@ Generate analyze task plan for a single business module. Reads features-*.json,
52
52
  "analyzer_skill": "speccrew-knowledge-bizs-ui-analyze",
53
53
  "tasks": [
54
54
  {
55
+ "id": "ki-web-vue-system-index",
55
56
  "fileName": "index",
56
57
  "sourcePath": "src/views/system/user/index.vue",
57
58
  "documentPath": "knowledges/bizs/web-vue/system/features",
@@ -59,7 +60,8 @@ Generate analyze task plan for a single business module. Reads features-*.json,
59
60
  "platform_type": "web",
60
61
  "platform_subtype": "vue",
61
62
  "tech_stack": ["vue", "typescript"],
62
- "language": "zh"
63
+ "language": "zh",
64
+ "status": "pending"
63
65
  }
64
66
  ],
65
67
  "total_pending": 90,
@@ -83,6 +85,18 @@ Generate analyze task plan for a single business module. Reads features-*.json,
83
85
  | `total_pending` | Count of pending features |
84
86
  | `summarize_params` | Parameters for module-summarize skill (to be executed after all analyze tasks complete) |
85
87
 
88
+ **Task ID Naming Convention**:
89
+
90
+ The `id` field follows the format: `ki-{platform_id}-{module}-{fileName}`
91
+ - `ki` = knowledge initialization
92
+ - `platform_id` = Platform identifier (e.g., "web-vue", "admin-api")
93
+ - `module` = Business module name
94
+ - `fileName` = Feature file name
95
+
96
+ Example: `"ki-web-vue-system-index"`
97
+
98
+ > **Note**: This ID is consistent with task IDs in DISPATCH-PROGRESS.json and is used for progress tracking.
99
+
86
100
  ## Workflow
87
101
 
88
102
  ```mermaid
@@ -132,6 +146,7 @@ For each pending feature from Step 1, build a task object with analyzer paramete
132
146
 
133
147
  ```json
134
148
  {
149
+ "id": "ki-{platform_id}-{feature.module}-{feature.fileName}",
135
150
  "fileName": "{feature.fileName}",
136
151
  "sourcePath": "{feature.sourcePath}",
137
152
  "documentPath": "{output_path}/bizs/{platform_id}/{feature.module}/features",
@@ -139,7 +154,8 @@ For each pending feature from Step 1, build a task object with analyzer paramete
139
154
  "platform_type": "{platform_type}",
140
155
  "platform_subtype": "{platform_subtype}",
141
156
  "tech_stack": "{tech_stack}",
142
- "language": "{language}"
157
+ "language": "{language}",
158
+ "status": "pending"
143
159
  }
144
160
  ```
145
161
 
@@ -151,6 +167,8 @@ For backend features (api-analyze), also include:
151
167
  }
152
168
  ```
153
169
 
170
+ **Note**: The `id` field format is `ki-{platform_id}-{module}-{fileName}` where `ki` stands for "knowledge initialization". This ID is consistent with task IDs in DISPATCH-PROGRESS.json for progress tracking.
171
+
154
172
  **Output**: "Step 3 Status: ✅ COMPLETED - Built {count} task entries"
155
173
 
156
174
  ### Step 4: Build Summarize Parameters
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speccrew",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "Spec-Driven Development toolkit for AI-powered IDEs",
5
5
  "author": "charlesmu99",
6
6
  "repository": {
@@ -56,6 +56,14 @@
56
56
  * --status <status> Status: pending/in_progress/completed/confirmed (required)
57
57
  * --output <text> Output information (optional)
58
58
  *
59
+ * 7. init-knowledge-tasks - Generate knowledge initialization tasks from matcher results
60
+ * node update-progress.js init-knowledge-tasks --file <path> --matcher-result <path> --features-dir <dir> [--force]
61
+ * Options:
62
+ * --file <path> Progress file path (required)
63
+ * --matcher-result <path> Matcher result JSON file path (required)
64
+ * --features-dir <dir> Directory containing features-*.json files (required)
65
+ * --force Overwrite existing file
66
+ *
59
67
  * Output Format:
60
68
  * Success: {"success": true, "message": "...", "data": {...}}
61
69
  * Failure: {"success": false, "error": "..."} (output to stderr, exit code 1)
@@ -345,6 +353,10 @@ function parseArgs() {
345
353
  case '-Force':
346
354
  result.force = true;
347
355
  break;
356
+ case '--matcher-result':
357
+ case '-Matcher-Result':
358
+ result.matcherResult = args[++i];
359
+ break;
348
360
  }
349
361
  }
350
362
 
@@ -816,6 +828,201 @@ function cmdUpdateWorkflow(args) {
816
828
  }
817
829
  }
818
830
 
831
+ /**
832
+ * Determine analyzer skill based on platform_id
833
+ * @param {string} platformId - Platform identifier
834
+ * @returns {string} Analyzer skill name
835
+ */
836
+ function getAnalyzerSkill(platformId) {
837
+ const pid = platformId.toLowerCase();
838
+ if (pid.includes('web') || pid.includes('mobile')) {
839
+ return 'speccrew-knowledge-bizs-ui-analyze';
840
+ }
841
+ if (pid.includes('backend') || pid.includes('api')) {
842
+ return 'speccrew-knowledge-bizs-api-analyze';
843
+ }
844
+ // Default to UI analyzer for unknown platforms
845
+ return 'speccrew-knowledge-bizs-ui-analyze';
846
+ }
847
+
848
+ /**
849
+ * Command: init-knowledge-tasks - Generate knowledge initialization tasks from matcher results
850
+ *
851
+ * Reads matcher result and features-*.json files to generate a task list for knowledge initialization.
852
+ * Each task corresponds to a feature that needs to be analyzed.
853
+ */
854
+ function cmdInitKnowledgeTasks(args) {
855
+ // Validate required arguments
856
+ if (!args.file || !args.matcherResult || !args.featuresDir) {
857
+ outputError('Usage: init-knowledge-tasks --file <path> --matcher-result <path> --features-dir <dir> [--force]');
858
+ }
859
+
860
+ const filePath = path.resolve(args.file);
861
+ const matcherResultPath = path.resolve(args.matcherResult);
862
+ const featuresDir = path.resolve(args.featuresDir);
863
+
864
+ // Check if matcher result file exists
865
+ if (!fs.existsSync(matcherResultPath)) {
866
+ outputError(`Matcher result file not found: ${matcherResultPath}`);
867
+ }
868
+
869
+ // Check if features directory exists
870
+ if (!fs.existsSync(featuresDir)) {
871
+ outputError(`Features directory not found: ${featuresDir}`);
872
+ }
873
+
874
+ // Check if target file already exists (prevent overwrite without --force)
875
+ if (fs.existsSync(filePath) && !args.force) {
876
+ outputError(`Progress file already exists: ${filePath}. Use --force to overwrite.`);
877
+ }
878
+
879
+ // Read matcher result
880
+ let matcherResult;
881
+ try {
882
+ matcherResult = readJsonFile(matcherResultPath);
883
+ } catch (e) {
884
+ outputError(`Failed to read matcher result: ${e.message}`);
885
+ }
886
+
887
+ // Extract matched modules (high + medium confidence)
888
+ const matchedModules = matcherResult.matched_modules || [];
889
+ if (matchedModules.length === 0) {
890
+ outputError('No matched modules found in matcher result');
891
+ }
892
+
893
+ // Filter to high and medium confidence matches
894
+ const validConfidences = ['high', 'medium'];
895
+ const filteredModules = matchedModules.filter(m =>
896
+ validConfidences.includes((m.confidence || '').toLowerCase())
897
+ );
898
+
899
+ if (filteredModules.length === 0) {
900
+ outputError('No modules with high or medium confidence found');
901
+ }
902
+
903
+ // Scan features-*.json files
904
+ const featuresFiles = fs.readdirSync(featuresDir).filter(f =>
905
+ f.startsWith('features-') && f.endsWith('.json')
906
+ );
907
+
908
+ if (featuresFiles.length === 0) {
909
+ outputError(`No features-*.json files found in: ${featuresDir}`);
910
+ }
911
+
912
+ // Load all features data indexed by platform_id
913
+ const featuresDataByPlatform = {};
914
+ for (const file of featuresFiles) {
915
+ const filePath = path.join(featuresDir, file);
916
+ try {
917
+ const data = readJsonFile(filePath);
918
+ if (data.platform_id) {
919
+ featuresDataByPlatform[data.platform_id] = data;
920
+ }
921
+ } catch (e) {
922
+ outputError(`Failed to parse features file ${file}: ${e.message}`);
923
+ }
924
+ }
925
+
926
+ // Generate tasks from matched modules and features
927
+ const tasks = [];
928
+ const now = getTimestamp();
929
+
930
+ for (const matchedModule of filteredModules) {
931
+ const { module_name, platform_id, features: matchedFeatures } = matchedModule;
932
+
933
+ // Determine analyzer skill based on platform
934
+ const analyzerSkill = getAnalyzerSkill(platform_id);
935
+
936
+ // Get features for this module
937
+ let featuresToProcess = [];
938
+
939
+ if (matchedFeatures && Array.isArray(matchedFeatures) && matchedFeatures.length > 0) {
940
+ // Use features directly from matcher result
941
+ featuresToProcess = matchedFeatures;
942
+ } else {
943
+ // Look up features from features-*.json files
944
+ const platformData = featuresDataByPlatform[platform_id];
945
+ if (platformData && platformData.modules && platformData.modules[module_name]) {
946
+ const moduleData = platformData.modules[module_name];
947
+ if (moduleData.features && Array.isArray(moduleData.features)) {
948
+ featuresToProcess = moduleData.features;
949
+ }
950
+ }
951
+ }
952
+
953
+ // Filter to only unanalyzed features (analyzed !== true)
954
+ const unanalyzedFeatures = featuresToProcess.filter(f => f.analyzed !== true);
955
+
956
+ // Create task for each unanalyzed feature
957
+ for (const feature of unanalyzedFeatures) {
958
+ const fileName = feature.fileName || feature.file_name || 'unknown';
959
+ const sourcePath = feature.sourcePath || feature.source_path || '';
960
+
961
+ // Generate task ID: ki-{platform_id}-{module}-{fileName}
962
+ // Sanitize fileName for ID (remove extension, replace special chars)
963
+ const fileNameForId = fileName.replace(/\.[^.]+$/, '').replace(/[^a-zA-Z0-9_-]/g, '_');
964
+ const taskId = `ki-${platform_id}-${module_name}-${fileNameForId}`;
965
+
966
+ tasks.push({
967
+ id: taskId,
968
+ name: `Analyze ${module_name}.${fileName} (${platform_id})`,
969
+ status: 'pending',
970
+ module: module_name,
971
+ platform_id: platform_id,
972
+ fileName: fileName,
973
+ sourcePath: sourcePath,
974
+ analyzer_skill: analyzerSkill,
975
+ created_at: now
976
+ });
977
+ }
978
+ }
979
+
980
+ // Sort tasks: by platform_id, then module, then fileName
981
+ tasks.sort((a, b) => {
982
+ if (a.platform_id !== b.platform_id) {
983
+ return a.platform_id.localeCompare(b.platform_id);
984
+ }
985
+ if (a.module !== b.module) {
986
+ return a.module.localeCompare(b.module);
987
+ }
988
+ return a.fileName.localeCompare(b.fileName);
989
+ });
990
+
991
+ // Create progress file structure
992
+ const progressData = {
993
+ stage: 'knowledge_initialization',
994
+ created_at: now,
995
+ updated_at: now,
996
+ counts: calculateCounts(tasks),
997
+ tasks: tasks,
998
+ checkpoints: {}
999
+ };
1000
+
1001
+ // Ensure directory exists
1002
+ const dir = path.dirname(filePath);
1003
+ if (!fs.existsSync(dir)) {
1004
+ fs.mkdirSync(dir, { recursive: true });
1005
+ }
1006
+
1007
+ // Acquire lock and write
1008
+ let lockPath = null;
1009
+ try {
1010
+ lockPath = acquireLock(filePath);
1011
+ atomicWriteJson(filePath, progressData);
1012
+ outputSuccess(
1013
+ `Generated ${tasks.length} knowledge initialization tasks`,
1014
+ {
1015
+ file: filePath,
1016
+ stage: 'knowledge_initialization',
1017
+ matched_modules: filteredModules.length,
1018
+ counts: progressData.counts
1019
+ }
1020
+ );
1021
+ } finally {
1022
+ if (lockPath) releaseLock(lockPath);
1023
+ }
1024
+ }
1025
+
819
1026
  /**
820
1027
  * Command: init-tasks - Scan feature-design directory to generate task list
821
1028
  */
@@ -983,6 +1190,7 @@ function main() {
983
1190
  console.error(' write-checkpoint Write or update a checkpoint');
984
1191
  console.error(' update-workflow Update a workflow stage status');
985
1192
  console.error(' init-tasks Generate tasks from feature-spec files');
1193
+ console.error(' init-knowledge-tasks Generate knowledge initialization tasks from matcher results');
986
1194
  console.error('');
987
1195
  console.error('Run "node update-progress.js <command> --help" for more information.');
988
1196
  process.exit(1);
@@ -1012,6 +1220,9 @@ function main() {
1012
1220
  case 'init-tasks':
1013
1221
  cmdInitTasks(args);
1014
1222
  break;
1223
+ case 'init-knowledge-tasks':
1224
+ cmdInitKnowledgeTasks(args);
1225
+ break;
1015
1226
  default:
1016
1227
  outputError(`Unknown command: ${args.command}`);
1017
1228
  }