speccrew 0.1.0

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.
Files changed (153) hide show
  1. package/.speccrew/agents/speccrew-feature-designer.md +142 -0
  2. package/.speccrew/agents/speccrew-product-manager.md +61 -0
  3. package/.speccrew/agents/speccrew-system-designer.md +200 -0
  4. package/.speccrew/agents/speccrew-system-developer.md +238 -0
  5. package/.speccrew/agents/speccrew-task-worker.md +80 -0
  6. package/.speccrew/agents/speccrew-team-leader.md +92 -0
  7. package/.speccrew/agents/speccrew-test-manager.md +313 -0
  8. package/.speccrew/skills/speccrew-create-agents/SKILL.md +98 -0
  9. package/.speccrew/skills/speccrew-create-agents/templates/agents/designer-agent.md +54 -0
  10. package/.speccrew/skills/speccrew-create-agents/templates/agents/dev-agent.md +79 -0
  11. package/.speccrew/skills/speccrew-create-agents/templates/agents/test-agent.md +80 -0
  12. package/.speccrew/skills/speccrew-dev-backend/SKILL.md +205 -0
  13. package/.speccrew/skills/speccrew-dev-backend/templates/TASK-RECORD-TEMPLATE.md +118 -0
  14. package/.speccrew/skills/speccrew-dev-desktop/SKILL.md +258 -0
  15. package/.speccrew/skills/speccrew-dev-desktop/templates/TASK-RECORD-TEMPLATE.md +161 -0
  16. package/.speccrew/skills/speccrew-dev-frontend/SKILL.md +202 -0
  17. package/.speccrew/skills/speccrew-dev-frontend/templates/TASK-RECORD-TEMPLATE.md +115 -0
  18. package/.speccrew/skills/speccrew-dev-mobile/SKILL.md +200 -0
  19. package/.speccrew/skills/speccrew-dev-mobile/templates/TASK-RECORD-TEMPLATE.md +125 -0
  20. package/.speccrew/skills/speccrew-fd-api-contract/SKILL.md +73 -0
  21. package/.speccrew/skills/speccrew-fd-api-contract/templates/API-CONTRACT-TEMPLATE.md +96 -0
  22. package/.speccrew/skills/speccrew-fd-feature-design/SKILL.md +395 -0
  23. package/.speccrew/skills/speccrew-fd-feature-design/templates/FEATURE-SPEC-TEMPLATE.md +387 -0
  24. package/.speccrew/skills/speccrew-get-timestamp/SKILL.md +80 -0
  25. package/.speccrew/skills/speccrew-get-timestamp/scripts/get-timestamp.js +35 -0
  26. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/SKILL.md +1116 -0
  27. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-FASTAPI.md +462 -0
  28. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-JAVA.md +480 -0
  29. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE-NET.md +464 -0
  30. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/FEATURE-DETAIL-TEMPLATE.md +480 -0
  31. package/.speccrew/skills/speccrew-knowledge-bizs-api-analyze/templates/MODULE-OVERVIEW-TEMPLATE.md +367 -0
  32. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/SKILL.md +667 -0
  33. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/STATUS-FORMATS.md +74 -0
  34. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js +176 -0
  35. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/get-next-batch.js +150 -0
  36. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/get-pending-features.js +106 -0
  37. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/mark-stale.js +249 -0
  38. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/process-batch-results.js +848 -0
  39. package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/scripts/update-feature-status.js +226 -0
  40. package/.speccrew/skills/speccrew-knowledge-bizs-init-features/SKILL.md +264 -0
  41. package/.speccrew/skills/speccrew-knowledge-bizs-init-features/examples/features.json +34 -0
  42. package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js +867 -0
  43. package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/test-inventory.js +26 -0
  44. package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/SKILL.md +165 -0
  45. package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/apply-module-mapping.js +208 -0
  46. package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/extract-module-summary.js +180 -0
  47. package/.speccrew/skills/speccrew-knowledge-bizs-module-classify/scripts/reindex-modules.js +358 -0
  48. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/SKILL.md +1055 -0
  49. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-DESKTOP.md +303 -0
  50. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-ELECTRON.md +327 -0
  51. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-MINIAPP.md +292 -0
  52. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI-MOBILE.md +281 -0
  53. package/.speccrew/skills/speccrew-knowledge-bizs-ui-analyze/templates/FEATURE-DETAIL-TEMPLATE-UI.md +324 -0
  54. package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/SKILL.md +270 -0
  55. package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/COMPONENT-PATTERN-TEMPLATE.md +33 -0
  56. package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/LAYOUT-PATTERN-TEMPLATE.md +33 -0
  57. package/.speccrew/skills/speccrew-knowledge-bizs-ui-style-extract/templates/PAGE-TYPE-TEMPLATE.md +33 -0
  58. package/.speccrew/skills/speccrew-knowledge-graph-query/SKILL.md +229 -0
  59. package/.speccrew/skills/speccrew-knowledge-graph-query/scripts/graph-query.js +549 -0
  60. package/.speccrew/skills/speccrew-knowledge-graph-write/SKILL.md +181 -0
  61. package/.speccrew/skills/speccrew-knowledge-graph-write/scripts/graph-write.js +651 -0
  62. package/.speccrew/skills/speccrew-knowledge-module-summarize/SKILL.md +305 -0
  63. package/.speccrew/skills/speccrew-knowledge-module-summarize/templates/MODULE-OVERVIEW-TEMPLATE.md +400 -0
  64. package/.speccrew/skills/speccrew-knowledge-system-summarize/SKILL.md +351 -0
  65. package/.speccrew/skills/speccrew-knowledge-system-summarize/templates/SYSTEM-OVERVIEW-TEMPLATE.md +294 -0
  66. package/.speccrew/skills/speccrew-knowledge-techs-dispatch/SKILL.md +683 -0
  67. package/.speccrew/skills/speccrew-knowledge-techs-dispatch/STATUS-FORMATS.md +550 -0
  68. package/.speccrew/skills/speccrew-knowledge-techs-dispatch/templates/techs-manifest-EXAMPLE.json +35 -0
  69. package/.speccrew/skills/speccrew-knowledge-techs-generate/SKILL.md +1087 -0
  70. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/ARCHITECTURE-TEMPLATE.md +240 -0
  71. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/COLOR-SYSTEM-TEMPLATE.md +68 -0
  72. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/COMPONENT-LIBRARY-TEMPLATE.md +86 -0
  73. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-BUILD-TEMPLATE.md +466 -0
  74. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DATA-TEMPLATE.md +432 -0
  75. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DESIGN-TEMPLATE.md +1209 -0
  76. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-DEV-TEMPLATE.md +1433 -0
  77. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-SYSTEM-TEST-TEMPLATE.md +1052 -0
  78. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/CONVENTIONS-UNIT-TEST-TEMPLATE.md +946 -0
  79. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/INDEX-TEMPLATE.md +29 -0
  80. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/PAGE-LAYOUTS-TEMPLATE.md +69 -0
  81. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/PAGE-TYPE-SUMMARY-TEMPLATE.md +74 -0
  82. package/.speccrew/skills/speccrew-knowledge-techs-generate/templates/TECH-STACK-TEMPLATE.md +232 -0
  83. package/.speccrew/skills/speccrew-knowledge-techs-generate-conventions/SKILL.md +628 -0
  84. package/.speccrew/skills/speccrew-knowledge-techs-generate-ui-style/SKILL.md +392 -0
  85. package/.speccrew/skills/speccrew-knowledge-techs-index/SKILL.md +489 -0
  86. package/.speccrew/skills/speccrew-knowledge-techs-index/templates/INDEX-TEMPLATE.md +243 -0
  87. package/.speccrew/skills/speccrew-knowledge-techs-init/SKILL.md +269 -0
  88. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/SKILL.md +562 -0
  89. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/BUSINESS-COMPONENTS-TEMPLATE.md +171 -0
  90. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMMON-COMPONENTS-TEMPLATE.md +177 -0
  91. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMPONENT-INDIVIDUAL-TEMPLATE.md +80 -0
  92. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/COMPONENT-LIBRARY-TEMPLATE.md +118 -0
  93. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/LAYOUT-INDIVIDUAL-TEMPLATE.md +97 -0
  94. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/LAYOUT-PATTERNS-TEMPLATE.md +208 -0
  95. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/NAVIGATION-PATTERNS-TEMPLATE.md +157 -0
  96. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/PAGE-TYPE-INDIVIDUAL-TEMPLATE.md +123 -0
  97. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/PAGE-TYPE-SUMMARY-TEMPLATE.md +58 -0
  98. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/SPACING-TEMPLATE.md +119 -0
  99. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/STYLE-SYSTEM-TEMPLATE.md +117 -0
  100. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/TYPOGRAPHY-TEMPLATE.md +107 -0
  101. package/.speccrew/skills/speccrew-knowledge-techs-ui-analyze/templates/UI-STYLE-GUIDE-TEMPLATE.md +171 -0
  102. package/.speccrew/skills/speccrew-pm-requirement-analysis/SKILL.md +434 -0
  103. package/.speccrew/skills/speccrew-pm-requirement-analysis/templates/BIZS-MODELING-TEMPLATE.md +332 -0
  104. package/.speccrew/skills/speccrew-pm-requirement-analysis/templates/PRD-TEMPLATE.md +200 -0
  105. package/.speccrew/skills/speccrew-pm-requirement-assess/SKILL.md +195 -0
  106. package/.speccrew/skills/speccrew-project-diagnosis/SKILL.md +208 -0
  107. package/.speccrew/skills/speccrew-project-diagnosis/templates/DIAGNOSIS-REPORT-TEMPLATE.md +202 -0
  108. package/.speccrew/skills/speccrew-sd-backend/SKILL.md +188 -0
  109. package/.speccrew/skills/speccrew-sd-backend/templates/INDEX-TEMPLATE.md +85 -0
  110. package/.speccrew/skills/speccrew-sd-backend/templates/SD-BACKEND-TEMPLATE.md +269 -0
  111. package/.speccrew/skills/speccrew-sd-desktop/SKILL.md +192 -0
  112. package/.speccrew/skills/speccrew-sd-desktop/templates/INDEX-TEMPLATE.md +271 -0
  113. package/.speccrew/skills/speccrew-sd-desktop/templates/SD-DESKTOP-TEMPLATE.md +673 -0
  114. package/.speccrew/skills/speccrew-sd-frontend/SKILL.md +176 -0
  115. package/.speccrew/skills/speccrew-sd-frontend/templates/INDEX-TEMPLATE.md +184 -0
  116. package/.speccrew/skills/speccrew-sd-frontend/templates/SD-FRONTEND-TEMPLATE.md +382 -0
  117. package/.speccrew/skills/speccrew-sd-mobile/SKILL.md +189 -0
  118. package/.speccrew/skills/speccrew-sd-mobile/templates/INDEX-TEMPLATE.md +219 -0
  119. package/.speccrew/skills/speccrew-sd-mobile/templates/SD-MOBILE-TEMPLATE.md +534 -0
  120. package/.speccrew/skills/speccrew-test-case-design/SKILL.md +284 -0
  121. package/.speccrew/skills/speccrew-test-case-design/templates/TEST-CASE-DESIGN-TEMPLATE.md +263 -0
  122. package/.speccrew/skills/speccrew-test-code-gen/SKILL.md +313 -0
  123. package/.speccrew/skills/speccrew-test-code-gen/templates/TEST-CODE-PLAN-TEMPLATE.md +180 -0
  124. package/.speccrew/skills/speccrew-test-execute/SKILL.md +283 -0
  125. package/.speccrew/skills/speccrew-test-execute/templates/BUG-REPORT-TEMPLATE.md +50 -0
  126. package/.speccrew/skills/speccrew-test-execute/templates/TEST-REPORT-TEMPLATE.md +57 -0
  127. package/.speccrew/skills/speccrew-workflow-diagnose/SKILL.md +155 -0
  128. package/LICENSE +21 -0
  129. package/README.ar.md +318 -0
  130. package/README.en.md +318 -0
  131. package/README.es.md +318 -0
  132. package/README.md +340 -0
  133. package/bin/cli.js +62 -0
  134. package/lib/commands/doctor.js +138 -0
  135. package/lib/commands/init.js +231 -0
  136. package/lib/commands/list.js +114 -0
  137. package/lib/commands/uninstall.js +117 -0
  138. package/lib/commands/update.js +351 -0
  139. package/lib/ide-adapters.js +73 -0
  140. package/lib/utils.js +104 -0
  141. package/package.json +28 -0
  142. package/workspace-template/docs/configs/document-templates.json +667 -0
  143. package/workspace-template/docs/configs/platform-mapping.json +194 -0
  144. package/workspace-template/docs/configs/tech-stack-mappings.json +313 -0
  145. package/workspace-template/docs/configs/validation-rules.json +87 -0
  146. package/workspace-template/docs/rules/mermaid-rule.md +114 -0
  147. package/workspace-template/docs/solutions/Agent/346/212/200/350/203/275/345/256/232/344/271/211+/351/234/200/346/261/202/346/226/207/346/241/243+UML/344/275/277/347/224/250/346/250/241/346/235/277/357/274/210ISA-95/345/205/255/346/256/265/345/274/217/350/236/215/345/220/210/347/211/210/357/274/211.md +586 -0
  148. package/workspace-template/docs/solutions/agent-knowledge-map.md +238 -0
  149. package/workspace-template/docs/solutions/bizs-knowledge-pipeline.md +678 -0
  150. package/workspace-template/docs/solutions/harness.md +410 -0
  151. package/workspace-template/docs/solutions/knowledge-incremental-sync-spec.md +943 -0
  152. package/workspace-template/docs/solutions/techs-knowledge-pipeline.md +803 -0
  153. package/workspace-template/docs/solutions/workspace-structure.md +318 -0
