musubi-sdd 5.1.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 +158 -146
  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 +241 -126
  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 +77 -81
  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 +48 -46
  87. package/src/monitoring/incident-manager.js +116 -106
  88. package/src/monitoring/index.js +144 -134
  89. package/src/monitoring/observability.js +75 -62
  90. package/src/monitoring/quality-dashboard.js +45 -41
  91. package/src/monitoring/release-manager.js +63 -53
  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,14 +1,14 @@
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
- *
6
+ *
7
7
  * Part of MUSUBI v5.0.0 - Codebase Intelligence
8
- *
8
+ *
9
9
  * @module analyzers/repository-map
10
10
  * @version 1.0.0
11
- *
11
+ *
12
12
  * @traceability
13
13
  * - Requirement: REQ-P4-001 (Repository Map Generation)
14
14
  * - Design: docs/design/tdd-musubi-v5.0.0.md#2.1
@@ -92,7 +92,7 @@ const LANGUAGE_MAP = {
92
92
  '.gql': 'graphql',
93
93
  '.dockerfile': 'dockerfile',
94
94
  '.vue': 'vue',
95
- '.svelte': 'svelte'
95
+ '.svelte': 'svelte',
96
96
  };
97
97
 
98
98
  /**
@@ -111,7 +111,7 @@ const ENTRY_PATTERNS = [
111
111
  /^pyproject\.toml$/,
112
112
  /^Gemfile$/,
113
113
  /^pom\.xml$/,
114
- /^build\.gradle(\.kts)?$/
114
+ /^build\.gradle(\.kts)?$/,
115
115
  ];
116
116
 
117
117
  /**
@@ -151,7 +151,7 @@ const DEFAULT_IGNORE_PATTERNS = [
151
151
  'pnpm-lock.yaml',
152
152
  'Cargo.lock',
153
153
  'Gemfile.lock',
154
- 'poetry.lock'
154
+ 'poetry.lock',
155
155
  ];
156
156
 
157
157
  /**
@@ -172,41 +172,38 @@ class RepositoryMap extends EventEmitter {
172
172
  constructor(options = {}) {
173
173
  super();
174
174
  this.rootPath = options.rootPath || process.cwd();
175
- this.ignorePatterns = [
176
- ...DEFAULT_IGNORE_PATTERNS,
177
- ...(options.ignorePatterns || [])
178
- ];
175
+ this.ignorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...(options.ignorePatterns || [])];
179
176
  this.maxDepth = options.maxDepth ?? 20;
180
177
  this.maxFiles = options.maxFiles ?? 10000;
181
178
  this.includeContent = options.includeContent ?? false;
182
179
  this.contentMaxSize = options.contentMaxSize ?? 10000;
183
-
180
+
184
181
  // Cache
185
182
  this.cache = new Map();
186
183
  this.lastScanTime = null;
187
-
184
+
188
185
  // Statistics
189
186
  this.stats = {
190
187
  totalFiles: 0,
191
188
  totalDirs: 0,
192
189
  totalSize: 0,
193
190
  byLanguage: {},
194
- byExtension: {}
191
+ byExtension: {},
195
192
  };
196
-
193
+
197
194
  // Results
198
195
  this.files = [];
199
196
  this.structure = {};
200
197
  this.entryPoints = [];
201
198
  }
202
-
199
+
203
200
  /**
204
201
  * Generate repository map
205
202
  * @returns {Promise<RepositoryMap>}
206
203
  */
