speccrew 0.6.66 → 0.6.68

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.
@@ -295,6 +295,37 @@ function loadTechStackConfig(platformType, framework, projectRoot) {
295
295
  return { extensions: [], exclude_file_suffixes: [], exclude_file_names: [] };
296
296
  }
297
297
 
298
+ /**
299
+ * Validate entry-dirs JSON schema
300
+ * @param {object} data - Parsed entry-dirs JSON data
301
+ * @returns {string[]|null} Array of error messages or null if valid
302
+ */
303
+ function validateEntryDirsSchema(data) {
304
+ const errors = [];
305
+ if (!data.platformId || typeof data.platformId !== 'string') {
306
+ errors.push('platformId must be a non-empty string');
307
+ } else if (!/^[a-zA-Z0-9_-]+$/.test(data.platformId)) {
308
+ errors.push(`platformId format invalid: "${data.platformId}" (only alphanumeric, hyphen, underscore allowed)`);
309
+ }
310
+ if (!data.sourcePath || typeof data.sourcePath !== 'string') {
311
+ errors.push('sourcePath must be a non-empty string');
312
+ }
313
+ if (!Array.isArray(data.modules) || data.modules.length === 0) {
314
+ errors.push('modules must be a non-empty array');
315
+ } else {
316
+ for (let i = 0; i < data.modules.length; i++) {
317
+ const mod = data.modules[i];
318
+ if (!mod.name || typeof mod.name !== 'string') {
319
+ errors.push(`modules[${i}].name must be a non-empty string`);
320
+ }
321
+ if (!Array.isArray(mod.entryDirs) || mod.entryDirs.length === 0) {
322
+ errors.push(`modules[${i}].entryDirs must be a non-empty array`);
323
+ }
324
+ }
325
+ }
326
+ return errors.length > 0 ? errors : null;
327
+ }
328
+
298
329
  /**
299
330
  * Infer platform info from platformId
300
331
  * @param {string} platformId - Platform ID like "backend-ai", "web-vue", "mobile-uniapp"
@@ -533,7 +564,7 @@ function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outpu
533
564
  platformName: platformConfig.platformName,
534
565
  platformType: platformType,
535
566
  sourcePath: sourcePath,
536
- techStack: [framework],
567
+ techStack: entryDirsData.techStack || [framework],
537
568
  modules: [...new Set(moduleNames)].sort(),
538
569
  totalFiles: features.length,
539
570
  analyzedCount: 0,
@@ -667,7 +698,15 @@ function main() {
667
698
  console.error(`Found top-level keys: ${foundKeys}`);
668
699
  process.exit(1);
669
700
  }
670
-
701
+
702
+ // Validate entry-dirs JSON schema
703
+ const schemaErrors = validateEntryDirsSchema(entryDirsData);
704
+ if (schemaErrors) {
705
+ console.error('Error: entry-dirs JSON schema validation failed:');
706
+ schemaErrors.forEach(err => console.error(` - ${err}`));
707
+ process.exit(1);
708
+ }
709
+
671
710
  // Find project root (use current directory or entryDirsFile directory)
672
711
  const projectRoot = findProjectRoot(path.dirname(entryDirsFilePath));
673
712
 
@@ -718,7 +757,10 @@ function main() {
718
757
  outputDir = path.resolve(params.outputDir);
719
758
  console.log(`Using outputDir from parameter: ${outputDir}`);
720
759
  } else {
760
+ console.warn('WARNING: --outputDir not specified, falling back to default path.');
761
+ console.warn(' Recommended: explicitly pass --outputDir to avoid incorrect output location.');
721
762
  outputDir = path.join(projectRoot, 'speccrew-workspace', 'knowledges', 'base', 'sync-state', 'knowledge-bizs');
763
+ console.warn(` Using fallback outputDir: ${outputDir}`);
722
764
  }
723
765
 
724
766
  // Generate features from entry dirs
@@ -840,7 +882,10 @@ function main() {
840
882
  syncStateDir = path.resolve(params.outputDir);
841
883
  console.log(`Using outputDir from parameter: ${syncStateDir}`);
842
884
  } else {
885
+ console.warn('WARNING: --outputDir not specified, falling back to default path.');
886
+ console.warn(' Recommended: explicitly pass --outputDir to avoid incorrect output location.');
843
887
  syncStateDir = path.join(projectRoot, 'speccrew-workspace', 'knowledges', 'base', 'sync-state', 'knowledge-bizs');
888
+ console.warn(` Using fallback outputDir: ${syncStateDir}`);
844
889
  }
845
890
  const outputPath = path.join(syncStateDir, outputFileName);
846
891
 
@@ -0,0 +1,249 @@
1
+ ---
2
+ name: speccrew-knowledge-bizs-init-features-xml
3
+ description: Execute generate-inventory.js script to create features.json inventory for a single platform. Called by bizs-dispatch-xml Stage 1b for each platform.
4
+ tools: Read, Write, Bash
5
+ ---
6
+
7
+ # speccrew-knowledge-bizs-init-features-xml
8
+
9
+ Execute generate-inventory.js script to create features.json inventory for a single platform. This is a Stage 1b worker skill called by dispatch-xml after platform detection and entry directory identification are complete.
10
+
11
+ ## Language Adaptation
12
+
13
+ All generated documents must match the user's language. Detect the language from the user's input and generate content accordingly.
14
+
15
+ - User writes in 中文 → Generate Chinese documents, use `language: "zh"`
16
+ - User writes in English → Generate English documents, use `language: "en"`
17
+ - User writes in other languages → Use appropriate language code
18
+
19
+ ## Trigger Scenarios
20
+
21
+ - Called by `speccrew-knowledge-bizs-dispatch-xml` Stage 1b
22
+ - "Generate feature inventory for platform"
23
+ - "Create features.json from entry-dirs"
24
+
25
+ ## Input Parameters
26
+
27
+ | Parameter | Type | Required | Description |
28
+ |-----------|------|----------|-------------|
29
+ | `platformId` | string | Yes | Platform identifier (e.g., "backend-system", "frontend-web", "mobile-app") |
30
+ | `platformName` | string | Yes | Platform display name |
31
+ | `platformType` | string | Yes | Platform type: backend, web, mobile |
32
+ | `platformSubtype` | string | No | Platform subtype (e.g., vue, react, uniapp) |
33
+ | `sourcePath` | string | Yes | Absolute path to platform source root |
34
+ | `techIdentifier` | string | Yes | Technology stack identifier |
35
+ | `entryDirsFile` | string | Yes | Absolute path to entry-dirs JSON file |
36
+ | `outputDir` | string | Yes | Absolute path to features JSON output directory |
37
+ | `workspace_path` | string | Yes | Absolute path to speccrew-workspace directory |
38
+ | `sync_state_bizs_dir` | string | Yes | Absolute path to sync-state/knowledge-bizs directory |
39
+ | `language` | string | Yes | Language code for generated content |
40
+
41
+ ## Output
42
+
43
+ - `${outputDir}/features-${platformId}.json`
44
+
45
+ ## Workflow
46
+
47
+ > **REQUIRED**: Before executing this workflow, read the XML workflow specification: `speccrew-workspace/docs/rules/xml-workflow-spec.md`
48
+
49
+ ```xml
50
+ <?xml version="1.0" encoding="UTF-8"?>
51
+ <workflow id="init-features-main" status="pending" version="1.0" desc="Generate features.json inventory for a single platform">
52
+
53
+ <!-- ============================================================
54
+ Input Parameters Definition
55
+ ============================================================ -->
56
+ <block type="input" id="I1" desc="Workflow input parameters">
57
+ <field name="platformId" required="true" type="string" desc="Platform identifier"/>
58
+ <field name="platformName" required="true" type="string" desc="Platform display name"/>
59
+ <field name="platformType" required="true" type="string" desc="Platform type: backend/web/mobile"/>
60
+ <field name="platformSubtype" required="false" type="string" desc="Platform subtype"/>
61
+ <field name="sourcePath" required="true" type="string" desc="Absolute path to platform source root"/>
62
+ <field name="techIdentifier" required="true" type="string" desc="Technology stack identifier"/>
63
+ <field name="entryDirsFile" required="true" type="string" desc="Absolute path to entry-dirs JSON file"/>
64
+ <field name="outputDir" required="true" type="string" desc="Absolute path to features JSON output directory"/>
65
+ <field name="workspace_path" required="true" type="string" desc="Absolute path to speccrew-workspace directory"/>
66
+ <field name="sync_state_bizs_dir" required="true" type="string" desc="Absolute path to sync-state/knowledge-bizs directory"/>
67
+ <field name="language" required="true" type="string" desc="Language code for generated content"/>
68
+ </block>
69
+
70
+ <!-- ============================================================
71
+ Global Constraints
72
+ ============================================================ -->
73
+ <block type="rule" id="R1" level="mandatory" desc="Path constraints">
74
+ <field name="text">Use the provided absolute paths directly. DO NOT construct or derive paths yourself.</field>
75
+ <field name="text">All paths must use forward slashes / as path separators (even on Windows)</field>
76
+ </block>
77
+
78
+ <block type="rule" id="R2" level="forbidden" desc="Script execution constraints">
79
+ <field name="text">DO NOT manually scan source files or manually construct features JSON</field>
80
+ <field name="text">MUST execute generate-inventory.js script - if script not found, STOP and report error</field>
81
+ <field name="text">DO NOT use read_file, Glob, Grep, or search_codebase as substitutes for script execution</field>
82
+ </block>
83
+
84
+ <!-- ============================================================
85
+ Global Continuous Execution Rules
86
+ ============================================================ -->
87
+ <block type="rule" id="GLOBAL-R1" level="forbidden" desc="Continuous execution constraints — NEVER violate">
88
+ <field name="text">DO NOT ask user "Should I continue?" or "How would you like to proceed?" during execution</field>
89
+ <field name="text">DO NOT offer options like "Full execution / Partial / Stop" — always execute ALL tasks to completion</field>
90
+ <field name="text">DO NOT suggest "Due to context window limits, let me pause" — complete current task, use checkpoint for resumption</field>
91
+ <field name="text">DO NOT estimate workload and suggest breaking it into phases — execute ALL items in sequence</field>
92
+ <field name="text">DO NOT warn about "large number of files" or "this may take a while" — proceed with generation</field>
93
+ <field name="text">Context window management: if approaching limit, save progress to checkpoint file and resume — do NOT ask user for guidance</field>
94
+ </block>
95
+
96
+ <!-- ============================================================
97
+ Main Processing Sequence
98
+ ============================================================ -->
99
+ <sequence id="S1" name="Generate Features Inventory" status="pending" desc="Execute script to generate features.json">
100
+
101
+ <!-- Step 1: Verify entry-dirs JSON exists and is valid -->
102
+ <block type="task" id="B1" action="read-file" desc="Read entry-dirs JSON to verify file exists and modules non-empty">
103
+ <field name="path" value="${entryDirsFile}"/>
104
+ <field name="output" var="entry_dirs_content"/>
105
+ </block>
106
+
107
+ <!-- Gateway: Validate entry-dirs content -->
108
+ <block type="gateway" id="G1" mode="guard" desc="Verify entry-dirs has modules"
109
+ test="${entry_dirs_content.modules} != null AND ${entry_dirs_content.modules.length} > 0"
110
+ fail-action="stop">
111
+ <field name="message">Entry-dirs JSON must have non-empty modules array: ${entryDirsFile}</field>
112
+ </block>
113
+
114
+ <!-- Step 2: Execute generate-inventory.js script -->
115
+ <block type="task" id="B2" action="run-script" desc="Execute generate-inventory.js to create features.json">
116
+ <field name="command">node "${workspace_path}/../.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js" --entryDirsFile "${entryDirsFile}" --outputDir "${outputDir}"</field>
117
+ <field name="note">Script path discovery: Worker must locate generate-inventory.js in IDE skills directory. Search order: 1) .qoder/skills/ 2) .speccrew/skills/ 3) .cursor/skills/ - all relative to project root (workspace_path parent). If script not found, STOP and report error.</field>
118
+ <field name="output" var="script_result"/>
119
+ </block>
120
+
121
+ <!-- Checkpoint: Verify features.json generated -->
122
+ <block type="checkpoint" id="CP1" name="features-generated" desc="Verify features JSON was generated">
123
+ <field name="file" value="${outputDir}/features-${platformId}.json"/>
124
+ <field name="verify" value="file_exists(${outputDir}/features-${platformId}.json)"/>
125
+ </block>
126
+
127
+ <!-- Step 3: Validate output JSON structure -->
128
+ <block type="task" id="B3" action="analyze" desc="Validate features.json structure">
129
+ <field name="input" value="${outputDir}/features-${platformId}.json"/>
130
+ <field name="validation_rules">
131
+ - platformName matches input platformName
132
+ - platformType matches input platformType
133
+ - techStack is valid array
134
+ - features array is non-empty
135
+ - each feature has: fileName, sourcePath, module, analyzed=false
136
+ - sourcePath uses forward slashes
137
+ </field>
138
+ <field name="output" var="validation_result"/>
139
+ </block>
140
+
141
+ <!-- Gateway: Handle validation result -->
142
+ <block type="gateway" id="G2" mode="exclusive" desc="Handle validation result">
143
+ <branch test="${validation_result.status} == 'failed'">
144
+ <block type="event" id="E1" action="log" level="error" desc="Log validation failure">
145
+ <field name="message">Features JSON validation failed for platform ${platformId}: ${validation_result.errors}</field>
146
+ </block>
147
+ <block type="error-handler" id="EH1" desc="Handle validation failure">
148
+ <catch error-type="validation_failed">
149
+ <field name="action">STOP - features.json structure invalid, manual intervention required</field>
150
+ </catch>
151
+ </block>
152
+ </branch>
153
+ <branch test="${validation_result.status} == 'passed'">
154
+ <block type="event" id="E2" action="log" level="info" desc="Log validation success">
155
+ <field name="message">Platform ${platformId} features.json validation passed</field>
156
+ </block>
157
+ </branch>
158
+ </block>
159
+
160
+ </sequence>
161
+
162
+ <!-- ============================================================
163
+ Output Results
164
+ ============================================================ -->
165
+ <block type="output" id="O1" desc="Workflow output results">
166
+ <field name="generated_file" value="${outputDir}/features-${platformId}.json" type="string" desc="Path to generated features JSON"/>
167
+ <field name="feature_count" from="${validation_result.feature_count}" type="number" desc="Number of features in inventory"/>
168
+ <field name="validation_status" from="${validation_result.status}" type="string" desc="Validation result status"/>
169
+ </block>
170
+
171
+ </workflow>
172
+ ```
173
+
174
+ ## Output JSON Format
175
+
176
+ ```json
177
+ {
178
+ "platformName": "Web Frontend",
179
+ "platformType": "web",
180
+ "sourcePath": "frontend-web/src/views",
181
+ "techStack": ["vue", "typescript"],
182
+ "modules": [
183
+ { "name": "chat", "featureCount": 12 },
184
+ { "name": "image", "featureCount": 8 }
185
+ ],
186
+ "totalFiles": 25,
187
+ "analyzedCount": 0,
188
+ "pendingCount": 25,
189
+ "generatedAt": "2024-01-15-103000",
190
+ "features": [
191
+ {
192
+ "fileName": "index",
193
+ "sourcePath": "frontend-web/src/views/system/user/index.vue",
194
+ "documentPath": "speccrew-workspace/knowledges/bizs/web-vue/src/views/system/user/index.md",
195
+ "module": "system",
196
+ "analyzed": false,
197
+ "startedAt": null,
198
+ "completedAt": null,
199
+ "analysisNotes": null
200
+ }
201
+ ]
202
+ }
203
+ ```
204
+
205
+ ### Field Definitions
206
+
207
+ - `platformName`: Human-readable platform name
208
+ - `platformType`: Platform type (backend, web, mobile)
209
+ - `sourcePath`: Platform source root path (project-root-relative)
210
+ - `techStack`: Array of technology identifiers
211
+ - `modules`: Array of modules with feature counts
212
+ - `totalFiles`: Total number of feature files
213
+ - `analyzedCount`: Number of analyzed features (initially 0)
214
+ - `pendingCount`: Number of pending features (initially totalFiles)
215
+ - `generatedAt`: ISO timestamp when file was generated
216
+ - `features`: Array of feature objects
217
+ - `fileName`: File name without extension
218
+ - `sourcePath`: Relative path to source file (project-root-relative)
219
+ - `documentPath`: Relative path to target document
220
+ - `module`: Module name this feature belongs to
221
+ - `analyzed`: Whether analysis is complete (initially false)
222
+ - `startedAt`: Analysis start timestamp (null initially)
223
+ - `completedAt`: Analysis completion timestamp (null initially)
224
+ - `analysisNotes`: Analysis notes (null initially)
225
+
226
+ ## Error Handling
227
+
228
+ | Scenario | Handling |
229
+ |----------|----------|
230
+ | entry-dirs JSON not found | STOP and report error with file path |
231
+ | entry-dirs modules array empty | STOP - cannot generate features without entry directories |
232
+ | generate-inventory.js script not found | STOP and report error - do NOT attempt manual generation |
233
+ | Script execution fails | STOP and report error with exit code and stderr |
234
+ | features.json validation fails | STOP - manual intervention required |
235
+ | features array empty | WARNING - platform may have no recognizable features |
236
+
237
+ ## Checklist
238
+
239
+ - [ ] entry-dirs JSON file exists and is readable
240
+ - [ ] entry-dirs JSON has non-empty modules array
241
+ - [ ] generate-inventory.js script located and executed
242
+ - [ ] features-${platformId}.json file generated
243
+ - [ ] Output JSON has valid platform metadata
244
+ - [ ] features array is non-empty
245
+ - [ ] Each feature has required fields (fileName, sourcePath, module, analyzed)
246
+ - [ ] All sourcePath values use forward slashes
247
+ - [ ] analyzed field is false for all features (initial state)
248
+
249
+ > **MANDATORY**: Use the provided absolute paths directly. DO NOT construct or derive paths yourself. DO NOT manually create JSON files - MUST execute the script.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speccrew",
3
- "version": "0.6.66",
3
+ "version": "0.6.68",
4
4
  "description": "Spec-Driven Development toolkit for AI-powered IDEs",
5
5
  "author": "charlesmu99",
6
6
  "repository": {