musubi-sdd 5.0.0 → 5.6.1

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 (232) hide show
  1. package/README.ja.md +106 -48
  2. package/README.md +110 -32
  3. package/bin/musubi-analyze.js +74 -67
  4. package/bin/musubi-browser.js +27 -26
  5. package/bin/musubi-change.js +48 -47
  6. package/bin/musubi-checkpoint.js +10 -7
  7. package/bin/musubi-convert.js +25 -25
  8. package/bin/musubi-costs.js +27 -10
  9. package/bin/musubi-gui.js +52 -46
  10. package/bin/musubi-init.js +1952 -10
  11. package/bin/musubi-orchestrate.js +327 -239
  12. package/bin/musubi-remember.js +69 -56
  13. package/bin/musubi-resolve.js +53 -45
  14. package/bin/musubi-trace.js +51 -22
  15. package/bin/musubi-validate.js +39 -30
  16. package/bin/musubi-workflow.js +33 -34
  17. package/bin/musubi.js +39 -2
  18. package/package.json +1 -1
  19. package/src/agents/agent-loop.js +94 -95
  20. package/src/agents/agentic/code-generator.js +119 -109
  21. package/src/agents/agentic/code-reviewer.js +105 -108
  22. package/src/agents/agentic/index.js +4 -4
  23. package/src/agents/browser/action-executor.js +13 -13
  24. package/src/agents/browser/ai-comparator.js +11 -10
  25. package/src/agents/browser/context-manager.js +6 -6
  26. package/src/agents/browser/index.js +5 -5
  27. package/src/agents/browser/nl-parser.js +31 -46
  28. package/src/agents/browser/screenshot.js +2 -2
  29. package/src/agents/browser/test-generator.js +6 -4
  30. package/src/agents/function-tool.js +71 -65
  31. package/src/agents/index.js +7 -7
  32. package/src/agents/schema-generator.js +98 -94
  33. package/src/analyzers/ast-extractor.js +164 -145
  34. package/src/analyzers/codegraph-auto-update.js +858 -0
  35. package/src/analyzers/complexity-analyzer.js +536 -0
  36. package/src/analyzers/context-optimizer.js +247 -125
  37. package/src/analyzers/impact-analyzer.js +1 -1
  38. package/src/analyzers/large-project-analyzer.js +766 -0
  39. package/src/analyzers/repository-map.js +83 -80
  40. package/src/analyzers/security-analyzer.js +19 -11
  41. package/src/analyzers/stuck-detector.js +19 -17
  42. package/src/converters/index.js +78 -57
  43. package/src/converters/ir/types.js +12 -12
  44. package/src/converters/parsers/musubi-parser.js +134 -126
  45. package/src/converters/parsers/openapi-parser.js +70 -53
  46. package/src/converters/parsers/speckit-parser.js +239 -175
  47. package/src/converters/writers/musubi-writer.js +123 -118
  48. package/src/converters/writers/speckit-writer.js +124 -113
  49. package/src/generators/rust-migration-generator.js +512 -0
  50. package/src/gui/public/index.html +1365 -1211
  51. package/src/gui/server.js +41 -40
  52. package/src/gui/services/file-watcher.js +23 -8
  53. package/src/gui/services/project-scanner.js +26 -20
  54. package/src/gui/services/replanning-service.js +27 -23
  55. package/src/gui/services/traceability-service.js +8 -8
  56. package/src/gui/services/workflow-service.js +14 -7
  57. package/src/index.js +151 -0
  58. package/src/integrations/cicd.js +90 -104
  59. package/src/integrations/codegraph-mcp.js +643 -0
  60. package/src/integrations/documentation.js +142 -103
  61. package/src/integrations/examples.js +95 -80
  62. package/src/integrations/github-client.js +17 -17
  63. package/src/integrations/index.js +5 -5
  64. package/src/integrations/mcp/index.js +21 -21
  65. package/src/integrations/mcp/mcp-context-provider.js +76 -78
  66. package/src/integrations/mcp/mcp-discovery.js +74 -72
  67. package/src/integrations/mcp/mcp-tool-registry.js +99 -94
  68. package/src/integrations/mcp-connector.js +70 -66
  69. package/src/integrations/platforms.js +50 -49
  70. package/src/integrations/tool-discovery.js +37 -31
  71. package/src/llm-providers/anthropic-provider.js +11 -11
  72. package/src/llm-providers/base-provider.js +16 -18
  73. package/src/llm-providers/copilot-provider.js +22 -19
  74. package/src/llm-providers/index.js +26 -25
  75. package/src/llm-providers/ollama-provider.js +11 -11
  76. package/src/llm-providers/openai-provider.js +12 -12
  77. package/src/managers/agent-memory.js +36 -24
  78. package/src/managers/checkpoint-manager.js +4 -8
  79. package/src/managers/delta-spec.js +19 -19
  80. package/src/managers/index.js +13 -4
  81. package/src/managers/memory-condenser.js +35 -45
  82. package/src/managers/repo-skill-manager.js +57 -31
  83. package/src/managers/skill-loader.js +25 -22
  84. package/src/managers/skill-tools.js +36 -72
  85. package/src/managers/workflow.js +30 -22
  86. package/src/monitoring/cost-tracker.js +53 -44
  87. package/src/monitoring/incident-manager.js +123 -103
  88. package/src/monitoring/index.js +144 -134
  89. package/src/monitoring/observability.js +82 -59
  90. package/src/monitoring/quality-dashboard.js +51 -39
  91. package/src/monitoring/release-manager.js +70 -50
  92. package/src/orchestration/agent-skill-binding.js +39 -47
  93. package/src/orchestration/error-handler.js +65 -107
  94. package/src/orchestration/guardrails/base-guardrail.js +26 -24
  95. package/src/orchestration/guardrails/guardrail-rules.js +50 -64
  96. package/src/orchestration/guardrails/index.js +5 -5
  97. package/src/orchestration/guardrails/input-guardrail.js +58 -45
  98. package/src/orchestration/guardrails/output-guardrail.js +104 -81
  99. package/src/orchestration/guardrails/safety-check.js +79 -79
  100. package/src/orchestration/index.js +38 -55
  101. package/src/orchestration/mcp-tool-adapters.js +96 -99
  102. package/src/orchestration/orchestration-engine.js +21 -21
  103. package/src/orchestration/pattern-registry.js +60 -45
  104. package/src/orchestration/patterns/auto.js +34 -47
  105. package/src/orchestration/patterns/group-chat.js +59 -65
  106. package/src/orchestration/patterns/handoff.js +67 -65
  107. package/src/orchestration/patterns/human-in-loop.js +51 -72
  108. package/src/orchestration/patterns/nested.js +25 -40
  109. package/src/orchestration/patterns/sequential.js +35 -34
  110. package/src/orchestration/patterns/swarm.js +63 -56
  111. package/src/orchestration/patterns/triage.js +150 -109
  112. package/src/orchestration/reasoning/index.js +9 -9
  113. package/src/orchestration/reasoning/planning-engine.js +143 -140
  114. package/src/orchestration/reasoning/reasoning-engine.js +206 -144
  115. package/src/orchestration/reasoning/self-correction.js +121 -128
  116. package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
  117. package/src/orchestration/replanning/alternative-generator.js +37 -42
  118. package/src/orchestration/replanning/config.js +63 -59
  119. package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
  120. package/src/orchestration/replanning/index.js +24 -20
  121. package/src/orchestration/replanning/plan-evaluator.js +49 -50
  122. package/src/orchestration/replanning/plan-monitor.js +32 -28
  123. package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
  124. package/src/orchestration/replanning/replan-history.js +33 -26
  125. package/src/orchestration/replanning/replanning-engine.js +106 -108
  126. package/src/orchestration/skill-executor.js +107 -109
  127. package/src/orchestration/skill-registry.js +85 -89
  128. package/src/orchestration/workflow-examples.js +228 -231
  129. package/src/orchestration/workflow-executor.js +65 -68
  130. package/src/orchestration/workflow-orchestrator.js +72 -73
  131. package/src/phase4-integration.js +47 -40
  132. package/src/phase5-integration.js +89 -30
  133. package/src/reporters/coverage-report.js +82 -30
  134. package/src/reporters/hierarchical-reporter.js +498 -0
  135. package/src/reporters/traceability-matrix-report.js +29 -20
  136. package/src/resolvers/issue-resolver.js +43 -31
  137. package/src/steering/advanced-validation.js +133 -124
  138. package/src/steering/auto-updater.js +60 -73
  139. package/src/steering/index.js +6 -6
  140. package/src/steering/quality-metrics.js +41 -35
  141. package/src/steering/steering-auto-update.js +83 -86
  142. package/src/steering/steering-validator.js +98 -106
  143. package/src/steering/template-constraints.js +53 -54
  144. package/src/templates/agents/claude-code/CLAUDE.md +32 -32
  145. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
  146. package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
  147. package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
  148. package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
  149. package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
  150. package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
  151. package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
  152. package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
  153. package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
  154. package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
  155. package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
  156. package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
  157. package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
  158. package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
  159. package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
  160. package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
  161. package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
  162. package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
  163. package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
  164. package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
  165. package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
  166. package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
  167. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
  168. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
  169. package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
  170. package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
  171. package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
  172. package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
  173. package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
  174. package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
  175. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
  176. package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
  177. package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
  178. package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
  179. package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
  180. package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
  181. package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
  182. package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
  183. package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
  184. package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
  185. package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
  186. package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
  187. package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
  188. package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
  189. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
  190. package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
  191. package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
  192. package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
  193. package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
  194. package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
  195. package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
  196. package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
  197. package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
  198. package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
  199. package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
  200. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
  201. package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
  202. package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
  203. package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
  204. package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
  205. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
  206. package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
  207. package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
  208. package/src/templates/agents/codex/AGENTS.md +74 -42
  209. package/src/templates/agents/cursor/AGENTS.md +74 -42
  210. package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
  211. package/src/templates/agents/github-copilot/AGENTS.md +83 -51
  212. package/src/templates/agents/qwen-code/QWEN.md +74 -42
  213. package/src/templates/agents/windsurf/AGENTS.md +74 -42
  214. package/src/templates/architectures/README.md +41 -0
  215. package/src/templates/architectures/clean-architecture/README.md +113 -0
  216. package/src/templates/architectures/event-driven/README.md +162 -0
  217. package/src/templates/architectures/hexagonal/README.md +130 -0
  218. package/src/templates/index.js +6 -1
  219. package/src/templates/locale-manager.js +16 -16
  220. package/src/templates/shared/delta-spec-template.md +20 -13
  221. package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
  222. package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
  223. package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
  224. package/src/templates/shared/steering/structure.md +95 -0
  225. package/src/templates/skills/browser-agent.md +21 -16
  226. package/src/templates/skills/web-gui.md +8 -0
  227. package/src/templates/template-constraints.js +50 -53
  228. package/src/validators/advanced-validation.js +30 -36
  229. package/src/validators/constitutional-validator.js +77 -73
  230. package/src/validators/critic-system.js +49 -59
  231. package/src/validators/delta-format.js +59 -55
  232. package/src/validators/traceability-validator.js +7 -11