207
204
  async generate() {
208
205
  this.emit('scan:start', { rootPath: this.rootPath });
209
-
206
+
210
207
  // Reset state
211
208
  this.files = [];
212
209
  this.structure = {};
@@ -216,31 +213,30 @@ class RepositoryMap extends EventEmitter {
216
213
  totalDirs: 0,
217
214
  totalSize: 0,
218
215
  byLanguage: {},
219
- byExtension: {}
216
+ byExtension: {},
220
217
  };
221
-
218
+
222
219
  try {
223
220
  await this.scanDirectory(this.rootPath, '', 0);
224
221
  this.lastScanTime = new Date();
225
-
222
+
226
223
  const result = {
227
224
  root: this.rootPath,
228
225
  generatedAt: this.lastScanTime,
229
226
  files: this.files,
230
227
  stats: this.stats,
231
228
  structure: this.structure,
232
- entryPoints: this.entryPoints
229
+ entryPoints: this.entryPoints,
233
230
  };
234
-
231
+
235
232
  this.emit('scan:complete', result);
236
233
  return result;
237
-
238
234
  } catch (error) {
239
235
  this.emit('scan:error', error);
240
236
  throw error;
241
237
  }
242
238
  }
243
-
239
+
244
240
  /**
245
241
  * Scan a directory recursively
246
242
  * @param {string} dirPath - Absolute directory path
@@ -251,7 +247,7 @@ class RepositoryMap extends EventEmitter {
251
247
  async scanDirectory(dirPath, relativePath, depth) {
252
248
  if (depth > this.maxDepth) return;
253
249
  if (this.files.length >= this.maxFiles) return;
254
-
250
+
255
251
  let entries;
256
252
  try {
257
253
  entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
@@ -259,14 +255,14 @@ class RepositoryMap extends EventEmitter {
259
255
  this.emit('scan:dirError', { path: relativePath, error });
260
256
  return;
261
257
  }
262
-
258
+
263
259
  for (const entry of entries) {
264
260
  if (this.files.length >= this.maxFiles) break;
265
261
  if (this.shouldIgnore(entry.name)) continue;
266
-
262
+
267
263
  const entryRelPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
268
264
  const entryAbsPath = path.join(dirPath, entry.name);
269
-
265
+
270
266
  if (entry.isDirectory()) {
271
267
  this.stats.totalDirs++;
272
268
  this.setStructureNode(entryRelPath, { type: 'directory', children: {} });
@@ -276,7 +272,7 @@ class RepositoryMap extends EventEmitter {
276
272
  }
277
273
  }
278
274
  }
279
-
275
+
280
276
  /**
281
277
  * Process a single file
282
278
  * @param {string} absPath - Absolute file path
@@ -289,13 +285,13 @@ class RepositoryMap extends EventEmitter {
289
285
  const ext = path.extname(relPath).toLowerCase();
290
286
  const basename = path.basename(relPath);
291
287
  const language = LANGUAGE_MAP[ext] || 'unknown';
292
-
288
+
293
289
  // Detect entry points
294
290
  const isEntry = ENTRY_PATTERNS.some(pattern => pattern.test(basename));
295
291
  if (isEntry) {
296
292
  this.entryPoints.push(relPath);
297
293
  }
298
-
294
+
299
295
  // File info
300
296
  const fileInfo = {
301
297
  path: relPath,
@@ -305,15 +301,15 @@ class RepositoryMap extends EventEmitter {
305
301
  mtime: stat.mtime.getTime(),
306
302
  language,
307
303
  isEntry,
308
- exports: []
304
+ exports: [],
309
305
  };
310
-
306
+
311
307
  // Extract exports for JS/TS files
312
308
  if (['javascript', 'typescript'].includes(language) && stat.size < 100000) {
313
309
  const exports = await this.extractExports(absPath);
314
310
  fileInfo.exports = exports;
315
311
  }
316
-
312
+
317
313
  // Optionally include content
318
314
  if (this.includeContent && stat.size <= this.contentMaxSize) {
319
315
  try {
@@ -323,24 +319,23 @@ class RepositoryMap extends EventEmitter {
323
319
  // Binary or unreadable file
324
320
  }
325
321
  }
326
-
322
+
327
323
  // Update statistics
328
324
  this.stats.totalFiles++;
329
325
  this.stats.totalSize += stat.size;
330
326
  this.stats.byLanguage[language] = (this.stats.byLanguage[language] || 0) + 1;
331
327
  this.stats.byExtension[ext] = (this.stats.byExtension[ext] || 0) + 1;
332
-
328
+
333
329
  // Add to results
334
330
  this.files.push(fileInfo);
335
331
  this.setStructureNode(relPath, { type: 'file', language, size: stat.size });
336
-
332
+
337
333
  this.emit('file:processed', fileInfo);
338
-
339
334
  } catch (error) {
340
335
  this.emit('file:error', { path: relPath, error });
341
336
  }
342
337
  }
343
-
338
+
344
339
  /**
345
340
  * Extract exported symbols from JS/TS file
346
341
  * @param {string} filePath - File path
@@ -351,39 +346,40 @@ class RepositoryMap extends EventEmitter {
351
346
  try {
352
347
  const content = await fs.promises.readFile(filePath, 'utf-8');
353
348
  const exports = [];
354
-
349
+
355
350
  // CommonJS exports
356
351
  const cjsMatch = content.match(/module\.exports\s*=\s*\{([^}]+)\}/);
357
352
  if (cjsMatch) {
358
353
  const props = cjsMatch[1].match(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g);
359
354
  if (props) exports.push(...props);
360
355
  }
361
-
356
+
362
357
  // Named exports
363
- 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
+ );
364
361
  for (const match of namedExports) {
365
362
  exports.push(match[1]);
366
363
  }
367
-
364
+
368
365
  // Export statements
369
366
  const exportStmts = content.matchAll(/export\s*\{\s*([^}]+)\s*\}/g);
370
367
  for (const match of exportStmts) {
371
368
  const names = match[1].match(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g);
372
369
  if (names) exports.push(...names);
373
370
  }
374
-
371
+
375
372
  // Default export
376
373
  if (/export\s+default/.test(content)) {
377
374
  exports.push('default');
378
375
  }
379
-
376
+
380
377
  return [...new Set(exports)];
381
-
382
378
  } catch {
383
379
  return [];
384
380
  }
385
381
  }
386
-
382
+
387
383
  /**
388
384
  * Set a node in the structure tree
389
385
  * @param {string} relPath - Relative path
@@ -393,14 +389,14 @@ class RepositoryMap extends EventEmitter {
393
389
  setStructureNode(relPath, value) {
394
390
  const parts = relPath.split('/');
395
391
  let current = this.structure;
396
-
392
+
397
393
  for (let i = 0; i < parts.length - 1; i++) {
398
394
  if (!current[parts[i]]) {
399
395
  current[parts[i]] = { type: 'directory', children: {} };
400
396
  }
401
397
  current = current[parts[i]].children || current[parts[i]];
402
398
  }
403
-
399
+
404
400
  const lastName = parts[parts.length - 1];
405
401
  if (value.type === 'directory') {
406
402
  if (!current[lastName]) {
@@ -410,7 +406,7 @@ class RepositoryMap extends EventEmitter {
410
406
  current[lastName] = value;
411
407
  }
412
408
  }
413
-
409
+
414
410
  /**
415
411
  * Check if a path should be ignored
416
412
  * @param {string} name - File/directory name
@@ -426,7 +422,7 @@ class RepositoryMap extends EventEmitter {
426
422
  return name === pattern;
427
423
  });
428
424
  }
429
-
425
+
430
426
  /**
431
427
  * Get files by language
432
428
  * @param {string} language - Programming language
@@ -435,7 +431,7 @@ class RepositoryMap extends EventEmitter {
435
431
  getFilesByLanguage(language) {
436
432
  return this.files.filter(f => f.language === language);
437
433
  }
438
-
434
+
439
435
  /**
440
436
  * Get files by extension
441
437
  * @param {string} extension - File extension (with dot)
@@ -444,7 +440,7 @@ class RepositoryMap extends EventEmitter {
444
440
  getFilesByExtension(extension) {
445
441
  return this.files.filter(f => f.extension === extension);
446
442
  }
447
-
443
+
448
444
  /**
449
445
  * Get files in directory
450
446
  * @param {string} dirPath - Relative directory path
@@ -454,7 +450,7 @@ class RepositoryMap extends EventEmitter {
454
450
  const prefix = dirPath.endsWith('/') ? dirPath : `${dirPath}/`;
455
451
  return this.files.filter(f => f.path.startsWith(prefix));
456
452
  }
457
-
453
+
458
454
  /**
459
455
  * Search files by pattern
460
456
  * @param {string|RegExp} pattern - Search pattern
@@ -464,7 +460,7 @@ class RepositoryMap extends EventEmitter {
464
460
  const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
465
461
  return this.files.filter(f => regex.test(f.path));
466
462
  }
467
-
463
+
468
464
  /**
469
465
  * Generate tree view string
470
466
  * @param {Object} [node] - Starting node
@@ -474,18 +470,18 @@ class RepositoryMap extends EventEmitter {
474
470
  */
