speccrew 0.1.2 → 0.1.4
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/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js
CHANGED
|
@@ -154,6 +154,14 @@ function isDataObjectFile(fileName, extension, excludeSuffixes) {
|
|
|
154
154
|
return false;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
// Check if file name matches exact exclusion list (e.g., package-info)
|
|
158
|
+
function isExcludedFileName(fileName, excludeFileNames) {
|
|
159
|
+
if (!excludeFileNames || excludeFileNames.length === 0) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return excludeFileNames.includes(fileName);
|
|
163
|
+
}
|
|
164
|
+
|
|
157
165
|
// Get module name (first non-excluded directory level)
|
|
158
166
|
function getModuleName(dirPath, excludeDirs, fallbackModuleName) {
|
|
159
167
|
const parts = normalizePath(dirPath).split('/').filter(p => p && p !== '.');
|
|
@@ -225,11 +233,12 @@ function loadTechStackConfig(platformType, framework, projectRoot) {
|
|
|
225
233
|
const techConfig = config.tech_stacks[platformType][framework];
|
|
226
234
|
return {
|
|
227
235
|
extensions: techConfig.extensions || [],
|
|
228
|
-
exclude_file_suffixes: techConfig.exclude_file_suffixes || []
|
|
236
|
+
exclude_file_suffixes: techConfig.exclude_file_suffixes || [],
|
|
237
|
+
exclude_file_names: techConfig.exclude_file_names || []
|
|
229
238
|
};
|
|
230
239
|
}
|
|
231
240
|
|
|
232
|
-
return { extensions: [], exclude_file_suffixes: [] };
|
|
241
|
+
return { extensions: [], exclude_file_suffixes: [], exclude_file_names: [] };
|
|
233
242
|
}
|
|
234
243
|
|
|
235
244
|
/**
|
|
@@ -380,7 +389,7 @@ function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outpu
|
|
|
380
389
|
|
|
381
390
|
// Load tech stack config for extensions and exclude_file_suffixes
|
|
382
391
|
const techConfig = loadTechStackConfig(platformType, framework, projectRoot);
|
|
383
|
-
const { extensions, exclude_file_suffixes } = techConfig;
|
|
392
|
+
const { extensions, exclude_file_suffixes, exclude_file_names } = techConfig;
|
|
384
393
|
|
|
385
394
|
if (extensions.length === 0) {
|
|
386
395
|
console.error(`Error: No extensions found for ${platformType}/${framework} in tech-stack-mappings.json`);
|
|
@@ -428,6 +437,11 @@ function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outpu
|
|
|
428
437
|
continue;
|
|
429
438
|
}
|
|
430
439
|
|
|
440
|
+
// Apply exclude_file_names filter (e.g., package-info)
|
|
441
|
+
if (isExcludedFileName(file.fileName, exclude_file_names)) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
431
445
|
// Build feature ID: moduleName-entryDirSegs-fileName
|
|
432
446
|
// entryDir like "controller/admin/chat" → "controller-admin-chat"
|
|
433
447
|
const entryDirNormalized = normalizePath(entryDir).replace(/[\/\\]/g, '-');
|
|
@@ -649,6 +663,7 @@ function main() {
|
|
|
649
663
|
|
|
650
664
|
// If excludeDirs not provided or empty, try to read from tech-stack-mappings.json
|
|
651
665
|
let excludeFileSuffixes = [];
|
|
666
|
+
let excludeFileNames = [];
|
|
652
667
|
if (!excludeDirsStr || excludeDirsStr === '[]') {
|
|
653
668
|
try {
|
|
654
669
|
const configPath = path.join(projectRoot, 'speccrew-workspace', 'docs', 'configs', 'tech-stack-mappings.json');
|
|
@@ -683,6 +698,17 @@ function main() {
|
|
|
683
698
|
console.log(`Loaded exclude_file_suffixes from tech-stack-mappings.json: ${excludeFileSuffixes.join(', ')}`);
|
|
684
699
|
}
|
|
685
700
|
}
|
|
701
|
+
|
|
702
|
+
// Load tech-stack-specific exclude_file_names
|
|
703
|
+
if (config.tech_stacks &&
|
|
704
|
+
config.tech_stacks[platformType] &&
|
|
705
|
+
config.tech_stacks[platformType][techIdentifier] &&
|
|
706
|
+
config.tech_stacks[platformType][techIdentifier].exclude_file_names) {
|
|
707
|
+
excludeFileNames = config.tech_stacks[platformType][techIdentifier].exclude_file_names;
|
|
708
|
+
if (excludeFileNames.length > 0) {
|
|
709
|
+
console.log(`Loaded exclude_file_names from tech-stack-mappings.json: ${excludeFileNames.join(', ')}`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
686
712
|
}
|
|
687
713
|
} catch (e) {
|
|
688
714
|
// Silent fallback - continue with default or empty
|
|
@@ -749,10 +775,21 @@ function main() {
|
|
|
749
775
|
excludedDataObjectsCount = filesBeforeFilter - files.length;
|
|
750
776
|
}
|
|
751
777
|
|
|
778
|
+
// Filter out files with excluded names (e.g., package-info)
|
|
779
|
+
let excludedFileNamesCount = 0;
|
|
780
|
+
if (excludeFileNames.length > 0) {
|
|
781
|
+
const filesBeforeFilter = files.length;
|
|
782
|
+
files = files.filter(file => !isExcludedFileName(file.fileName, excludeFileNames));
|
|
783
|
+
excludedFileNamesCount = filesBeforeFilter - files.length;
|
|
784
|
+
}
|
|
785
|
+
|
|
752
786
|
console.log(`Found ${allFiles.length} total files, ${files.length} after excluding components directories`);
|
|
753
787
|
if (excludedDataObjectsCount > 0) {
|
|
754
788
|
console.log(`Excluded: ${excludedDataObjectsCount} data objects (VO/DTO/DO/Entity/Convert)`);
|
|
755
789
|
}
|
|
790
|
+
if (excludedFileNamesCount > 0) {
|
|
791
|
+
console.log(`Excluded: ${excludedFileNamesCount} files by name (${excludeFileNames.join(', ')})`);
|
|
792
|
+
}
|
|
756
793
|
|
|
757
794
|
// Build flat feature list - each file is a feature
|
|
758
795
|
const features = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speccrew",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Spec-Driven Development toolkit for AI-powered IDEs",
|
|
5
5
|
"author": "charlesmu99",
|
|
6
6
|
"repository": {
|
|
@@ -22,9 +22,6 @@
|
|
|
22
22
|
"docs/",
|
|
23
23
|
"README*.md"
|
|
24
24
|
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"postinstall": "node bin/postinstall.js"
|
|
27
|
-
},
|
|
28
25
|
"engines": {
|
|
29
26
|
"node": ">=16.0.0"
|
|
30
27
|
},
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
"extensions": [".java", ".kt"],
|
|
133
133
|
"exclude_dirs": ["controller", "controllers", "admin", "app", "api", "service", "services", "repository", "repositories", "dao", "dal", "mysql", "redis", "dataobject", "entity", "entities", "model", "models", "dto", "dtos", "vo", "vos", "mapper", "mappers", "convert", "converter", "converters", "config", "configs", "util", "utils", "common", "exception", "exceptions", "enums", "framework", "job", "mq", "listener", "listeners", "producer", "consumer"],
|
|
134
134
|
"exclude_file_suffixes": ["VO", "DTO", "DO", "Entity", "Convert", "Converter"],
|
|
135
|
+
"exclude_file_names": ["package-info"],
|
|
135
136
|
"entry_patterns": ["**/*Controller.java", "**/*Controller.kt", "**/*Service.java"],
|
|
136
137
|
"api_patterns": {
|
|
137
138
|
"controller": ["@Controller", "@RestController", "@RequestMapping"],
|
package/bin/postinstall.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const readline = require('readline');
|
|
6
|
-
|
|
7
|
-
// Get package version
|
|
8
|
-
function getPackageVersion() {
|
|
9
|
-
try {
|
|
10
|
-
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
11
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
12
|
-
return packageJson.version;
|
|
13
|
-
} catch (e) {
|
|
14
|
-
return 'unknown';
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Get npm package root directory
|
|
19
|
-
function getPackageRoot() {
|
|
20
|
-
return path.resolve(__dirname, '..');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Check if a path is a speccrew file (starts with speccrew-)
|
|
24
|
-
function isSpeccrewFile(name) {
|
|
25
|
-
return name.startsWith('speccrew-');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Count agents and skills in the package
|
|
29
|
-
function countPackageResources(packageRoot) {
|
|
30
|
-
let agentCount = 0;
|
|
31
|
-
let skillCount = 0;
|
|
32
|
-
|
|
33
|
-
const agentsDir = path.join(packageRoot, '.speccrew', 'agents');
|
|
34
|
-
const skillsDir = path.join(packageRoot, '.speccrew', 'skills');
|
|
35
|
-
|
|
36
|
-
if (fs.existsSync(agentsDir)) {
|
|
37
|
-
const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
|
|
38
|
-
agentCount = entries.filter(e => isSpeccrewFile(e.name)).length;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (fs.existsSync(skillsDir)) {
|
|
42
|
-
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
43
|
-
skillCount = entries.filter(e => isSpeccrewFile(e.name)).length;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { agentCount, skillCount };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Detect IDE directories in the project
|
|
50
|
-
function detectIDE(projectRoot) {
|
|
51
|
-
const ideConfigs = [
|
|
52
|
-
{ id: 'qoder', name: 'Qoder', baseDir: '.qoder' },
|
|
53
|
-
{ id: 'cursor', name: 'Cursor', baseDir: '.cursor' },
|
|
54
|
-
{ id: 'claude', name: 'Claude', baseDir: '.claude' },
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
const detected = [];
|
|
58
|
-
for (const config of ideConfigs) {
|
|
59
|
-
const basePath = path.join(projectRoot, config.baseDir);
|
|
60
|
-
if (fs.existsSync(basePath)) {
|
|
61
|
-
detected.push(config);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return detected;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Ask user for confirmation
|
|
68
|
-
function askConfirm(message) {
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
const rl = readline.createInterface({
|
|
71
|
-
input: process.stdin,
|
|
72
|
-
output: process.stdout,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
rl.question(message, (answer) => {
|
|
76
|
-
rl.close();
|
|
77
|
-
const normalized = answer.trim().toLowerCase();
|
|
78
|
-
resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Main postinstall logic
|
|
84
|
-
async function main() {
|
|
85
|
-
const version = getPackageVersion();
|
|
86
|
-
const packageRoot = getPackageRoot();
|
|
87
|
-
|
|
88
|
-
// Get the project directory where npm install was run
|
|
89
|
-
const initCwd = process.env.INIT_CWD;
|
|
90
|
-
|
|
91
|
-
// If INIT_CWD is not set or doesn't exist, just show welcome message
|
|
92
|
-
if (!initCwd || !fs.existsSync(initCwd)) {
|
|
93
|
-
console.log(`\nSpecCrew v${version}\n`);
|
|
94
|
-
console.log("Run 'speccrew init' in your project directory to get started.\n");
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Count resources in the package
|
|
99
|
-
const { agentCount, skillCount } = countPackageResources(packageRoot);
|
|
100
|
-
|
|
101
|
-
// Detect IDE in the project directory
|
|
102
|
-
const detectedIDEs = detectIDE(initCwd);
|
|
103
|
-
|
|
104
|
-
// Display welcome banner
|
|
105
|
-
console.log(`\nSpecCrew v${version}\n`);
|
|
106
|
-
|
|
107
|
-
// Display installation summary
|
|
108
|
-
console.log('Installation Summary:');
|
|
109
|
-
console.log(` Project: ${initCwd}`);
|
|
110
|
-
|
|
111
|
-
if (detectedIDEs.length === 0) {
|
|
112
|
-
console.log(' IDE: Not detected (use --ide to specify)');
|
|
113
|
-
} else if (detectedIDEs.length === 1) {
|
|
114
|
-
console.log(` IDE: ${detectedIDEs[0].name} (${detectedIDEs[0].baseDir}/)`);
|
|
115
|
-
} else {
|
|
116
|
-
console.log(` IDE: ${detectedIDEs.map(i => i.name).join(', ')}`);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
console.log(` Agents: ${agentCount} agents`);
|
|
120
|
-
console.log(` Skills: ${skillCount} skills`);
|
|
121
|
-
console.log(` Workspace: speccrew-workspace/`);
|
|
122
|
-
console.log(` Docs: README + Getting Started guides\n`);
|
|
123
|
-
|
|
124
|
-
// Non-interactive environment check
|
|
125
|
-
if (!process.stdin.isTTY) {
|
|
126
|
-
console.log("Run 'speccrew init' in your project directory to complete installation.\n");
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// No IDE detected - prompt user to specify
|
|
131
|
-
if (detectedIDEs.length === 0) {
|
|
132
|
-
console.log('No supported IDE detected in your project directory.');
|
|
133
|
-
console.log("Run 'speccrew init --ide <name>' to specify an IDE.");
|
|
134
|
-
console.log('Supported IDEs: qoder, cursor, claude\n');
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Ask for confirmation
|
|
139
|
-
try {
|
|
140
|
-
const confirmed = await askConfirm('Proceed with installation? (Y/n) ');
|
|
141
|
-
|
|
142
|
-
if (confirmed) {
|
|
143
|
-
// Import and run init
|
|
144
|
-
const { runInit } = require('../lib/commands/init.js');
|
|
145
|
-
await runInit({ projectRoot: initCwd, skipConfirm: true });
|
|
146
|
-
} else {
|
|
147
|
-
console.log('\nInstallation skipped. You can run \'speccrew init\' later in your project directory.\n');
|
|
148
|
-
}
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.log(`\nInstallation skipped. You can run 'speccrew init' later in your project directory.\n`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Run main with error handling - postinstall failures should not block npm install
|
|
155
|
-
main().catch(() => {
|
|
156
|
-
console.log('\nPostinstall hook encountered an issue. You can run \'speccrew init\' manually.\n');
|
|
157
|
-
});
|