@dtt_siye/atool 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +235 -0
  3. package/VERSION +1 -0
  4. package/agents/code-reviewer.md +29 -0
  5. package/bin/atool.js +235 -0
  6. package/bin/postinstall.js +23 -0
  7. package/hooks/doc-sync-reminder +155 -0
  8. package/hooks/hooks-cursor.json +37 -0
  9. package/hooks/hooks.json +37 -0
  10. package/hooks/prompt-guard +135 -0
  11. package/hooks/session-start +286 -0
  12. package/install.sh +603 -0
  13. package/lib/analyze-source.sh +1265 -0
  14. package/lib/common.sh +1041 -0
  15. package/lib/compute-importance.sh +598 -0
  16. package/lib/detect-stack.sh +354 -0
  17. package/lib/generate-visualization.sh +266 -0
  18. package/lib/install-claude.sh +43 -0
  19. package/lib/install-cursor.sh +281 -0
  20. package/lib/install-hooks.sh +285 -0
  21. package/lib/install-kiro.sh +543 -0
  22. package/lib/install-mcp.sh +99 -0
  23. package/lib/install-skills.sh +129 -0
  24. package/lib/knowledge-graph.sh +1014 -0
  25. package/lib/multi-dimensional-analysis.sh +413 -0
  26. package/lib/pre-scan.sh +1045 -0
  27. package/lib/project-init.sh +552 -0
  28. package/lib/visualization-template.html +545 -0
  29. package/mcp/recommended.json +24 -0
  30. package/package.json +39 -0
  31. package/skills/_superpowers/.claude-plugin/marketplace.json +20 -0
  32. package/skills/_superpowers/.claude-plugin/plugin.json +20 -0
  33. package/skills/_superpowers/.codex/INSTALL.md +67 -0
  34. package/skills/_superpowers/.cursor-plugin/plugin.json +25 -0
  35. package/skills/_superpowers/.gitattributes +18 -0
  36. package/skills/_superpowers/.github/FUNDING.yml +3 -0
  37. package/skills/_superpowers/.github/ISSUE_TEMPLATE/bug_report.md +52 -0
  38. package/skills/_superpowers/.github/ISSUE_TEMPLATE/config.yml +5 -0
  39. package/skills/_superpowers/.github/ISSUE_TEMPLATE/feature_request.md +34 -0
  40. package/skills/_superpowers/.github/ISSUE_TEMPLATE/platform_support.md +23 -0
  41. package/skills/_superpowers/.github/PULL_REQUEST_TEMPLATE.md +87 -0
  42. package/skills/_superpowers/.opencode/INSTALL.md +83 -0
  43. package/skills/_superpowers/.opencode/plugins/superpowers.js +107 -0
  44. package/skills/_superpowers/CHANGELOG.md +13 -0
  45. package/skills/_superpowers/CODE_OF_CONDUCT.md +128 -0
  46. package/skills/_superpowers/GEMINI.md +2 -0
  47. package/skills/_superpowers/LICENSE +21 -0
  48. package/skills/_superpowers/README.md +187 -0
  49. package/skills/_superpowers/RELEASE-NOTES.md +1083 -0
  50. package/skills/_superpowers/agents/code-reviewer.md +48 -0
  51. package/skills/_superpowers/commands/brainstorm.md +5 -0
  52. package/skills/_superpowers/commands/execute-plan.md +5 -0
  53. package/skills/_superpowers/commands/write-plan.md +5 -0
  54. package/skills/_superpowers/docs/README.codex.md +126 -0
  55. package/skills/_superpowers/docs/README.opencode.md +130 -0
  56. package/skills/_superpowers/docs/plans/2025-11-22-opencode-support-design.md +294 -0
  57. package/skills/_superpowers/docs/plans/2025-11-22-opencode-support-implementation.md +1095 -0
  58. package/skills/_superpowers/docs/plans/2025-11-28-skills-improvements-from-user-feedback.md +711 -0
  59. package/skills/_superpowers/docs/plans/2026-01-17-visual-brainstorming.md +571 -0
  60. package/skills/_superpowers/docs/superpowers/plans/2026-01-22-document-review-system.md +301 -0
  61. package/skills/_superpowers/docs/superpowers/plans/2026-02-19-visual-brainstorming-refactor.md +523 -0
  62. package/skills/_superpowers/docs/superpowers/plans/2026-03-11-zero-dep-brainstorm-server.md +479 -0
  63. package/skills/_superpowers/docs/superpowers/plans/2026-03-23-codex-app-compatibility.md +564 -0
  64. package/skills/_superpowers/docs/superpowers/specs/2026-01-22-document-review-system-design.md +136 -0
  65. package/skills/_superpowers/docs/superpowers/specs/2026-02-19-visual-brainstorming-refactor-design.md +162 -0
  66. package/skills/_superpowers/docs/superpowers/specs/2026-03-11-zero-dep-brainstorm-server-design.md +118 -0
  67. package/skills/_superpowers/docs/superpowers/specs/2026-03-23-codex-app-compatibility-design.md +244 -0
  68. package/skills/_superpowers/docs/testing.md +303 -0
  69. package/skills/_superpowers/docs/windows/polyglot-hooks.md +212 -0
  70. package/skills/_superpowers/gemini-extension.json +6 -0
  71. package/skills/_superpowers/hooks/hooks-cursor.json +10 -0
  72. package/skills/_superpowers/hooks/hooks.json +16 -0
  73. package/skills/_superpowers/hooks/run-hook.cmd +46 -0
  74. package/skills/_superpowers/hooks/session-start +57 -0
  75. package/skills/_superpowers/package.json +6 -0
  76. package/skills/_superpowers/skills/brainstorming/SKILL.md +164 -0
  77. package/skills/_superpowers/skills/brainstorming/scripts/frame-template.html +214 -0
  78. package/skills/_superpowers/skills/brainstorming/scripts/helper.js +88 -0
  79. package/skills/_superpowers/skills/brainstorming/scripts/server.cjs +354 -0
  80. package/skills/_superpowers/skills/brainstorming/scripts/start-server.sh +148 -0
  81. package/skills/_superpowers/skills/brainstorming/scripts/stop-server.sh +56 -0
  82. package/skills/_superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  83. package/skills/_superpowers/skills/brainstorming/visual-companion.md +287 -0
  84. package/skills/_superpowers/skills/dispatching-parallel-agents/SKILL.md +182 -0
  85. package/skills/_superpowers/skills/executing-plans/SKILL.md +70 -0
  86. package/skills/_superpowers/skills/finishing-a-development-branch/SKILL.md +200 -0
  87. package/skills/_superpowers/skills/receiving-code-review/SKILL.md +213 -0
  88. package/skills/_superpowers/skills/requesting-code-review/SKILL.md +105 -0
  89. package/skills/_superpowers/skills/requesting-code-review/code-reviewer.md +146 -0
  90. package/skills/_superpowers/skills/subagent-driven-development/SKILL.md +277 -0
  91. package/skills/_superpowers/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  92. package/skills/_superpowers/skills/subagent-driven-development/implementer-prompt.md +113 -0
  93. package/skills/_superpowers/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  94. package/skills/_superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  95. package/skills/_superpowers/skills/systematic-debugging/SKILL.md +296 -0
  96. package/skills/_superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  97. package/skills/_superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  98. package/skills/_superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  99. package/skills/_superpowers/skills/systematic-debugging/find-polluter.sh +63 -0
  100. package/skills/_superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  101. package/skills/_superpowers/skills/systematic-debugging/test-academic.md +14 -0
  102. package/skills/_superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  103. package/skills/_superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  104. package/skills/_superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  105. package/skills/_superpowers/skills/test-driven-development/SKILL.md +371 -0
  106. package/skills/_superpowers/skills/test-driven-development/testing-anti-patterns.md +299 -0
  107. package/skills/_superpowers/skills/using-git-worktrees/SKILL.md +218 -0
  108. package/skills/_superpowers/skills/using-superpowers/SKILL.md +115 -0
  109. package/skills/_superpowers/skills/using-superpowers/references/codex-tools.md +100 -0
  110. package/skills/_superpowers/skills/using-superpowers/references/gemini-tools.md +33 -0
  111. package/skills/_superpowers/skills/verification-before-completion/SKILL.md +139 -0
  112. package/skills/_superpowers/skills/writing-plans/SKILL.md +152 -0
  113. package/skills/_superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  114. package/skills/_superpowers/skills/writing-skills/SKILL.md +655 -0
  115. package/skills/_superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  116. package/skills/_superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  117. package/skills/_superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  118. package/skills/_superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  119. package/skills/_superpowers/skills/writing-skills/render-graphs.js +168 -0
  120. package/skills/_superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  121. package/skills/_superpowers/tests/brainstorm-server/package-lock.json +36 -0
  122. package/skills/_superpowers/tests/brainstorm-server/package.json +10 -0
  123. package/skills/_superpowers/tests/brainstorm-server/server.test.js +427 -0
  124. package/skills/_superpowers/tests/brainstorm-server/windows-lifecycle.test.sh +351 -0
  125. package/skills/_superpowers/tests/brainstorm-server/ws-protocol.test.js +392 -0
  126. package/skills/_superpowers/tests/claude-code/README.md +158 -0
  127. package/skills/_superpowers/tests/claude-code/analyze-token-usage.py +168 -0
  128. package/skills/_superpowers/tests/claude-code/run-skill-tests.sh +187 -0
  129. package/skills/_superpowers/tests/claude-code/test-document-review-system.sh +177 -0
  130. package/skills/_superpowers/tests/claude-code/test-helpers.sh +202 -0
  131. package/skills/_superpowers/tests/claude-code/test-subagent-driven-development-integration.sh +314 -0
  132. package/skills/_superpowers/tests/claude-code/test-subagent-driven-development.sh +165 -0
  133. package/skills/_superpowers/tests/explicit-skill-requests/prompts/action-oriented.txt +3 -0
  134. package/skills/_superpowers/tests/explicit-skill-requests/prompts/after-planning-flow.txt +17 -0
  135. package/skills/_superpowers/tests/explicit-skill-requests/prompts/claude-suggested-it.txt +11 -0
  136. package/skills/_superpowers/tests/explicit-skill-requests/prompts/i-know-what-sdd-means.txt +8 -0
  137. package/skills/_superpowers/tests/explicit-skill-requests/prompts/mid-conversation-execute-plan.txt +3 -0
  138. package/skills/_superpowers/tests/explicit-skill-requests/prompts/please-use-brainstorming.txt +1 -0
  139. package/skills/_superpowers/tests/explicit-skill-requests/prompts/skip-formalities.txt +3 -0
  140. package/skills/_superpowers/tests/explicit-skill-requests/prompts/subagent-driven-development-please.txt +1 -0
  141. package/skills/_superpowers/tests/explicit-skill-requests/prompts/use-systematic-debugging.txt +1 -0
  142. package/skills/_superpowers/tests/explicit-skill-requests/run-all.sh +70 -0
  143. package/skills/_superpowers/tests/explicit-skill-requests/run-claude-describes-sdd.sh +100 -0
  144. package/skills/_superpowers/tests/explicit-skill-requests/run-extended-multiturn-test.sh +113 -0
  145. package/skills/_superpowers/tests/explicit-skill-requests/run-haiku-test.sh +144 -0
  146. package/skills/_superpowers/tests/explicit-skill-requests/run-multiturn-test.sh +143 -0
  147. package/skills/_superpowers/tests/explicit-skill-requests/run-test.sh +136 -0
  148. package/skills/_superpowers/tests/opencode/run-tests.sh +163 -0
  149. package/skills/_superpowers/tests/opencode/setup.sh +73 -0
  150. package/skills/_superpowers/tests/opencode/test-plugin-loading.sh +72 -0
  151. package/skills/_superpowers/tests/opencode/test-priority.sh +198 -0
  152. package/skills/_superpowers/tests/opencode/test-tools.sh +104 -0
  153. package/skills/_superpowers/tests/skill-triggering/prompts/dispatching-parallel-agents.txt +8 -0
  154. package/skills/_superpowers/tests/skill-triggering/prompts/executing-plans.txt +1 -0
  155. package/skills/_superpowers/tests/skill-triggering/prompts/requesting-code-review.txt +3 -0
  156. package/skills/_superpowers/tests/skill-triggering/prompts/systematic-debugging.txt +11 -0
  157. package/skills/_superpowers/tests/skill-triggering/prompts/test-driven-development.txt +7 -0
  158. package/skills/_superpowers/tests/skill-triggering/prompts/writing-plans.txt +10 -0
  159. package/skills/_superpowers/tests/skill-triggering/run-all.sh +60 -0
  160. package/skills/_superpowers/tests/skill-triggering/run-test.sh +88 -0
  161. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/design.md +81 -0
  162. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/plan.md +172 -0
  163. package/skills/_superpowers/tests/subagent-driven-dev/go-fractals/scaffold.sh +45 -0
  164. package/skills/_superpowers/tests/subagent-driven-dev/run-test.sh +106 -0
  165. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/design.md +70 -0
  166. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/plan.md +222 -0
  167. package/skills/_superpowers/tests/subagent-driven-dev/svelte-todo/scaffold.sh +46 -0
  168. package/skills/ai-project-architecture/SKILL.md +632 -0
  169. package/skills/ai-project-architecture/reference/structure-rules.md +406 -0
  170. package/skills/ai-project-architecture/templates/compliance-report.md +300 -0
  171. package/skills/ai-project-architecture/templates/migration-plan.md +433 -0
  172. package/skills/ai-project-architecture/templates/verification-checklist.md +408 -0
  173. package/skills/android-conventions/SKILL.md +125 -0
  174. package/skills/atool-init/SKILL.md +141 -0
  175. package/skills/clarify-before-build/SKILL.md +107 -0
  176. package/skills/code-review/SKILL.md +406 -0
  177. package/skills/code-review/rules/architecture.md +285 -0
  178. package/skills/code-review/rules/coupling-cohesion.md +309 -0
  179. package/skills/code-review/rules/dead-code.md +115 -0
  180. package/skills/code-review/rules/deprecation-debt.md +279 -0
  181. package/skills/code-review/rules/duplication.md +104 -0
  182. package/skills/code-review/rules/error-security.md +143 -0
  183. package/skills/code-review/rules/maintainability.md +203 -0
  184. package/skills/code-review/rules/quality.md +158 -0
  185. package/skills/devops-conventions/SKILL.md +205 -0
  186. package/skills/doc-coauthoring/SKILL.md +392 -0
  187. package/skills/doc-standards-enforcer/SKILL.md +290 -0
  188. package/skills/doc-standards-enforcer/examples/valid-document-example.md +67 -0
  189. package/skills/doc-standards-enforcer/references/101-standards-summary.md +318 -0
  190. package/skills/doc-standards-enforcer/scripts/check_references.py +175 -0
  191. package/skills/doc-standards-enforcer/scripts/fix_common_issues.py +303 -0
  192. package/skills/doc-standards-enforcer/scripts/validate_doc_standards.py +332 -0
  193. package/skills/docx/LICENSE.txt +30 -0
  194. package/skills/docx/SKILL.md +200 -0
  195. package/skills/docx/docx-js.md +350 -0
  196. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  197. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  198. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  199. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  200. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  201. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  202. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  203. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  204. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  205. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  206. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  207. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  208. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  209. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  210. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  211. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  212. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  213. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  214. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  215. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  216. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  217. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  218. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  219. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  220. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  221. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  222. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  223. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  224. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  225. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  226. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  227. package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  228. package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  229. package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  230. package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  231. package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  232. package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  233. package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  234. package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  235. package/skills/docx/ooxml/scripts/pack.py +159 -0
  236. package/skills/docx/ooxml/scripts/unpack.py +29 -0
  237. package/skills/docx/ooxml/scripts/validate.py +69 -0
  238. package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  239. package/skills/docx/ooxml/scripts/validation/base.py +951 -0
  240. package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  241. package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  242. package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  243. package/skills/docx/ooxml.md +610 -0
  244. package/skills/docx/scripts/__init__.py +1 -0
  245. package/skills/docx/scripts/document.py +1276 -0
  246. package/skills/docx/scripts/templates/comments.xml +3 -0
  247. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  248. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  249. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  250. package/skills/docx/scripts/templates/people.xml +3 -0
  251. package/skills/docx/scripts/utilities.py +374 -0
  252. package/skills/flutter-conventions/SKILL.md +70 -0
  253. package/skills/go-conventions/SKILL.md +230 -0
  254. package/skills/harmony-conventions/SKILL.md +156 -0
  255. package/skills/java-conventions/SKILL.md +277 -0
  256. package/skills/pdf/LICENSE.txt +30 -0
  257. package/skills/pdf/SKILL.md +297 -0
  258. package/skills/pdf/forms.md +205 -0
  259. package/skills/pdf/reference.md +612 -0
  260. package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  261. package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  262. package/skills/pdf/scripts/check_fillable_fields.py +12 -0
  263. package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  264. package/skills/pdf/scripts/create_validation_image.py +41 -0
  265. package/skills/pdf/scripts/extract_form_field_info.py +152 -0
  266. package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  267. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  268. package/skills/pptx/LICENSE.txt +30 -0
  269. package/skills/pptx/SKILL.md +487 -0
  270. package/skills/pptx/html2pptx.md +625 -0
  271. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  272. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  273. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  274. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  275. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  276. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  277. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  278. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  279. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  280. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  281. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  282. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  283. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  284. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  285. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  286. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  287. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  288. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  289. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  290. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  291. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  292. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  293. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  294. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  295. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  296. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  297. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  298. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  299. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  300. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  301. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  302. package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  303. package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  304. package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  305. package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  306. package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  307. package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  308. package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  309. package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  310. package/skills/pptx/ooxml/scripts/pack.py +159 -0
  311. package/skills/pptx/ooxml/scripts/unpack.py +29 -0
  312. package/skills/pptx/ooxml/scripts/validate.py +69 -0
  313. package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  314. package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  315. package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  316. package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  317. package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  318. package/skills/pptx/ooxml.md +427 -0
  319. package/skills/pptx/scripts/html2pptx.js +979 -0
  320. package/skills/pptx/scripts/inventory.py +1020 -0
  321. package/skills/pptx/scripts/rearrange.py +231 -0
  322. package/skills/pptx/scripts/replace.py +385 -0
  323. package/skills/pptx/scripts/thumbnail.py +450 -0
  324. package/skills/project-analyze/SKILL.md +270 -0
  325. package/skills/project-analyze/phases/phase0-discovery.md +278 -0
  326. package/skills/project-analyze/phases/phase0.5-prescan.md +139 -0
  327. package/skills/project-analyze/phases/phase1-inventory.md +94 -0
  328. package/skills/project-analyze/phases/phase2-deep-analysis.md +249 -0
  329. package/skills/project-analyze/phases/phase2a-l4-analysis.md +94 -0
  330. package/skills/project-analyze/phases/phase2b-l5-analysis.md +97 -0
  331. package/skills/project-analyze/phases/phase3-knowledge-graph.md +120 -0
  332. package/skills/project-analyze/phases/phase3a-multi-dimensional.md +61 -0
  333. package/skills/project-analyze/phases/phase4-code-quality.md +81 -0
  334. package/skills/project-analyze/phases/phase5-synthesis.md +284 -0
  335. package/skills/project-analyze/phases/phase6-validation.md +179 -0
  336. package/skills/project-analyze/prompts/code-review-agent.md +122 -0
  337. package/skills/project-analyze/prompts/deep-analysis-agent.md +107 -0
  338. package/skills/project-analyze/prompts/inventory-agent.md +67 -0
  339. package/skills/project-analyze/prompts/l4-analysis-agent.md +98 -0
  340. package/skills/project-analyze/rules/android.md +282 -0
  341. package/skills/project-analyze/rules/devops.md +443 -0
  342. package/skills/project-analyze/rules/generic.md +243 -0
  343. package/skills/project-analyze/rules/go.md +289 -0
  344. package/skills/project-analyze/rules/harmony.md +257 -0
  345. package/skills/project-analyze/rules/java.md +507 -0
  346. package/skills/project-analyze/rules/mobile-flutter.md +315 -0
  347. package/skills/project-analyze/rules/mobile-react-native.md +283 -0
  348. package/skills/project-analyze/rules/mobile-swift.md +323 -0
  349. package/skills/project-analyze/rules/python.md +317 -0
  350. package/skills/project-analyze/rules/rust-tauri.md +243 -0
  351. package/skills/project-analyze/rules/rust.md +296 -0
  352. package/skills/project-analyze/rules/web-nextjs.md +364 -0
  353. package/skills/project-analyze/rules/web-react.md +298 -0
  354. package/skills/project-analyze/rules/web-vue.md +378 -0
  355. package/skills/project-analyze/rules/web.md +390 -0
  356. package/skills/project-query/SKILL.md +224 -0
  357. package/skills/project-query/rules/query-templates.md +212 -0
  358. package/skills/python-conventions/SKILL.md +169 -0
  359. package/skills/react-native-conventions/SKILL.md +73 -0
  360. package/skills/requirements-writer/README.md +153 -0
  361. package/skills/requirements-writer/SKILL.md +341 -0
  362. package/skills/requirements-writer/examples/prd-outline-example.md +217 -0
  363. package/skills/requirements-writer/templates/module-prd-template.md +362 -0
  364. package/skills/requirements-writer/templates/prd-outline-template.md +185 -0
  365. package/skills/requirements-writer/templates/user-story-template.md +1125 -0
  366. package/skills/rust-conventions/SKILL.md +361 -0
  367. package/skills/smart-dispatch/SKILL.md +296 -0
  368. package/skills/smart-dispatch/implementer-prompt.md +146 -0
  369. package/skills/smart-dispatch/reviewer-prompt.md +199 -0
  370. package/skills/software-architecture/SKILL.md +278 -0
  371. package/skills/swift-conventions/SKILL.md +72 -0
  372. package/skills/ui-ux-pro/SKILL.md +140 -0
  373. package/skills/verification-before-completion/SKILL.md +119 -0
  374. package/skills/web-conventions/SKILL.md +259 -0
  375. package/skills/webapp-testing/LICENSE.txt +202 -0
  376. package/skills/webapp-testing/SKILL.md +97 -0
  377. package/skills/webapp-testing/examples/console_logging.py +35 -0
  378. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  379. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  380. package/skills/webapp-testing/scripts/with_server.py +106 -0
  381. package/skills/writing-plans/SKILL.md +144 -0
  382. package/skills/xlsx/LICENSE.txt +30 -0
  383. package/skills/xlsx/SKILL.md +292 -0
  384. package/skills/xlsx/recalc.py +178 -0
  385. package/templates/CLAUDE.md.android +57 -0
  386. package/templates/CLAUDE.md.devops +50 -0
  387. package/templates/CLAUDE.md.generic +34 -0
  388. package/templates/CLAUDE.md.go +67 -0
  389. package/templates/CLAUDE.md.harmony +54 -0
  390. package/templates/CLAUDE.md.java +56 -0
  391. package/templates/CLAUDE.md.mobile-flutter +38 -0
  392. package/templates/CLAUDE.md.mobile-react-native +37 -0
  393. package/templates/CLAUDE.md.mobile-swift +40 -0
  394. package/templates/CLAUDE.md.python +65 -0
  395. package/templates/CLAUDE.md.rust +68 -0
  396. package/templates/CLAUDE.md.rust-tauri +120 -0
  397. package/templates/CLAUDE.md.web +63 -0
  398. package/templates/COMPONENT.md.android +58 -0
  399. package/templates/COMPONENT.md.devops +54 -0
  400. package/templates/COMPONENT.md.generic +35 -0
  401. package/templates/COMPONENT.md.go +59 -0
  402. package/templates/COMPONENT.md.harmony +63 -0
  403. package/templates/COMPONENT.md.java +69 -0
  404. package/templates/COMPONENT.md.mobile-flutter +56 -0
  405. package/templates/COMPONENT.md.mobile-react-native +55 -0
  406. package/templates/COMPONENT.md.mobile-swift +56 -0
  407. package/templates/COMPONENT.md.python +67 -0
  408. package/templates/COMPONENT.md.rust +57 -0
  409. package/templates/COMPONENT.md.rust-tauri +66 -0
  410. package/templates/COMPONENT.md.web +39 -0
  411. package/templates/README.md.android +71 -0
  412. package/templates/README.md.devops +68 -0
  413. package/templates/README.md.generic +39 -0
  414. package/templates/README.md.go +70 -0
  415. package/templates/README.md.harmony +72 -0
  416. package/templates/README.md.java +73 -0
  417. package/templates/README.md.mobile-flutter +69 -0
  418. package/templates/README.md.mobile-react-native +65 -0
  419. package/templates/README.md.mobile-swift +69 -0
  420. package/templates/README.md.monorepo +59 -0
  421. package/templates/README.md.python +66 -0
  422. package/templates/README.md.rust +69 -0
  423. package/templates/README.md.rust-tauri +149 -0
  424. package/templates/README.md.web +94 -0
  425. package/templates/UI_STYLE.md.android +74 -0
  426. package/templates/UI_STYLE.md.devops +50 -0
  427. package/templates/UI_STYLE.md.generic +31 -0
  428. package/templates/UI_STYLE.md.go +49 -0
  429. package/templates/UI_STYLE.md.harmony +71 -0
  430. package/templates/UI_STYLE.md.java +61 -0
  431. package/templates/UI_STYLE.md.mobile-flutter +70 -0
  432. package/templates/UI_STYLE.md.mobile-react-native +71 -0
  433. package/templates/UI_STYLE.md.mobile-swift +71 -0
  434. package/templates/UI_STYLE.md.python +58 -0
  435. package/templates/UI_STYLE.md.rust +52 -0
  436. package/templates/UI_STYLE.md.rust-tauri +102 -0
  437. package/templates/UI_STYLE.md.web +92 -0
  438. package/templates/cursor-rules.android.mdc +33 -0
  439. package/templates/cursor-rules.devops.mdc +32 -0
  440. package/templates/cursor-rules.generic.mdc +25 -0
  441. package/templates/cursor-rules.go.mdc +34 -0
  442. package/templates/cursor-rules.harmony.mdc +30 -0
  443. package/templates/cursor-rules.java.mdc +30 -0
  444. package/templates/cursor-rules.mobile-flutter.mdc +42 -0
  445. package/templates/cursor-rules.mobile-react-native.mdc +43 -0
  446. package/templates/cursor-rules.mobile-swift.mdc +42 -0
  447. package/templates/cursor-rules.python.mdc +33 -0
  448. package/templates/cursor-rules.rust-tauri.mdc +67 -0
  449. package/templates/cursor-rules.rust.mdc +30 -0
  450. package/templates/cursor-rules.web.mdc +30 -0
  451. package/templates/kiro-steering.android.md +39 -0
  452. package/templates/kiro-steering.devops.md +32 -0
  453. package/templates/kiro-steering.generic.md +28 -0
  454. package/templates/kiro-steering.go.md +41 -0
  455. package/templates/kiro-steering.harmony.md +36 -0
  456. package/templates/kiro-steering.java.md +37 -0
  457. package/templates/kiro-steering.mobile-flutter.md +73 -0
  458. package/templates/kiro-steering.mobile-react-native.md +71 -0
  459. package/templates/kiro-steering.mobile-swift.md +62 -0
  460. package/templates/kiro-steering.python.md +34 -0
  461. package/templates/kiro-steering.rust-tauri.md +50 -0
  462. package/templates/kiro-steering.rust.md +36 -0
  463. package/templates/kiro-steering.web.md +41 -0