475
471
  toTreeString(node = this.structure, prefix = '', maxDepth = 5) {
476
472
  if (maxDepth <= 0) return prefix + '...\n';
477
-
473
+
478
474
  let result = '';
479
475
  const entries = Object.entries(node);
480
-
476
+
481
477
  for (let i = 0; i < entries.length; i++) {
482
478
  const [name, info] = entries[i];
483
479
  const isLast = i === entries.length - 1;
484
480
  const connector = isLast ? '└── ' : '├── ';
485
481
  const childPrefix = isLast ? ' ' : '│ ';
486
-
482
+
487
483
  result += `${prefix}${connector}${name}`;
488
-
484
+
489
485
  if (info.type === 'file') {
490
486
  result += ` (${info.language})\n`;
491
487
  } else {
@@ -495,10 +491,10 @@ class RepositoryMap extends EventEmitter {
495
491
  }
496
492
  }
497
493
  }
498
-
494
+
499
495
  return result;
500
496
  }
501
-
497
+
502
498
  /**
503
499
  * Generate LLM-optimized context
504
500
  * @param {Object} options - Context options
@@ -509,17 +505,17 @@ class RepositoryMap extends EventEmitter {
509
505
  */
510
506
  toLLMContext(options = {}) {
511
507
  const { maxTokens = 4000, focusPaths = [], languages = [] } = options;
512
-
508
+
513
509
  let context = `# Repository Map\n\n`;
514
510
  context += `**Root**: ${this.rootPath}\n`;
515
511
  context += `**Generated**: ${this.lastScanTime?.toISOString() || 'N/A'}\n\n`;
516
-
512
+
517
513
  // Statistics
518
514
  context += `## Statistics\n\n`;
519
515
  context += `- Total Files: ${this.stats.totalFiles}\n`;
520
516
  context += `- Total Directories: ${this.stats.totalDirs}\n`;
521
517
  context += `- Total Size: ${this.formatBytes(this.stats.totalSize)}\n\n`;
522
-
518
+
523
519
  // Language breakdown
524
520
  context += `### Languages\n\n`;
525
521
  const langEntries = Object.entries(this.stats.byLanguage)
@@ -529,7 +525,7 @@ class RepositoryMap extends EventEmitter {
529
525
  context += `- ${lang}: ${count} files\n`;
530
526
  }
531
527
  context += '\n';
532
-
528
+
533
529
  // Entry points
534
530
  if (this.entryPoints.length > 0) {
535
531
  context += `## Entry Points\n\n`;
@@ -538,36 +534,36 @@ class RepositoryMap extends EventEmitter {
538
534
  }
539
535
  context += '\n';
540
536
  }
541
-
537
+
542
538
  // Structure (token-limited)
543
539
  context += `## Structure\n\n\`\`\`\n`;
544
540
  const treeStr = this.toTreeString(this.structure, '', 4);
545
541
  const truncatedTree = this.truncateToTokens(treeStr, Math.floor(maxTokens * 0.6));
546
542
  context += truncatedTree;
547
543
  context += `\`\`\`\n\n`;
548
-
544
+
549
545
  // Key files
550
546
  let keyFiles = this.files;
551
-
547
+
552
548
  // Filter by focus paths
553
549
  if (focusPaths.length > 0) {
554
- keyFiles = keyFiles.filter(f =>
550
+ keyFiles = keyFiles.filter(f =>
555
551
  focusPaths.some(fp => f.path.startsWith(fp) || f.path.includes(fp))
556
552
  );
557
553
  }
558
-
554
+
559
555
  // Filter by languages
560
556
  if (languages.length > 0) {
561
557
  keyFiles = keyFiles.filter(f => languages.includes(f.language));
562
558
  }
563
-
559
+
564
560
  // Sort by importance (entry points first, then by size)
565
561
  keyFiles.sort((a, b) => {
566
562
  if (a.isEntry && !b.isEntry) return -1;
567
563
  if (!a.isEntry && b.isEntry) return 1;
568
564
  return b.exports.length - a.exports.length;
569
565
  });
570
-
566
+
571
567
  // Add key files with exports
572
568
  context += `## Key Modules\n\n`;
573
569
  for (const file of keyFiles.slice(0, 20)) {
@@ -581,10 +577,10 @@ class RepositoryMap extends EventEmitter {
581
577
  context += '\n';
582
578
  }
583
579
  }
584
-
580
+
585
581
  return context;
586
582
  }
587
-
583
+
588
584
  /**
589
585
  * Format bytes to human readable
590
586
  * @param {number} bytes - Size in bytes
@@ -598,7 +594,7 @@ class RepositoryMap extends EventEmitter {
598
594
  const i = Math.floor(Math.log(bytes) / Math.log(k));
599
595
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
600
596
  }
601
-
597
+
602
598
  /**
603
599
  * Truncate string to approximate token count
604
600
  * @param {string} str - Input string
@@ -612,7 +608,7 @@ class RepositoryMap extends EventEmitter {
612
608
  if (str.length <= maxChars) return str;
613
609
  return str.slice(0, maxChars) + '\n... (truncated)\n';
614
610
  }
615
-
611
+
616
612
  /**
617
613
  * Export to JSON
618
614
  * @returns {Object}
@@ -624,10 +620,10 @@ class RepositoryMap extends EventEmitter {
624
620
  stats: this.stats,
625
621
  files: this.files,
626
622
  entryPoints: this.entryPoints,
627
- structure: this.structure
623
+ structure: this.structure,
628
624
  };
629
625
  }
630
-
626
+
631
627
  /**
632
628
  * Import from JSON
633
629
  * @param {Object} data - JSON data
@@ -640,7 +636,7 @@ class RepositoryMap extends EventEmitter {
640
636
  this.entryPoints = data.entryPoints;
641
637
  this.structure = data.structure;
642
638
  }
643
-
639
+
644
640
  /**
645
641
  * Get cache key for incremental updates
646
642
  * @returns {string}
@@ -648,7 +644,7 @@ class RepositoryMap extends EventEmitter {
648
644
  getCacheKey() {
649
645
  return `repomap:${this.rootPath}`;
650
646
  }
651
-
647
+
652
648
  /**
653
649
  * Check if file has changed since last scan
654
650
  * @param {string} filePath - Relative file path
@@ -688,5 +684,5 @@ module.exports = {
688
684
  generateRepositoryMap,
689
685
  LANGUAGE_MAP,
690
686
  ENTRY_PATTERNS,
691
- DEFAULT_IGNORE_PATTERNS
687
+ DEFAULT_IGNORE_PATTERNS,
692
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