@@ -1,11 +1,18 @@
1
1
  /**
2
2
  * Repository Map Generator
3
- *
3
+ *
4
4
  * Generates a comprehensive map of the repository structure for LLM context.
5
5
  * Implements efficient file scanning, caching, and incremental updates.
6
- *
7
- * Part of MUSUBI v4.1.0 - Codebase Intelligence
6
+ *
7
+ * Part of MUSUBI v5.0.0 - Codebase Intelligence
8
+ *
9
+ * @module analyzers/repository-map
8
10
  * @version 1.0.0
11
+ *
12
+ * @traceability
13
+ * - Requirement: REQ-P4-001 (Repository Map Generation)
14
+ * - Design: docs/design/tdd-musubi-v5.0.0.md#2.1
15
+ * - Test: tests/analyzers/repository-map.test.js
9
16
  */
10
17
 
11
18
  const fs = require('fs');
@@ -85,7 +92,7 @@ const LANGUAGE_MAP = {
85
92
  '.gql': 'graphql',
86
93
  '.dockerfile': 'dockerfile',
87
94
  '.vue': 'vue',
88
- '.svelte': 'svelte'
95
+ '.svelte': 'svelte',
89
96
  };
90
97
 
91
98
  /**
@@ -104,7 +111,7 @@ const ENTRY_PATTERNS = [
104
111
  /^pyproject\.toml$/,
105
112
  /^Gemfile$/,
106
113
  /^pom\.xml$/,
107
- /^build\.gradle(\.kts)?$/
114
+ /^build\.gradle(\.kts)?$/,
108
115
  ];
109
116
 
110
117
  /**
@@ -144,7 +151,7 @@ const DEFAULT_IGNORE_PATTERNS = [
144
151
  'pnpm-lock.yaml',
145
152
  'Cargo.lock',
146
153
  'Gemfile.lock',
147
- 'poetry.lock'
154
+ 'poetry.lock',
148
155
  ];
149
156
 
150
157
  /**
@@ -165,41 +172,38 @@ class RepositoryMap extends EventEmitter {
165
172
  constructor(options = {}) {
166
173
  super();
167
174
  this.rootPath = options.rootPath || process.cwd();
168
- this.ignorePatterns = [
169
- ...DEFAULT_IGNORE_PATTERNS,
170
- ...(options.ignorePatterns || [])
171
- ];
175
+ this.ignorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...(options.ignorePatterns || [])];
172
176
  this.maxDepth = options.maxDepth ?? 20;
173
177
  this.maxFiles = options.maxFiles ?? 10000;
174
178
  this.includeContent = options.includeContent ?? false;
175
179
  this.contentMaxSize = options.contentMaxSize ?? 10000;
176
-
180
+
177
181
  // Cache
178
182
  this.cache = new Map();
179
183
  this.lastScanTime = null;
180
-
184
+
181
185
  // Statistics
182
186
  this.stats = {
183
187
  totalFiles: 0,
184
188
  totalDirs: 0,
185
189
  totalSize: 0,
186
190
  byLanguage: {},
187
- byExtension: {}
191
+ byExtension: {},
188
192
  };
189
-
193
+
190
194
  // Results
191
195
  this.files = [];
192
196
  this.structure = {};
193
197
  this.entryPoints = [];
194
198
  }
195
-
199
+
196
200
  /**
197
201
  * Generate repository map
198
202
  * @returns {Promise<RepositoryMap>}
199
203
  */
