@girardelli/architect 2.1.0 → 4.0.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 (296) hide show
  1. package/README.md +105 -116
  2. package/__test_agent_output__/INDEX.md +1 -0
  3. package/__test_agent_output__/agents/AGENT-ORCHESTRATOR.md +1 -0
  4. package/__test_agent_output__/agents/DATABASE-ENGINEER.md +174 -0
  5. package/__test_agent_output__/agents/QA-TEST-ENGINEER.md +138 -0
  6. package/__test_agent_output__/agents/SECURITY-AUDITOR.md +106 -0
  7. package/__test_agent_output__/agents/TECH-DEBT-CONTROLLER.md +104 -0
  8. package/__test_agent_output__/agents/TYPESCRIPT-BACKEND-DEVELOPER.md +135 -0
  9. package/__test_agent_output__/guards/CODE-REVIEW-CHECKLIST.md +95 -0
  10. package/__test_agent_output__/guards/PREFLIGHT.md +200 -0
  11. package/__test_agent_output__/guards/QUALITY-GATES.md +1 -0
  12. package/__test_agent_output__/rules/00-general.md +229 -0
  13. package/__test_agent_output__/rules/01-architecture.md +191 -0
  14. package/__test_agent_output__/rules/02-security.md +402 -0
  15. package/__test_agent_output__/rules/03-nestjs.md +124 -0
  16. package/__test_agent_output__/templates/ADR.md +95 -0
  17. package/__test_agent_output__/templates/BDD.md +58 -0
  18. package/__test_agent_output__/templates/C4.md +68 -0
  19. package/__test_agent_output__/templates/TDD.md +86 -0
  20. package/__test_agent_output__/templates/THREAT-MODEL.md +82 -0
  21. package/__test_agent_output__/workflows/fix-bug.md +228 -0
  22. package/__test_agent_output__/workflows/new-feature.md +311 -0
  23. package/__test_agent_output__/workflows/review.md +95 -0
  24. package/__test_context_7RvUrO/src/modules/empty/empty.ts +0 -0
  25. package/__test_context_Rf5fNJ/src/modules/mixed/mixed.ts +5 -0
  26. package/__test_context_WRCnYH/src/modules/test/test.ts +10 -0
  27. package/__test_context_YsnVS3/src/modules/test/test.ts +10 -0
  28. package/__test_context_w7XZeH/src/modules/mixed/mixed.ts +5 -0
  29. package/__test_context_y5noh6/src/modules/empty/empty.ts +0 -0
  30. package/__test_framework__24OjAu/package.json +1 -0
  31. package/__test_framework__3ZDZsx/pyproject.toml +8 -0
  32. package/__test_framework__4T54Jn/package.json +1 -0
  33. package/__test_framework__4tlXu9/pyproject.toml +8 -0
  34. package/__test_framework__6boWqQ/Pipfile +6 -0
  35. package/__test_framework__6gygMU/pom.xml +10 -0
  36. package/__test_framework__6kxj0N/go.mod +8 -0
  37. package/__test_framework__7CEoXw/pom.xml +10 -0
  38. package/__test_framework__85DDz0/Pipfile +6 -0
  39. package/__test_framework__9WrRIr/pom.xml +7 -0
  40. package/__test_framework__ANqGKl/Gemfile +5 -0
  41. package/__test_framework__BCXTEM/go.mod +3 -0
  42. package/__test_framework__BHiPNq/setup.py +2 -0
  43. package/__test_framework__BqkiKv/package.json +1 -0
  44. package/__test_framework__C5yd8X/Pipfile.lock +1 -0
  45. package/__test_framework__C5yd8X/requirements.txt +1 -0
  46. package/__test_framework__C87d3a/manage.py +1 -0
  47. package/__test_framework__C87d3a/requirements.txt +2 -0
  48. package/__test_framework__DXNwc5/build.gradle +7 -0
  49. package/__test_framework__GhHSt3/build.gradle.kts +4 -0
  50. package/__test_framework__GzklJP/Cargo.toml +7 -0
  51. package/__test_framework__H4hd13/go.mod +8 -0
  52. package/__test_framework__HKjOXO/composer.json +1 -0
  53. package/__test_framework__HaDN45/Gemfile +3 -0
  54. package/__test_framework__IBO7YG/pyproject.toml +9 -0
  55. package/__test_framework__JwSOyF/pyproject.toml +6 -0
  56. package/__test_framework__K6HrCr/build.gradle +2 -0
  57. package/__test_framework__KzRPlh/pubspec.yaml +9 -0
  58. package/__test_framework__L6uIym/pyproject.toml +6 -0
  59. package/__test_framework__LOdoGK/requirements.txt +4 -0
  60. package/__test_framework__LgHzss/package.json +1 -0
  61. package/__test_framework__M76M6q/Gemfile +5 -0
  62. package/__test_framework__Mr9vWW/composer.json +1 -0
  63. package/__test_framework__N03Gnv/package.json +1 -0
  64. package/__test_framework__Num4UE/requirements +1 -0
  65. package/__test_framework__OAGw3Y/build.gradle +7 -0
  66. package/__test_framework__OQc8yG/pubspec.yaml +9 -0
  67. package/__test_framework__OwKZcd/requirements.txt +3 -0
  68. package/__test_framework__P0gFv7/requirements +1 -0
  69. package/__test_framework__PN55Rq/package.json +1 -0
  70. package/__test_framework__PQiqX8/pubspec.yaml +3 -0
  71. package/__test_framework__RBHsg7/composer.json +1 -0
  72. package/__test_framework__RHxif4/Cargo.toml +7 -0
  73. package/__test_framework__T0v0p1/Cargo.toml +4 -0
  74. package/__test_framework__Tu0clt/Pipfile.lock +1 -0
  75. package/__test_framework__Tu0clt/requirements.txt +1 -0
  76. package/__test_framework__TwDj9P/Cargo.toml +4 -0
  77. package/__test_framework__VQJNC4/pom.xml +7 -0
  78. package/__test_framework__W6sm05/package.json +1 -0
  79. package/__test_framework__W7vBLy/pyproject.toml +4 -0
  80. package/__test_framework__WNJOWT/setup.py +2 -0
  81. package/__test_framework__WSJs7U/package.json +1 -0
  82. package/__test_framework__YQ5VpA/build.gradle.kts +4 -0
  83. package/__test_framework__ZNEUEs/package.json +1 -0
  84. package/__test_framework__Znt922/pom.xml +7 -0
  85. package/__test_framework__azyg0h/pom.xml +7 -0
  86. package/__test_framework__c6otLr/package.json +1 -0
  87. package/__test_framework__cl9S9G/build.gradle +2 -0
  88. package/__test_framework__eilvV4/composer.json +1 -0
  89. package/__test_framework__gQZxXO/manage.py +1 -0
  90. package/__test_framework__gQZxXO/requirements.txt +2 -0
  91. package/__test_framework__ghvl26/poetry.lock +1 -0
  92. package/__test_framework__ghvl26/pyproject.toml +2 -0
  93. package/__test_framework__hR7b9U/Makefile +11 -0
  94. package/__test_framework__iESVsi/composer.json +1 -0
  95. package/__test_framework__jm6TJy/package.json +1 -0
  96. package/__test_framework__kBUpjs/pyproject.toml +9 -0
  97. package/__test_framework__kqoZrw/requirements.txt +4 -0
  98. package/__test_framework__lWkoyO/pyproject.toml +4 -0
  99. package/__test_framework__mTKnUO/package.json +1 -0
  100. package/__test_framework__nCeZwe/Makefile +11 -0
  101. package/__test_framework__oljsU0/package.json +1 -0
  102. package/__test_framework__osRG4q/go.mod +3 -0
  103. package/__test_framework__pCHH4F/package.json +1 -0
  104. package/__test_framework__pExx6E/Gemfile +3 -0
  105. package/__test_framework__pyBoGd/pyproject.toml +5 -0
  106. package/__test_framework__qw16VQ/package.json +1 -0
  107. package/__test_framework__rRayrG/package.json +1 -0
  108. package/__test_framework__s82zO5/package.json +1 -0
  109. package/__test_framework__tp8MFK/pyproject.toml +5 -0
  110. package/__test_framework__w44k4w/composer.json +1 -0
  111. package/__test_framework__yefPZY/poetry.lock +1 -0
  112. package/__test_framework__yefPZY/pyproject.toml +2 -0
  113. package/__test_framework__zCiyDT/requirements.txt +3 -0
  114. package/__test_framework__zGZN3j/pubspec.yaml +3 -0
  115. package/__test_framework__zXpnxL/package.json +1 -0
  116. package/architect-run.sh +431 -0
  117. package/assets/banner-v3.html +561 -0
  118. package/dist/agent-generator/context-enricher.d.ts +58 -0
  119. package/dist/agent-generator/context-enricher.d.ts.map +1 -0
  120. package/dist/agent-generator/context-enricher.js +581 -0
  121. package/dist/agent-generator/context-enricher.js.map +1 -0
  122. package/dist/agent-generator/domain-inferrer.d.ts +52 -0
  123. package/dist/agent-generator/domain-inferrer.d.ts.map +1 -0
  124. package/dist/agent-generator/domain-inferrer.js +575 -0
  125. package/dist/agent-generator/domain-inferrer.js.map +1 -0
  126. package/dist/agent-generator/framework-detector.d.ts +40 -0
  127. package/dist/agent-generator/framework-detector.d.ts.map +1 -0
  128. package/dist/agent-generator/framework-detector.js +611 -0
  129. package/dist/agent-generator/framework-detector.js.map +1 -0
  130. package/dist/agent-generator/index.d.ts +33 -0
  131. package/dist/agent-generator/index.d.ts.map +1 -0
  132. package/dist/agent-generator/index.js +477 -0
  133. package/dist/agent-generator/index.js.map +1 -0
  134. package/dist/agent-generator/stack-detector.d.ts +12 -0
  135. package/dist/agent-generator/stack-detector.d.ts.map +1 -0
  136. package/dist/agent-generator/stack-detector.js +128 -0
  137. package/dist/agent-generator/stack-detector.js.map +1 -0
  138. package/dist/agent-generator/templates/core/agents.d.ts +17 -0
  139. package/dist/agent-generator/templates/core/agents.d.ts.map +1 -0
  140. package/dist/agent-generator/templates/core/agents.js +1252 -0
  141. package/dist/agent-generator/templates/core/agents.js.map +1 -0
  142. package/dist/agent-generator/templates/core/architecture-rules.d.ts +7 -0
  143. package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +1 -0
  144. package/dist/agent-generator/templates/core/architecture-rules.js +274 -0
  145. package/dist/agent-generator/templates/core/architecture-rules.js.map +1 -0
  146. package/dist/agent-generator/templates/core/general-rules.d.ts +8 -0
  147. package/dist/agent-generator/templates/core/general-rules.d.ts.map +1 -0
  148. package/dist/agent-generator/templates/core/general-rules.js +301 -0
  149. package/dist/agent-generator/templates/core/general-rules.js.map +1 -0
  150. package/dist/agent-generator/templates/core/index-md.d.ts +7 -0
  151. package/dist/agent-generator/templates/core/index-md.d.ts.map +1 -0
  152. package/dist/agent-generator/templates/core/index-md.js +246 -0
  153. package/dist/agent-generator/templates/core/index-md.js.map +1 -0
  154. package/dist/agent-generator/templates/core/orchestrator.d.ts +8 -0
  155. package/dist/agent-generator/templates/core/orchestrator.d.ts.map +1 -0
  156. package/dist/agent-generator/templates/core/orchestrator.js +422 -0
  157. package/dist/agent-generator/templates/core/orchestrator.js.map +1 -0
  158. package/dist/agent-generator/templates/core/preflight.d.ts +8 -0
  159. package/dist/agent-generator/templates/core/preflight.d.ts.map +1 -0
  160. package/dist/agent-generator/templates/core/preflight.js +213 -0
  161. package/dist/agent-generator/templates/core/preflight.js.map +1 -0
  162. package/dist/agent-generator/templates/core/quality-gates.d.ts +11 -0
  163. package/dist/agent-generator/templates/core/quality-gates.d.ts.map +1 -0
  164. package/dist/agent-generator/templates/core/quality-gates.js +254 -0
  165. package/dist/agent-generator/templates/core/quality-gates.js.map +1 -0
  166. package/dist/agent-generator/templates/core/security-rules.d.ts +7 -0
  167. package/dist/agent-generator/templates/core/security-rules.d.ts.map +1 -0
  168. package/dist/agent-generator/templates/core/security-rules.js +528 -0
  169. package/dist/agent-generator/templates/core/security-rules.js.map +1 -0
  170. package/dist/agent-generator/templates/core/skills-generator.d.ts +6 -0
  171. package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
  172. package/dist/agent-generator/templates/core/skills-generator.js +207 -0
  173. package/dist/agent-generator/templates/core/skills-generator.js.map +1 -0
  174. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +7 -0
  175. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +1 -0
  176. package/dist/agent-generator/templates/core/workflow-fix-bug.js +237 -0
  177. package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
  178. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +8 -0
  179. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +1 -0
  180. package/dist/agent-generator/templates/core/workflow-new-feature.js +321 -0
  181. package/dist/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
  182. package/dist/agent-generator/templates/core/workflow-review.d.ts +7 -0
  183. package/dist/agent-generator/templates/core/workflow-review.d.ts.map +1 -0
  184. package/dist/agent-generator/templates/core/workflow-review.js +104 -0
  185. package/dist/agent-generator/templates/core/workflow-review.js.map +1 -0
  186. package/dist/agent-generator/templates/domain/index.d.ts +22 -0
  187. package/dist/agent-generator/templates/domain/index.d.ts.map +1 -0
  188. package/dist/agent-generator/templates/domain/index.js +1176 -0
  189. package/dist/agent-generator/templates/domain/index.js.map +1 -0
  190. package/dist/agent-generator/templates/stack/index.d.ts +8 -0
  191. package/dist/agent-generator/templates/stack/index.d.ts.map +1 -0
  192. package/dist/agent-generator/templates/stack/index.js +695 -0
  193. package/dist/agent-generator/templates/stack/index.js.map +1 -0
  194. package/dist/agent-generator/templates/template-helpers.d.ts +75 -0
  195. package/dist/agent-generator/templates/template-helpers.d.ts.map +1 -0
  196. package/dist/agent-generator/templates/template-helpers.js +726 -0
  197. package/dist/agent-generator/templates/template-helpers.js.map +1 -0
  198. package/dist/agent-generator/types.d.ts +196 -0
  199. package/dist/agent-generator/types.d.ts.map +1 -0
  200. package/dist/agent-generator/types.js +27 -0
  201. package/dist/agent-generator/types.js.map +1 -0
  202. package/dist/analyzer.d.ts +5 -0
  203. package/dist/analyzer.d.ts.map +1 -1
  204. package/dist/analyzer.js +35 -4
  205. package/dist/analyzer.js.map +1 -1
  206. package/dist/analyzers/forecast.d.ts +85 -0
  207. package/dist/analyzers/forecast.d.ts.map +1 -0
  208. package/dist/analyzers/forecast.js +337 -0
  209. package/dist/analyzers/forecast.js.map +1 -0
  210. package/dist/analyzers/git-cache.d.ts +7 -0
  211. package/dist/analyzers/git-cache.d.ts.map +1 -0
  212. package/dist/analyzers/git-cache.js +41 -0
  213. package/dist/analyzers/git-cache.js.map +1 -0
  214. package/dist/analyzers/git-history.d.ts +113 -0
  215. package/dist/analyzers/git-history.d.ts.map +1 -0
  216. package/dist/analyzers/git-history.js +333 -0
  217. package/dist/analyzers/git-history.js.map +1 -0
  218. package/dist/analyzers/index.d.ts +10 -0
  219. package/dist/analyzers/index.d.ts.map +1 -0
  220. package/dist/analyzers/index.js +7 -0
  221. package/dist/analyzers/index.js.map +1 -0
  222. package/dist/analyzers/temporal-scorer.d.ts +72 -0
  223. package/dist/analyzers/temporal-scorer.d.ts.map +1 -0
  224. package/dist/analyzers/temporal-scorer.js +140 -0
  225. package/dist/analyzers/temporal-scorer.js.map +1 -0
  226. package/dist/cli.d.ts +2 -3
  227. package/dist/cli.d.ts.map +1 -1
  228. package/dist/cli.js +287 -82
  229. package/dist/cli.js.map +1 -1
  230. package/dist/html-reporter.d.ts +3 -1
  231. package/dist/html-reporter.d.ts.map +1 -1
  232. package/dist/html-reporter.js +594 -100
  233. package/dist/html-reporter.js.map +1 -1
  234. package/dist/index.d.ts +16 -3
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +63 -4
  237. package/dist/index.js.map +1 -1
  238. package/dist/project-summarizer.d.ts +18 -0
  239. package/dist/project-summarizer.d.ts.map +1 -0
  240. package/dist/project-summarizer.js +306 -0
  241. package/dist/project-summarizer.js.map +1 -0
  242. package/dist/refactor-reporter.js +1 -1
  243. package/dist/types.d.ts +13 -0
  244. package/dist/types.d.ts.map +1 -1
  245. package/package.json +12 -3
  246. package/src/agent-generator/context-enricher.ts +643 -0
  247. package/src/agent-generator/domain-inferrer.ts +625 -0
  248. package/src/agent-generator/framework-detector.ts +669 -0
  249. package/src/agent-generator/index.ts +555 -0
  250. package/src/agent-generator/stack-detector.ts +103 -0
  251. package/src/agent-generator/templates/core/agents.ts +1293 -0
  252. package/src/agent-generator/templates/core/architecture-rules.ts +287 -0
  253. package/src/agent-generator/templates/core/general-rules.ts +306 -0
  254. package/src/agent-generator/templates/core/index-md.ts +260 -0
  255. package/src/agent-generator/templates/core/orchestrator.ts +459 -0
  256. package/src/agent-generator/templates/core/preflight.ts +215 -0
  257. package/src/agent-generator/templates/core/quality-gates.ts +256 -0
  258. package/src/agent-generator/templates/core/security-rules.ts +543 -0
  259. package/src/agent-generator/templates/core/skills-generator.ts +236 -0
  260. package/src/agent-generator/templates/core/workflow-fix-bug.ts +239 -0
  261. package/src/agent-generator/templates/core/workflow-new-feature.ts +323 -0
  262. package/src/agent-generator/templates/core/workflow-review.ts +106 -0
  263. package/src/agent-generator/templates/domain/index.ts +1201 -0
  264. package/src/agent-generator/templates/stack/index.ts +705 -0
  265. package/src/agent-generator/templates/template-helpers.ts +776 -0
  266. package/src/agent-generator/types.ts +232 -0
  267. package/src/analyzer.ts +38 -4
  268. package/src/analyzers/forecast.ts +496 -0
  269. package/src/analyzers/git-cache.ts +52 -0
  270. package/src/analyzers/git-history.ts +488 -0
  271. package/src/analyzers/index.ts +33 -0
  272. package/src/analyzers/temporal-scorer.ts +227 -0
  273. package/src/cli.ts +336 -83
  274. package/src/html-reporter.ts +616 -108
  275. package/src/index.ts +92 -9
  276. package/src/project-summarizer.ts +347 -0
  277. package/src/refactor-reporter.ts +1 -1
  278. package/src/types.ts +10 -0
  279. package/tests/agent-generator.test.ts +411 -0
  280. package/tests/analyzers-integration.test.ts +174 -0
  281. package/tests/architect-adapter-enrichment.test.ts +9 -0
  282. package/tests/context-enricher.test.ts +971 -0
  283. package/tests/forecast.test.ts +509 -0
  284. package/tests/framework-detector.test.ts +1172 -0
  285. package/tests/git-history.test.ts +254 -0
  286. package/tests/scanner.test.ts +7 -8
  287. package/tests/scorer.test.ts +588 -0
  288. package/tests/stack-detector.test.ts +241 -0
  289. package/tests/template-generation.test.ts +706 -0
  290. package/tests/template-helpers.test.ts +1152 -0
  291. package/tests/temporal-scorer.test.ts +307 -0
  292. package/dist/agent-generator.d.ts +0 -95
  293. package/dist/agent-generator.d.ts.map +0 -1
  294. package/dist/agent-generator.js +0 -1295
  295. package/dist/agent-generator.js.map +0 -1
  296. package/src/agent-generator.ts +0 -1401
