@mrciphersmith/keryx 0.2.9

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 (297) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +351 -0
  3. package/dist/cli.js +48427 -0
  4. package/dist/proxy-worker.js +381 -0
  5. package/package.json +63 -0
  6. package/src/gdgraph/affected.test.ts +100 -0
  7. package/src/gdgraph/affected.ts +135 -0
  8. package/src/gdgraph/build-integrity.test.ts +193 -0
  9. package/src/gdgraph/build-lang.test.ts +399 -0
  10. package/src/gdgraph/build.test.ts +120 -0
  11. package/src/gdgraph/build.ts +804 -0
  12. package/src/gdgraph/config.test.ts +47 -0
  13. package/src/gdgraph/config.ts +113 -0
  14. package/src/gdgraph/core-sources.test.ts +99 -0
  15. package/src/gdgraph/core-sources.ts +20 -0
  16. package/src/gdgraph/enrich.ts +79 -0
  17. package/src/gdgraph/fallback.test.ts +153 -0
  18. package/src/gdgraph/find.test.ts +78 -0
  19. package/src/gdgraph/find.ts +107 -0
  20. package/src/gdgraph/pagerank.ts +129 -0
  21. package/src/gdgraph/path.test.ts +56 -0
  22. package/src/gdgraph/path.ts +112 -0
  23. package/src/gdgraph/query.ts +133 -0
  24. package/src/gdgraph/repomap.test.ts +110 -0
  25. package/src/gdgraph/repomap.ts +193 -0
  26. package/src/gdgraph/service.test.ts +59 -0
  27. package/src/gdgraph/service.ts +51 -0
  28. package/src/gdgraph/staleness.ts +20 -0
  29. package/src/gdgraph/symbol.test.ts +89 -0
  30. package/src/gdgraph/symbol.ts +123 -0
  31. package/src/gdgraph/symbols-capability.test.ts +41 -0
  32. package/src/gdgraph/symbols-capability.ts +49 -0
  33. package/src/gdgraph/target.ts +56 -0
  34. package/src/gdgraph/treesitter/adapter.test.ts +249 -0
  35. package/src/gdgraph/treesitter/adapter.ts +213 -0
  36. package/src/gdgraph/treesitter/extract.test.ts +278 -0
  37. package/src/gdgraph/treesitter/extract.ts +389 -0
  38. package/src/gdgraph/treesitter/grammars.ts +110 -0
  39. package/src/gdgraph/treesitter/no-treesitter-import.test.ts +51 -0
  40. package/src/gdgraph/treesitter/resolve-calls.test.ts +38 -0
  41. package/src/gdgraph/types.ts +63 -0
  42. package/src/gdskills/bundled/rules/core/api-contracts.mdc +148 -0
  43. package/src/gdskills/bundled/rules/core/async-patterns.mdc +185 -0
  44. package/src/gdskills/bundled/rules/core/clean-architecture.mdc +163 -0
  45. package/src/gdskills/bundled/rules/core/code-review-ai-assistant.mdc +49 -0
  46. package/src/gdskills/bundled/rules/core/code-review-b091-profile.mdc +48 -0
  47. package/src/gdskills/bundled/rules/core/code-style-patterns.mdc +54 -0
  48. package/src/gdskills/bundled/rules/core/commit-message-formatting.mdc +25 -0
  49. package/src/gdskills/bundled/rules/core/database-patterns.mdc +162 -0
  50. package/src/gdskills/bundled/rules/core/documentation-management.mdc +106 -0
  51. package/src/gdskills/bundled/rules/core/error-handling.mdc +163 -0
  52. package/src/gdskills/bundled/rules/core/execution-metrics.md +99 -0
  53. package/src/gdskills/bundled/rules/core/frontend-assistant.mdc +40 -0
  54. package/src/gdskills/bundled/rules/core/git-rules.mdc +37 -0
  55. package/src/gdskills/bundled/rules/core/gproject-contracts.mdc +198 -0
  56. package/src/gdskills/bundled/rules/core/implementation-doc-mandate.mdc +149 -0
  57. package/src/gdskills/bundled/rules/core/implementation-plans.mdc +58 -0
  58. package/src/gdskills/bundled/rules/core/jobs-documentation.mdc +221 -0
  59. package/src/gdskills/bundled/rules/core/mobx-store-template.mdc +561 -0
  60. package/src/gdskills/bundled/rules/core/model-selection.mdc +53 -0
  61. package/src/gdskills/bundled/rules/core/nestjs-dto.mdc +50 -0
  62. package/src/gdskills/bundled/rules/core/playwright-testing.mdc +321 -0
  63. package/src/gdskills/bundled/rules/core/requirements-management.mdc +35 -0
  64. package/src/gdskills/bundled/rules/core/requirements-package-standard.mdc +103 -0
  65. package/src/gdskills/bundled/rules/core/review-agent-profile.mdc +49 -0
  66. package/src/gdskills/bundled/rules/core/review-strict-profile.mdc +44 -0
  67. package/src/gdskills/bundled/rules/core/rule-management-workflow.mdc +62 -0
  68. package/src/gdskills/bundled/rules/core/security-baseline.mdc +155 -0
  69. package/src/gdskills/bundled/rules/core/shared-definitions.mdc +79 -0
  70. package/src/gdskills/bundled/rules/core/skill-lifecycle.mdc +55 -0
  71. package/src/gdskills/bundled/rules/core/skills-storage-workflow.mdc +88 -0
  72. package/src/gdskills/bundled/rules/core/solid-principles.mdc +149 -0
  73. package/src/gdskills/bundled/rules/core/storybook-guidelines.mdc +36 -0
  74. package/src/gdskills/bundled/rules/core/subagent-context-construction.md +107 -0
  75. package/src/gdskills/bundled/rules/core/subagent-status-protocol.md +169 -0
  76. package/src/gdskills/bundled/rules/core/tdd-workflow.mdc +96 -0
  77. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.codex.md +47 -0
  78. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.cursor.md +55 -0
  79. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.md +352 -0
  80. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.opencode.md +39 -0
  81. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.zed.md +29 -0
  82. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.codex.md +567 -0
  83. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.cursor.md +567 -0
  84. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.md +655 -0
  85. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.opencode.md +567 -0
  86. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.zed.md +567 -0
  87. package/src/gdskills/bundled/skills/orchestration/context-collector/input-contract.schema.json +134 -0
  88. package/src/gdskills/bundled/skills/orchestration/context-collector/orchestrator-prompt.md +183 -0
  89. package/src/gdskills/bundled/skills/orchestration/context-collector/output-contract.schema.json +208 -0
  90. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.codex.md +1412 -0
  91. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.cursor.md +1412 -0
  92. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.detail.md +735 -0
  93. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.md +468 -0
  94. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.opencode.md +1412 -0
  95. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.zed.md +1412 -0
  96. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/analysis-request.md +62 -0
  97. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/analysis-request.template.md +79 -0
  98. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/input-contract.schema.json +247 -0
  99. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/orchestrator-prompt.md +362 -0
  100. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/output-contract.schema.json +87 -0
  101. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.codex.md +105 -0
  102. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.cursor.md +105 -0
  103. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.md +165 -0
  104. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +379 -0
  105. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/input-contract.schema.json +33 -0
  106. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/output-contract.schema.json +41 -0
  107. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.codex.md +307 -0
  108. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.cursor.md +307 -0
  109. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.md +373 -0
  110. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.opencode.md +307 -0
  111. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.zed.md +307 -0
  112. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/input-contract.schema.json +130 -0
  113. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/issue-request.template.md +50 -0
  114. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/orchestrator-prompt.md +155 -0
  115. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/output-contract.schema.json +61 -0
  116. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.codex.md +365 -0
  117. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.cursor.md +365 -0
  118. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.md +373 -0
  119. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.opencode.md +365 -0
  120. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.zed.md +365 -0
  121. package/src/gdskills/bundled/skills/orchestration/job-documenter/input-contract.schema.json +55 -0
  122. package/src/gdskills/bundled/skills/orchestration/job-documenter/output-contract.schema.json +58 -0
  123. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.codex.md +1701 -0
  124. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.cursor.md +1701 -0
  125. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +1734 -0
  126. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.opencode.md +1701 -0
  127. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.zed.md +1701 -0
  128. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/input-contract.schema.json +188 -0
  129. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/orchestrator-prompt.md +179 -0
  130. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/output-contract.schema.json +103 -0
  131. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/state.schema.json +164 -0
  132. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.codex.md +395 -0
  133. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.cursor.md +395 -0
  134. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +556 -0
  135. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.opencode.md +395 -0
  136. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.zed.md +395 -0
  137. package/src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json +204 -0
  138. package/src/gdskills/bundled/skills/orchestration/task-implementer/orchestrator-prompt.md +206 -0
  139. package/src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json +51 -0
  140. package/src/gdskills/bundled/skills/orchestration/task-implementer/task-request.template.md +111 -0
  141. package/src/gdskills/bundled/skills/planning/autodoc-analyst/SKILL.md +163 -0
  142. package/src/gdskills/bundled/skills/planning/autodoc-architect/SKILL.md +161 -0
  143. package/src/gdskills/bundled/skills/planning/autodoc-assembler/SKILL.md +128 -0
  144. package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +321 -0
  145. package/src/gdskills/bundled/skills/planning/autodoc-scanner/SKILL.md +166 -0
  146. package/src/gdskills/bundled/skills/planning/autodoc-writer/SKILL.md +253 -0
  147. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.claude.md +46 -0
  148. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.codex.md +90 -0
  149. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.cursor.md +90 -0
  150. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.md +90 -0
  151. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.codex.md +33 -0
  152. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.cursor.md +33 -0
  153. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.md +190 -0
  154. package/src/gdskills/bundled/skills/planning/docpack-orchestrator/SKILL.md +142 -0
  155. package/src/gdskills/bundled/skills/planning/docpack-orchestrator/input-contract.schema.json +31 -0
  156. package/src/gdskills/bundled/skills/planning/docpack-orchestrator/output-contract.schema.json +31 -0
  157. package/src/gdskills/bundled/skills/planning/docpack-review/SKILL.md +80 -0
  158. package/src/gdskills/bundled/skills/planning/docpack-review/input-contract.schema.json +20 -0
  159. package/src/gdskills/bundled/skills/planning/docpack-review/output-contract.schema.json +36 -0
  160. package/src/gdskills/bundled/skills/planning/interview/SKILL.codex.md +181 -0
  161. package/src/gdskills/bundled/skills/planning/interview/SKILL.cursor.md +181 -0
  162. package/src/gdskills/bundled/skills/planning/interview/SKILL.md +187 -0
  163. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.claude.md +94 -0
  164. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.codex.md +99 -0
  165. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.cursor.md +99 -0
  166. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +105 -0
  167. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.codex.md +33 -0
  168. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.cursor.md +33 -0
  169. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.md +237 -0
  170. package/src/gdskills/bundled/skills/planning/planner/SKILL.codex.md +33 -0
  171. package/src/gdskills/bundled/skills/planning/planner/SKILL.cursor.md +33 -0
  172. package/src/gdskills/bundled/skills/planning/planner/SKILL.md +190 -0
  173. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.codex.md +193 -0
  174. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.cursor.md +193 -0
  175. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.md +193 -0
  176. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.opencode.md +193 -0
  177. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.zed.md +193 -0
  178. package/src/gdskills/bundled/skills/planning/prd-creator/input-contract.schema.json +63 -0
  179. package/src/gdskills/bundled/skills/planning/prd-creator/output-contract.schema.json +175 -0
  180. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.codex.md +31 -0
  181. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.cursor.md +31 -0
  182. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.md +153 -0
  183. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.codex.md +32 -0
  184. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.cursor.md +32 -0
  185. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.md +166 -0
  186. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.codex.md +44 -0
  187. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.cursor.md +44 -0
  188. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.md +243 -0
  189. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.codex.md +43 -0
  190. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.cursor.md +43 -0
  191. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.md +193 -0
  192. package/src/gdskills/bundled/skills/platform/agent-entrypoint-distiller/SKILL.md +47 -0
  193. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.codex.md +87 -0
  194. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.cursor.md +87 -0
  195. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.md +87 -0
  196. package/src/gdskills/bundled/skills/platform/hookify/SKILL.codex.md +100 -0
  197. package/src/gdskills/bundled/skills/platform/hookify/SKILL.cursor.md +100 -0
  198. package/src/gdskills/bundled/skills/platform/hookify/SKILL.md +100 -0
  199. package/src/gdskills/bundled/skills/quality/changelog/SKILL.claude.md +45 -0
  200. package/src/gdskills/bundled/skills/quality/changelog/SKILL.codex.md +84 -0
  201. package/src/gdskills/bundled/skills/quality/changelog/SKILL.cursor.md +84 -0
  202. package/src/gdskills/bundled/skills/quality/changelog/SKILL.md +84 -0
  203. package/src/gdskills/bundled/skills/quality/commit/SKILL.codex.md +66 -0
  204. package/src/gdskills/bundled/skills/quality/commit/SKILL.cursor.md +66 -0
  205. package/src/gdskills/bundled/skills/quality/commit/SKILL.md +66 -0
  206. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.claude.md +40 -0
  207. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.codex.md +66 -0
  208. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.cursor.md +66 -0
  209. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.md +66 -0
  210. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.claude.md +45 -0
  211. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.codex.md +81 -0
  212. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.cursor.md +81 -0
  213. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.md +81 -0
  214. package/src/gdskills/bundled/skills/quality/deploy/SKILL.claude.md +42 -0
  215. package/src/gdskills/bundled/skills/quality/deploy/SKILL.codex.md +70 -0
  216. package/src/gdskills/bundled/skills/quality/deploy/SKILL.cursor.md +70 -0
  217. package/src/gdskills/bundled/skills/quality/deploy/SKILL.md +70 -0
  218. package/src/gdskills/bundled/skills/quality/metaproject-security/SKILL.md +103 -0
  219. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.claude.md +48 -0
  220. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.codex.md +83 -0
  221. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.cursor.md +83 -0
  222. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.md +83 -0
  223. package/src/gdskills/bundled/skills/quality/pr/SKILL.codex.md +75 -0
  224. package/src/gdskills/bundled/skills/quality/pr/SKILL.cursor.md +75 -0
  225. package/src/gdskills/bundled/skills/quality/pr/SKILL.md +75 -0
  226. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.codex.md +364 -0
  227. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.cursor.md +295 -0
  228. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.md +378 -0
  229. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.opencode.md +364 -0
  230. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.zed.md +38 -0
  231. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/input-contract.schema.json +53 -0
  232. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/output-contract.schema.json +46 -0
  233. package/src/gdskills/bundled/skills/quality/push/SKILL.codex.md +52 -0
  234. package/src/gdskills/bundled/skills/quality/push/SKILL.cursor.md +52 -0
  235. package/src/gdskills/bundled/skills/quality/push/SKILL.md +52 -0
  236. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.claude.md +40 -0
  237. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.codex.md +61 -0
  238. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.cursor.md +61 -0
  239. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.md +61 -0
  240. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.claude.md +30 -0
  241. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.codex.md +75 -0
  242. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.cursor.md +75 -0
  243. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.md +75 -0
  244. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.codex.md +64 -0
  245. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.cursor.md +74 -0
  246. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.md +339 -0
  247. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.opencode.md +48 -0
  248. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.zed.md +44 -0
  249. package/src/gdskills/bundled/skills/quality/tests-creator/input-contract.schema.json +121 -0
  250. package/src/gdskills/bundled/skills/quality/tests-creator/output-contract.schema.json +127 -0
  251. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.codex.md +204 -0
  252. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.cursor.md +204 -0
  253. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.md +203 -0
  254. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.opencode.md +204 -0
  255. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.zed.md +204 -0
  256. package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.codex.md +209 -0
  257. package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.cursor.md +209 -0
  258. package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.md +208 -0
  259. package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.opencode.md +209 -0
  260. package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.zed.md +209 -0
  261. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.codex.md +263 -0
  262. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.cursor.md +263 -0
  263. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.md +258 -0
  264. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.opencode.md +263 -0
  265. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.zed.md +263 -0
  266. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.codex.md +175 -0
  267. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.cursor.md +175 -0
  268. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.md +168 -0
  269. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.opencode.md +175 -0
  270. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.zed.md +175 -0
  271. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +360 -0
  272. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +337 -0
  273. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +477 -0
  274. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +93 -0
  275. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +119 -0
  276. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +595 -0
  277. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +144 -0
  278. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +519 -0
  279. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +323 -0
  280. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +927 -0
  281. package/src/gdskills/bundled/skills/review/review-orchestrator/input-contract.schema.json +153 -0
  282. package/src/gdskills/bundled/skills/review/review-orchestrator/output-contract.schema.json +77 -0
  283. package/src/gdskills/bundled/skills/review/review-orchestrator/review-context.schema.json +389 -0
  284. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +189 -0
  285. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +241 -0
  286. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +344 -0
  287. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +327 -0
  288. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +348 -0
  289. package/src/gdskills/bundled/skills/review/review-strict/SKILL.md +328 -0
  290. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +343 -0
  291. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +134 -0
  292. package/src/gdskills/bundled/skills/shared/git-merge-base.md +33 -0
  293. package/src/gdskills/contracts/agent-event.schema.json +32 -0
  294. package/src/gdskills/contracts/orchestrator-state.schema.json +58 -0
  295. package/src/gdskills/contracts/review-finding.schema.json +59 -0
  296. package/src/gdskills/contracts/subagent-dispatch.schema.json +123 -0
  297. package/src/gdskills/contracts/subagent-result.schema.json +136 -0