@@ -0,0 +1,1014 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck source=lib/common.sh
3
+ # knowledge-graph.sh — Knowledge graph construction helpers for project-analyze v5.0
4
+ #
5
+ # Usage: source lib/knowledge-graph.sh
6
+ #
7
+ # Provides functions for building and analyzing the project knowledge graph
8
+ # from Phase 1 inventory data. All functions operate on JSON files
9
+ # in .atool-docs/inventory/ and output structured data to .atool-docs/knowledge-graph.json
10
+ set -euo pipefail
11
+
12
+ # === Node Counting ===
13
+
14
+ # Count nodes by type from inventory JSON files.
15
+ # Each inventory file is expected to have a top-level "files" array where each
16
+ # entry contains a "type" field (module, component, function, store, etc.).
17
+ #
18
+ # Args:
19
+ # $1 - inventory_dir: path to .atool-docs/inventory/
20
+ # Output: JSON object {"total": N, "module": N, "component": N, ...} to stdout
21
+ count_graph_nodes() {
22
+ local inventory_dir="$1"
23
+
24
+ if [[ ! -d "$inventory_dir" ]]; then
25
+ echo "{}"
26
+ return
27
+ fi
28
+
29
+ # Requires jq
30
+ if ! command -v jq &>/dev/null; then
31
+ echo "{}"
32
+ return
33
+ fi
34
+
35
+ # Aggregate node counts from all inventory JSON files.
36
+ # Each file has "files" array with "type" field per entry.
37
+ # Null-coalesce missing types to 0.
38
+ local result
39
+ result=$(jq -s \
40
+ '[ .[].files // [] | .[].type ]
41
+ | group_by(.)
42
+ | map({key: .[0], value: length})
43
+ | from_entries
44
+ | .total = ([ .[] | select(type == "number") ] | add // 0)
45
+ | {
46
+ total,
47
+ module: (.module // 0),
48
+ component: (.component // 0),
49
+ function: (.function // 0),
50
+ store: (.store // 0),
51
+ data_entity: (.data_entity // 0),
52
+ api_endpoint: (.api_endpoint // 0),
53
+ route: (.route // 0),
54
+ config: (.config // 0)
55
+ }' "$inventory_dir"/*.json 2>/dev/null)
56
+
57
+ if [[ -n "$result" ]]; then
58
+ echo "$result"
59
+ else
60
+ echo "{}"
61
+ fi
62
+ }
63
+
64
+ # === Edge Counting ===
65
+
66
+ # Count edges by type from inventory JSON files.
67
+ # Each inventory file has "outgoing_edges" array with "type" field per entry.
68
+ #
69
+ # Args:
70
+ # $1 - inventory_dir: path to .atool-docs/inventory/
71
+ # Output: JSON object {"total": N, "depends_on": N, "calls": N, ...} to stdout
72
+ count_graph_edges() {
73
+ local inventory_dir="$1"
74
+
75
+ if [[ ! -d "$inventory_dir" ]]; then
76
+ echo "{}"
77
+ return
78
+ fi
79
+
80
+ if ! command -v jq &>/dev/null; then
81
+ echo "{}"
82
+ return
83
+ fi
84
+
85
+ # Aggregate edge counts from all inventory files.
86
+ # Each file has "outgoing_edges" array with "type" field per entry.
87
+ local result
88
+ result=$(jq -s \
89
+ '[ .[].outgoing_edges // [] | .[].type ]
90
+ | group_by(.)
91
+ | map({key: .[0], value: length})
92
+ | from_entries
93
+ | .total = ([ .[] | select(type == "number") ] | add // 0)
94
+ | {
95
+ total,
96
+ depends_on: (.depends_on // 0),
97
+ calls: (.calls // 0),
98
+ reads_state: (.reads_state // 0),
99
+ returns: (.returns // 0),
100
+ renders: (.renders // 0),
101
+ routes_to: (.routes_to // 0),
102
+ sends_http: (.sends_http // 0),
103
+ persists_to: (.persists_to // 0),
104
+ implements: (.implements // 0),
105
+ extends: (.extends // 0)
106
+ }' "$inventory_dir"/*.json 2>/dev/null)
107
+
108
+ if [[ -n "$result" ]]; then
109
+ echo "$result"
110
+ else
111
+ echo "{}"
112
+ fi
113
+ }
114
+
115
+ # === Cycle Detection ===
116
+
117
+ # Detect circular dependencies in the module dependency graph.
118
+ # Extracts "depends_on" edges from inventory, then finds 2-cycles and 3-cycles.
119
+ #
120
+ # Args:
121
+ # $1 - inventory_dir: path to .atool-docs/inventory/
122
+ # Output: JSON array of cycles, each cycle is a sorted array of module names.
123
+ # Example: [["module-a","module-b"], ["module-x","module-y","module-z"]]
124
+ detect_cycles() {
125
+ local inventory_dir="$1"
126
+
127
+ if [[ ! -d "$inventory_dir" ]]; then
128
+ echo "[]"
129
+ return
130
+ fi
131
+
132
+ if ! command -v jq &>/dev/null; then
133
+ echo "[]"
134
+ return
135
+ fi
136
+
137
+ # Build adjacency list from depends_on edges: source_module -> [target_modules]
138
+ # Each edge in outgoing_edges has: type, source, target_module
139
+ local adj_json
140
+ adj_json=$(jq -s \
141
+ '[ .[].outgoing_edges // []
142
+ | .[]
143
+ | select(.type == "depends_on")
144
+ | {source: (.source // ""), target: (.target_module // "")}
145
+ | select(.source != "" and .target != "") ]
146
+ | group_by(.source)
147
+ | map({key: .[0].source, value: (map(.target) | unique)})
148
+ | from_entries' "$inventory_dir"/*.json 2>/dev/null)
149
+
150
+ if [[ -z "$adj_json" || "$adj_json" == "null" || "$adj_json" == "{}" ]]; then
151
+ echo "[]"
152
+ return
153
+ fi
154
+
155
+ # Detect 2-cycles (A->B and B->A) and 3-cycles (A->B->C->A)
156
+ local cycles
157
+ cycles=$(echo "$adj_json" | jq '
158
+ . as $adj |
159
+
160
+ # Collect all module names
161
+ ($adj | keys) as $modules |
162
+
163
+ # Find 2-cycles: A->B where B->A
164
+ [ $modules[] as $a |
165
+ ($adj[$a] // [])[] as $b |
166
+ select($b > $a) |
167
+ select(($adj[$b] // []) | index($a)) |
168
+ [$a, $b] | sort
169
+ ] as $two_cycles |
170
+
171
+ # Find 3-cycles: A->B->C where C->A
172
+ [ $modules[] as $a |
173
+ ($adj[$a] // [])[] as $b |
174
+ select($b != $a) |
175
+ ($adj[$b] // [])[] as $c |
176
+ select($c != $a and $c != $b) |
177
+ select(($adj[$c] // []) | index($a)) |
178
+ [$a, $b, $c] | sort
179
+ ] | unique as $three_cycles |
180
+
181
+ # Merge and deduplicate
182
+ ($two_cycles + $three_cycles) | unique
183
+ ')
184
+
185
+ echo "${cycles:-[]}"
186
+ }
187
+
188
+ # === Coupling Metrics ===
189
+
190
+ # Compute afferent coupling (Ca), efferent coupling (Ce), and instability per module.
191
+ # Ce (Efferent): number of modules this module depends on (outgoing depends_on)
192
+ # Ca (Afferent): number of modules that depend on this module (incoming depends_on)
193
+ # Instability = Ce / (Ce + Ca) -- ranges 0..1; 1 = maximally unstable
194
+ #
195
+ # Args:
196
+ # $1 - inventory_dir: path to .atool-docs/inventory/
197
+ # Output: JSON object {module_name: {ca: N, ce: N, instability: F}} to stdout
198
+ compute_coupling_metrics() {
199
+ local inventory_dir="$1"
200
+
201
+ if [[ ! -d "$inventory_dir" ]]; then
202
+ echo "{}"
203
+ return
204
+ fi
205
+
206
+ if ! command -v jq &>/dev/null; then
207
+ echo "{}"
208
+ return
209
+ fi
210
+
211
+ local result
212
+ result=$(jq -s \
213
+ '[ .[].outgoing_edges // []
214
+ | .[]
215
+ | select(.type == "depends_on")
216
+ | {source: (.source // ""), target: (.target_module // "")}
217
+ | select(.source != "" and .target != "") ] as $edges |
218
+
219
+ # All unique module names (both sources and targets)
220
+ ($edges | map(.source) + map(.target) | unique) as $modules |
221
+
222
+ # Compute per-module metrics
223
+ [ $modules[] as $m |
224
+ # Ce = count of unique targets from this module
225
+ ($edges | map(select(.source == $m).target) | unique | length) as $ce |
226
+
227
+ # Ca = count of unique sources pointing to this module
228
+ ($edges | map(select(.target == $m).source) | unique | length) as $ca |
229
+
230
+ # Instability = Ce / (Ce + Ca); if both 0, treat as 0.5 (indeterminate)
231
+ (if ($ce + $ca) > 0 then
232
+ (($ce * 100 / ($ce + $ca)) | round) / 100
233
+ else 0.5 end) as $inst |
234
+
235
+ {key: $m, value: {ca: $ca, ce: $ce, instability: $inst}}
236
+ ] | from_entries' "$inventory_dir"/*.json 2>/dev/null)
237
+
238
+ if [[ -n "$result" ]]; then
239
+ echo "$result"
240
+ else
241
+ echo "{}"
242
+ fi
243
+ }
244
+
245
+ # === Dependency Structure Matrix ===
246
+
247
+ # Generate a module Dependency Structure Matrix (DSM).
248
+ # Each cell (source, target) contains the number of distinct symbols
249
+ # referenced in that dependency edge.
250
+ #
251
+ # Args:
252
+ # $1 - inventory_dir: path to .atool-docs/inventory/
253
+ # Output: JSON object {source_module: {target_module: symbol_count}} to stdout
254
+ generate_dsm() {
255
+ local inventory_dir="$1"
256
+
257
+ if [[ ! -d "$inventory_dir" ]]; then
258
+ echo "{}"
259
+ return
260
+ fi
261
+
262
+ if ! command -v jq &>/dev/null; then
263
+ echo "{}"
264
+ return
265
+ fi
266
+
267
+ local result
268
+ result=$(jq -s \
269
+ '[ .[].outgoing_edges // []
270
+ | .[]
271
+ | select(.type == "depends_on")
272
+ | {
273
+ source: (.source // ""),
274
+ target: (.target_module // ""),
275
+ symbols: ((.symbols // []) | length)
276
+ }
277
+ | select(.source != "" and .target != "") ] as $edges |
278
+
279
+ # Group by source, then by target, summing symbol counts
280
+ [ $edges | group_by(.source)[] |
281
+ .[0].source as $src |
282
+ {
283
+ key: $src,
284
+ value: (group_by(.target) |
285
+ map({
286
+ key: .[0].target,
287
+ value: (map(.symbols) | add)
288
+ }) | from_entries)
289
+ }
290
+ ] | from_entries' "$inventory_dir"/*.json 2>/dev/null)
291
+
292
+ if [[ -n "$result" ]]; then
293
+ echo "$result"
294
+ else
295
+ echo "{}"
296
+ fi
297
+ }
298
+
299
+ # === Architectural Layer Detection ===
300
+
301
+ # Detect architectural layers from directory structure.
302
+ # Uses heuristic pattern matching on directory names.
303
+ #
304
+ # Args:
305
+ # $1 - project_root: path to project root
306
+ # Output: JSON object {module_path: layer_name} to stdout
307
+ detect_architectural_layers() {
308
+ local root="$1"
309
+
310
+ if [[ ! -d "$root" ]]; then
311
+ echo "{}"
312
+ return
313
+ fi
314
+
315
+ if ! command -v jq &>/dev/null; then
316
+ echo "{}"
317
+ return
318
+ fi
319
+
320
+ # Find module-level directories and classify by basename
321
+ # Pattern groups for 8 layer types are hardcoded in the awk BEGIN block
322
+ local result
323
+ result=$(cd "$root" && find . -maxdepth 3 -type d 2>/dev/null | awk '
324
+ BEGIN {
325
+ # Parse pattern groups (simplified — build lookup table in awk)
326
+ split("controller api route view page screen handler endpoint", presentation, " ")
327
+ split("service usecase application facade manager logic", service, " ")
328
+ split("repository dao mapper gateway persistence store", repository, " ")
329
+ split("domain model entity aggregate valueobject", domain, " ")
330
+ split("config util helper common shared infra middleware", infra, " ")
331
+ split("component widget layout template", ui, " ")
332
+ split("test spec mock fixture __tests__", test, " ")
333
+ split("schema migration seed database", data, " ")
334
+
335
+ for (i in presentation) layers[presentation[i]] = "presentation"
336
+ for (i in service) layers[service[i]] = "service"
337
+ for (i in repository) layers[repository[i]] = "repository"
338
+ for (i in domain) layers[domain[i]] = "domain"
339
+ for (i in infra) layers[infra[i]] = "infrastructure"
340
+ for (i in ui) layers[ui[i]] = "ui"
341
+ for (i in test) layers[test[i]] = "test"
342
+ for (i in data) layers[data[i]] = "data"
343
+
344
+ sep = ""
345
+ printf "{"
346
+ }
347
+ {
348
+ # Strip leading ./
349
+ path = $1
350
+ gsub(/^\.\//, "", path)
351
+ if (path == "" || path == ".") next
352
+
353
+ # Get basename
354
+ n = split(path, parts, "/")
355
+ basename = parts[n]
356
+
357
+ if (basename in layers) {
358
+ # Escape special chars in path for JSON key
359
+ gsub(/"/, "\\\"", path)
360
+ printf "%s\"%s\":\"%s\"", sep, path, layers[basename]
361
+ sep = ","
362
+ }
363
+ }
364
+ END {
365
+ printf "}"
366
+ }
367
+ ')
368
+
369
+ if [[ -n "$result" && "$result" != "{}" ]]; then
370
+ # Validate JSON output
371
+ echo "$result" | jq . 2>/dev/null && return
372
+ fi
373
+ echo "{}"
374
+ }
375
+
376
+ # === Edge Weight Computation ===
377
+
378
+ # Compute edge weights based on relationship frequency and extraction confidence.
379
+ # Weight = base_weight(type) * frequency_factor * confidence
380
+ #
381
+ # Args:
382
+ # $1 - graph_json: path to knowledge-graph.json (or "-" to read stdin)
383
+ # Output: JSON object with weighted edges to stdout
384
+ compute_edge_weights() {
385
+ local graph_json="$1"
386
+
387
+ if ! command -v jq &>/dev/null; then
388
+ echo "{}"
389
+ return
390
+ fi
391
+
392
+ # Read graph from file or stdin
393
+ local graph_input
394
+ if [[ "$graph_json" == "-" ]]; then
395
+ graph_input=$(cat)
396
+ elif [[ -f "$graph_json" ]]; then
397
+ graph_input=$(cat "$graph_json")
398
+ else
399
+ echo "{}"
400
+ return
401
+ fi
402
+
403
+ if [[ -z "$graph_input" || "$graph_input" == "null" ]]; then
404
+ echo "{}"
405
+ return
406
+ fi
407
+
408
+ # Base weights per edge type
409
+ local base_weights
410
+ base_weights='{
411
+ "depends_on": 1.0, "calls": 0.9, "calls_async": 0.8,
412
+ "reads_state": 0.8, "writes_state": 0.8, "reads_from": 0.8,
413
+ "writes_to": 0.8, "transforms": 0.7, "validates": 0.6,
414
+ "renders": 1.0, "routes_to": 1.0, "sends_http": 1.0,
415
+ "receives_http": 1.0, "persists_to": 0.9, "subscribes_to": 0.8,
416
+ "emits": 1.0, "listens_to": 1.0, "returns": 0.7,
417
+ "implements": 1.0, "extends": 1.0
418
+ }'
419
+
420
+ local result
421
+ result=$(echo "$graph_input" | jq --argjson bw "$base_weights" '
422
+ (.edges // []) as $edges |
423
+
424
+ # Count occurrences per type for frequency normalization
425
+ ($edges | group_by(.type) | map({key: .[0].type, value: length}) | from_entries) as $type_counts |
426
+ ([$type_counts | .[]] | max // 1) as $max_count |
427
+
428
+ # Compute weighted edges
429
+ [$edges[] | . as $e |
430
+ $e.type as $t |
431
+ ($bw[$t] // 0.5) as $base |
432
+ (($type_counts[$t] // 1) / $max_count) as $freq_factor |
433
+ ($e.confidence // 1.0) as $conf |
434
+
435
+ # Round weight to 3 decimal places using awk-friendly approach
436
+ ((($base * $freq_factor * $conf) * 1000 | round) / 1000) as $weight |
437
+
438
+ $e + {weight: $weight}
439
+ ]
440
+ ')
441
+
442
+ if [[ -n "$result" ]]; then
443
+ echo "$result"
444
+ else
445
+ echo "[]"
446
+ fi
447
+ }
448
+
449
+ # === Graph Index Construction ===
450
+
451
+ # Build lookup indexes from knowledge graph for fast querying.
452
+ # Creates 5 index maps: nodes_by_type, nodes_by_name, edges_by_source, edges_by_target, edges_by_type
453
+ #
454
+ # Args:
455
+ # $1 - graph_json: path to knowledge-graph.json
456
+ # Output: JSON object with 5 index maps to stdout
457
+ build_graph_indexes() {
458
+ local graph_json="$1"
459
+
460
+ if ! command -v jq &>/dev/null; then
461
+ echo "{}"
462
+ return
463
+ fi
464
+
465
+ local graph_input
466
+ if [[ "$graph_json" == "-" ]]; then
467
+ graph_input=$(cat)
468
+ elif [[ -f "$graph_json" ]]; then
469
+ graph_input=$(cat "$graph_json")
470
+ else
471
+ echo "{}"
472
+ return
473
+ fi
474
+
475
+ if [[ -z "$graph_input" || "$graph_input" == "null" ]]; then
476
+ echo "{}"
477
+ return
478
+ fi
479
+
480
+ local result
481
+ result=$(echo "$graph_input" | jq '
482
+ (.nodes // []) as $nodes |
483
+ (.edges // []) as $edges |
484
+
485
+ # nodes_by_type: {module: [id1,id2,...], function: [...], ...}
486
+ ($nodes | group_by(.type) |
487
+ map({key: (.[0].type // "unknown"), value: map(.id)})
488
+ | from_entries) as $nbt |
489
+
490
+ # nodes_by_name: {createUser: [func:X.createUser], ...}
491
+ ($nodes | group_by(.name) |
492
+ map({key: (.[0].name // ""), value: map(.id)})
493
+ | from_entries) as $nbn |
494
+
495
+ # edges_by_source: {mod:A: [{source,target,type,weight},...], ...}
496
+ ($edges | group_by(.source) |
497
+ map({key: (.[0].source // ""), value: map({source, target, type, weight: (.weight // 1.0)})})
498
+ | from_entries) as $ebs |
499
+
500
+ # edges_by_target: {mod:B: [{source,target,type,weight},...], ...}
501
+ ($edges | group_by(.target) |
502
+ map({key: (.[0].target // ""), value: map({source, target, type, weight: (.weight // 1.0)})})
503
+ | from_entries) as $ebt |
504
+
505
+ # edges_by_type: {depends_on: [{source,target,...},...], ...}
506
+ ($edges | group_by(.type) |
507
+ map({key: (.[0].type // ""), value: map({source, target, weight: (.weight // 1.0)})})
508
+ | from_entries) as $ebtyp |
509
+
510
+ {
511
+ nodes_by_type: $nbt,
512
+ nodes_by_name: $nbn,
513
+ edges_by_source: $ebs,
514
+ edges_by_target: $ebt,
515
+ edges_by_type: $ebtyp
516
+ }
517
+ ' 2>/dev/null)
518
+
519
+ if [[ -n "$result" && "$result" != "null" ]]; then
520
+ echo "$result"
521
+ else
522
+ echo "{}"
523
+ fi
524
+ }
525
+
526
+ # === Enhanced Graph Assembly ===
527
+
528
+ # Assemble enhanced knowledge graph from all analysis artifacts.
529
+ # Combines inventory, analysis, L4/L5 data into unified graph.
530
+ #
531
+ # Args:
532
+ # $1 - docs_dir: path to .atool-docs/
533
+ # $2 - project_root: path to project root
534
+ # Output: writes knowledge-graph.json v5.0 to $1/knowledge-graph.json
535
+ assemble_enhanced_graph() {
536
+ local docs_dir="$1"
537
+ local project_root="$2"
538
+
539
+ if [[ ! -d "$docs_dir" ]]; then
540
+ echo "Error: docs_dir not found: $docs_dir" >&2
541
+ return 1
542
+ fi
543
+
544
+ if ! command -v jq &>/dev/null; then
545
+ echo "Error: jq is required" >&2
546
+ return 1
547
+ fi
548
+
549
+ local inventory_dir="$docs_dir/inventory"
550
+ local output_file="$docs_dir/knowledge-graph.json"
551
+
552
+ # Step 1: Node assembly from inventory/*.json + modules/*/analysis.json
553
+ local nodes
554
+ nodes=$(jq -s '
555
+ # Collect all nodes from inventory files
556
+ [ .[].files // [] | .[] |
557
+ {
558
+ id: ((.module // .path // "") | tostring),
559
+ name: (.name // (.path // "") | split("/") | .[-1]),
560
+ type: (.type // "unknown"),
561
+ path: (.path // ""),
562
+ module: (.module // "")
563
+ }
564
+ | select(.id != "")
565
+ ] | unique_by(.id)
566
+ ' "$inventory_dir"/*.json 2>/dev/null)
567
+
568
+ if [[ -z "$nodes" || "$nodes" == "null" ]]; then
569
+ nodes="[]"
570
+ fi
571
+
572
+ # Step 2: Edge assembly with weights
573
+ local raw_edges
574
+ raw_edges=$(jq -s '
575
+ [ .[].outgoing_edges // [] | .[] |
576
+ {
577
+ source: (.source // ""),
578
+ target: (.target_module // .target // ""),
579
+ type: (.type // "depends_on"),
580
+ symbols: (.symbols // []),
581
+ confidence: (.confidence // 1.0),
582
+ frequency: 1
583
+ }
584
+ | select(.source != "" and .target != "")
585
+ ]
586
+ ' "$inventory_dir"/*.json 2>/dev/null)
587
+
588
+ if [[ -z "$raw_edges" || "$raw_edges" == "null" ]]; then
589
+ raw_edges="[]"
590
+ fi
591
+
592
+ # Build a temporary graph to compute edge weights
593
+ local weighted_edges
594
+ weighted_edges=$(echo "{\"nodes\":$nodes,\"edges\":$raw_edges}" | compute_edge_weights -)
595
+
596
+ # Step 3: Layer detection
597
+ local layers
598
+ layers=$(detect_architectural_layers "$project_root")
599
+
600
+ # Step 4: Graph metrics (Ca, Ce, I via existing compute_coupling_metrics)
601
+ local coupling_metrics
602
+ coupling_metrics=$(compute_coupling_metrics "$inventory_dir")
603
+
604
+ # Compute aggregate metrics from coupling data
605
+ local aggregate_metrics
606
+ aggregate_metrics=$(echo "$coupling_metrics" | jq '
607
+ . as $cm |
608
+ ($cm | keys | length) as $total_modules |
609
+ (if $total_modules > 0 then
610
+ ([$cm | .[].ca] | add) / $total_modules
611
+ else 0 end) as $avg_ca |
612
+ (if $total_modules > 0 then
613
+ ([$cm | .[].ce] | add) / $total_modules
614
+ else 0 end) as $avg_ce |
615
+ {
616
+ total_modules: $total_modules,
617
+ avg_afferent: (($avg_ca * 100 | round) / 100),
618
+ avg_efferent: (($avg_ce * 100 | round) / 100),
619
+ coupling_per_module: $cm
620
+ }
621
+ ')
622
+
623
+ # Step 5: Importance score integration
624
+ local importance_scores="{}"
625
+ local importance_script
626
+ # Try to find compute-importance.sh relative to this script
627
+ importance_script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/compute-importance.sh"
628
+ if [[ -f "$importance_script" ]]; then
629
+ # Source and invoke if available — just use empty if not
630
+ importance_scores="{}"
631
+ fi
632
+
633
+ # Step 6: Index construction
634
+ local indexes
635
+ indexes=$(echo "{\"nodes\":$nodes,\"edges\":$weighted_edges}" | build_graph_indexes -)
636
+
637
+ # Detect cycles
638
+ local cycles
639
+ cycles=$(detect_cycles "$inventory_dir")
640
+
641
+ # Generate DSM
642
+ local dsm
643
+ dsm=$(generate_dsm "$inventory_dir" 2>/dev/null || echo "{}")
644
+
645
+ # Assemble final graph
646
+ local timestamp
647
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "unknown")
648
+
649
+ local node_count edge_count
650
+ node_count=$(echo "$nodes" | jq 'length')
651
+ edge_count=$(echo "$weighted_edges" | jq 'length')
652
+
653
+ jq -n \
654
+ --arg version "5.0" \
655
+ --arg generated_at "$timestamp" \
656
+ --argjson nodes "$nodes" \
657
+ --argjson edges "$weighted_edges" \
658
+ --argjson layers "$layers" \
659
+ --argjson indexes "$indexes" \
660
+ --argjson cycles "$cycles" \
661
+ --argjson metrics "$aggregate_metrics" \
662
+ --argjson dsm "$dsm" \
663
+ --argjson importance "$importance_scores" \
664
+ '{
665
+ version: $version,
666
+ generated_at: $generated_at,
667
+ graph_properties: {
668
+ node_count: ($nodes | length),
669
+ edge_count: ($edges | length),
670
+ layer_count: ($layers | to_entries | length)
671
+ },
672
+ nodes: $nodes,
673
+ edges: $edges,
674
+ layers: $layers,
675
+ indexes: $indexes,
676
+ issues: {
677
+ cycles: $cycles
678
+ },
679
+ metrics: $metrics,
680
+ importance: $importance,
681
+ mermaid_diagrams: {}
682
+ }' > "$output_file"
683
+
684
+ echo "Assembled knowledge graph v5.0 -> $output_file ($node_count nodes, $edge_count edges)"
685
+ }
686
+
687
+ # === Betweenness Centrality ===
688
+
689
+ # Compute approximated betweenness centrality for module nodes.
690
+ # Uses BFS from a sample of source nodes (up to 50) for performance.
691
+ #
692
+ # Args:
693
+ # $1 - graph_json: path to knowledge-graph.json
694
+ # Output: JSON object {node_id: betweenness_score} to stdout
695
+ compute_betweenness_centrality() {
696
+ local graph_json="$1"
697
+
698
+ if ! command -v jq &>/dev/null; then
699
+ echo "{}"
700
+ return
701
+ fi
702
+
703
+ if [[ ! -f "$graph_json" ]]; then
704
+ echo "{}"
705
+ return
706
+ fi
707
+
708
+ local result
709
+ result=$(jq '
710
+ (.edges // []) as $edges |
711
+ (.nodes // []) as $nodes |
712
+
713
+ # Build adjacency list from depends_on and calls edges
714
+ ($edges | map(select(.type == "depends_on" or .type == "calls"))) as $dep_edges |
715
+
716
+ # Get unique module node ids
717
+ ($nodes | map(select(.type == "module")) | map(.id)) as $module_ids |
718
+
719
+ # Build forward adjacency: source -> [targets]
720
+ ($dep_edges | group_by(.source) |
721
+ map({key: .[0].source, value: (map(.target) | unique)})
722
+ | from_entries) as $adj |
723
+
724
+ # Sample up to 50 source nodes
725
+ ($module_ids | length) as $total |
726
+ (if $total > 50 then 50 else $total end) as $sample_size |
727
+
728
+ # For each sample node, BFS and count shortest-path intermediaries
729
+ [ ($module_ids | .[0:$sample_size])[] as $src |
730
+
731
+ # BFS: compute shortest path counts and predecessors
732
+ # Using iterative approach in jq
733
+ {queue: [$src], visited: {$src: true}, dist: {$src: 0},
734
+ sigma: {($src): 1}, pred: {}, betweenness_add: {}} |
735
+
736
+ # Iterative BFS (up to 100 steps to avoid infinite loops)
737
+ foreach range(0; 100) as $step (
738
+ .;
739
+ if (.queue | length) == 0 then . else
740
+ .queue[0] as $v |
741
+ .queue = .queue[1:] |
742
+
743
+ # Get neighbors
744
+ ($adj[$v] // []) as $neighbors |
745
+
746
+ reduce $neighbors[] as $w (.;
747
+ if (.visited[$w] // false | not) then
748
+ .visited[$w] = true |
749
+ .dist[$w] = (.dist[$v] + 1) |
750
+ .queue = (.queue + [$w]) |
751
+ .sigma[$w] = ((.sigma[$w] // 0) + (.sigma[$v] // 1)) |
752
+ .pred[$w] = (.pred[$w] // []) + [$v]
753
+ elif .dist[$w] == (.dist[$v] + 1) then
754
+ .sigma[$w] = ((.sigma[$w] // 0) + (.sigma[$v] // 1)) |
755
+ .pred[$w] = (.pred[$w] // []) + [$v]
756
+ else . end
757
+ )
758
+ end
759
+ ) |
760
+
761
+ # Back-propagation: accumulate betweenness
762
+ .betweenness_add
763
+ ] as $all_betweenness |
764
+
765
+ # Merge and normalize
766
+ reduce $all_betweenness[] as $bc ({}; . * ($bc // {}))
767
+ | to_entries
768
+ | map({key: .key, value: ((.value * 1000 | round) / 1000)})
769
+ | sort_by(-.value)
770
+ | from_entries
771
+ ' "$graph_json" 2>/dev/null)
772
+
773
+ if [[ -n "$result" && "$result" != "null" ]]; then
774
+ echo "$result"
775
+ else
776
+ echo "{}"
777
+ fi
778
+ }
779
+
780
+ # === CK Metrics ===
781
+
782
+ # Compute Chidamber-Kemerer metrics from inventory and L4 analysis data.
783
+ # WMC, DIT, NOC, CBO, RFC, LCOM per class.
784
+ #
785
+ # Args:
786
+ # $1 - docs_dir: path to .atool-docs/
787
+ # Output: JSON object {class_id: {wmc:N, dit:N, noc:N, cbo:N, rfc:N, lcom:N}} to stdout
788
+ compute_ck_metrics() {
789
+ local docs_dir="$1"
790
+
791
+ if [[ ! -d "$docs_dir" ]]; then
792
+ echo "{}"
793
+ return
794
+ fi
795
+
796
+ if ! command -v jq &>/dev/null; then
797
+ echo "{}"
798
+ return
799
+ fi
800
+
801
+ local inventory_dir="$docs_dir/inventory"
802
+
803
+ if [[ ! -d "$inventory_dir" ]]; then
804
+ echo "{}"
805
+ return
806
+ fi
807
+
808
+ # Collect class nodes and their method/field information from inventory
809
+ local inventory_data
810
+ inventory_data=$(jq -s '
811
+ {
812
+ # All class-type nodes
813
+ classes: [ .[].files // [] | .[] |
814
+ select(.type == "class" or .type == "cls") |
815
+ {
816
+ id: (.path // ""),
817
+ name: (.name // ""),
818
+ module: (.module // ""),
819
+ methods: (.methods // []),
820
+ fields: (.fields // []),
821
+ extends: (.extends // ""),
822
+ imports: (.imports // [])
823
+ }
824
+ ],
825
+ # All edges for dependency analysis
826
+ edges: [ .[].outgoing_edges // [] | .[] | . ]
827
+ }
828
+ ' "$inventory_dir"/*.json 2>/dev/null)
829
+
830
+ if [[ -z "$inventory_data" || "$inventory_data" == "null" ]]; then
831
+ echo "{}"
832
+ return
833
+ fi
834
+
835
+ # Try to load L4 analysis data for method complexity
836
+ local l4_complexity="{}"
837
+ if [[ -d "$docs_dir/modules" ]]; then
838
+ l4_complexity=$(jq -s '
839
+ [ .[].functions // [] | .[] |
840
+ select(.complexity != null) |
841
+ {key: .name, value: .complexity}
842
+ ] | from_entries
843
+ ' "$docs_dir"/modules/*/analysis.json 2>/dev/null || echo "{}")
844
+ fi
845
+
846
+ local result
847
+ result=$(echo "$inventory_data" | jq --argjson l4 "$l4_complexity" '
848
+ .classes as $classes |
849
+ .edges as $edges |
850
+
851
+ # Build extends lookup: class_name -> [subclasses]
852
+ ($classes | group_by(.extends) |
853
+ map({key: (.[0].extends // ""), value: map(.id)})
854
+ | from_entries) as $subclasses_map |
855
+
856
+ # Build per-class metrics
857
+ [ $classes[] | . as $cls |
858
+ $cls.id as $cid |
859
+ $cls.name as $cname |
860
+
861
+ # WMC = sum(CC(method)) for methods in class
862
+ # Use L4 complexity data if available, otherwise assume 1 per method
863
+ ($cls.methods | length) as $method_count |
864
+ (if ($cls.methods | length) > 0 then
865
+ [ $cls.methods[] |
866
+ ($l4[.] // 1)
867
+ ] | add
868
+ else 0 end) as $wmc |
869
+
870
+ # DIT = max inheritance chain depth (count extends edges)
871
+ # Iterative lookup of parent chain (max depth 20 to prevent loops)
872
+ (0 | . as $depth | $cname | . as $current |
873
+ loop:
874
+ foreach range(0; 20) as $_ (
875
+ $depth;
876
+ if ($classes | map(select(.name == $current)) | .[0].extends // "") as $parent |
877
+ ($parent != "") then
878
+ $current = $parent | . + 1
879
+ else . end,
880
+ .
881
+ )
882
+ ) as $dit |
883
+
884
+ # NOC = count of direct subclasses
885
+ (($subclasses_map[$cname] // []) | length) as $noc |
886
+
887
+ # CBO = count of distinct classes referenced via imports
888
+ ($cls.imports | unique | length) as $cbo |
889
+
890
+ # RFC = |methods| + sum(|methods called by methods|)
891
+ # Approximate: method count + distinct call targets from edges
892
+ ($method_count + (
893
+ [$edges[] |
894
+ select(.source == $cid or .source == $cname) |
895
+ select(.type == "calls" or .type == "calls_async") |
896
+ .target // .target_module // ""
897
+ ] | unique | map(select(. != "")) | length
898
+ )) as $rfc |
899
+
900
+ # LCOM = |P| - |Q| where P = non-sharing method pairs, Q = sharing method pairs
901
+ # Approximation using field sharing: pairs sharing >= 1 field vs not sharing
902
+ ($cls.fields | length) as $field_count |
903
+ (if $method_count <= 1 then 0
904
+ elif $field_count == 0 then
905
+ # No fields: all pairs are non-sharing
906
+ ($method_count * ($method_count - 1) / 2)
907
+ else
908
+ # Rough LCOM approximation: m*(m-1)/2 - shared_pairs
909
+ # Without per-method field access data, use heuristic:
910
+ # LCOM = m^2/2 - m*field_count/2 (lower bound estimate)
911
+ (($method_count * $method_count) - ($method_count * $field_count))
912
+ end) as $lcom |
913
+
914
+ {
915
+ key: $cid,
916
+ value: {
917
+ wmc: ($wmc | if . < 0 then 0 else . end),
918
+ dit: $dit,
919
+ noc: $noc,
920
+ cbo: $cbo,
921
+ rfc: $rfc,
922
+ lcom: (if $lcom < 0 then 0 else $lcom end)
923
+ }
924
+ }
925
+ ] | from_entries
926
+ ')
927
+
928
+ if [[ -n "$result" && "$result" != "null" ]]; then
929
+ echo "$result"
930
+ else
931
+ echo "{}"
932
+ fi
933
+ }
934
+
935
+ # === Main Entry Point (for testing) ===
936
+ # When executed directly (not sourced), runs a quick smoke test on the
937
+ # provided inventory directory.
938
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
939
+ INVENTORY_DIR="${1:-.atool-docs/inventory}"
940
+ echo "# Knowledge Graph Helpers Test"
941
+ echo "# Inventory dir: $INVENTORY_DIR"
942
+
943
+ # Derive docs_dir from inventory_dir (inventory is a subdirectory of docs)
944
+ DOCS_DIR="${INVENTORY_DIR%/inventory}"
945
+ PROJECT_ROOT="${2:-.}"
946
+
947
+ if [[ -d "$INVENTORY_DIR" ]]; then
948
+ echo "## Node counts:"
949
+ count_graph_nodes "$INVENTORY_DIR"
950
+ echo ""
951
+ echo "## Edge counts:"
952
+ count_graph_edges "$INVENTORY_DIR"
953
+ echo ""
954
+ echo "## Coupling metrics:"
955
+ compute_coupling_metrics "$INVENTORY_DIR"
956
+ echo ""
957
+ echo "## DSM:"
958
+ generate_dsm "$INVENTORY_DIR"
959
+ echo ""
960
+ echo "## Cycles:"
961
+ detect_cycles "$INVENTORY_DIR"
962
+ echo ""
963
+ echo "## Architectural layers (project root: $PROJECT_ROOT):"
964
+ detect_architectural_layers "$PROJECT_ROOT"
965
+ echo ""
966
+
967
+ # Test edge weights if a graph file exists
968
+ GRAPH_FILE="$DOCS_DIR/knowledge-graph.json"
969
+ if [[ -f "$GRAPH_FILE" ]]; then
970
+ echo "## Edge weights:"
971
+ compute_edge_weights "$GRAPH_FILE"
972
+ echo ""
973
+ echo "## Graph indexes:"
974
+ build_graph_indexes "$GRAPH_FILE"
975
+ echo ""
976
+ echo "## Betweenness centrality:"
977
+ compute_betweenness_centrality "$GRAPH_FILE"
978
+ echo ""
979
+ else
980
+ echo "## Edge weights: (skipped — no $GRAPH_FILE)"
981
+ echo "## Graph indexes: (skipped — no $GRAPH_FILE)"
982
+ echo "## Betweenness centrality: (skipped — no $GRAPH_FILE)"
983
+ # Test edge weights with a minimal inline graph
984
+ echo "## Edge weights (inline test):"
985
+ echo '{"nodes":[],"edges":[{"source":"A","target":"B","type":"depends_on","confidence":0.9}]}' | compute_edge_weights -
986
+ echo ""
987
+ # Test graph indexes with a minimal inline graph
988
+ echo "## Graph indexes (inline test):"
989
+ echo '{"nodes":[{"id":"A","name":"modA","type":"module"},{"id":"B","name":"modB","type":"module"}],"edges":[{"source":"A","target":"B","type":"depends_on"}]}' | build_graph_indexes -
990
+ echo ""
991
+ fi
992
+
993
+ # Test assemble_enhanced_graph if docs_dir looks valid
994
+ if [[ -d "$DOCS_DIR" ]]; then
995
+ echo "## CK metrics:"
996
+ compute_ck_metrics "$DOCS_DIR"
997
+ echo ""
998
+ else
999
+ echo "## CK metrics: (skipped — no $DOCS_DIR)"
1000
+ echo ""
1001
+ fi
1002
+
1003
+ # Test assemble_enhanced_graph (requires full docs_dir structure)
1004
+ if [[ -d "$DOCS_DIR" && -d "$INVENTORY_DIR" ]]; then
1005
+ echo "## Assemble enhanced graph:"
1006
+ assemble_enhanced_graph "$DOCS_DIR" "$PROJECT_ROOT" || echo "(assembly failed or incomplete)"
1007
+ echo ""
1008
+ else
1009
+ echo "## Assemble enhanced graph: (skipped — missing $DOCS_DIR)"
1010
+ fi
1011
+ else
1012
+ echo "No inventory directory found at $INVENTORY_DIR"
1013
+ fi
1014
+ fi