200
204
  async generate() {
201
205
  this.emit('scan:start', { rootPath: this.rootPath });
202
-
206
+
203
207
  // Reset state
204
208
  this.files = [];
205
209
  this.structure = {};
@@ -209,31 +213,30 @@ class RepositoryMap extends EventEmitter {
209
213
  totalDirs: 0,
210
214
  totalSize: 0,
211
215
  byLanguage: {},
212
- byExtension: {}
216
+ byExtension: {},
213
217
  };
214
-
218
+
215
219
  try {
216
220
  await this.scanDirectory(this.rootPath, '', 0);
217
221
  this.lastScanTime = new Date();
218
-
222
+
219
223
  const result = {
220
224
  root: this.rootPath,
221
225
  generatedAt: this.lastScanTime,
222
226
  files: this.files,
223
227
  stats: this.stats,
224
228
  structure: this.structure,
225
- entryPoints: this.entryPoints
229
+ entryPoints: this.entryPoints,
226
230
  };
227
-
231
+
228
232
  this.emit('scan:complete', result);
229
233
  return result;
230
-
231
234
  } catch (error) {
232
235
  this.emit('scan:error', error);
233
236
  throw error;
234
237
  }
235
238
  }
236
-
239
+
237
240
  /**
238
241
  * Scan a directory recursively
239
242
  * @param {string} dirPath - Absolute directory path
@@ -244,7 +247,7 @@ class RepositoryMap extends EventEmitter {
244
247
  async scanDirectory(dirPath, relativePath, depth) {
245
248
  if (depth > this.maxDepth) return;
246
249
  if (this.files.length >= this.maxFiles) return;
247
-
250
+
248
251
  let entries;
249
252
  try {
250
253
  entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
@@ -252,14 +255,14 @@ class RepositoryMap extends EventEmitter {
252
255
  this.emit('scan:dirError', { path: relativePath, error });
253
256
  return;
254
257
  }
255
-
258
+
256
259
  for (const entry of entries) {
257
260
  if (this.files.length >= this.maxFiles) break;
258
261
  if (this.shouldIgnore(entry.name)) continue;
259
-
262
+
260
263
  const entryRelPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
261
264
  const entryAbsPath = path.join(dirPath, entry.name);
262
-
265
+
263
266
  if (entry.isDirectory()) {
264
267
  this.stats.totalDirs++;
265
268
  this.setStructureNode(entryRelPath, { type: 'directory', children: {} });
@@ -269,7 +272,7 @@ class RepositoryMap extends EventEmitter {
269
272
  }
270
273
  }
271
274
  }
272
-
275
+
273
276
  /**
274
277
  * Process a single file
275
278
  * @param {string} absPath - Absolute file path
@@ -282,13 +285,13 @@ class RepositoryMap extends EventEmitter {
282
285
  const ext = path.extname(relPath).toLowerCase();
283
286
  const basename = path.basename(relPath);
284
287
  const language = LANGUAGE_MAP[ext] || 'unknown';
285
-
288
+
286
289
  // Detect entry points
287
290
  const isEntry = ENTRY_PATTERNS.some(pattern => pattern.test(basename));
288
291
  if (isEntry) {
289
292
  this.entryPoints.push(relPath);
290
293
  }
291
-
294
+
292
295
  // File info
293
296
  const fileInfo = {
294
297
  path: relPath,
@@ -298,15 +301,15 @@ class RepositoryMap extends EventEmitter {
298
301
  mtime: stat.mtime.getTime(),
299
302
  language,
300
303
  isEntry,
301
- exports: []
304
+ exports: [],
302
305
  };
303
-
306
+
304
307
  // Extract exports for JS/TS files
305
308
  if (['javascript', 'typescript'].includes(language) && stat.size < 100000) {
306
309
  const exports = await this.extractExports(absPath);
307
310
  fileInfo.exports = exports;
308
311
  }
309
-
312
+
310
313
  // Optionally include content
311
314
  if (this.includeContent && stat.size <= this.contentMaxSize) {
312
315
  try {
@@ -316,24 +319,23 @@ class RepositoryMap extends EventEmitter {
316
319
  // Binary or unreadable file
317
320
  }
318
321
  }
319
-
322
+
320
323
  // Update statistics
321
324
  this.stats.totalFiles++;
322
325
  this.stats.totalSize += stat.size;
323
326
  this.stats.byLanguage[language] = (this.stats.byLanguage[language] || 0) + 1;
324
327
  this.stats.byExtension[ext] = (this.stats.byExtension[ext] || 0) + 1;
325
-
328
+
326
329
  // Add to results
327
330
  this.files.push(fileInfo);
328
331
  this.setStructureNode(relPath, { type: 'file', language, size: stat.size });
329
-
332
+
330
333
  this.emit('file:processed', fileInfo);
331
-
332
334
  } catch (error) {
333
335
  this.emit('file:error', { path: relPath, error });
334
336
  }
335
337
  }
336
-
338
+
337
339
  /**
338
340
  * Extract exported symbols from JS/TS file
339
341
  * @param {string} filePath - File path
@@ -344,39 +346,40 @@ class RepositoryMap extends EventEmitter {
344
346
  try {
345
347
  const content = await fs.promises.readFile(filePath, 'utf-8');
346
348
  const exports = [];
347
-
349
+
348
350
  // CommonJS exports
349
351
  const cjsMatch = content.match(/module\.exports\s*=\s*\{([^}]+)\}/);
350
352
  if (cjsMatch) {
351
353
  const props = cjsMatch[1].match(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g);
352
354
  if (props) exports.push(...props);
353
355
  }
354
-
356
+
355
357
  // Named exports
356
- const namedExports = content.matchAll(/export\s+(?:const|let|var|function|class|async function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g);
358
+ const namedExports = content.matchAll(
359
+ /export\s+(?:const|let|var|function|class|async function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g
360
+ );
357
361
  for (const match of namedExports) {
358
362
  exports.push(match[1]);
359
363
  }
360
-
364
+
361
365
  // Export statements
362
366
  const exportStmts = content.matchAll(/export\s*\{\s*([^}]+)\s*\}/g);
363
367
  for (const match of exportStmts) {
364
368
  const names = match[1].match(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g);
365
369
  if (names) exports.push(...names);
366
370
  }
367
-
371
+
368
372
  // Default export
369
373
  if (/export\s+default/.test(content)) {
370
374
  exports.push('default');
371
375
  }
372
-
376
+
373
377
  return [...new Set(exports)];
374
-
375
378
  } catch {
376
379
  return [];
377
380
  }
378
381
  }
379
-
382
+
380
383
  /**
381
384
  * Set a node in the structure tree
382
385
  * @param {string} relPath - Relative path
@@ -386,14 +389,14 @@ class RepositoryMap extends EventEmitter {
386
389
  setStructureNode(relPath, value) {
387
390
  const parts = relPath.split('/');
388
391
  let current = this.structure;
389
-
392
+
390
393
  for (let i = 0; i < parts.length - 1; i++) {
391
394
  if (!current[parts[i]]) {
392
395
  current[parts[i]] = { type: 'directory', children: {} };
393
396
  }
394
397
  current = current[parts[i]].children || current[parts[i]];
395
398
  }
396
-
399
+
397
400
  const lastName = parts[parts.length - 1];
398
401
  if (value.type === 'directory') {
399
402
  if (!current[lastName]) {
@@ -403,7 +406,7 @@ class RepositoryMap extends EventEmitter {
403
406
  current[lastName] = value;
404
407
  }
405
408
  }
406
-
409
+
407
410
  /**
408
411
  * Check if a path should be ignored
409
412
  * @param {string} name - File/directory name
@@ -419,7 +422,7 @@ class RepositoryMap extends EventEmitter {
419
422
  return name === pattern;
420
423
  });
421
424
  }
422
-
425
+
423
426
  /**
424
427
  * Get files by language
425
428
  * @param {string} language - Programming language
@@ -428,7 +431,7 @@ class RepositoryMap extends EventEmitter {
428
431
  getFilesByLanguage(language) {
429
432
  return this.files.filter(f => f.language === language);
430
433
  }
431
-
434
+
432
435
  /**
433
436
  * Get files by extension
434
437
  * @param {string} extension - File extension (with dot)
@@ -437,7 +440,7 @@ class RepositoryMap extends EventEmitter {
437
440
  getFilesByExtension(extension) {
438
441
  return this.files.filter(f => f.extension === extension);
439
442
  }
440
-
443
+
441
444
  /**
442
445
  * Get files in directory
443
446
  * @param {string} dirPath - Relative directory path
@@ -447,7 +450,7 @@ class RepositoryMap extends EventEmitter {
447
450
  const prefix = dirPath.endsWith('/') ? dirPath : `${dirPath}/`;
448
451
  return this.files.filter(f => f.path.startsWith(prefix));
449
452
  }
450
-
453
+
451
454
  /**
452
455
  * Search files by pattern
453
456
  * @param {string|RegExp} pattern - Search pattern
@@ -457,7 +460,7 @@ class RepositoryMap extends EventEmitter {
457
460
  const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
458
461
  return this.files.filter(f => regex.test(f.path));
459
462
  }
460
-
463
+
461
464
  /**
462
465
  * Generate tree view string
463
466
  * @param {Object} [node] - Starting node
@@ -467,18 +470,18 @@ class RepositoryMap extends EventEmitter {
467
470
  */