@@ -0,0 +1,193 @@
1
+ // Regression tests for the three defects that made gdgraph return wrong answers
2
+ // on keryx's own repository (review 2026-07-26, finding B-02):
3
+ //
4
+ // 1. `.claude/worktrees/**` (nested git checkouts of this repo) was indexed as
5
+ // first-class source — 74% of all nodes were stale duplicates.
6
+ // 2. `affected` resolved a target with one `===`-or-`endsWith` predicate, so an
7
+ // earlier suffix match beat a later exact match and ambiguity was silent.
8
+ // 3. `Bun.Transpiler#scanImports` erases type-only imports, and the regex
9
+ // fallback that handles them was only reached when the transpiler threw — so
10
+ // every `import type` edge was missing and type-only modules were orphans.
11
+ //
12
+ // Plus the artifact-parity invariant: `summary.md` must describe the very graph
13
+ // that was written to `storage/nodes.jsonl` in the same build.
14
+
15
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
16
+ import { tmpdir } from "node:os";
17
+ import path from "node:path";
18
+ import { expect, test } from "bun:test";
19
+ import { buildGraph } from "./build";
20
+ import { computeAffected } from "./affected";
21
+ import { getAffected, getOrphans, loadGraph } from "./query";
22
+ import { resolveGraphTarget } from "./target";
23
+ import type { GraphData } from "./types";
24
+ import { uniqueTestRoot } from "../lib/test-tmp";
25
+
26
+ // --- 1. nested-worktree pollution -------------------------------------------
27
+
28
+ test("buildGraph never indexes a nested checkout under .claude/worktrees", async () => {
29
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-worktree");
30
+ await reset(root);
31
+ await mkdir(path.join(root, "src", "lib"), { recursive: true });
32
+ await mkdir(path.join(root, ".claude", "worktrees", "wt-1", "src", "lib"), { recursive: true });
33
+
34
+ await writeFile(path.join(root, "src", "lib", "fs.ts"), "export const real = true;\n");
35
+ // A byte-identical copy of the repo inside the agent-harness worktree dir.
36
+ await writeFile(
37
+ path.join(root, ".claude", "worktrees", "wt-1", "src", "lib", "fs.ts"),
38
+ "export const real = true;\n",
39
+ );
40
+
41
+ await buildGraph(root);
42
+ const graph = await loadGraph(root);
43
+ const paths = graph.nodes.map((node) => node.path);
44
+
45
+ expect(paths).toEqual(["src/lib/fs.ts"]);
46
+ expect(paths.some((file) => file.startsWith(".claude/"))).toBe(false);
47
+ });
48
+
49
+ // --- 2. target resolution ----------------------------------------------------
50
+
51
+ function graphOf(...paths: string[]): GraphData {
52
+ return {
53
+ nodes: paths.map((file) => ({ id: file, kind: "file", path: file, language: "typescript" })),
54
+ edges: [],
55
+ };
56
+ }
57
+
58
+ test("an exact path wins over an earlier-sorted suffix match", () => {
59
+ // `.claude/...` sorts before `src/...`, so the old single-predicate `find`
60
+ // returned the worktree copy for the exact target `src/lib/fs.ts`.
61
+ const graph = graphOf(".claude/worktrees/wt-1/src/lib/fs.ts", "src/lib/fs.ts");
62
+
63
+ expect(resolveGraphTarget(graph, "src/lib/fs.ts")).toBe("src/lib/fs.ts");
64
+ expect(computeAffected(graph, "src/lib/fs.ts").target).toBe("src/lib/fs.ts");
65
+ expect(getAffected(graph, "src/lib/fs.ts").target).toBe("src/lib/fs.ts");
66
+ });
67
+
68
+ test("a suffix match only matches on a path-segment boundary", () => {
69
+ const graph = graphOf("src/lib/myfs.ts", "src/lib/fs.ts");
70
+
71
+ expect(resolveGraphTarget(graph, "lib/fs.ts")).toBe("src/lib/fs.ts");
72
+ // `fs.ts` must not be satisfied by `myfs.ts`.
73
+ expect(resolveGraphTarget(graph, "fs.ts")).toBe("src/lib/fs.ts");
74
+ });
75
+
76
+ test("an ambiguous suffix refuses instead of guessing the first candidate", () => {
77
+ const graph = graphOf("src/a/config.ts", "src/b/config.ts");
78
+
79
+ expect(() => resolveGraphTarget(graph, "config.ts")).toThrow(/ambiguous/i);
80
+ expect(() => computeAffected(graph, "config.ts")).toThrow(/src\/a\/config\.ts/);
81
+ expect(() => getAffected(graph, "config.ts")).toThrow(/src\/b\/config\.ts/);
82
+ });
83
+
84
+ test("an unknown target still resolves to itself with an empty blast radius", () => {
85
+ const graph = graphOf("src/lib/fs.ts");
86
+ const result = computeAffected(graph, "./src/does-not-exist.ts");
87
+
88
+ expect(result.target).toBe("src/does-not-exist.ts");
89
+ expect(result.dependents).toEqual([]);
90
+ });
91
+
92
+ // --- 3. type-only import edges ----------------------------------------------
93
+
94
+ test("type-only imports produce graph edges and are not reported as orphans", async () => {
95
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-typeonly");
96
+ await reset(root);
97
+ await mkdir(path.join(root, "src"), { recursive: true });
98
+
99
+ await writeFile(path.join(root, "src", "types.ts"), "export type Config = { ok: boolean };\n");
100
+ // `import type` / `export type … from` are BOTH erased by the transpiler.
101
+ await writeFile(
102
+ path.join(root, "src", "consumer.ts"),
103
+ [
104
+ "import type { Config } from './types';",
105
+ "export const make = (c: Config) => c;",
106
+ "",
107
+ ].join("\n"),
108
+ );
109
+ await writeFile(
110
+ path.join(root, "src", "reexport.ts"),
111
+ "export type { Config } from './types';\n",
112
+ );
113
+
114
+ await buildGraph(root);
115
+ const graph = await loadGraph(root);
116
+
117
+ const intoTypes = graph.edges
118
+ .filter((edge) => edge.kind === "imports" && edge.to === "src/types.ts")
119
+ .map((edge) => edge.from)
120
+ .sort();
121
+ expect(intoTypes).toEqual(["src/consumer.ts", "src/reexport.ts"]);
122
+
123
+ // The whole point: a module imported only for its types is NOT an orphan.
124
+ expect(getOrphans(graph)).not.toContain("src/types.ts");
125
+ expect(getAffected(graph, "src/types.ts").dependents).toEqual([
126
+ "src/consumer.ts",
127
+ "src/reexport.ts",
128
+ ]);
129
+ });
130
+
131
+ test("value imports still resolve when unioned with the regex fallback", async () => {
132
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-union");
133
+ await reset(root);
134
+ await mkdir(path.join(root, "src"), { recursive: true });
135
+
136
+ await writeFile(path.join(root, "src", "dep.ts"), "export const dep = 1;\n");
137
+ await writeFile(
138
+ path.join(root, "src", "index.ts"),
139
+ [
140
+ "import { dep } from './dep';",
141
+ "const lazy = () => import('./dep');",
142
+ "export const out = { dep, lazy };",
143
+ "",
144
+ ].join("\n"),
145
+ );
146
+
147
+ await buildGraph(root);
148
+ const graph = await loadGraph(root);
149
+
150
+ // Unioning must not duplicate an edge the transpiler and the regex both see.
151
+ const edges = graph.edges.filter((edge) => edge.from === "src/index.ts");
152
+ expect(edges.map((edge) => edge.to)).toEqual(["src/dep.ts"]);
153
+ });
154
+
155
+ // --- 4. summary / storage parity --------------------------------------------
156
+
157
+ test("summary.md counts describe the graph written to storage in the same build", async () => {
158
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-parity");
159
+ await reset(root);
160
+ await mkdir(path.join(root, "src", "feature"), { recursive: true });
161
+ await mkdir(path.join(root, ".claude", "worktrees", "wt-1", "src"), { recursive: true });
162
+
163
+ await writeFile(path.join(root, "src", "feature", "style.css"), ".x { color: red; }\n");
164
+ await writeFile(
165
+ path.join(root, "src", "feature", "index.ts"),
166
+ ["import './style.css';", "export { value } from './value';", ""].join("\n"),
167
+ );
168
+ await writeFile(path.join(root, "src", "feature", "value.ts"), "export const value = 1;\n");
169
+ await writeFile(path.join(root, ".claude", "worktrees", "wt-1", "src", "copy.ts"), "export const c = 1;\n");
170
+
171
+ const result = await buildGraph(root);
172
+ const graph = await loadGraph(root);
173
+ const summary = await readFile(result.summaryPath, "utf8");
174
+
175
+ const storedFiles = graph.nodes.filter((node) => node.kind === "file").length;
176
+ const storedAssets = graph.nodes.filter((node) => node.kind === "asset").length;
177
+
178
+ expect(summary).toContain(`- Source files indexed: ${storedFiles}`);
179
+ expect(summary).toContain(`- Imported asset files indexed: ${storedAssets}`);
180
+ expect(summary).toContain(`- Total nodes: ${graph.nodes.length}`);
181
+ expect(summary).toContain(`- Edges: ${graph.edges.length}`);
182
+ // And the storage file itself has exactly one line per node.
183
+ const nodesJsonl = await readFile(
184
+ path.join(root, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl"),
185
+ "utf8",
186
+ );
187
+ expect(nodesJsonl.trimEnd().split("\n").length).toBe(graph.nodes.length);
188
+ });
189
+
190
+ async function reset(root: string): Promise<void> {
191
+ await rm(root, { recursive: true, force: true });
192
+ await mkdir(root, { recursive: true });
193
+ }
@@ -0,0 +1,399 @@
1
+ // gdgraph Java/Python import-resolution tests (flow 002 — TDD red phase).
2
+ //
3
+ // These tests are written BEFORE implementation. Everything except the TS/JS
4
+ // byte-identical regression guard (test 3) is expected to FAIL against the
5
+ // current code and must go green only once the Java/Python resolvers, the
6
+ // metric fix, and the parser helpers land.
7
+ //
8
+ // Conventions mirror build.test.ts exactly: tmpdir() fixtures, reset(root),
9
+ // buildGraph(root), loadGraph(root). JS/TS fixtures that must not be
10
+ // pre-resolved by the Bun transpiler use the importLine() helper.
11
+ //
12
+ // ---------------------------------------------------------------------------
13
+ // PARSER CONTRACT the implementer MUST satisfy (unit tests, test 5)
14
+ //
15
+ // The implementer MUST export these two functions from `src/gdgraph/` (module
16
+ // path is their choice, e.g. `./sourceRoots` or `./build`), with these EXACT
17
+ // names and signatures. If a cleaner signature is chosen it must still return
18
+ // the repo-relative source roots described here; update the imports below to
19
+ // match, but keep the documented behavior.
20
+ //
21
+ // parseMavenSourceRoots(pomXml: string): string[]
22
+ // - default (no <build> overrides, single module):
23
+ // ["src/main/java", "src/test/java"]
24
+ // - honors <build><sourceDirectory> / <testSourceDirectory>
25
+ // - multi-module: <modules><module>svc-a</module></modules> unions
26
+ // "svc-a/src/main/java", "svc-a/src/test/java", ...
27
+ //
28
+ // parseGradleSourceRoots(buildGradle: string): string[]
29
+ // - Groovy + Kotlin DSL: sourceSets { main { java { srcDirs 'x' } } }
30
+ // - default (no sourceSets block): ["src/main/java", "src/test/java"]
31
+ // ---------------------------------------------------------------------------
32
+
33
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
34
+ import { tmpdir } from "node:os";
35
+ import path from "node:path";
36
+ import { expect, test } from "bun:test";
37
+ import { buildGraph } from "./build";
38
+ import { loadGraph } from "./query";
39
+ import { uniqueTestRoot } from "../lib/test-tmp";
40
+
41
+ // Parser API under contract — resolved from ./build at runtime (see PARSER
42
+ // CONTRACT above). We load these lazily rather than via a top-level
43
+ // `import { parseMavenSourceRoots } from "./build"` on purpose: a missing named
44
+ // export would throw at module-load time and take the whole test file down with
45
+ // it, including the AC4 byte-identical guard that MUST stay green. With a
46
+ // runtime lookup, only the parser unit tests fail (RED) until the implementer
47
+ // adds the exports; every other test still runs. If the implementer places
48
+ // these functions in a different module, update the specifier below.
49
+ type SourceRootParser = (input: string) => string[];
50
+
51
+ async function loadParser(name: string): Promise<SourceRootParser> {
52
+ const mod = (await import("./build")) as Record<string, unknown>;
53
+ const fn = mod[name];
54
+ if (typeof fn !== "function") {
55
+ throw new Error(
56
+ `Expected ./build to export ${name}(input: string): string[] (see PARSER CONTRACT).`,
57
+ );
58
+ }
59
+ return fn as SourceRootParser;
60
+ }
61
+
62
+ const parseMavenSourceRoots = (pom: string): Promise<string[]> =>
63
+ loadParser("parseMavenSourceRoots").then((fn) => fn(pom));
64
+ const parseGradleSourceRoots = (gradle: string): Promise<string[]> =>
65
+ loadParser("parseGradleSourceRoots").then((fn) => fn(gradle));
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Test 1 — Maven Java build-level resolution (RED now: currently 0 edges)
69
+ // AC1 / AC3 / AC8
70
+ // ---------------------------------------------------------------------------
71
+
72
+ test("buildGraph resolves Maven Java FQN imports to files and emits imports edges", async () => {
73
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-lang-maven");
74
+ await reset(root);
75
+ const javaRoot = path.join(root, "src", "main", "java", "com", "example", "admin");
76
+ await mkdir(path.join(javaRoot, "dto"), { recursive: true });
77
+
78
+ // Minimal pom.xml with default source dirs (no <build> overrides).
79
+ await writeFile(
80
+ path.join(root, "pom.xml"),
81
+ [
82
+ '<?xml version="1.0" encoding="UTF-8"?>',
83
+ '<project xmlns="http://maven.apache.org/POM/4.0.0">',
84
+ " <modelVersion>4.0.0</modelVersion>",
85
+ " <groupId>com.example</groupId>",
86
+ " <artifactId>admin</artifactId>",
87
+ " <version>1.0.0</version>",
88
+ "</project>",
89
+ "",
90
+ ].join("\n"),
91
+ );
92
+
93
+ await writeFile(
94
+ path.join(javaRoot, "dto", "FixReplicaRequest.java"),
95
+ [
96
+ "package com.example.admin.dto;",
97
+ "public class FixReplicaRequest {}",
98
+ "",
99
+ ].join("\n"),
100
+ );
101
+ await writeFile(
102
+ path.join(javaRoot, "AdminService.java"),
103
+ [
104
+ "package com.example.admin;",
105
+ "import com.example.admin.dto.FixReplicaRequest;",
106
+ "public class AdminService {",
107
+ " private FixReplicaRequest request;",
108
+ "}",
109
+ "",
110
+ ].join("\n"),
111
+ );
112
+
113
+ await buildGraph(root);
114
+ const graph = await loadGraph(root);
115
+
116
+ const importEdges = graph.edges.filter((edge) => edge.kind === "imports");
117
+ expect(importEdges.length).toBeGreaterThan(0);
118
+
119
+ const specific = graph.edges.find(
120
+ (edge) =>
121
+ edge.from === "src/main/java/com/example/admin/AdminService.java" &&
122
+ edge.to === "src/main/java/com/example/admin/dto/FixReplicaRequest.java" &&
123
+ edge.kind === "imports",
124
+ );
125
+ expect(specific).toBeDefined();
126
+ });
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // Test 2 — Python build-level resolution (RED now)
130
+ // AC2 / AC8 — absolute + relative + __init__.py packages
131
+ // ---------------------------------------------------------------------------
132
+
133
+ test("buildGraph resolves Python absolute, relative, and __init__.py imports", async () => {
134
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-lang-python");
135
+ await reset(root);
136
+ await mkdir(path.join(root, "pkg", "sub"), { recursive: true });
137
+
138
+ await writeFile(path.join(root, "pkg", "__init__.py"), "\n");
139
+ await writeFile(path.join(root, "pkg", "mod.py"), "thing = 1\n");
140
+ await writeFile(path.join(root, "pkg", "sub", "__init__.py"), "\n");
141
+ await writeFile(path.join(root, "pkg", "sub", "child.py"), "child = 1\n");
142
+
143
+ // consumer.py exercises: absolute import, a relative sibling import, and a
144
+ // relative parent-package import.
145
+ await writeFile(
146
+ path.join(root, "pkg", "consumer.py"),
147
+ [
148
+ "from pkg.mod import thing",
149
+ "from . import mod",
150
+ "from .sub import child",
151
+ "",
152
+ "def use():",
153
+ " return thing",
154
+ "",
155
+ ].join("\n"),
156
+ );
157
+
158
+ await buildGraph(root);
159
+ const graph = await loadGraph(root);
160
+
161
+ const importEdges = graph.edges.filter((edge) => edge.kind === "imports");
162
+ expect(importEdges.length).toBeGreaterThan(0);
163
+
164
+ // Absolute import resolves to the module file.
165
+ expect(importEdges.some((edge) => edge.to === "pkg/mod.py")).toBe(true);
166
+
167
+ // At least one edge resolves to a package __init__.py (either pkg or pkg/sub).
168
+ expect(importEdges.some((edge) => edge.to.endsWith("__init__.py"))).toBe(true);
169
+
170
+ // A relative-import edge is produced (exercises the extraction fix that adds
171
+ // the leading-dot Python patterns). `from . import mod` resolves to a module
172
+ // or package inside pkg; assert at least one edge originates from consumer.py
173
+ // and resolves to a sibling within pkg/ that is not the absolute-import path.
174
+ const relativeEdges = importEdges.filter(
175
+ (edge) => edge.from === "pkg/consumer.py",
176
+ );
177
+ expect(relativeEdges.length).toBeGreaterThan(1);
178
+ });
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // Test 3 — TS/JS byte-identical regression GUARD (MUST PASS now and forever)
182
+ // AC4 — zero behavior change for TS/JS.
183
+ //
184
+ // The golden strings below were captured from the CURRENT build output on
185
+ // 2026-07-10. They encode the invariant that TS/JS nodes.jsonl / edges.jsonl
186
+ // output does not change when Java/Python support is added.
187
+ //
188
+ // !!! NEVER regenerate these goldens to make a diff disappear. If this test
189
+ // !!! fails, the TS/JS code path changed and AC4 is violated — fix the code,
190
+ // !!! not the golden.
191
+ // ---------------------------------------------------------------------------
192
+
193
+ const GOLDEN_NODES_JSONL =
194
+ `{"id":"src/feature/helper.js","kind":"file","path":"src/feature/helper.js","language":"javascript"}\n` +
195
+ `{"id":"src/feature/index.ts","kind":"file","path":"src/feature/index.ts","language":"typescript"}\n` +
196
+ `{"id":"src/feature/style.css","kind":"asset","path":"src/feature/style.css","language":"asset"}\n` +
197
+ `{"id":"src/feature/value.ts","kind":"file","path":"src/feature/value.ts","language":"typescript"}\n`;
198
+
199
+ const GOLDEN_EDGES_JSONL =
200
+ `{"id":"edge:1","from":"src/feature/helper.js","to":"src/feature/value.ts","kind":"imports","specifier":"./value"}\n` +
201
+ `{"id":"edge:2","from":"src/feature/index.ts","to":"src/feature/style.css","kind":"asset","specifier":"./style.css"}\n` +
202
+ `{"id":"edge:3","from":"src/feature/index.ts","to":"src/feature/value.ts","kind":"imports","specifier":"./value"}\n`;
203
+
204
+ test("buildGraph output is byte-identical for a TS/JS-only project (AC4 guard)", async () => {
205
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-lang-regression");
206
+ await reset(root);
207
+ await mkdir(path.join(root, "src", "feature"), { recursive: true });
208
+
209
+ await writeFile(
210
+ path.join(root, "src", "feature", "index.ts"),
211
+ [
212
+ importLine("{ value } from './value';"),
213
+ importLine("'./style.css';"),
214
+ "export const result = `${value}`;",
215
+ "",
216
+ ].join("\n"),
217
+ );
218
+ await writeFile(path.join(root, "src", "feature", "value.ts"), "export const value = 'ok';\n");
219
+ await writeFile(path.join(root, "src", "feature", "style.css"), ".x { color: red; }\n");
220
+ await writeFile(
221
+ path.join(root, "src", "feature", "helper.js"),
222
+ importLine("{ value } from './value';\nexport const helper = value;\n"),
223
+ );
224
+
225
+ await buildGraph(root);
226
+
227
+ const storageDir = path.join(root, ".metaproject", "data", "gdgraph", "storage");
228
+ const nodes = await readFile(path.join(storageDir, "nodes.jsonl"), "utf8");
229
+ const edges = await readFile(path.join(storageDir, "edges.jsonl"), "utf8");
230
+
231
+ // Exact byte comparison — any divergence in TS/JS output must fail here.
232
+ expect(nodes).toBe(GOLDEN_NODES_JSONL);
233
+ expect(edges).toBe(GOLDEN_EDGES_JSONL);
234
+ });
235
+
236
+ // ---------------------------------------------------------------------------
237
+ // Test 4 — Metric honesty (RED now)
238
+ // AC5 — 0 extracted → n/a (never 100%); non-relative unresolved → unresolved edge
239
+ // ---------------------------------------------------------------------------
240
+
241
+ test("summary reports n/a (not 100%) when zero imports are extracted", async () => {
242
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-lang-metric-na");
243
+ await reset(root);
244
+ await mkdir(path.join(root, "src"), { recursive: true });
245
+ // A source file with no extractable imports at all.
246
+ await writeFile(path.join(root, "src", "lonely.ts"), "export const x = 1;\n");
247
+
248
+ const result = await buildGraph(root);
249
+ const summary = await readFile(result.summaryPath, "utf8");
250
+
251
+ expect(summary).not.toContain("Import resolution: 100%");
252
+ expect(summary).toMatch(/Import resolution:\s*n\/a/i);
253
+ });
254
+
255
+ test("non-relative unresolved import is recorded as an unresolved edge, not dropped", async () => {
256
+ const root = uniqueTestRoot(tmpdir(), "keryx-gdgraph-lang-unresolved");
257
+ await reset(root);
258
+ const javaRoot = path.join(root, "src", "main", "java", "com", "example", "admin");
259
+ await mkdir(javaRoot, { recursive: true });
260
+
261
+ await writeFile(
262
+ path.join(root, "pom.xml"),
263
+ [
264
+ '<?xml version="1.0" encoding="UTF-8"?>',
265
+ '<project xmlns="http://maven.apache.org/POM/4.0.0">',
266
+ " <modelVersion>4.0.0</modelVersion>",
267
+ " <groupId>com.example</groupId>",
268
+ " <artifactId>admin</artifactId>",
269
+ " <version>1.0.0</version>",
270
+ "</project>",
271
+ "",
272
+ ].join("\n"),
273
+ );
274
+ await writeFile(
275
+ path.join(javaRoot, "AdminService.java"),
276
+ [
277
+ "package com.example.admin;",
278
+ "import com.external.Nope;",
279
+ "public class AdminService {}",
280
+ "",
281
+ ].join("\n"),
282
+ );
283
+
284
+ await buildGraph(root);
285
+ const graph = await loadGraph(root);
286
+
287
+ expect(
288
+ graph.edges.some(
289
+ (edge) => edge.kind === "unresolved" && edge.specifier === "com.external.Nope",
290
+ ),
291
+ ).toBe(true);
292
+ });
293
+
294
+ // ---------------------------------------------------------------------------
295
+ // Test 5 — Parser unit tests (RED now: functions not yet exported)
296
+ // AC7 — Maven + Gradle source-root parsing
297
+ // ---------------------------------------------------------------------------
298
+
299
+ test("parseMavenSourceRoots returns default roots for a single-module pom", async () => {
300
+ const pom = [
301
+ '<?xml version="1.0" encoding="UTF-8"?>',
302
+ '<project xmlns="http://maven.apache.org/POM/4.0.0">',
303
+ " <modelVersion>4.0.0</modelVersion>",
304
+ " <groupId>com.example</groupId>",
305
+ " <artifactId>admin</artifactId>",
306
+ " <version>1.0.0</version>",
307
+ "</project>",
308
+ ].join("\n");
309
+
310
+ const roots = await parseMavenSourceRoots(pom);
311
+ expect(roots).toContain("src/main/java");
312
+ expect(roots).toContain("src/test/java");
313
+ });
314
+
315
+ test("parseMavenSourceRoots honors <build><sourceDirectory> overrides", async () => {
316
+ const pom = [
317
+ '<project xmlns="http://maven.apache.org/POM/4.0.0">',
318
+ " <build>",
319
+ " <sourceDirectory>src/main/kotlin</sourceDirectory>",
320
+ " <testSourceDirectory>src/test/kotlin</testSourceDirectory>",
321
+ " </build>",
322
+ "</project>",
323
+ ].join("\n");
324
+
325
+ const roots = await parseMavenSourceRoots(pom);
326
+ expect(roots).toContain("src/main/kotlin");
327
+ expect(roots).toContain("src/test/kotlin");
328
+ });
329
+
330
+ test("parseMavenSourceRoots unions per-module roots for a multi-module pom", async () => {
331
+ const pom = [
332
+ '<project xmlns="http://maven.apache.org/POM/4.0.0">',
333
+ " <modules>",
334
+ " <module>svc-a</module>",
335
+ " <module>svc-b</module>",
336
+ " </modules>",
337
+ "</project>",
338
+ ].join("\n");
339
+
340
+ const roots = await parseMavenSourceRoots(pom);
341
+ expect(roots).toContain("svc-a/src/main/java");
342
+ expect(roots).toContain("svc-a/src/test/java");
343
+ expect(roots).toContain("svc-b/src/main/java");
344
+ expect(roots).toContain("svc-b/src/test/java");
345
+ });
346
+
347
+ test("parseGradleSourceRoots returns default roots when no sourceSets block", async () => {
348
+ const gradle = [
349
+ "plugins {",
350
+ " id 'java'",
351
+ "}",
352
+ "repositories { mavenCentral() }",
353
+ ].join("\n");
354
+
355
+ const roots = await parseGradleSourceRoots(gradle);
356
+ expect(roots).toContain("src/main/java");
357
+ expect(roots).toContain("src/test/java");
358
+ });
359
+
360
+ test("parseGradleSourceRoots reads srcDirs from a Groovy sourceSets block", async () => {
361
+ const gradle = [
362
+ "sourceSets {",
363
+ " main {",
364
+ " java {",
365
+ " srcDirs 'src/main/java', 'generated/java'",
366
+ " }",
367
+ " }",
368
+ "}",
369
+ ].join("\n");
370
+
371
+ const roots = await parseGradleSourceRoots(gradle);
372
+ expect(roots).toContain("src/main/java");
373
+ expect(roots).toContain("generated/java");
374
+ });
375
+
376
+ test("parseGradleSourceRoots reads srcDirs from a Kotlin DSL sourceSets block", async () => {
377
+ const gradle = [
378
+ "sourceSets {",
379
+ ' main {',
380
+ " java {",
381
+ ' srcDirs("src/main/java", "build/generated")',
382
+ " }",
383
+ " }",
384
+ "}",
385
+ ].join("\n");
386
+
387
+ const roots = await parseGradleSourceRoots(gradle);
388
+ expect(roots).toContain("src/main/java");
389
+ expect(roots).toContain("build/generated");
390
+ });
391
+
392
+ async function reset(root: string): Promise<void> {
393
+ await rm(root, { recursive: true, force: true });
394
+ await mkdir(root, { recursive: true });
395
+ }
396
+
397
+ function importLine(rest: string): string {
398
+ return `im${"port"} ${rest}`;
399
+ }