@@ -17,17 +17,65 @@ ${this.getStyles()}
17
17
  </head>
18
18
  <body>
19
19
  ${this.renderHeader(report)}
20
- <div class="container">
21
- ${this.renderScoreHero(report)}
22
- ${this.renderRadarChart(report)}
23
- ${this.renderStats(report)}
24
- ${this.renderLayers(report)}
25
- ${this.renderDependencyGraph(report)}
26
- ${this.renderAntiPatternBubbles(report, grouped)}
27
- ${this.renderAntiPatterns(report, grouped)}
28
- ${this.renderSuggestions(sugGrouped)}
29
- ${plan ? this.renderRefactoringPlan(plan) : ''}
30
- ${agentSuggestion ? this.renderAgentSuggestions(agentSuggestion) : ''}
20
+ <div class="report-layout">
21
+ <nav class="sidebar" id="reportSidebar">
22
+ <div class="sidebar-title">Navigation</div>
23
+ <a href="#score" class="sidebar-link active" data-section="score">📊 Score</a>
24
+ ${report.projectSummary ? `<a href="#overview" class="sidebar-link" data-section="overview">📋 Overview</a>` : ''}
25
+ <a href="#layers" class="sidebar-link" data-section="layers">📐 Layers & Graph</a>
26
+ <a href="#anti-patterns" class="sidebar-link" data-section="anti-patterns">⚠️ Anti-Patterns (${report.antiPatterns.length})</a>
27
+ <a href="#suggestions" class="sidebar-link" data-section="suggestions">💡 Suggestions (${report.suggestions.length})</a>
28
+ ${plan ? `<a href="#refactoring" class="sidebar-link" data-section="refactoring">🔧 Refactoring (${plan.steps.length})</a>` : ''}
29
+ ${agentSuggestion ? `<a href="#agents" class="sidebar-link" data-section="agents">🤖 Agents</a>` : ''}
30
+ </nav>
31
+ <button class="sidebar-toggle" onclick="document.getElementById('reportSidebar').classList.toggle('sidebar-open')">☰</button>
32
+
33
+ <div class="container">
34
+ <div id="score">
35
+ ${this.renderScoreHero(report)}
36
+ ${this.renderRadarChart(report)}
37
+ ${this.renderStats(report)}
38
+ </div>
39
+
40
+ ${this.renderProjectOverview(report)}
41
+
42
+ <details class="section-accordion" id="layers" open>
43
+ <summary class="section-accordion-header">📐 Layer Analysis & Dependencies</summary>
44
+ <div class="section-accordion-body">
45
+ ${this.renderLayers(report)}
46
+ ${this.renderDependencyGraph(report)}
47
+ </div>
48
+ </details>
49
+
50
+ <details class="section-accordion" id="anti-patterns" open>
51
+ <summary class="section-accordion-header">⚠️ Anti-Patterns (${report.antiPatterns.length})</summary>
52
+ <div class="section-accordion-body">
53
+ ${this.renderAntiPatternBubbles(report, grouped)}
54
+ ${this.renderAntiPatterns(report, grouped)}
55
+ </div>
56
+ </details>
57
+
58
+ <details class="section-accordion" id="suggestions">
59
+ <summary class="section-accordion-header">💡 Suggestions (${report.suggestions.length})</summary>
60
+ <div class="section-accordion-body">
61
+ ${this.renderSuggestions(sugGrouped)}
62
+ </div>
63
+ </details>
64
+
65
+ ${plan ? `<details class="section-accordion" id="refactoring" open>
66
+ <summary class="section-accordion-header">🔧 Refactoring Plan (${plan.steps.length} steps, ${plan.totalOperations} operations)</summary>
67
+ <div class="section-accordion-body">
68
+ ${this.renderRefactoringPlan(plan)}
69
+ </div>
70
+ </details>` : ''}
71
+
72
+ ${agentSuggestion ? `<details class="section-accordion" id="agents" open>
73
+ <summary class="section-accordion-header">🤖 Agent System</summary>
74
+ <div class="section-accordion-body">
75
+ ${this.renderAgentSuggestions(agentSuggestion)}
76
+ </div>
77
+ </details>` : ''}
78
+ </div>
31
79
  </div>