468
471
  toTreeString(node = this.structure, prefix = '', maxDepth = 5) {
469
472
  if (maxDepth <= 0) return prefix + '...\n';
470
-
473
+
471
474
  let result = '';
472
475
  const entries = Object.entries(node);
473
-
476
+
474
477
  for (let i = 0; i < entries.length; i++) {
475
478
  const [name, info] = entries[i];
476
479
  const isLast = i === entries.length - 1;
477
480
  const connector = isLast ? '└── ' : '├── ';
478
481
  const childPrefix = isLast ? ' ' : '│ ';
479
-
482
+
480
483
  result += `${prefix}${connector}${name}`;
481
-
484
+
482
485
  if (info.type === 'file') {
483
486
  result += ` (${info.language})\n`;
484
487
  } else {
@@ -488,10 +491,10 @@ class RepositoryMap extends EventEmitter {
488
491
  }
489
492
  }
490
493
  }
491
-
494
+
492
495
  return result;
493
496
  }
494
-
497
+
495
498
  /**
496
499
  * Generate LLM-optimized context
497
500
  * @param {Object} options - Context options
@@ -502,17 +505,17 @@ class RepositoryMap extends EventEmitter {
502
505
  */
503
506
  toLLMContext(options = {}) {
504
507
  const { maxTokens = 4000, focusPaths = [], languages = [] } = options;
505
-
508
+
506
509
  let context = `# Repository Map\n\n`;
507
510
  context += `**Root**: ${this.rootPath}\n`;
508
511
  context += `**Generated**: ${this.lastScanTime?.toISOString() || 'N/A'}\n\n`;
509
-
512
+
510
513
  // Statistics
511
514
  context += `## Statistics\n\n`;
512
515
  context += `- Total Files: ${this.stats.totalFiles}\n`;
513
516
  context += `- Total Directories: ${this.stats.totalDirs}\n`;
514
517
  context += `- Total Size: ${this.formatBytes(this.stats.totalSize)}\n\n`;
515
-
518
+
516
519
  // Language breakdown
517
520
  context += `### Languages\n\n`;
518
521
  const langEntries = Object.entries(this.stats.byLanguage)
@@ -522,7 +525,7 @@ class RepositoryMap extends EventEmitter {
522
525
  context += `- ${lang}: ${count} files\n`;
523
526
  }
524
527
  context += '\n';
525
-
528
+
526
529
  // Entry points
527
530
  if (this.entryPoints.length > 0) {
528
531
  context += `## Entry Points\n\n`;
@@ -531,36 +534,36 @@ class RepositoryMap extends EventEmitter {
531
534
  }
532
535
  context += '\n';
533
536
  }
534
-
537
+
535
538
  // Structure (token-limited)
536
539
  context += `## Structure\n\n\`\`\`\n`;
537
540
  const treeStr = this.toTreeString(this.structure, '', 4);
538
541
  const truncatedTree = this.truncateToTokens(treeStr, Math.floor(maxTokens * 0.6));
539
542
  context += truncatedTree;
540
543
  context += `\`\`\`\n\n`;
541
-
544
+
542
545
  // Key files
543
546
  let keyFiles = this.files;
544
-
547
+
545
548
  // Filter by focus paths
546
549
  if (focusPaths.length > 0) {
547
- keyFiles = keyFiles.filter(f =>
550
+ keyFiles = keyFiles.filter(f =>
548
551
  focusPaths.some(fp => f.path.startsWith(fp) || f.path.includes(fp))
549
552
  );
550
553
  }
551
-
554
+
552
555
  // Filter by languages
553
556
  if (languages.length > 0) {
554
557
  keyFiles = keyFiles.filter(f => languages.includes(f.language));
555
558
  }
556
-
559
+
557
560
  // Sort by importance (entry points first, then by size)
558
561
  keyFiles.sort((a, b) => {
559
562
  if (a.isEntry && !b.isEntry) return -1;
560
563
  if (!a.isEntry && b.isEntry) return 1;
561
564
  return b.exports.length - a.exports.length;
562
565
  });
563
-
566
+
564
567
  // Add key files with exports
565
568
  context += `## Key Modules\n\n`;
566
569
  for (const file of keyFiles.slice(0, 20)) {
@@ -574,10 +577,10 @@ class RepositoryMap extends EventEmitter {
574
577
  context += '\n';
575
578
  }
576
579
  }
577
-
580
+
578
581
  return context;
579
582
  }
580
-
583
+
581
584
  /**
582
585
  * Format bytes to human readable
583
586
  * @param {number} bytes - Size in bytes
@@ -591,7 +594,7 @@ class RepositoryMap extends EventEmitter {
591
594
  const i = Math.floor(Math.log(bytes) / Math.log(k));
592
595
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
593
596
  }
594
-
597
+
595
598
  /**
596
599
  * Truncate string to approximate token count
597
600
  * @param {string} str - Input string
@@ -605,7 +608,7 @@ class RepositoryMap extends EventEmitter {
605
608
  if (str.length <= maxChars) return str;
606
609
  return str.slice(0, maxChars) + '\n... (truncated)\n';
607
610
  }
608
-
611
+
609
612
  /**
610
613
  * Export to JSON
611
614
  * @returns {Object}
@@ -617,10 +620,10 @@ class RepositoryMap extends EventEmitter {
617
620
  stats: this.stats,
618
621
  files: this.files,
619
622
  entryPoints: this.entryPoints,
620
- structure: this.structure
623
+ structure: this.structure,
621
624
  };
622
625
  }
623
-
626
+
624
627
  /**
625
628
  * Import from JSON
626
629
  * @param {Object} data - JSON data
@@ -633,7 +636,7 @@ class RepositoryMap extends EventEmitter {
633
636
  this.entryPoints = data.entryPoints;
634
637
  this.structure = data.structure;
635
638
  }
636
-
639
+
637
640
  /**
638
641
  * Get cache key for incremental updates
639
642
  * @returns {string}
@@ -641,7 +644,7 @@ class RepositoryMap extends EventEmitter {
641
644
  getCacheKey() {
642
645
  return `repomap:${this.rootPath}`;
643
646
  }
644
-
647
+
645
648
  /**
646
649
  * Check if file has changed since last scan
647
650
  * @param {string} filePath - Relative file path
@@ -681,5 +684,5 @@ module.exports = {
681
684
  generateRepositoryMap,
682
685
  LANGUAGE_MAP,
683
686
  ENTRY_PATTERNS,
684
- DEFAULT_IGNORE_PATTERNS
687
+ DEFAULT_IGNORE_PATTERNS,
685
688
  };
@@ -87,7 +87,7 @@ const SECURITY_PATTERNS = {
87
87
  ],
88
88
  dangerousCommands: [
89
89
  {
90
- pattern: /rm\s+(-rf?|--recursive)\s+[\/~]/g,
90
+ pattern: /rm\s+(-rf?|--recursive)\s+[/~]/g,
91
91
  name: 'Recursive Delete (root/home)',
92
92
  level: RiskLevel.CRITICAL,
93
93
  },
@@ -316,7 +316,7 @@ class SecurityAnalysisResult {
316
316
  */
317
317
  exceedsThreshold(threshold) {
318
318
  const thresholdSeverity = RISK_SEVERITY[threshold] || 2;
319
- return this.risks.some((risk) => risk.getSeverity() >= thresholdSeverity);
319
+ return this.risks.some(risk => risk.getSeverity() >= thresholdSeverity);
320
320
  }
321
321
 
322
322
  /**
@@ -324,7 +324,7 @@ class SecurityAnalysisResult {
324
324
  * @param {string} level
325
325
  */
326
326
  getRisksByLevel(level) {
327
- return this.risks.filter((risk) => risk.level === level);
327
+ return this.risks.filter(risk => risk.level === level);
328
328
  }
329
329
 
330
330
  /**
@@ -332,14 +332,14 @@ class SecurityAnalysisResult {
332
332
  * @param {string} category
333
333
  */
334
334
  getRisksByCategory(category) {
335
- return this.risks.filter((risk) => risk.category === category);
335
+ return this.risks.filter(risk => risk.category === category);
336
336
  }
337
337
 
338
338
  /**
339
339
  * Check if action should be blocked
340
340
  */
341
341
  shouldBlock() {
342
- return this.risks.some((risk) => risk.level === RiskLevel.CRITICAL);
342
+ return this.risks.some(risk => risk.level === RiskLevel.CRITICAL);
343
343
  }
344
344
 
345
345
  /**
@@ -375,7 +375,7 @@ class SecurityAnalysisResult {
375
375
 
376
376
  toJSON() {
377
377
  return {
378
- risks: this.risks.map((r) => r.toJSON()),
378
+ risks: this.risks.map(r => r.toJSON()),
379
379
  summary: this.getSummary(),
380
380
  timestamp: this.timestamp.toISOString(),
381
381
  };
@@ -527,7 +527,7 @@ class SecurityAnalyzer {
527
527
  * @param {string} command
528
528
  */
529
529
  isAllowedCommand(command) {
530
- return this.options.allowedCommands.some((allowed) => command.includes(allowed));
530
+ return this.options.allowedCommands.some(allowed => command.includes(allowed));
531
531
  }
532
532
 
533
533
  /**
@@ -535,7 +535,7 @@ class SecurityAnalyzer {
535
535
  * @param {string} filePath
536
536
  */
537
537
  shouldIgnorePath(filePath) {
538
- return this.options.ignorePaths.some((pattern) => {
538
+ return this.options.ignorePaths.some(pattern => {
539
539
  if (pattern.includes('*')) {
540
540
  const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
541
541
  return regex.test(filePath);
@@ -590,7 +590,7 @@ class SecurityAnalyzer {
590
590
  if (result.shouldBlock()) {
591
591
  return {
592
592
  allowed: false,
593
- reason: `Critical security risk detected: ${result.risks.find((r) => r.level === RiskLevel.CRITICAL).name}`,
593
+ reason: `Critical security risk detected: ${result.risks.find(r => r.level === RiskLevel.CRITICAL).name}`,
594
594
  result,
595
595
  };
596
596
  }
@@ -605,7 +605,10 @@ class SecurityAnalyzer {
605
605
 
606
606
  return {
607
607
  allowed: true,
608
- reason: result.risks.length > 0 ? `${result.risks.length} low-level risks detected but within threshold` : 'No security risks detected',
608
+ reason:
609
+ result.risks.length > 0
610
+ ? `${result.risks.length} low-level risks detected but within threshold`
611
+ : 'No security risks detected',
609
612
  result,
610
613
  };
611
614
  }
@@ -632,7 +635,12 @@ class SecurityAnalyzer {
632
635
  * @returns {string}
633
636
  */
634
637
  generateReport(result) {
635
- const lines = ['# Security Analysis Report', '', `Generated: ${result.timestamp.toISOString()}`, ''];
638
+ const lines = [
639
+ '# Security Analysis Report',
640
+ '',
641
+ `Generated: ${result.timestamp.toISOString()}`,
642
+ '',
643
+ ];
636
644
 
637
645
  const summary = result.getSummary();
638
646