@@ -0,0 +1,358 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * reindex-modules.js - 确定性脚本,用更新后的 exclude_dirs 对已有 features JSON 重新提取 module 名
4
+ *
5
+ * 调用方式:
6
+ * node reindex-modules.js --featuresFile "path/to/features-backend-system.json" --projectRoot "d:\dev\ruoyi-vue-pro"
7
+ *
8
+ * 可选参数:
9
+ * --platformType "backend" - 如果不提供,从 features JSON 的 platformType 字段读取
10
+ * --techIdentifier "spring" - 如果不提供,尝试从 features JSON 推断(如 techStack 数组)
11
+ * --excludeDirs "controller,admin,api,service" - 如果不提供,从 tech-stack-mappings.json 加载
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ // === 工具函数(从 generate-inventory.js 复用) ===
18
+
19
+ function normalizePath(filePath) {
20
+ if (!filePath) return '';
21
+ return filePath.replace(/\\/g, '/');
22
+ }
23
+
24
+ function parseArrayParam(value) {
25
+ if (!value) return [];
26
+ const trimmed = value.trim();
27
+ if (trimmed.startsWith('[')) {
28
+ try { return JSON.parse(trimmed); } catch (e) {
29
+ return trimmed.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean);
30
+ }
31
+ }
32
+ return trimmed.split(',').map(s => s.trim()).filter(Boolean);
33
+ }
34
+
35
+ // Java/Kotlin 标准源码路径前缀
36
+ const STANDARD_SOURCE_PREFIXES = [
37
+ 'src/main/java',
38
+ 'src/main/kotlin',
39
+ 'src/main/scala',
40
+ 'src/main/groovy',
41
+ 'src/main/resources',
42
+ 'src/test/java',
43
+ 'src/test/kotlin',
44
+ ];
45
+
46
+ /**
47
+ * Fallback exclude_dirs when tech-stack-mappings.json is missing or incomplete.
48
+ * Covers the most common container directories across all platforms.
49
+ */
50
+ const FALLBACK_EXCLUDE_DIRS = {
51
+ web: ["src", "views", "pages", "components", "composables", "hooks", "utils", "mixins", "directives"],
52
+ mobile: ["src", "views", "pages", "components", "composables", "hooks", "utils", "mixins", "directives"],
53
+ backend: ["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"],
54
+ };
55
+
56
+ function getModuleName(dirPath, excludeDirs, fallbackModuleName) {
57
+ let normalized = normalizePath(dirPath);
58
+
59
+ // Strip standard source directory prefixes (Java/Kotlin/etc.)
60
+ for (const prefix of STANDARD_SOURCE_PREFIXES) {
61
+ if (normalized.startsWith(prefix + '/')) {
62
+ normalized = normalized.slice(prefix.length + 1);
63
+ break;
64
+ }
65
+ }
66
+
67
+ const parts = normalized.split('/').filter(p => p && p !== '.');
68
+
69
+ for (const part of parts) {
70
+ if (!excludeDirs.includes(part)) {
71
+ return part;
72
+ }
73
+ }
74
+
75
+ // All parts were excluded (e.g., "src/utils/helper.ts" with src and utils both excluded)
76
+ // Return "_root" to indicate framework/root-level files, NOT the original module name
77
+ return '_root';
78
+ }
79
+
80
+ // === 辅助函数 ===
81
+
82
+ function parseArgs(argv) {
83
+ const args = {};
84
+ for (let i = 0; i < argv.length; i++) {
85
+ if (argv[i].startsWith('--') && i + 1 < argv.length) {
86
+ const key = argv[i].slice(2);
87
+ args[key] = argv[i + 1];
88
+ i++;
89
+ }
90
+ }
91
+ return args;
92
+ }
93
+
94
+ /**
95
+ * Find project root by searching upward for speccrew-workspace directory
96
+ */
97
+ function findProjectRoot(startPath) {
98
+ let currentDir = path.resolve(startPath);
99
+ const root = path.parse(currentDir).root;
100
+
101
+ while (currentDir !== root) {
102
+ const workspaceDir = path.join(currentDir, 'speccrew-workspace');
103
+ if (fs.existsSync(workspaceDir) && fs.statSync(workspaceDir).isDirectory()) {
104
+ return currentDir;
105
+ }
106
+ currentDir = path.dirname(currentDir);
107
+ }
108
+
109
+ // Fallback: return start path's parent directory
110
+ return path.dirname(path.resolve(startPath));
111
+ }
112
+
113
+ function loadExcludeDirs(projectRoot, platformType, techIdentifier, featuresData) {
114
+ console.log(`Loading exclude_dirs: platformType="${platformType}", techIdentifier="${techIdentifier || '(auto)'}"`);
115
+
116
+ // 尝试推断 techIdentifier
117
+ if (!techIdentifier) {
118
+ const techStack = featuresData.techStack || [];
119
+ // 常见映射
120
+ const techMap = {
121
+ 'spring': 'spring', 'spring-boot': 'spring', 'java': 'spring',
122
+ 'vue': 'vue', 'vue3': 'vue', 'vue2': 'vue',
123
+ 'react': 'react', 'next': 'nextjs', 'nextjs': 'nextjs',
124
+ 'angular': 'angular',
125
+ 'uniapp': 'uniapp', 'uni-app': 'uniapp',
126
+ 'flutter': 'flutter',
127
+ 'react-native': 'react-native',
128
+ };
129
+ for (const tech of techStack) {
130
+ const lower = tech.toLowerCase();
131
+ if (techMap[lower]) {
132
+ techIdentifier = techMap[lower];
133
+ console.log(`Inferred techIdentifier from techStack "${tech}": "${techIdentifier}"`);
134
+ break;
135
+ }
136
+ }
137
+ }
138
+
139
+ if (!platformType || !techIdentifier) {
140
+ console.warn('WARNING: Cannot determine platformType/techIdentifier for exclude_dirs lookup');
141
+ // Return fallback even when platformType/techIdentifier unknown
142
+ const fallbackDirs = FALLBACK_EXCLUDE_DIRS[platformType] || [];
143
+ console.log(`Using fallback exclude_dirs (${fallbackDirs.length}): ${fallbackDirs.slice(0, 5).join(', ')}...`);
144
+ return { excludeDirs: fallbackDirs, stripModulePrefixes: [] };
145
+ }
146
+
147
+ // Get fallback dirs for this platformType
148
+ const fallback = FALLBACK_EXCLUDE_DIRS[platformType] || [];
149
+
150
+ // 查找 tech-stack-mappings.json
151
+ const configPaths = [
152
+ path.join(projectRoot, 'speccrew-workspace', 'docs', 'configs', 'tech-stack-mappings.json'),
153
+ path.join(projectRoot, 'docs', 'configs', 'tech-stack-mappings.json'),
154
+ ];
155
+
156
+ let loadedDirs = [];
157
+ let globalDirs = [];
158
+ let stripModulePrefixes = [];
159
+ for (const configPath of configPaths) {
160
+ try {
161
+ if (fs.existsSync(configPath)) {
162
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
163
+
164
+ // Load tech-stack-specific exclude_dirs
165
+ if (config.tech_stacks &&
166
+ config.tech_stacks[platformType] &&
167
+ config.tech_stacks[platformType][techIdentifier]) {
168
+ const techConfig = config.tech_stacks[platformType][techIdentifier];
169
+ if (techConfig.exclude_dirs) {
170
+ loadedDirs = techConfig.exclude_dirs;
171
+ }
172
+ // Load strip_module_prefixes
173
+ if (techConfig.strip_module_prefixes) {
174
+ stripModulePrefixes = techConfig.strip_module_prefixes;
175
+ }
176
+ }
177
+
178
+ // Load global exclude_dirs (applies to all platforms)
179
+ globalDirs = config.global_exclude_dirs || [];
180
+
181
+ if (loadedDirs.length > 0 || globalDirs.length > 0) {
182
+ console.log(`Loaded exclude_dirs from: ${configPath}`);
183
+ break;
184
+ }
185
+ }
186
+ } catch (e) {
187
+ // continue to next path
188
+ }
189
+ }
190
+
191
+ // MERGE: global + tech-specific + fallback — ensure critical container dirs are always included
192
+ const merged = [...new Set([...globalDirs, ...loadedDirs, ...fallback])];
193
+
194
+ if (loadedDirs.length === 0 && globalDirs.length === 0) {
195
+ console.warn(`WARNING: No tech-stack-specific exclude_dirs found for ${platformType}/${techIdentifier}, using fallback`);
196
+ console.log(`Fallback exclude_dirs (${fallback.length}): ${fallback.slice(0, 5).join(', ')}...`);
197
+ } else {
198
+ console.log(`Loaded exclude_dirs: ${globalDirs.length} global + ${loadedDirs.length} tech-specific (${platformType}/${techIdentifier})`);
199
+ console.log(`Merged with fallback = ${merged.length} total dirs`);
200
+ }
201
+
202
+ if (stripModulePrefixes.length > 0) {
203
+ console.log(`Loaded strip_module_prefixes: ${stripModulePrefixes.join(', ')}`);
204
+ }
205
+
206
+ return { excludeDirs: merged, stripModulePrefixes };
207
+ }
208
+
209
+ function extractPlatformId(featuresData) {
210
+ // 从第一个 feature 的 documentPath 提取 platformId
211
+ // 格式: "speccrew-workspace/knowledges/bizs/{platformId}/..."
212
+ for (const feature of (featuresData.features || [])) {
213
+ if (feature.documentPath) {
214
+ const match = normalizePath(feature.documentPath).match(/knowledges\/bizs\/([^/]+)\//);
215
+ if (match) return match[1];
216
+ }
217
+ }
218
+ // 如果无法提取,用 platformType-platformSubtype 构建
219
+ if (featuresData.platformType && featuresData.platformSubtype) {
220
+ return `${featuresData.platformType}-${featuresData.platformSubtype}`;
221
+ }
222
+ return null;
223
+ }
224
+
225
+ // === 主逻辑 ===
226
+
227
+ function main() {
228
+ // 1. 解析命令行参数
229
+ const args = parseArgs(process.argv.slice(2));
230
+ const featuresFile = args.featuresFile;
231
+
232
+ if (!featuresFile) {
233
+ console.error('Error: --featuresFile is required');
234
+ process.exit(1);
235
+ }
236
+
237
+ // 2. 读取 features JSON
238
+ let featuresData;
239
+ try {
240
+ featuresData = JSON.parse(fs.readFileSync(featuresFile, 'utf8'));
241
+ } catch (e) {
242
+ console.error(`Error: Failed to read/parse features file: ${e.message}`);
243
+ process.exit(1);
244
+ }
245
+
246
+ // Auto-detect projectRoot from featuresFile if not provided
247
+ const projectRoot = args.projectRoot || findProjectRoot(featuresFile);
248
+ console.log(`Project root: ${projectRoot}`);
249
+
250
+ const inventorySourcePath = normalizePath(featuresData.sourcePath || '');
251
+ const platformType = args.platformType || featuresData.platformType || '';
252
+
253
+ // 3. 加载 exclude_dirs
254
+ let excludeDirs = [];
255
+ let stripModulePrefixes = [];
256
+ if (args.excludeDirs) {
257
+ excludeDirs = parseArrayParam(args.excludeDirs);
258
+ } else {
259
+ // 从 tech-stack-mappings.json 加载,按优先级确定 techIdentifier:
260
+ // 1. 命令行参数 --techIdentifier
261
+ // 2. features JSON 中的 techIdentifier
262
+ // 3. features JSON 中的 platformSubtype (兼容旧数据)
263
+ const techId = args.techIdentifier || featuresData.techIdentifier || featuresData.platformSubtype;
264
+ const config = loadExcludeDirs(projectRoot, platformType, techId, featuresData);
265
+ excludeDirs = config.excludeDirs;
266
+ stripModulePrefixes = config.stripModulePrefixes;
267
+ }
268
+
269
+ if (excludeDirs.length === 0) {
270
+ console.error('Warning: exclude_dirs is empty, module names may not be optimal');
271
+ }
272
+
273
+ console.log(`Platform: ${platformType}`);
274
+ console.log(`Exclude dirs (${excludeDirs.length}): ${excludeDirs.join(', ')}`);
275
+ console.log(`Total features: ${featuresData.features.length}`);
276
+
277
+ // 4. 重新计算每个 feature 的 module
278
+ const modulesBefore = [...new Set(featuresData.features.map(f => f.module))].sort();
279
+ let reclassifiedCount = 0;
280
+
281
+ // 从 features JSON 获取 platformId(用于重建 documentPath)
282
+ // platformId 格式: "{platformType}-{platformSubtype}"
283
+ // 从现有 documentPath 提取: "speccrew-workspace/knowledges/bizs/{platformId}/..."
284
+ const platformId = extractPlatformId(featuresData);
285
+
286
+ featuresData.features.forEach(feature => {
287
+ // 计算 feature 源文件相对于 inventorySourcePath 的路径
288
+ let relativePath = normalizePath(feature.sourcePath || '');
289
+
290
+ // 如果 feature.sourcePath 是绝对路径或相对于项目根,需要去掉 inventorySourcePath 前缀
291
+ if (inventorySourcePath && relativePath.startsWith(inventorySourcePath)) {
292
+ relativePath = relativePath.slice(inventorySourcePath.length);
293
+ if (relativePath.startsWith('/')) relativePath = relativePath.slice(1);
294
+ }
295
+ // 也可能 inventorySourcePath 只是部分匹配
296
+ else if (inventorySourcePath) {
297
+ const invParts = inventorySourcePath.split('/');
298
+ const relParts = relativePath.split('/');
299
+ // 找到重叠部分
300
+ let startIdx = 0;
301
+ for (let i = 0; i < relParts.length; i++) {
302
+ if (relParts.slice(i, i + invParts.length).join('/') === inventorySourcePath) {
303
+ startIdx = i + invParts.length;
304
+ break;
305
+ }
306
+ }
307
+ if (startIdx > 0) {
308
+ relativePath = relParts.slice(startIdx).join('/');
309
+ }
310
+ }
311
+
312
+ // 取目录部分(去掉文件名)
313
+ const dirPath = path.dirname(relativePath).replace(/\\/g, '/');
314
+
315
+ // 用 getModuleName 重新提取模块名
316
+ const fallback = feature.module || '_root';
317
+ let newModule = getModuleName(dirPath, excludeDirs, fallback);
318
+
319
+ // 应用 strip_module_prefixes 前缀去除
320
+ for (const prefix of stripModulePrefixes) {
321
+ if (newModule.startsWith(prefix)) {
322
+ newModule = newModule.substring(prefix.length);
323
+ break;
324
+ }
325
+ }
326
+
327
+ if (newModule !== feature.module) {
328
+ reclassifiedCount++;
329
+ feature.module = newModule;
330
+
331
+ // 重建 documentPath(使用 fileName 而非 feature.id,避免文件名过长)
332
+ if (platformId) {
333
+ feature.documentPath = `speccrew-workspace/knowledges/bizs/${platformId}/${newModule}/${feature.fileName}.md`;
334
+ }
335
+ }
336
+ });
337
+
338
+ // 5. 更新 modules 数组
339
+ const modulesAfter = [...new Set(featuresData.features.map(f => f.module))].sort();
340
+ featuresData.modules = modulesAfter;
341
+
342
+ // 6. 写回文件
343
+ fs.writeFileSync(featuresFile, JSON.stringify(featuresData, null, 2), 'utf8');
344
+
345
+ // 7. 输出结果
346
+ const result = {
347
+ status: 'success',
348
+ modules_before: modulesBefore,
349
+ modules_after: modulesAfter,
350
+ reclassified_count: reclassifiedCount,
351
+ total_features: featuresData.features.length
352
+ };
353
+
354
+ console.log('\n=== Reindex Result ===');
355
+ console.log(JSON.stringify(result, null, 2));
356
+ }
357
+
358
+ main();