32
80
  ${this.renderFooter()}
33
81
  ${this.getScripts(report)}
@@ -110,6 +158,69 @@ ${this.getScripts(report)}
110
158
  </div>
111
159
  </div>`;
112
160
  }
161
+ renderProjectOverview(report) {
162
+ const summary = report.projectSummary;
163
+ if (!summary)
164
+ return '';
165
+ const modulesHtml = summary.modules.length > 0
166
+ ? summary.modules.map(m => `
167
+ <div class="overview-module">
168
+ <div class="overview-module-name">${this.esc(m.name)}</div>
169
+ <div class="overview-module-desc">${this.esc(m.description)}</div>
170
+ <div class="overview-module-files">${m.files} file${m.files > 1 ? 's' : ''}</div>
171
+ </div>`).join('')
172
+ : '<div class="overview-empty">Nenhum módulo detectado</div>';
173
+ const techHtml = summary.techStack
174
+ .map(t => `<span class="overview-tag tech-tag">${this.esc(t)}</span>`)
175
+ .join('');
176
+ const keywordsHtml = summary.keywords
177
+ .map(k => `<span class="overview-tag keyword-tag">${this.esc(k)}</span>`)
178
+ .join('');
179
+ const entryHtml = summary.entryPoints.length > 0
180
+ ? summary.entryPoints.map(e => `<code class="overview-entry">${this.esc(e)}</code>`).join(' ')
181
+ : '<span class="overview-empty">—</span>';
182
+ return `
183
+ <details class="section-accordion" id="overview" open>
184
+ <summary class="section-accordion-header">📋 Project Overview</summary>
185
+ <div class="section-accordion-body">
186
+ <div class="overview-grid">
187
+ <div class="overview-card overview-main">
188
+ <div class="overview-label">O que é</div>
189
+ <div class="overview-description">${this.esc(summary.description)}</div>
190
+ <div class="overview-purpose-row">
191
+ <span class="overview-purpose-label">Tipo:</span>
192
+ <span class="overview-purpose-value">${this.esc(summary.purpose)}</span>
193
+ </div>
194
+ </div>
195
+ <div class="overview-card">
196
+ <div class="overview-label">Tech Stack</div>
197
+ <div class="overview-tags">${techHtml || '<span class="overview-empty">—</span>'}</div>
198
+ </div>
199
+ <div class="overview-card">
200
+ <div class="overview-label">Keywords</div>
201
+ <div class="overview-tags">${keywordsHtml || '<span class="overview-empty">—</span>'}</div>
202
+ </div>
203
+ <div class="overview-card">
204
+ <div class="overview-label">Entry Points</div>
205
+ <div class="overview-entries">${entryHtml}</div>
206
+ </div>
207
+ </div>
208
+ <div class="overview-modules-section">
209
+ <div class="overview-label">Módulos Detectados (${summary.modules.length})</div>
210
+ <div class="overview-modules-grid">
211
+ ${modulesHtml}
212
+ </div>
213
+ </div>
214
+ </div>
215
+ </details>`;
216
+ }
217
+ esc(text) {
218
+ return text
219
+ .replace(/&/g, '&amp;')
220
+ .replace(/</g, '&lt;')
221
+ .replace(/>/g, '&gt;')
222
+ .replace(/"/g, '&quot;');
223
+ }
113
224
  renderScoreHero(report) {
114
225
  const overall = report.score.overall;
115
226
  const circumference = 2 * Math.PI * 85;
@@ -208,44 +319,112 @@ ${this.getScripts(report)}
208
319
  renderDependencyGraph(report) {
209
320
  if (report.dependencyGraph.edges.length === 0)
210
321
  return '';
211
- // Build node data with connection counts
322
+ // Build real file set only files that appear as SOURCE in edges (these are real scanned files)
323
+ const realFiles = new Set(report.dependencyGraph.edges.map(e => e.from));
324
+ // Count connections only for real files
212
325
  const connectionCount = {};
213
326
  for (const edge of report.dependencyGraph.edges) {
214
- connectionCount[edge.from] = (connectionCount[edge.from] || 0) + 1;
215
- connectionCount[edge.to] = (connectionCount[edge.to] || 0) + 1;
327
+ if (realFiles.has(edge.from)) {
328
+ connectionCount[edge.from] = (connectionCount[edge.from] || 0) + 1;
329
+ }
330
+ if (realFiles.has(edge.to)) {
331
+ connectionCount[edge.to] = (connectionCount[edge.to] || 0) + 1;
332
+ }
216
333
  }
334
+ // Build layer map from report layers
217
335
  const layerMap = {};
218
336
  for (const layer of report.layers) {
219
337
  for (const file of layer.files) {
220
338
  layerMap[file] = layer.name;
221
339
  }
222
340
  }
223
- const nodes = report.dependencyGraph.nodes.map(n => ({
341
+ // Create nodes only from real files
342
+ const allNodes = [...realFiles].map(n => ({
224
343
  id: n,
225
344
  name: n.split('/').pop() || n,
226
345
  connections: connectionCount[n] || 0,
227
346
  layer: layerMap[n] || 'Other',
228
347
  }));
229
- const links = report.dependencyGraph.edges.map(e => ({
230
- source: e.from,
231
- target: e.to,
232
- }));
348
+ // ── Fallback: color by module/directory when layer detection is weak ──
349
+ const otherCount = allNodes.filter(n => n.layer === 'Other').length;
350
+ const useModuleColoring = allNodes.length > 0 && (otherCount / allNodes.length) > 0.7;
351
+ // Palette for module-based coloring (10 distinct, vibrant colors)
352
+ const modulePalette = [
353
+ '#3b82f6', '#ec4899', '#10b981', '#f59e0b', '#8b5cf6',
354
+ '#06b6d4', '#ef4444', '#84cc16', '#f97316', '#6366f1',
355
+ ];
356
+ let moduleColorMap = {};
357
+ if (useModuleColoring) {
358
+ // Extract module (first meaningful directory) from each node path
359
+ const getModule = (filePath) => {
360
+ const parts = filePath.split('/');
361
+ if (parts.length < 2)
362
+ return 'root';
363
+ const first = parts[0];
364
+ // If first dir is common source dir, use second level
365
+ if (['src', 'lib', 'app', 'packages', 'modules', 'features', 'apps'].includes(first)) {
366
+ return parts.length > 2 ? parts[1] : first;
367
+ }
368
+ return first;
369
+ };
370
+ // Assign colors to modules
371
+ const moduleNames = [...new Set(allNodes.map(n => getModule(n.id)))];
372
+ moduleNames.forEach((mod, i) => {
373
+ moduleColorMap[mod] = modulePalette[i % modulePalette.length];
374
+ });
375
+ // Reassign layer field to module name for coloring
376
+ for (const node of allNodes) {
377
+ node.layer = getModule(node.id);
378
+ }
379
+ }
380
+ // Build links only between real files
381
+ const allLinks = report.dependencyGraph.edges
382
+ .filter(e => realFiles.has(e.from) && realFiles.has(e.to))
383
+ .map(e => ({ source: e.from, target: e.to }));
384
+ // Limit to top N most-connected nodes for large projects
385
+ const maxNodes = 60;
386
+ const sortedNodes = [...allNodes].sort((a, b) => b.connections - a.connections);
387
+ const limitedNodes = sortedNodes.slice(0, maxNodes);
388
+ const limitedNodeIds = new Set(limitedNodes.map(n => n.id));
389
+ const limitedLinks = allLinks.filter(l => limitedNodeIds.has(l.source) && limitedNodeIds.has(l.target));
390
+ const isLimited = allNodes.length > maxNodes;
391
+ // Collect unique layers/modules from limited nodes
392
+ const uniqueLayers = [...new Set(limitedNodes.map(n => n.layer))];
393
+ // Build dynamic color map for legend and D3
394
+ const colorMap = useModuleColoring
395
+ ? moduleColorMap
396
+ : { API: '#ec4899', Service: '#3b82f6', Data: '#10b981', UI: '#f59e0b', Infrastructure: '#8b5cf6', Other: '#64748b' };
397
+ const legendLabel = useModuleColoring ? 'Colored by module' : 'Colored by layer';
398
+ const legendHtml = uniqueLayers.map(l => {
399
+ const color = colorMap[l] || '#64748b';
400
+ return `<span class="legend-item"><span class="legend-dot" style="background: ${color}"></span> ${l}</span>`;
401
+ }).join('');
402
+ const filterHtml = uniqueLayers.map(l => {
403
+ const color = colorMap[l] || '#64748b';
404
+ return `<label class="graph-filter-check"><input type="checkbox" checked data-layer="${l}" onchange="toggleGraphLayer('${l}', this.checked)"><span class="legend-dot" style="background: ${color}"></span> ${l}</label>`;
405
+ }).join('');
233
406
  return `
