speccrew 0.6.67 → 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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speccrew",
3
- "version": "0.6.67",
3
+ "version": "0.6.68",
4
4
  "description": "Spec-Driven Development toolkit for AI-powered IDEs",
5
5
  "author": "charlesmu99",
6
6
  "repository": {