234
407
  <h2 class="section-title">🔗 Dependency Graph</h2>
235
408
  <div class="card graph-card">
236
- <div class="graph-legend">
237
- <span class="legend-item"><span class="legend-dot" style="background: #ec4899"></span> API</span>
238
- <span class="legend-item"><span class="legend-dot" style="background: #3b82f6"></span> Service</span>
239
- <span class="legend-item"><span class="legend-dot" style="background: #10b981"></span> Data</span>
240
- <span class="legend-item"><span class="legend-dot" style="background: #f59e0b"></span> UI</span>
241
- <span class="legend-item"><span class="legend-dot" style="background: #8b5cf6"></span> Infra</span>
242
- <span class="legend-item"><span class="legend-dot" style="background: #64748b"></span> Other</span>
409
+ <div class="graph-controls">
410
+ <div class="graph-legend">
411
+ <span class="legend-label" style="color:#94a3b8;font-size:11px;margin-right:8px;">${legendLabel}:</span>
412
+ ${legendHtml}
413
+ </div>
414
+ <div class="graph-filters">
415
+ <input type="text" id="graphSearch" class="graph-search" placeholder="🔍 Search node..." oninput="filterGraphNodes(this.value)">
416
+ <div class="graph-layer-filters">
417
+ ${filterHtml}
418
+ </div>
419
+ </div>
420
+ ${isLimited ? `<div class="graph-limit-notice">Showing top ${maxNodes} of ${allNodes.length} source files (most connected) · ${limitedLinks.length} links</div>` : ''}
243
421
  </div>
244
- <div id="dep-graph" style="width:100%; min-height:400px;"></div>
245
- <div class="graph-hint">🖱️ Drag nodes to explore • Node size = number of connections</div>
422
+ <div id="dep-graph" style="width:100%; min-height:500px;"></div>
423
+ <div class="graph-hint">🖱️ Drag nodes • Scroll to zoomDouble-click to reset • Node size = connections</div>
246
424
  </div>
247
- <script type="application/json" id="graph-nodes">${JSON.stringify(nodes)}<\/script>
248
- <script type="application/json" id="graph-links">${JSON.stringify(links)}<\/script>`;
425
+ <script type="application/json" id="graph-nodes">${JSON.stringify(limitedNodes)}${'</' + 'script>'}
426
+ <script type="application/json" id="graph-links">${JSON.stringify(limitedLinks)}${'</' + 'script>'}
427
+ <script type="application/json" id="graph-colors">${JSON.stringify(colorMap)}${'</' + 'script>'}`;
249
428
  }
250
429
  /**
251
430
  * Bubble chart for anti-patterns — bigger = more severe
@@ -347,7 +526,7 @@ ${this.getScripts(report)}
347
526
  renderFooter() {
348
527
  return `
349
528
  <div class="footer">
350
- <p>Generated by <a href="https://github.com/camilooscargbaptista/architect">🏗️ Architect v2.0</a> — AI-powered architecture analysis + refactoring engine</p>
529
+ <p>Generated by <a href="https://github.com/camilooscargbaptista/architect">⚡ Architect v3.1</a> — Enterprise Architecture Intelligence</p>
351
530
  <p>By <strong>Camilo Girardelli</strong> · <a href="https://www.girardellitecnologia.com">Girardelli Tecnologia</a></p>
352
531
  </div>`;
353
532
  }
@@ -476,10 +655,12 @@ ${this.getScripts(report)}
476
655
  </details>
477
656
  </div>
478
657
  </div>
479
- <div class="rstep-ops">
480
- <h4>📋 Operations (${step.operations.length})</h4>
481
- ${operationsHtml}
482
- </div>
658
+ <details class="rstep-ops-accordion">
659
+ <summary class="rstep-ops-toggle">📋 Operations (${step.operations.length})</summary>
660
+ <div class="rstep-ops">
661
+ ${operationsHtml}
662
+ </div>
663
+ </details>
483
664
  <div class="rstep-impact">
484
665
  <h4>📈 Score Impact</h4>
485
666
  <div class="rimpact-tags">${impactHtml}</div>
@@ -507,6 +688,23 @@ document.addEventListener('DOMContentLoaded', () => {
507
688
  }, { threshold: 0.5 });
508
689
 
509
690
  counters.forEach(c => observer.observe(c));
691
+
692
+ // ── Sidebar Active Section Tracking ──
693
+ const sectionIds = ['score', 'layers', 'anti-patterns', 'suggestions', 'refactoring', 'agents'];
694
+ const sectionObserver = new IntersectionObserver((entries) => {
695
+ entries.forEach(entry => {
696
+ if (entry.isIntersecting) {
697
+ document.querySelectorAll('.sidebar-link').forEach(l => l.classList.remove('active'));
698
+ const link = document.querySelector('.sidebar-link[data-section="' + entry.target.id + '"]');
699
+ if (link) link.classList.add('active');
700
+ }
701
+ });
702
+ }, { threshold: 0.15, rootMargin: '-80px 0px -60% 0px' });
703
+
704
+ sectionIds.forEach(id => {
705
+ const el = document.getElementById(id);
706
+ if (el) sectionObserver.observe(el);
707
+ });
510
708
  });
511
709
 
512
710
  function animateCounter(el, target) {
@@ -609,10 +807,12 @@ function animateCounter(el, target) {
609
807
 
610
808
  const container = document.getElementById('dep-graph');
611
809
  const width = container.clientWidth || 800;
612
- const height = 450;
810
+ const height = 500;
613
811
  container.style.height = height + 'px';
614
812
 
615
- const layerColors = {
813
+ // Dynamic color map — loaded from JSON (supports both layer and module coloring)
814
+ const colorsEl = document.getElementById('graph-colors');
815
+ const layerColors = colorsEl ? JSON.parse(colorsEl.textContent || '{}') : {
616
816
  API: '#ec4899', Service: '#3b82f6', Data: '#10b981',
617
817
  UI: '#f59e0b', Infrastructure: '#8b5cf6', Other: '#64748b',
618
818
  };
@@ -621,28 +821,43 @@ function animateCounter(el, target) {
621
821
  .attr('width', width).attr('height', height)
622
822
  .attr('viewBox', [0, 0, width, height]);
623
823
 
824
+ // Zoom container
825
+ const g = svg.append('g');
826
+
827
+ // Zoom behavior
828
+ const zoom = d3.zoom()
829
+ .scaleExtent([0.2, 5])
830
+ .on('zoom', (event) => { g.attr('transform', event.transform); });
831
+ svg.call(zoom);
832
+
833
+ // Double-click to reset zoom
834
+ svg.on('dblclick.zoom', () => {
835
+ svg.transition().duration(500).call(zoom.transform, d3.zoomIdentity);
836
+ });
837
+
624
838
  // Arrow marker
625
- svg.append('defs').append('marker')
839
+ g.append('defs').append('marker')
626
840
  .attr('id', 'arrowhead').attr('viewBox', '-0 -5 10 10')
627
841
  .attr('refX', 20).attr('refY', 0).attr('orient', 'auto')
628
842
  .attr('markerWidth', 6).attr('markerHeight', 6)
629
843
  .append('path').attr('d', 'M 0,-5 L 10,0 L 0,5')
630
844
  .attr('fill', '#475569');
631
845
 
846
+ // Tuned simulation for better spread
632
847
  const simulation = d3.forceSimulation(nodes)
633
- .force('link', d3.forceLink(links).id(d => d.id).distance(60))
634
- .force('charge', d3.forceManyBody().strength(-150))
848
+ .force('link', d3.forceLink(links).id(d => d.id).distance(80))
849
+ .force('charge', d3.forceManyBody().strength(-250))
635
850
  .force('center', d3.forceCenter(width / 2, height / 2))
636
- .force('x', d3.forceX(width / 2).strength(0.1))
637
- .force('y', d3.forceY(height / 2).strength(0.1))
638
- .force('collision', d3.forceCollide().radius(d => Math.max(d.connections * 3 + 12, 15)));
851
+ .force('x', d3.forceX(width / 2).strength(0.05))
852
+ .force('y', d3.forceY(height / 2).strength(0.05))
853
+ .force('collision', d3.forceCollide().radius(d => Math.max(d.connections * 2 + 16, 20)));
639
854
 
640
- const link = svg.append('g')
855
+ const link = g.append('g')
641
856
  .selectAll('line').data(links).join('line')
642
- .attr('stroke', '#334155').attr('stroke-width', 1.5)
643
- .attr('stroke-opacity', 0.6).attr('marker-end', 'url(#arrowhead)');
857
+ .attr('stroke', '#334155').attr('stroke-width', 1)
858
+ .attr('stroke-opacity', 0.4).attr('marker-end', 'url(#arrowhead)');
644
859
 
645
- const node = svg.append('g')
860
+ const node = g.append('g')
646
861
  .selectAll('g').data(nodes).join('g')
647
862
  .call(d3.drag()
648
863
  .on('start', (e, d) => { if (!e.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })
@@ -650,37 +865,55 @@ function animateCounter(el, target) {
650
865
  .on('end', (e, d) => { if (!e.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })
651
866
  );
652
867
 
653
- // Node circles — size based on connections
868
+ // Node circles — color by layer
654
869
  node.append('circle')
655
- .attr('r', d => Math.max(d.connections * 3 + 6, 8))
870
+ .attr('r', d => Math.max(d.connections * 2.5 + 5, 6))
656
871
  .attr('fill', d => layerColors[d.layer] || '#64748b')
657
- .attr('stroke', '#0f172a').attr('stroke-width', 2)
658
- .attr('opacity', 0.85);
872
+ .attr('stroke', '#0f172a').attr('stroke-width', 1.5)
873
+ .attr('opacity', 0.9);
659
874
 
660
- // Node labels
661
- node.append('text')
875
+ // Node labels — only show for nodes with enough connections
876
+ node.filter(d => d.connections >= 2).append('text')
662
877
  .text(d => d.name.replace(/\\.[^.]+$/, ''))
663
- .attr('x', 0).attr('y', d => -(Math.max(d.connections * 3 + 6, 8) + 6))
878
+ .attr('x', 0).attr('y', d => -(Math.max(d.connections * 2.5 + 5, 6) + 4))
664
879
  .attr('text-anchor', 'middle')
665
- .attr('fill', '#94a3b8').attr('font-size', '10px').attr('font-weight', '500');
880
+ .attr('fill', '#e2e8f0').attr('font-size', '9px').attr('font-weight', '500');
666
881
 
667
- // Tooltip on hover
882
+ // Tooltip
668
883
  node.append('title')
669
884
  .text(d => d.id + '\\nConnections: ' + d.connections + '\\nLayer: ' + d.layer);
670
885
 
671
886
  simulation.on('tick', () => {
672
- // Clamp nodes to stay within SVG bounds
673
- nodes.forEach(d => {
674
- const r = Math.max(d.connections * 3 + 6, 8) + 10;
675
- d.x = Math.max(r, Math.min(width - r, d.x));
676
- d.y = Math.max(r, Math.min(height - r, d.y));
677
- });
678
-
679
887
  link
680
888
  .attr('x1', d => d.source.x).attr('y1', d => d.source.y)
681
889
  .attr('x2', d => d.target.x).attr('y2', d => d.target.y);
682
890
  node.attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');
683
891
  });
892
+
893
+ // Expose search and filter functions
894
+ window.filterGraphNodes = function(query) {
895
+ if (!query) {
896
+ node.attr('opacity', 1);
897
+ link.attr('opacity', 0.4);
898
+ return;
899
+ }
900
+ query = query.toLowerCase();
901
+ node.attr('opacity', d => d.id.toLowerCase().includes(query) || d.name.toLowerCase().includes(query) ? 1 : 0.1);
902
+ link.attr('opacity', d => {
903
+ const srcMatch = d.source.id.toLowerCase().includes(query);
904
+ const tgtMatch = d.target.id.toLowerCase().includes(query);
905
+ return (srcMatch || tgtMatch) ? 0.6 : 0.05;
906
+ });
907
+ };
908
+
909
+ window.toggleGraphLayer = function(layer, visible) {
910
+ node.filter(d => d.layer === layer)
911
+ .transition().duration(300)
912
+ .attr('opacity', visible ? 1 : 0.05);
913
+ link.filter(d => d.source.layer === layer || d.target.layer === layer)
914
+ .transition().duration(300)
915
+ .attr('opacity', visible ? 0.4 : 0.02);
916
+ };
684
917
  })();
685
918
 
686
919
  // ── Bubble Chart ──
@@ -785,49 +1018,60 @@ function animateCounter(el, target) {
785
1018
  return '#fbbf24';
786
1019
  return '#60a5fa';
787
1020
  };
788
- const agentCards = s.suggestedAgents.map(a => `<label class="agent-toggle-card" data-category="agents" data-name="${a}">
789
- <input type="checkbox" class="agent-check" checked data-type="agents" data-item="${a}">
790
- <div class="agent-toggle-inner">
791
- <div class="agent-toggle-icon">${roleIcon(a)}</div>
1021
+ // Status helpers
1022
+ const statusBadge = (status) => {
1023
+ const map = {
1024
+ 'KEEP': { icon: '✅', label: 'KEEP', color: '#22c55e' },
1025
+ 'MODIFY': { icon: '🔵', label: 'MODIFY', color: '#3b82f6' },
1026
+ 'CREATE': { icon: '🟡', label: 'NEW', color: '#f59e0b' },
1027
+ 'DELETE': { icon: '🔴', label: 'REMOVE', color: '#ef4444' },
1028
+ };
1029
+ const s = map[status] || map['CREATE'];
1030
+ return `<span class="agent-status-badge" style="background:${s.color}20;color:${s.color};border:1px solid ${s.color}40">${s.icon} ${s.label}</span>`;
1031
+ };
1032
+ const statusBorder = (status) => {
1033
+ const map = {
1034
+ 'KEEP': '#22c55e', 'MODIFY': '#3b82f6', 'CREATE': '#f59e0b', 'DELETE': '#ef4444',
1035
+ };
1036
+ return map[status] || '#334155';
1037
+ };
1038
+ const agentCards = s.suggestedAgents.map(a => `<label class="agent-toggle-card" data-category="agents" data-name="${a.name}">
1039
+ <input type="checkbox" class="agent-check" ${a.status !== 'DELETE' ? 'checked' : ''} data-type="agents" data-item="${a.name}">
1040
+ <div class="agent-toggle-inner" style="border-color:${statusBorder(a.status)}">
1041
+ <div class="agent-toggle-icon">${roleIcon(a.name)}</div>
792
1042
  <div class="agent-toggle-info">
793
- <span class="agent-toggle-name">${a}</span>
794
- <span class="agent-toggle-role" style="color:${roleColor(a)}">${roleLabel(a)}</span>
1043
+ <span class="agent-toggle-name">${a.name}</span>
1044
+ <span class="agent-toggle-role" style="color:${roleColor(a.name)}">${roleLabel(a.name)}</span>
1045
+ ${a.description ? `<span class="agent-toggle-desc">${a.description}</span>` : ''}
795
1046
  </div>
1047
+ ${statusBadge(a.status)}
796
1048
  <div class="agent-toggle-check">\u2713</div>
797
1049
  </div>
798
1050
  </label>`).join('\n');
799
- const ruleCards = s.suggestedRules.map(r => `<label class="agent-toggle-card mini" data-category="rules">
800
- <input type="checkbox" class="agent-check" checked data-type="rules" data-item="${r}">
801
- <div class="agent-toggle-inner">
802
- <span class="agent-toggle-icon">\u{1F4CF}</span>
803
- <span class="agent-toggle-name">${r}.md</span>
804
- <div class="agent-toggle-check">\u2713</div>
805
- </div>
806
- </label>`).join('\n');
807
- const guardCards = s.suggestedGuards.map(g => `<label class="agent-toggle-card mini" data-category="guards">
808
- <input type="checkbox" class="agent-check" checked data-type="guards" data-item="${g}">
809
- <div class="agent-toggle-inner">
810
- <span class="agent-toggle-icon">\u{1F6E1}\uFE0F</span>
811
- <span class="agent-toggle-name">${g}.md</span>
812
- <div class="agent-toggle-check">\u2713</div>
813
- </div>
814
- </label>`).join('\n');
815
- const workflowCards = s.suggestedWorkflows.map(w => `<label class="agent-toggle-card mini" data-category="workflows">
816
- <input type="checkbox" class="agent-check" checked data-type="workflows" data-item="${w}">
817
- <div class="agent-toggle-inner">
818
- <span class="agent-toggle-icon">\u26A1</span>
819
- <span class="agent-toggle-name">${w}.md</span>
1051
+ const miniCard = (item, icon, type) => `<label class="agent-toggle-card mini" data-category="${type}">
1052
+ <input type="checkbox" class="agent-check" ${item.status !== 'DELETE' ? 'checked' : ''} data-type="${type}" data-item="${item.name}">
1053
+ <div class="agent-toggle-inner" style="border-color:${statusBorder(item.status)}">
1054
+ <span class="agent-toggle-icon">${icon}</span>
1055
+ <div class="agent-toggle-info">
1056
+ <span class="agent-toggle-name">${item.name}.md</span>
1057
+ ${item.description ? `<span class="agent-toggle-desc">${item.description}</span>` : ''}
1058
+ </div>
1059
+ ${statusBadge(item.status)}
820
1060
  <div class="agent-toggle-check">\u2713</div>
821
1061
  </div>
822
- </label>`).join('\n');
1062
+ </label>`;
1063
+ const ruleCards = s.suggestedRules.map(r => miniCard(r, '\u{1F4CF}', 'rules')).join('\n');
1064
+ const guardCards = s.suggestedGuards.map(g => miniCard(g, '\u{1F6E1}\uFE0F', 'guards')).join('\n');
1065
+ const workflowCards = s.suggestedWorkflows.map(w => miniCard(w, '\u26A1', 'workflows')).join('\n');
823
1066
  const skillCards = s.suggestedSkills.map(sk => `<label class="agent-toggle-card" data-category="skills">
824
1067
  <input type="checkbox" class="agent-check" checked data-type="skills" data-item="${sk.source}">
825
- <div class="agent-toggle-inner">
1068
+ <div class="agent-toggle-inner" style="border-color:${statusBorder(sk.status)}">
826
1069
  <span class="agent-toggle-icon">\u{1F9E0}</span>
827
1070
  <div class="agent-toggle-info">
828
1071
  <span class="agent-toggle-name">${sk.name}</span>
829
1072
  <span class="agent-toggle-role" style="color:#34d399">${sk.description}</span>
830
1073
  </div>
1074
+ ${statusBadge(sk.status)}
831
1075
  <div class="agent-toggle-check">\u2713</div>
832
1076
  </div>
833
1077
  </label>`).join('\n');
@@ -852,17 +1096,31 @@ function animateCounter(el, target) {
852
1096
  `\u{1F527} ${s.stack.primary}`,
853
1097
  `\u{1F4E6} ${s.stack.frameworks.length > 0 ? s.stack.frameworks.join(', ') : 'No framework'}`,
854
1098
  s.hasExistingAgents ? '\u{1F4C1} Existing .agent/' : '\u{1F4C1} New .agent/',
855
- [s.stack.hasBackend ? '\u{1F519} Backend' : '', s.stack.hasFrontend ? '\u{1F5A5}\uFE0F Frontend' : '', s.stack.hasMobile ? '\u{1F4F1} Mobile' : '', s.stack.hasDatabase ? '\u{1F5C4}\uFE0F DB' : ''].filter(Boolean).join('\n ')
1099
+ ...(s.stack.hasBackend ? ['\u{1F519} Backend'] : []),
1100
+ ...(s.stack.hasFrontend ? ['\u{1F5A5}\uFE0F Frontend'] : []),
1101
+ ...(s.stack.hasMobile ? ['\u{1F4F1} Mobile'] : []),
1102
+ ...(s.stack.hasDatabase ? ['\u{1F5C4}\uFE0F Database'] : []),
856
1103
  ];
857
1104
  const totalItems = s.suggestedAgents.length + s.suggestedRules.length + s.suggestedGuards.length + s.suggestedWorkflows.length + s.suggestedSkills.length;
1105
+ // Status summary counts
1106
+ const allItems = [...s.suggestedAgents, ...s.suggestedRules, ...s.suggestedGuards, ...s.suggestedWorkflows];
1107
+ const keepCount = allItems.filter(i => i.status === 'KEEP').length;
1108
+ const modifyCount = allItems.filter(i => i.status === 'MODIFY').length;
1109
+ const createCount = allItems.filter(i => i.status === 'CREATE').length;
858
1110
  return `
859
- <h2 class="section-title">\u{1F916} Agent System (Suggested)</h2>
1111
+ <h2 class="section-title">\u{1F916} Agent System</h2>
860
1112
 
861
1113
  <div class="card agent-system-card">
862
1114
  <div class="agent-stack-banner">
863
1115
  ${stackPills.map(p => `<div class="stack-pill">${p}</div>`).join('\n ')}
864
1116
  </div>
865
1117
 
1118
+ <div class="agent-status-legend">
1119
+ <span class="status-legend-item"><span class="legend-dot" style="background:#22c55e"></span> KEEP (${keepCount})</span>
1120
+ <span class="status-legend-item"><span class="legend-dot" style="background:#3b82f6"></span> MODIFY (${modifyCount})</span>
1121
+ <span class="status-legend-item"><span class="legend-dot" style="background:#f59e0b"></span> NEW (${createCount})</span>
1122
+ </div>
1123
+
866
1124
  <div class="agent-controls">
867
1125
  <button class="agent-ctrl-btn" onclick="toggleAll(true)">\u2705 Select All</button>
868
1126
  <button class="agent-ctrl-btn" onclick="toggleAll(false)">\u2B1C Select None</button>
@@ -910,18 +1168,22 @@ function animateCounter(el, target) {
910
1168
  <style>
911
1169
  .agent-system-card { padding: 1.5rem; }
912
1170
  .agent-stack-banner { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
913
- .stack-pill { background: #1e293b; border: 1px solid #334155; border-radius: 99px; padding: 0.4rem 1rem; font-size: 0.8rem; color: #94a3b8; white-space: pre-line; }
1171
+ .stack-pill { background: #1e293b; border: 1px solid #334155; border-radius: 99px; padding: 0.4rem 1rem; font-size: 0.8rem; color: #94a3b8; white-space: nowrap; }
1172
+ .agent-status-legend { display: flex; gap: 1.5rem; margin-bottom: 1rem; padding: 0.5rem 0; border-bottom: 1px solid #1e293b; }
1173
+ .status-legend-item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; color: #94a3b8; }
1174
+ .agent-status-badge { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.15rem 0.5rem; border-radius: 99px; font-size: 0.65rem; font-weight: 700; flex-shrink: 0; letter-spacing: 0.03em; }
1175
+ .agent-toggle-desc { display: block; font-size: 0.65rem; color: #64748b; margin-top: 0.15rem; line-height: 1.3; }
914
1176
  .agent-controls { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; }
915
1177
  .agent-ctrl-btn { background: #1e293b; border: 1px solid #334155; color: #e2e8f0; padding: 0.4rem 1rem; border-radius: 8px; font-size: 0.8rem; cursor: pointer; transition: all 0.2s; }
916
1178
  .agent-ctrl-btn:hover { background: #334155; }
917
1179
  .agent-count-label { color: #94a3b8; font-size: 0.85rem; margin-left: auto; }
918
1180
  #agentSelectedCount { color: #c084fc; font-weight: 700; }
919
1181
  .agent-section-subtitle { color: #e2e8f0; font-size: 1.05rem; font-weight: 700; margin: 1.25rem 0 0.75rem; }
920
- .agent-toggle-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.75rem; }
1182
+ .agent-toggle-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 0.75rem; }
921
1183
  .agent-toggle-card { cursor: pointer; transition: all 0.3s; }
922
1184
  .agent-toggle-card input { display: none; }
923
1185
  .agent-toggle-inner { display: flex; align-items: center; gap: 0.75rem; background: #1e293b; border: 2px solid #334155; border-radius: 12px; padding: 0.75rem 1rem; transition: all 0.3s; }
924
- .agent-toggle-card input:checked + .agent-toggle-inner { border-color: #818cf8; background: #1e1b4b; }
1186
+ .agent-toggle-card input:checked + .agent-toggle-inner { background: #1e1b4b; }
925
1187
  .agent-toggle-icon { font-size: 1.3rem; flex-shrink: 0; }
926
1188
  .agent-toggle-info { flex: 1; min-width: 0; }
927
1189
  .agent-toggle-name { display: block; color: #e2e8f0; font-weight: 600; font-size: 0.85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -992,7 +1254,50 @@ function animateCounter(el, target) {
992
1254
  min-height: 100vh;
993
1255
  }
994
1256
 
995
- .container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
1257
+ html { scroll-behavior: smooth; }
1258
+
1259
+ /* ── Layout ── */
1260
+ .report-layout { display: flex; min-height: 100vh; }
1261
+
1262
+ .sidebar {
1263
+ position: sticky; top: 0; height: 100vh; width: 220px; min-width: 220px;
1264
+ background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
1265
+ border-right: 1px solid #334155; padding: 1.5rem 0;
1266
+ display: flex; flex-direction: column; gap: 0.25rem;
1267
+ overflow-y: auto; z-index: 100;
1268
+ }
1269
+ .sidebar-title {
1270
+ font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
1271
+ letter-spacing: 0.15em; color: #475569; padding: 0 1.25rem; margin-bottom: 0.75rem;
1272
+ }
1273
+ .sidebar-link {
1274
+ display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 1.25rem;
1275
+ color: #94a3b8; text-decoration: none; font-size: 0.8rem; font-weight: 500;
1276
+ border-left: 3px solid transparent; transition: all 0.2s;
1277
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1278
+ }
1279
+ .sidebar-link:hover { color: #e2e8f0; background: #1e293b; border-left-color: #475569; }
1280
+ .sidebar-link.active { color: #c084fc; background: #c084fc10; border-left-color: #c084fc; font-weight: 700; }
1281
+
1282
+ .sidebar-toggle {
1283
+ display: none; position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 200;
1284
+ width: 48px; height: 48px; border-radius: 50%; border: none;
1285
+ background: #c084fc; color: #0f172a; font-size: 1.2rem; cursor: pointer;
1286
+ box-shadow: 0 4px 16px rgba(192,132,252,0.4); transition: all 0.2s;
1287
+ }
1288
+ .sidebar-toggle:hover { transform: scale(1.1); }
1289
+
1290
+ @media (max-width: 1024px) {
1291
+ .sidebar {
1292
+ position: fixed; left: -240px; top: 0; width: 240px; min-width: 240px;
1293
+ transition: left 0.3s ease; box-shadow: none;
1294
+ }
1295
+ .sidebar.sidebar-open { left: 0; box-shadow: 4px 0 24px rgba(0,0,0,0.5); }
1296
+ .sidebar-toggle { display: flex; align-items: center; justify-content: center; }
1297
+ .report-layout { flex-direction: column; }
1298
+ }
1299
+
1300
+ .container { max-width: 1200px; margin: 0 auto; padding: 2rem; flex: 1; min-width: 0; }
996
1301
 
997
1302
  /* ── Header ── */
998
1303
  .header {
@@ -1071,6 +1376,170 @@ function animateCounter(el, target) {
1071
1376
  display: flex; align-items: center; gap: 0.5rem;
1072
1377
  }
1073
1378
 
1379
+ /* ── Section Accordion ── */
1380
+ .section-accordion {
1381
+ margin: 1.5rem 0; border: 1px solid #334155; border-radius: 16px;
1382
+ background: transparent; overflow: hidden;
1383
+ }
1384
+ .section-accordion-header {
1385
+ cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.75rem;
1386
+ font-size: 1.3rem; font-weight: 700; color: #e2e8f0;
1387
+ padding: 1.25rem 1.5rem; background: linear-gradient(135deg, #1e293b, #0f172a);
1388
+ border-bottom: 1px solid transparent; transition: all 0.3s; user-select: none;
1389
+ }
1390
+ .section-accordion-header:hover { background: linear-gradient(135deg, #334155, #1e293b); }
1391
+ .section-accordion[open] > .section-accordion-header { border-bottom-color: #334155; }
1392
+ .section-accordion-header::after {
1393
+ content: '\\25B6'; margin-left: auto; font-size: 0.8rem; color: #818cf8;
1394
+ transition: transform 0.3s;
1395
+ }
1396
+ .section-accordion[open] > .section-accordion-header::after { transform: rotate(90deg); }
1397
+ .section-accordion-header::-webkit-details-marker { display: none; }
1398
+ .section-accordion-body { padding: 0.5rem 0; }
1399
+
1400
+ /* ── Project Overview ── */
1401
+ .overview-grid {
1402
+ display: grid;
1403
+ grid-template-columns: 1fr 1fr;
1404
+ gap: 1rem;
1405
+ margin-bottom: 1.5rem;
1406
+ }
1407
+ .overview-card {
1408
+ background: rgba(255,255,255,0.03);
1409
+ border: 1px solid #334155;
1410
+ border-radius: 12px;
1411
+ padding: 1.25rem;
1412
+ }
1413
+ .overview-main {
1414
+ grid-column: 1 / -1;
1415
+ background: linear-gradient(135deg, rgba(59,130,246,0.08), rgba(139,92,246,0.08));
1416
+ border-color: #3b82f6;
1417
+ }
1418
+ .overview-label {
1419
+ font-size: 0.75rem;
1420
+ font-weight: 600;
1421
+ text-transform: uppercase;
1422
+ letter-spacing: 0.05em;
1423
+ color: #94a3b8;
1424
+ margin-bottom: 0.75rem;
1425
+ }
1426
+ .overview-description {
1427
+ font-size: 1.1rem;
1428
+ color: #e2e8f0;
1429
+ line-height: 1.6;
1430
+ margin-bottom: 0.75rem;
1431
+ }
1432
+ .overview-purpose-row {
1433
+ display: flex;
1434
+ align-items: center;
1435
+ gap: 0.5rem;
1436
+ }
1437
+ .overview-purpose-label {
1438
+ font-size: 0.8rem;
1439
+ color: #64748b;
1440
+ }
1441
+ .overview-purpose-value {
1442
+ font-size: 0.85rem;
1443
+ color: #a78bfa;
1444
+ font-weight: 600;
1445
+ background: rgba(139,92,246,0.1);
1446
+ padding: 0.2rem 0.6rem;
1447
+ border-radius: 6px;
1448
+ }
1449
+ .overview-tags {
1450
+ display: flex;
1451
+ flex-wrap: wrap;
1452
+ gap: 0.4rem;
1453
+ }
1454
+ .overview-tag {
1455
+ font-size: 0.75rem;
1456
+ padding: 0.25rem 0.6rem;
1457
+ border-radius: 6px;
1458
+ font-weight: 500;
1459
+ }
1460
+ .tech-tag {
1461
+ background: rgba(59,130,246,0.15);
1462
+ color: #60a5fa;
1463
+ border: 1px solid rgba(59,130,246,0.3);
1464
+ }
1465
+ .keyword-tag {
1466
+ background: rgba(16,185,129,0.1);
1467
+ color: #34d399;
1468
+ border: 1px solid rgba(16,185,129,0.2);
1469
+ }
1470
+ .overview-entry {
1471
+ font-size: 0.8rem;
1472
+ background: rgba(255,255,255,0.05);
1473
+ padding: 0.25rem 0.5rem;
1474
+ border-radius: 4px;
1475
+ color: #e2e8f0;
1476
+ font-family: 'SF Mono', monospace;
1477
+ }
1478
+ .overview-entries {
1479
+ display: flex;
1480
+ flex-wrap: wrap;
1481
+ gap: 0.4rem;
1482
+ }
1483
+ .overview-modules-section {
1484
+ margin-top: 0.5rem;
1485
+ }
1486
+ .overview-modules-grid {
1487
+ display: grid;
1488
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
1489
+ gap: 0.75rem;
1490
+ margin-top: 0.5rem;
1491
+ }
1492
+ .overview-module {
1493
+ background: rgba(255,255,255,0.03);
1494
+ border: 1px solid #1e293b;
1495
+ border-radius: 8px;
1496
+ padding: 0.75rem 1rem;
1497
+ transition: border-color 0.2s;
1498
+ }
1499
+ .overview-module:hover {
1500
+ border-color: #3b82f6;
1501
+ }
1502
+ .overview-module-name {
1503
+ font-weight: 600;
1504
+ color: #e2e8f0;
1505
+ font-size: 0.9rem;
1506
+ margin-bottom: 0.25rem;
1507
+ }
1508
+ .overview-module-desc {
1509
+ color: #94a3b8;
1510
+ font-size: 0.75rem;
1511
+ margin-bottom: 0.25rem;
1512
+ }
1513
+ .overview-module-files {
1514
+ color: #64748b;
1515
+ font-size: 0.7rem;
1516
+ }
1517
+ .overview-empty {
1518
+ color: #475569;
1519
+ font-size: 0.85rem;
1520
+ font-style: italic;
1521
+ }
1522
+ @media (max-width: 768px) {
1523
+ .overview-grid { grid-template-columns: 1fr; }
1524
+ }
1525
+
1526
+ /* ── Operations Accordion (inside refactoring steps) ── */
1527
+ .rstep-ops-accordion {
1528
+ margin: 0.75rem 0; border: 1px solid #1e293b; border-radius: 10px; overflow: hidden;
1529
+ }
1530
+ .rstep-ops-toggle {
1531
+ cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.5rem;
1532
+ font-size: 0.9rem; font-weight: 600; color: #94a3b8;
1533
+ padding: 0.75rem 1rem; background: #0f172a; transition: all 0.2s;
1534
+ }
1535
+ .rstep-ops-toggle:hover { background: #1e293b; color: #e2e8f0; }
1536
+ .rstep-ops-toggle::after {
1537
+ content: '\\25B6'; margin-left: auto; font-size: 0.65rem; color: #818cf8;
1538
+ transition: transform 0.3s;
1539
+ }
1540
+ .rstep-ops-accordion[open] > .rstep-ops-toggle::after { transform: rotate(90deg); }
1541
+ .rstep-ops-toggle::-webkit-details-marker { display: none; }
1542
+
1074
1543
  /* ── Cards ── */
1075
1544
  .card {
1076
1545
  background: #1e293b; border-radius: 16px; border: 1px solid #334155;
@@ -1080,17 +1549,42 @@ function animateCounter(el, target) {
1080
1549
 
1081
1550
  /* ── Graph ── */
1082
1551
  .graph-card { padding: 1rem; }
1552
+ .graph-controls { margin-bottom: 0.75rem; }
1083
1553
  .graph-legend {
1084
1554
  display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.5rem;
1085
1555
  justify-content: center;
1086
1556
  }
1087
1557
  .legend-item { display: flex; align-items: center; gap: 4px; font-size: 0.75rem; color: #94a3b8; }
1088
- .legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
1558
+ .legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
1559
+ .graph-filters {
1560
+ display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap;
1561
+ justify-content: center; margin-top: 0.5rem;
1562
+ }
1563
+ .graph-search {
1564
+ background: #0f172a; border: 1px solid #334155; border-radius: 8px;
1565
+ padding: 0.4rem 0.75rem; color: #e2e8f0; font-size: 0.8rem;
1566
+ outline: none; width: 180px; transition: border-color 0.2s;
1567
+ }
1568
+ .graph-search:focus { border-color: #818cf8; }
1569
+ .graph-layer-filters {
1570
+ display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;
1571
+ }
1572
+ .graph-filter-check {
1573
+ display: flex; align-items: center; gap: 4px;
1574
+ font-size: 0.75rem; color: #94a3b8; cursor: pointer;
1575
+ }
1576
+ .graph-filter-check input { width: 14px; height: 14px; accent-color: #818cf8; }
1577
+ .graph-limit-notice {
1578
+ text-align: center; font-size: 0.75rem; color: #f59e0b;
1579
+ background: #f59e0b15; padding: 0.3rem 0.75rem; border-radius: 6px;
1580
+ margin-top: 0.5rem;
1581
+ }
1089
1582
  .graph-hint {
1090
1583
  text-align: center; font-size: 0.75rem; color: #475569; margin-top: 0.5rem;
1091
1584
  font-style: italic;
1092
1585
  }
1093
- #dep-graph svg { background: rgba(0,0,0,0.2); border-radius: 12px; }
1586
+ #dep-graph svg { background: rgba(0,0,0,0.2); border-radius: 12px; cursor: grab; }
1587
+ #dep-graph svg:active { cursor: grabbing; }
1094
1588
 
1095
1589
  /* ── Layers Grid ── */
1096
1590
  .layers-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; }