@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.
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/cli.js +48427 -0
- package/dist/proxy-worker.js +381 -0
- package/package.json +63 -0
- package/src/gdgraph/affected.test.ts +100 -0
- package/src/gdgraph/affected.ts +135 -0
- package/src/gdgraph/build-integrity.test.ts +193 -0
- package/src/gdgraph/build-lang.test.ts +399 -0
- package/src/gdgraph/build.test.ts +120 -0
- package/src/gdgraph/build.ts +804 -0
- package/src/gdgraph/config.test.ts +47 -0
- package/src/gdgraph/config.ts +113 -0
- package/src/gdgraph/core-sources.test.ts +99 -0
- package/src/gdgraph/core-sources.ts +20 -0
- package/src/gdgraph/enrich.ts +79 -0
- package/src/gdgraph/fallback.test.ts +153 -0
- package/src/gdgraph/find.test.ts +78 -0
- package/src/gdgraph/find.ts +107 -0
- package/src/gdgraph/pagerank.ts +129 -0
- package/src/gdgraph/path.test.ts +56 -0
- package/src/gdgraph/path.ts +112 -0
- package/src/gdgraph/query.ts +133 -0
- package/src/gdgraph/repomap.test.ts +110 -0
- package/src/gdgraph/repomap.ts +193 -0
- package/src/gdgraph/service.test.ts +59 -0
- package/src/gdgraph/service.ts +51 -0
- package/src/gdgraph/staleness.ts +20 -0
- package/src/gdgraph/symbol.test.ts +89 -0
- package/src/gdgraph/symbol.ts +123 -0
- package/src/gdgraph/symbols-capability.test.ts +41 -0
- package/src/gdgraph/symbols-capability.ts +49 -0
- package/src/gdgraph/target.ts +56 -0
- package/src/gdgraph/treesitter/adapter.test.ts +249 -0
- package/src/gdgraph/treesitter/adapter.ts +213 -0
- package/src/gdgraph/treesitter/extract.test.ts +278 -0
- package/src/gdgraph/treesitter/extract.ts +389 -0
- package/src/gdgraph/treesitter/grammars.ts +110 -0
- package/src/gdgraph/treesitter/no-treesitter-import.test.ts +51 -0
- package/src/gdgraph/treesitter/resolve-calls.test.ts +38 -0
- package/src/gdgraph/types.ts +63 -0
- package/src/gdskills/bundled/rules/core/api-contracts.mdc +148 -0
- package/src/gdskills/bundled/rules/core/async-patterns.mdc +185 -0
- package/src/gdskills/bundled/rules/core/clean-architecture.mdc +163 -0
- package/src/gdskills/bundled/rules/core/code-review-ai-assistant.mdc +49 -0
- package/src/gdskills/bundled/rules/core/code-review-b091-profile.mdc +48 -0
- package/src/gdskills/bundled/rules/core/code-style-patterns.mdc +54 -0
- package/src/gdskills/bundled/rules/core/commit-message-formatting.mdc +25 -0
- package/src/gdskills/bundled/rules/core/database-patterns.mdc +162 -0
- package/src/gdskills/bundled/rules/core/documentation-management.mdc +106 -0
- package/src/gdskills/bundled/rules/core/error-handling.mdc +163 -0
- package/src/gdskills/bundled/rules/core/execution-metrics.md +99 -0
- package/src/gdskills/bundled/rules/core/frontend-assistant.mdc +40 -0
- package/src/gdskills/bundled/rules/core/git-rules.mdc +37 -0
- package/src/gdskills/bundled/rules/core/gproject-contracts.mdc +198 -0
- package/src/gdskills/bundled/rules/core/implementation-doc-mandate.mdc +149 -0
- package/src/gdskills/bundled/rules/core/implementation-plans.mdc +58 -0
- package/src/gdskills/bundled/rules/core/jobs-documentation.mdc +221 -0
- package/src/gdskills/bundled/rules/core/mobx-store-template.mdc +561 -0
- package/src/gdskills/bundled/rules/core/model-selection.mdc +53 -0
- package/src/gdskills/bundled/rules/core/nestjs-dto.mdc +50 -0
- package/src/gdskills/bundled/rules/core/playwright-testing.mdc +321 -0
- package/src/gdskills/bundled/rules/core/requirements-management.mdc +35 -0
- package/src/gdskills/bundled/rules/core/requirements-package-standard.mdc +103 -0
- package/src/gdskills/bundled/rules/core/review-agent-profile.mdc +49 -0
- package/src/gdskills/bundled/rules/core/review-strict-profile.mdc +44 -0
- package/src/gdskills/bundled/rules/core/rule-management-workflow.mdc +62 -0
- package/src/gdskills/bundled/rules/core/security-baseline.mdc +155 -0
- package/src/gdskills/bundled/rules/core/shared-definitions.mdc +79 -0
- package/src/gdskills/bundled/rules/core/skill-lifecycle.mdc +55 -0
- package/src/gdskills/bundled/rules/core/skills-storage-workflow.mdc +88 -0
- package/src/gdskills/bundled/rules/core/solid-principles.mdc +149 -0
- package/src/gdskills/bundled/rules/core/storybook-guidelines.mdc +36 -0
- package/src/gdskills/bundled/rules/core/subagent-context-construction.md +107 -0
- package/src/gdskills/bundled/rules/core/subagent-status-protocol.md +169 -0
- package/src/gdskills/bundled/rules/core/tdd-workflow.mdc +96 -0
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.codex.md +47 -0
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.cursor.md +55 -0
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.md +352 -0
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.opencode.md +39 -0
- package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.zed.md +29 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.codex.md +567 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.cursor.md +567 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.md +655 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.opencode.md +567 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.zed.md +567 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/input-contract.schema.json +134 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/orchestrator-prompt.md +183 -0
- package/src/gdskills/bundled/skills/orchestration/context-collector/output-contract.schema.json +208 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.codex.md +1412 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.cursor.md +1412 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.detail.md +735 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.md +468 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.opencode.md +1412 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.zed.md +1412 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/analysis-request.md +62 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/analysis-request.template.md +79 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/input-contract.schema.json +247 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/orchestrator-prompt.md +362 -0
- package/src/gdskills/bundled/skills/orchestration/feature-analyzer/output-contract.schema.json +87 -0
- package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.codex.md +105 -0
- package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.cursor.md +105 -0
- package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.md +165 -0
- package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +379 -0
- package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/input-contract.schema.json +33 -0
- package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/output-contract.schema.json +41 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.codex.md +307 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.cursor.md +307 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.md +373 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.opencode.md +307 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.zed.md +307 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/input-contract.schema.json +130 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/issue-request.template.md +50 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/orchestrator-prompt.md +155 -0
- package/src/gdskills/bundled/skills/orchestration/issue-analyzer/output-contract.schema.json +61 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.codex.md +365 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.cursor.md +365 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.md +373 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.opencode.md +365 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.zed.md +365 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/input-contract.schema.json +55 -0
- package/src/gdskills/bundled/skills/orchestration/job-documenter/output-contract.schema.json +58 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.codex.md +1701 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.cursor.md +1701 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +1734 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.opencode.md +1701 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.zed.md +1701 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/input-contract.schema.json +188 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/orchestrator-prompt.md +179 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/output-contract.schema.json +103 -0
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/state.schema.json +164 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.codex.md +395 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.cursor.md +395 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +556 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.opencode.md +395 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.zed.md +395 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json +204 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/orchestrator-prompt.md +206 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json +51 -0
- package/src/gdskills/bundled/skills/orchestration/task-implementer/task-request.template.md +111 -0
- package/src/gdskills/bundled/skills/planning/autodoc-analyst/SKILL.md +163 -0
- package/src/gdskills/bundled/skills/planning/autodoc-architect/SKILL.md +161 -0
- package/src/gdskills/bundled/skills/planning/autodoc-assembler/SKILL.md +128 -0
- package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +321 -0
- package/src/gdskills/bundled/skills/planning/autodoc-scanner/SKILL.md +166 -0
- package/src/gdskills/bundled/skills/planning/autodoc-writer/SKILL.md +253 -0
- package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.claude.md +46 -0
- package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.codex.md +90 -0
- package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.cursor.md +90 -0
- package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.md +90 -0
- package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.codex.md +33 -0
- package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.cursor.md +33 -0
- package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.md +190 -0
- package/src/gdskills/bundled/skills/planning/docpack-orchestrator/SKILL.md +142 -0
- package/src/gdskills/bundled/skills/planning/docpack-orchestrator/input-contract.schema.json +31 -0
- package/src/gdskills/bundled/skills/planning/docpack-orchestrator/output-contract.schema.json +31 -0
- package/src/gdskills/bundled/skills/planning/docpack-review/SKILL.md +80 -0
- package/src/gdskills/bundled/skills/planning/docpack-review/input-contract.schema.json +20 -0
- package/src/gdskills/bundled/skills/planning/docpack-review/output-contract.schema.json +36 -0
- package/src/gdskills/bundled/skills/planning/interview/SKILL.codex.md +181 -0
- package/src/gdskills/bundled/skills/planning/interview/SKILL.cursor.md +181 -0
- package/src/gdskills/bundled/skills/planning/interview/SKILL.md +187 -0
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.claude.md +94 -0
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.codex.md +99 -0
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.cursor.md +99 -0
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +105 -0
- package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.codex.md +33 -0
- package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.cursor.md +33 -0
- package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.md +237 -0
- package/src/gdskills/bundled/skills/planning/planner/SKILL.codex.md +33 -0
- package/src/gdskills/bundled/skills/planning/planner/SKILL.cursor.md +33 -0
- package/src/gdskills/bundled/skills/planning/planner/SKILL.md +190 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.codex.md +193 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.cursor.md +193 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.md +193 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.opencode.md +193 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.zed.md +193 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/input-contract.schema.json +63 -0
- package/src/gdskills/bundled/skills/planning/prd-creator/output-contract.schema.json +175 -0
- package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.codex.md +31 -0
- package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.cursor.md +31 -0
- package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.md +153 -0
- package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.codex.md +32 -0
- package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.cursor.md +32 -0
- package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.md +166 -0
- package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.codex.md +44 -0
- package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.cursor.md +44 -0
- package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.md +243 -0
- package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.codex.md +43 -0
- package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.cursor.md +43 -0
- package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.md +193 -0
- package/src/gdskills/bundled/skills/platform/agent-entrypoint-distiller/SKILL.md +47 -0
- package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.codex.md +87 -0
- package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.cursor.md +87 -0
- package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.md +87 -0
- package/src/gdskills/bundled/skills/platform/hookify/SKILL.codex.md +100 -0
- package/src/gdskills/bundled/skills/platform/hookify/SKILL.cursor.md +100 -0
- package/src/gdskills/bundled/skills/platform/hookify/SKILL.md +100 -0
- package/src/gdskills/bundled/skills/quality/changelog/SKILL.claude.md +45 -0
- package/src/gdskills/bundled/skills/quality/changelog/SKILL.codex.md +84 -0
- package/src/gdskills/bundled/skills/quality/changelog/SKILL.cursor.md +84 -0
- package/src/gdskills/bundled/skills/quality/changelog/SKILL.md +84 -0
- package/src/gdskills/bundled/skills/quality/commit/SKILL.codex.md +66 -0
- package/src/gdskills/bundled/skills/quality/commit/SKILL.cursor.md +66 -0
- package/src/gdskills/bundled/skills/quality/commit/SKILL.md +66 -0
- package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.claude.md +40 -0
- package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.codex.md +66 -0
- package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.cursor.md +66 -0
- package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.md +66 -0
- package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.claude.md +45 -0
- package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.codex.md +81 -0
- package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.cursor.md +81 -0
- package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.md +81 -0
- package/src/gdskills/bundled/skills/quality/deploy/SKILL.claude.md +42 -0
- package/src/gdskills/bundled/skills/quality/deploy/SKILL.codex.md +70 -0
- package/src/gdskills/bundled/skills/quality/deploy/SKILL.cursor.md +70 -0
- package/src/gdskills/bundled/skills/quality/deploy/SKILL.md +70 -0
- package/src/gdskills/bundled/skills/quality/metaproject-security/SKILL.md +103 -0
- package/src/gdskills/bundled/skills/quality/perf-check/SKILL.claude.md +48 -0
- package/src/gdskills/bundled/skills/quality/perf-check/SKILL.codex.md +83 -0
- package/src/gdskills/bundled/skills/quality/perf-check/SKILL.cursor.md +83 -0
- package/src/gdskills/bundled/skills/quality/perf-check/SKILL.md +83 -0
- package/src/gdskills/bundled/skills/quality/pr/SKILL.codex.md +75 -0
- package/src/gdskills/bundled/skills/quality/pr/SKILL.cursor.md +75 -0
- package/src/gdskills/bundled/skills/quality/pr/SKILL.md +75 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.codex.md +364 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.cursor.md +295 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.md +378 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.opencode.md +364 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.zed.md +38 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/input-contract.schema.json +53 -0
- package/src/gdskills/bundled/skills/quality/pr-issue-documenter/output-contract.schema.json +46 -0
- package/src/gdskills/bundled/skills/quality/push/SKILL.codex.md +52 -0
- package/src/gdskills/bundled/skills/quality/push/SKILL.cursor.md +52 -0
- package/src/gdskills/bundled/skills/quality/push/SKILL.md +52 -0
- package/src/gdskills/bundled/skills/quality/security-audit/SKILL.claude.md +40 -0
- package/src/gdskills/bundled/skills/quality/security-audit/SKILL.codex.md +61 -0
- package/src/gdskills/bundled/skills/quality/security-audit/SKILL.cursor.md +61 -0
- package/src/gdskills/bundled/skills/quality/security-audit/SKILL.md +61 -0
- package/src/gdskills/bundled/skills/quality/test-gen/SKILL.claude.md +30 -0
- package/src/gdskills/bundled/skills/quality/test-gen/SKILL.codex.md +75 -0
- package/src/gdskills/bundled/skills/quality/test-gen/SKILL.cursor.md +75 -0
- package/src/gdskills/bundled/skills/quality/test-gen/SKILL.md +75 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.codex.md +64 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.cursor.md +74 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.md +339 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.opencode.md +48 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.zed.md +44 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/input-contract.schema.json +121 -0
- package/src/gdskills/bundled/skills/quality/tests-creator/output-contract.schema.json +127 -0
- package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.codex.md +204 -0
- package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.cursor.md +204 -0
- package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.md +203 -0
- package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.opencode.md +204 -0
- package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.zed.md +204 -0
- package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.codex.md +209 -0
- package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.cursor.md +209 -0
- package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.md +208 -0
- package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.opencode.md +209 -0
- package/src/gdskills/bundled/skills/review/code-b091-review/SKILL.zed.md +209 -0
- package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.codex.md +263 -0
- package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.cursor.md +263 -0
- package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.md +258 -0
- package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.opencode.md +263 -0
- package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.zed.md +263 -0
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.codex.md +175 -0
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.cursor.md +175 -0
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.md +168 -0
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.opencode.md +175 -0
- package/src/gdskills/bundled/skills/review/code-style-review/SKILL.zed.md +175 -0
- package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +360 -0
- package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +337 -0
- package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +477 -0
- package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +93 -0
- package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +119 -0
- package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +595 -0
- package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +144 -0
- package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +519 -0
- package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +323 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +927 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/input-contract.schema.json +153 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/output-contract.schema.json +77 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/review-context.schema.json +389 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +189 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +241 -0
- package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +344 -0
- package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +327 -0
- package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +348 -0
- package/src/gdskills/bundled/skills/review/review-strict/SKILL.md +328 -0
- package/src/gdskills/bundled/skills/review/review-style/SKILL.md +343 -0
- package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +134 -0
- package/src/gdskills/bundled/skills/shared/git-merge-base.md +33 -0
- package/src/gdskills/contracts/agent-event.schema.json +32 -0
- package/src/gdskills/contracts/orchestrator-state.schema.json +58 -0
- package/src/gdskills/contracts/review-finding.schema.json +59 -0
- package/src/gdskills/contracts/subagent-dispatch.schema.json +123 -0
- package/src/gdskills/contracts/subagent-result.schema.json +136 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { expect, test } from "bun:test";
|
|
5
|
+
import { DEFAULT_GDGRAPH_CONFIG, loadGdgraphConfig, mergeGdgraphConfig } from "./config";
|
|
6
|
+
|
|
7
|
+
test("AC5.1 — defaults: affected.defaultDepth is 1 (back-compat)", () => {
|
|
8
|
+
expect(DEFAULT_GDGRAPH_CONFIG.affected.defaultDepth).toBe(1);
|
|
9
|
+
expect(mergeGdgraphConfig({}).repomap.tokenBudget).toBe(8000);
|
|
10
|
+
expect(mergeGdgraphConfig({}).repomap.tokenEstimator).toBe("chars-div-4");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("AC5.1 — deep-merge overrides individual fields, keeps the rest", () => {
|
|
14
|
+
const merged = mergeGdgraphConfig({
|
|
15
|
+
affected: { defaultDepth: 3 },
|
|
16
|
+
repomap: { tokenBudget: 100 },
|
|
17
|
+
treesitter: { languages: ["typescript"] },
|
|
18
|
+
});
|
|
19
|
+
expect(merged.affected.defaultDepth).toBe(3);
|
|
20
|
+
expect(merged.repomap.tokenBudget).toBe(100);
|
|
21
|
+
// Untouched fields fall back to defaults.
|
|
22
|
+
expect(merged.repomap.damping).toBe(DEFAULT_GDGRAPH_CONFIG.repomap.damping);
|
|
23
|
+
expect(merged.treesitter.languages).toEqual(["typescript"]);
|
|
24
|
+
expect(merged.treesitter.grammarsPath).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("AC5.1/C0-8 — missing config file ⇒ defaults", async () => {
|
|
28
|
+
const root = await mkdtemp(path.join(tmpdir(), "keryx-cfg-"));
|
|
29
|
+
try {
|
|
30
|
+
const config = await loadGdgraphConfig(root);
|
|
31
|
+
expect(config).toEqual(mergeGdgraphConfig({}));
|
|
32
|
+
} finally {
|
|
33
|
+
await rm(root, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("AC5.1/C0-8 — malformed JSON ⇒ defaults (never throws)", async () => {
|
|
38
|
+
const root = await mkdtemp(path.join(tmpdir(), "keryx-cfg-bad-"));
|
|
39
|
+
try {
|
|
40
|
+
await mkdir(path.join(root, ".metaproject"), { recursive: true });
|
|
41
|
+
await writeFile(path.join(root, ".metaproject", "gdgraph.config.json"), "{ not valid json ");
|
|
42
|
+
const config = await loadGdgraphConfig(root);
|
|
43
|
+
expect(config).toEqual(mergeGdgraphConfig({}));
|
|
44
|
+
} finally {
|
|
45
|
+
await rm(root, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// gdgraph config loader + defaults (specification.md §5; T-B2, C0-8).
|
|
2
|
+
//
|
|
3
|
+
// `.metaproject/gdgraph.config.json` is an OPTIONAL file, deep-merged over the
|
|
4
|
+
// built-in defaults. Missing OR malformed JSON degrades to the defaults so every
|
|
5
|
+
// gdgraph command keeps working deterministically (mirrors `loadSecurityConfig`
|
|
6
|
+
// and the `ctx.ts` config idiom). Every field falls back individually.
|
|
7
|
+
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { pathExists } from "../lib/fs";
|
|
10
|
+
import { readJsonFileOr } from "../lib/json";
|
|
11
|
+
|
|
12
|
+
export type TokenEstimator = "chars-div-4";
|
|
13
|
+
|
|
14
|
+
export interface GdgraphConfig {
|
|
15
|
+
affected: {
|
|
16
|
+
// MUST default to 1 for back-compat (B-3): depth-1 == today's dependents.
|
|
17
|
+
defaultDepth: number;
|
|
18
|
+
};
|
|
19
|
+
repomap: {
|
|
20
|
+
tokenBudget: number;
|
|
21
|
+
tokenEstimator: TokenEstimator;
|
|
22
|
+
maxSymbolsPerFile: number;
|
|
23
|
+
// PageRank params — FIXED ⇒ deterministic convergence (B-4, B-5).
|
|
24
|
+
damping: number;
|
|
25
|
+
iterations: number;
|
|
26
|
+
tolerance: number;
|
|
27
|
+
// CALL edge weight for personalized PageRank (import=1.0, defines=0.5).
|
|
28
|
+
callWeight: number;
|
|
29
|
+
};
|
|
30
|
+
treesitter: {
|
|
31
|
+
// T1 user-provided dir of *.wasm grammars (A-1); null ⇒ resolver cache/pull.
|
|
32
|
+
grammarsPath: string | null;
|
|
33
|
+
// Bounded to the languages this project extracts (NG-B3/B-8).
|
|
34
|
+
languages: string[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_GDGRAPH_CONFIG: GdgraphConfig = {
|
|
39
|
+
affected: {
|
|
40
|
+
defaultDepth: 1,
|
|
41
|
+
},
|
|
42
|
+
repomap: {
|
|
43
|
+
tokenBudget: 8000,
|
|
44
|
+
tokenEstimator: "chars-div-4",
|
|
45
|
+
maxSymbolsPerFile: 12,
|
|
46
|
+
damping: 0.85,
|
|
47
|
+
iterations: 50,
|
|
48
|
+
tolerance: 1e-8,
|
|
49
|
+
callWeight: 1.5,
|
|
50
|
+
},
|
|
51
|
+
treesitter: {
|
|
52
|
+
grammarsPath: null,
|
|
53
|
+
languages: ["typescript", "tsx", "javascript"],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function gdgraphConfigPath(cwd: string): string {
|
|
58
|
+
return path.join(cwd, ".metaproject", "gdgraph.config.json");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Deep-merge a partial user config over the defaults, field-by-field. Unknown
|
|
62
|
+
// keys are ignored; each known block falls back individually. Never throws.
|
|
63
|
+
export function mergeGdgraphConfig(parsed: DeepPartial<GdgraphConfig>): GdgraphConfig {
|
|
64
|
+
const base = DEFAULT_GDGRAPH_CONFIG;
|
|
65
|
+
const affected = parsed.affected ?? {};
|
|
66
|
+
const repomap = parsed.repomap ?? {};
|
|
67
|
+
const treesitter = parsed.treesitter ?? {};
|
|
68
|
+
return {
|
|
69
|
+
affected: {
|
|
70
|
+
defaultDepth: numberOr(affected.defaultDepth, base.affected.defaultDepth),
|
|
71
|
+
},
|
|
72
|
+
repomap: {
|
|
73
|
+
tokenBudget: numberOr(repomap.tokenBudget, base.repomap.tokenBudget),
|
|
74
|
+
tokenEstimator:
|
|
75
|
+
repomap.tokenEstimator === "chars-div-4"
|
|
76
|
+
? repomap.tokenEstimator
|
|
77
|
+
: base.repomap.tokenEstimator,
|
|
78
|
+
maxSymbolsPerFile: numberOr(repomap.maxSymbolsPerFile, base.repomap.maxSymbolsPerFile),
|
|
79
|
+
damping: numberOr(repomap.damping, base.repomap.damping),
|
|
80
|
+
iterations: numberOr(repomap.iterations, base.repomap.iterations),
|
|
81
|
+
tolerance: numberOr(repomap.tolerance, base.repomap.tolerance),
|
|
82
|
+
callWeight: numberOr(repomap.callWeight, base.repomap.callWeight),
|
|
83
|
+
},
|
|
84
|
+
treesitter: {
|
|
85
|
+
grammarsPath:
|
|
86
|
+
typeof treesitter.grammarsPath === "string"
|
|
87
|
+
? treesitter.grammarsPath
|
|
88
|
+
: base.treesitter.grammarsPath,
|
|
89
|
+
languages: Array.isArray(treesitter.languages)
|
|
90
|
+
? treesitter.languages.filter((entry): entry is string => typeof entry === "string")
|
|
91
|
+
: base.treesitter.languages,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Load `.metaproject/gdgraph.config.json`, falling back to defaults when the
|
|
97
|
+
// file is absent OR malformed (advisory-safe, never throws).
|
|
98
|
+
export async function loadGdgraphConfig(cwd: string): Promise<GdgraphConfig> {
|
|
99
|
+
const file = gdgraphConfigPath(cwd);
|
|
100
|
+
if (!(await pathExists(file))) {
|
|
101
|
+
return mergeGdgraphConfig({});
|
|
102
|
+
}
|
|
103
|
+
const parsed = await readJsonFileOr<DeepPartial<GdgraphConfig>>(file, {});
|
|
104
|
+
return mergeGdgraphConfig(parsed);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function numberOr(value: unknown, fallback: number): number {
|
|
108
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type DeepPartial<T> = {
|
|
112
|
+
[K in keyof T]?: T[K] extends Record<string, unknown> ? DeepPartial<T[K]> : T[K];
|
|
113
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// The copied gdgraph core must be import-closed.
|
|
2
|
+
//
|
|
3
|
+
// `init` and `update` copy a few `src/gdgraph/*.ts` files into
|
|
4
|
+
// `.metaproject/core/gdgraph/` so a project can run the graph builder without
|
|
5
|
+
// the full toolkit. The list was hand-maintained, in two places, and nothing
|
|
6
|
+
// checked it against what those files actually import.
|
|
7
|
+
//
|
|
8
|
+
// So when `query.ts` gained `import { resolveGraphTarget } from "./target"`,
|
|
9
|
+
// neither copy learned about it, and `keryx gdgraph build` — the very first
|
|
10
|
+
// "Next step" that `init` prints — died on every fresh install with
|
|
11
|
+
// `Cannot find module './target'`. The suite stayed green throughout, because
|
|
12
|
+
// nothing ever ran the copied tree.
|
|
13
|
+
//
|
|
14
|
+
// The domain of "which files does the copied core need" is not a list. It is
|
|
15
|
+
// the transitive closure of RUNTIME imports from the entry points, and written
|
|
16
|
+
// as a list it goes stale on the next `import`.
|
|
17
|
+
//
|
|
18
|
+
// The first version of this test matched imports with a regular expression and
|
|
19
|
+
// immediately proved the repository's own lesson about pattern guards: it
|
|
20
|
+
// matched the string `from "./m"` inside a COMMENT in `build.ts` and demanded a
|
|
21
|
+
// file called `m.ts`. So it uses `Bun.Transpiler.scanImports` instead — the same
|
|
22
|
+
// parser-backed scan gdgraph itself uses. That also gets the semantics right:
|
|
23
|
+
// the transpiler drops type-only imports, and a type-only import genuinely does
|
|
24
|
+
// not need its file present at runtime.
|
|
25
|
+
import { describe, expect, test } from "bun:test";
|
|
26
|
+
import { readFileSync } from "node:fs";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import { GDGRAPH_CORE_SOURCES } from "./core-sources";
|
|
29
|
+
|
|
30
|
+
const GDGRAPH_DIR = import.meta.dir;
|
|
31
|
+
const transpiler = new Bun.Transpiler({ loader: "ts" });
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Local imports of one module that must resolve for it to LOAD.
|
|
35
|
+
*
|
|
36
|
+
* Two exclusions, both deliberate rather than convenient:
|
|
37
|
+
*
|
|
38
|
+
* * type-only imports never reach runtime — the transpiler drops them, and
|
|
39
|
+
* `scanImports` does not report them;
|
|
40
|
+
* * a `dynamic-import` is a deliberate lazy edge. `build.ts` reaches `enrich`
|
|
41
|
+
* that way precisely so it can run in an environment that lacks it —
|
|
42
|
+
* `enrich.ts:9` names "the copied `.metaproject/core/gdgraph`" as that
|
|
43
|
+
* environment. Requiring it would copy the whole optional-capability tree
|
|
44
|
+
* into every scaffolded project and invert the design.
|
|
45
|
+
*
|
|
46
|
+
* So the closure is over `import-statement` only. That is the set whose absence
|
|
47
|
+
* is a crash at load, which is the failure this test exists to prevent.
|
|
48
|
+
*/
|
|
49
|
+
function runtimeImportsOf(basename: string): string[] {
|
|
50
|
+
const source = readFileSync(path.join(GDGRAPH_DIR, basename), "utf8");
|
|
51
|
+
return transpiler
|
|
52
|
+
.scanImports(source)
|
|
53
|
+
.filter((entry) => entry.kind === "import-statement" && entry.path.startsWith("./"))
|
|
54
|
+
.map((entry) => `${entry.path.slice(2).replace(/\.(ts|js)$/, "")}.ts`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Every module reachable from `entries` through runtime local imports. */
|
|
58
|
+
function importClosure(entries: readonly string[]): Set<string> {
|
|
59
|
+
const seen = new Set<string>();
|
|
60
|
+
const queue = [...entries];
|
|
61
|
+
while (queue.length > 0) {
|
|
62
|
+
const current = queue.shift()!;
|
|
63
|
+
if (seen.has(current)) continue;
|
|
64
|
+
seen.add(current);
|
|
65
|
+
for (const next of runtimeImportsOf(current)) queue.push(next);
|
|
66
|
+
}
|
|
67
|
+
return seen;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
describe("the copied gdgraph core is import-closed", () => {
|
|
71
|
+
// `cli.ts` is rendered rather than copied, and it drives these two.
|
|
72
|
+
const ENTRY_POINTS = ["build.ts", "query.ts"] as const;
|
|
73
|
+
|
|
74
|
+
test("every module the entry points reach at runtime is copied", () => {
|
|
75
|
+
const needed = importClosure(ENTRY_POINTS);
|
|
76
|
+
const copied = new Set(GDGRAPH_CORE_SOURCES);
|
|
77
|
+
const missing = [...needed].filter((f) => !copied.has(f)).sort();
|
|
78
|
+
// A failure here means a fresh `keryx init` followed by `keryx gdgraph
|
|
79
|
+
// build` dies on a missing module. Add the file to GDGRAPH_CORE_SOURCES.
|
|
80
|
+
expect(missing).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("every file in the copy list exists", () => {
|
|
84
|
+
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
85
|
+
expect(() => readFileSync(path.join(GDGRAPH_DIR, file), "utf8")).not.toThrow();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("the closure is non-trivial, so a passing test is not vacuous", () => {
|
|
90
|
+
// If `scanImports` ever silently returned nothing, the first assertion
|
|
91
|
+
// would pass against an empty set. Pin the floor, and pin the specific file
|
|
92
|
+
// whose absence caused the outage.
|
|
93
|
+
const needed = importClosure(ENTRY_POINTS);
|
|
94
|
+
expect(needed.size).toBeGreaterThanOrEqual(3);
|
|
95
|
+
expect(needed.has("build.ts")).toBe(true);
|
|
96
|
+
expect(needed.has("query.ts")).toBe(true);
|
|
97
|
+
expect(needed.has("target.ts")).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// The `src/gdgraph/*.ts` files that `init` and `update` copy into
|
|
2
|
+
// `.metaproject/core/gdgraph/`, so a scaffolded project can run the graph
|
|
3
|
+
// builder without the full toolkit installed.
|
|
4
|
+
//
|
|
5
|
+
// This list used to live inline in BOTH `commands/init.ts` and
|
|
6
|
+
// `commands/update.ts`, which meant two hand-maintained copies of a fact that
|
|
7
|
+
// nothing checked. When `query.ts` gained an import of `./target`, neither copy
|
|
8
|
+
// learned about it and `keryx gdgraph build` broke on every fresh install —
|
|
9
|
+
// while the suite stayed green, because nothing ran the copied tree.
|
|
10
|
+
//
|
|
11
|
+
// It is one constant now, and `core-sources.test.ts` computes the transitive
|
|
12
|
+
// closure of local imports from the entry points and asserts this list equals
|
|
13
|
+
// it, in both directions. A new `import` in a copied file fails that test
|
|
14
|
+
// instead of a stranger's first five minutes.
|
|
15
|
+
export const GDGRAPH_CORE_SOURCES: readonly string[] = [
|
|
16
|
+
"build.ts",
|
|
17
|
+
"query.ts",
|
|
18
|
+
"target.ts",
|
|
19
|
+
"types.ts",
|
|
20
|
+
];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Symbol-layer enrichment behind the capability seam (specification.md §7, §8.1;
|
|
2
|
+
// T-B13). Called by `build.ts` AFTER the unchanged file-level build. When
|
|
3
|
+
// `gdgraph.treesitter` resolves to an adapter it writes `storage/symbols.jsonl`
|
|
4
|
+
// and `storage/calls.jsonl` ADDITIVELY; when it degrades to `null` (default /
|
|
5
|
+
// dep or grammar missing) nothing is written and the four legacy artifacts stay
|
|
6
|
+
// byte-identical (the golden rule, B-1/C0-7/F-3).
|
|
7
|
+
//
|
|
8
|
+
// `build.ts` imports this module DYNAMICALLY inside a try/catch, so an
|
|
9
|
+
// environment that lacks the seam (e.g. the copied `.metaproject/core/gdgraph`
|
|
10
|
+
// runner) simply falls back to file-level output — the exact degraded behavior.
|
|
11
|
+
|
|
12
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import {
|
|
15
|
+
resolveCapability,
|
|
16
|
+
runCapabilityOrFallback,
|
|
17
|
+
type CapabilityAdapter,
|
|
18
|
+
type CapabilitySpec,
|
|
19
|
+
} from "../capability/seam";
|
|
20
|
+
import { loadGdgraphConfig } from "./config";
|
|
21
|
+
import { createTreesitterSpec, type BuildInput, type FileRecord } from "./treesitter/adapter";
|
|
22
|
+
import type { SymbolLayer } from "./types";
|
|
23
|
+
|
|
24
|
+
export interface EnrichResult {
|
|
25
|
+
enriched: boolean;
|
|
26
|
+
symbols: number;
|
|
27
|
+
calls: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Seam resolver, injectable for tests so the availability-true write path can be
|
|
31
|
+
// proven with a mock adapter (the real optional dep is not installed offline).
|
|
32
|
+
export type CapabilityResolver = (
|
|
33
|
+
cwd: string,
|
|
34
|
+
spec: CapabilitySpec<BuildInput, SymbolLayer>,
|
|
35
|
+
) => Promise<CapabilityAdapter<BuildInput, SymbolLayer> | null>;
|
|
36
|
+
|
|
37
|
+
export async function enrichBuildWithSymbols(
|
|
38
|
+
cwd: string,
|
|
39
|
+
files: FileRecord[],
|
|
40
|
+
resolve: CapabilityResolver = resolveCapability,
|
|
41
|
+
): Promise<EnrichResult> {
|
|
42
|
+
const config = await loadGdgraphConfig(cwd);
|
|
43
|
+
const spec = createTreesitterSpec(cwd, {
|
|
44
|
+
languages: config.treesitter.languages,
|
|
45
|
+
grammarsPath: config.treesitter.grammarsPath,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Gate 1 (manifest-enabled) + dep + grammar + isAvailable. `null` ⇒ degrade
|
|
49
|
+
// with NO symbol files written; the seam emits the single warn-once on an
|
|
50
|
+
// enabled-but-unavailable ceiling.
|
|
51
|
+
const adapter = await resolve(cwd, spec);
|
|
52
|
+
if (!adapter) {
|
|
53
|
+
return { enriched: false, symbols: 0, calls: 0 };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const layer = await runCapabilityOrFallback<BuildInput, SymbolLayer>(
|
|
57
|
+
adapter,
|
|
58
|
+
{ files },
|
|
59
|
+
() => ({ symbols: [], calls: [] }),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await writeSymbolLayer(cwd, layer);
|
|
63
|
+
return { enriched: true, symbols: layer.symbols.length, calls: layer.calls.length };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function writeSymbolLayer(cwd: string, layer: SymbolLayer): Promise<void> {
|
|
67
|
+
const storageDir = path.join(cwd, ".metaproject", "data", "gdgraph", "storage");
|
|
68
|
+
await mkdir(storageDir, { recursive: true });
|
|
69
|
+
await writeFile(
|
|
70
|
+
path.join(storageDir, "symbols.jsonl"),
|
|
71
|
+
layer.symbols.map((symbol) => JSON.stringify(symbol)).join("\n") + "\n",
|
|
72
|
+
"utf8",
|
|
73
|
+
);
|
|
74
|
+
await writeFile(
|
|
75
|
+
path.join(storageDir, "calls.jsonl"),
|
|
76
|
+
layer.calls.map((call) => JSON.stringify(call)).join("\n") + "\n",
|
|
77
|
+
"utf8",
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile, stat } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import net from "node:net";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { expect, test } from "bun:test";
|
|
7
|
+
import { buildGraph } from "./build";
|
|
8
|
+
import { computeAffected } from "./affected";
|
|
9
|
+
import { loadGdgraphConfig } from "./config";
|
|
10
|
+
import { computeRepomap } from "./repomap";
|
|
11
|
+
import { loadGraph } from "./query";
|
|
12
|
+
import { resetWarnOnce, hasWarned } from "../capability/warn-once";
|
|
13
|
+
|
|
14
|
+
const ARTIFACTS = [
|
|
15
|
+
"storage/nodes.jsonl",
|
|
16
|
+
"storage/edges.jsonl",
|
|
17
|
+
"artifacts/module-map.json",
|
|
18
|
+
"artifacts/summary.md",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
async function makeProject(): Promise<string> {
|
|
22
|
+
const root = await mkdtemp(path.join(tmpdir(), "keryx-fallback-"));
|
|
23
|
+
await mkdir(path.join(root, "src", "feature"), { recursive: true });
|
|
24
|
+
await writeFile(
|
|
25
|
+
path.join(root, "src", "index.ts"),
|
|
26
|
+
"import { value } from './feature/value';\nexport const app = value;\n",
|
|
27
|
+
);
|
|
28
|
+
await writeFile(path.join(root, "src", "feature", "value.ts"), "export const value = 1;\n");
|
|
29
|
+
return root;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function snapshot(root: string): Promise<Record<string, string>> {
|
|
33
|
+
const out: Record<string, string> = {};
|
|
34
|
+
for (const rel of ARTIFACTS) {
|
|
35
|
+
out[rel] = await readFile(
|
|
36
|
+
path.join(root, ".metaproject", "data", "gdgraph", rel),
|
|
37
|
+
"utf8",
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
test("AC4.1/AC4.2 — capability OFF: 4 legacy artifacts deterministic; no symbol files written", async () => {
|
|
44
|
+
// Two fresh, identical projects, each built ONCE (a rebuild in the same dir is
|
|
45
|
+
// pre-existingly non-deterministic because the build creates `.metaproject`,
|
|
46
|
+
// which then appears in the summary's skipped-dirs — unrelated to this block).
|
|
47
|
+
// Comparing two first-builds isolates the capability-off artifacts precisely.
|
|
48
|
+
const a = await makeProject();
|
|
49
|
+
const b = await makeProject();
|
|
50
|
+
try {
|
|
51
|
+
await buildGraph(a);
|
|
52
|
+
await buildGraph(b);
|
|
53
|
+
expect(await snapshot(b)).toEqual(await snapshot(a));
|
|
54
|
+
|
|
55
|
+
for (const root of [a, b]) {
|
|
56
|
+
const storage = path.join(root, ".metaproject", "data", "gdgraph", "storage");
|
|
57
|
+
expect(existsSync(path.join(storage, "symbols.jsonl"))).toBe(false);
|
|
58
|
+
expect(existsSync(path.join(storage, "calls.jsonl"))).toBe(false);
|
|
59
|
+
}
|
|
60
|
+
} finally {
|
|
61
|
+
await rm(a, { recursive: true, force: true });
|
|
62
|
+
await rm(b, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("AC4.4 — no-network sandbox: build/affected/repomap open zero sockets", async () => {
|
|
67
|
+
const root = await makeProject();
|
|
68
|
+
const originalConnect = net.Socket.prototype.connect;
|
|
69
|
+
const originalFetch = globalThis.fetch;
|
|
70
|
+
let socketAttempts = 0;
|
|
71
|
+
let fetchAttempts = 0;
|
|
72
|
+
|
|
73
|
+
net.Socket.prototype.connect = function connect(this: net.Socket) {
|
|
74
|
+
socketAttempts += 1;
|
|
75
|
+
// Never actually connect.
|
|
76
|
+
return this;
|
|
77
|
+
};
|
|
78
|
+
// @ts-expect-error — deliberately override for the sandbox assertion.
|
|
79
|
+
globalThis.fetch = async () => {
|
|
80
|
+
fetchAttempts += 1;
|
|
81
|
+
throw new Error("network blocked in sandbox");
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await buildGraph(root);
|
|
86
|
+
const config = await loadGdgraphConfig(root);
|
|
87
|
+
const graph = await loadGraph(root);
|
|
88
|
+
computeAffected(graph, "src/feature/value.ts", { depth: 3 });
|
|
89
|
+
computeRepomap(graph, config, {});
|
|
90
|
+
expect(socketAttempts).toBe(0);
|
|
91
|
+
expect(fetchAttempts).toBe(0);
|
|
92
|
+
} finally {
|
|
93
|
+
net.Socket.prototype.connect = originalConnect;
|
|
94
|
+
globalThis.fetch = originalFetch;
|
|
95
|
+
await rm(root, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("AC4.3 — capability ENABLED but unavailable: exactly one warn, regex path, exit 0, no symbol files", async () => {
|
|
100
|
+
const root = await makeProject();
|
|
101
|
+
resetWarnOnce();
|
|
102
|
+
try {
|
|
103
|
+
// Enable the ceiling in the manifest but provide NO resolvable grammar and
|
|
104
|
+
// no installed dep ⇒ resolveCapability degrades with a single warn-once.
|
|
105
|
+
await mkdir(path.join(root, ".metaproject"), { recursive: true });
|
|
106
|
+
await writeFile(
|
|
107
|
+
path.join(root, ".metaproject", "metaproject.json"),
|
|
108
|
+
JSON.stringify({
|
|
109
|
+
modules: {
|
|
110
|
+
gdgraph: {
|
|
111
|
+
enabled: true,
|
|
112
|
+
capabilities: [
|
|
113
|
+
{ id: "gdgraph.treesitter", enabled: true, kind: "ceiling", optionalDependency: "web-tree-sitter" },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
let stderr = "";
|
|
121
|
+
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
122
|
+
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
123
|
+
stderr += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
|
|
124
|
+
return true;
|
|
125
|
+
}) as typeof process.stderr.write;
|
|
126
|
+
|
|
127
|
+
let exitCodeBefore = process.exitCode;
|
|
128
|
+
try {
|
|
129
|
+
await buildGraph(root);
|
|
130
|
+
} finally {
|
|
131
|
+
process.stderr.write = originalWrite;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Build did not hard-fail (exitCode untouched by build).
|
|
135
|
+
expect(process.exitCode).toBe(exitCodeBefore);
|
|
136
|
+
// Exactly one capability degradation warning was emitted.
|
|
137
|
+
const warnings = stderr.split("\n").filter((line) => line.includes("gdgraph.treesitter unavailable"));
|
|
138
|
+
expect(warnings).toHaveLength(1);
|
|
139
|
+
expect(hasWarned("gdgraph.treesitter")).toBe(true);
|
|
140
|
+
|
|
141
|
+
// No symbol files were written (regex/scan path only).
|
|
142
|
+
const storage = path.join(root, ".metaproject", "data", "gdgraph", "storage");
|
|
143
|
+
expect(existsSync(path.join(storage, "symbols.jsonl"))).toBe(false);
|
|
144
|
+
// The 4 legacy artifacts were still produced.
|
|
145
|
+
for (const rel of ARTIFACTS) {
|
|
146
|
+
const info = await stat(path.join(root, ".metaproject", "data", "gdgraph", rel));
|
|
147
|
+
expect(info.isFile()).toBe(true);
|
|
148
|
+
}
|
|
149
|
+
} finally {
|
|
150
|
+
resetWarnOnce();
|
|
151
|
+
await rm(root, { recursive: true, force: true });
|
|
152
|
+
}
|
|
153
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { findNodes, findSymbols } from "./find";
|
|
3
|
+
import type { GraphData, SymbolNode } from "./types";
|
|
4
|
+
|
|
5
|
+
function fileNode(path: string) {
|
|
6
|
+
return { id: path, kind: "file" as const, path, language: "typescript" as const };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function edge(from: string, to: string) {
|
|
10
|
+
return { id: `${from}->${to}`, from, to, kind: "imports" as const, specifier: to };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const GRAPH: GraphData = {
|
|
14
|
+
nodes: [
|
|
15
|
+
fileNode("src/pipelines/utils/clone-pipeline.ts"),
|
|
16
|
+
fileNode("src/pipelines/features/pipeline-variables/pipeline-variables-store.ts"),
|
|
17
|
+
fileNode("src/pipelines/api/pipeline-api.ts"),
|
|
18
|
+
fileNode("src/case/store/case-store.ts"),
|
|
19
|
+
],
|
|
20
|
+
edges: [
|
|
21
|
+
edge("src/case/store/case-store.ts", "src/pipelines/api/pipeline-api.ts"),
|
|
22
|
+
edge("src/pipelines/utils/clone-pipeline.ts", "src/pipelines/api/pipeline-api.ts"),
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
test("finds files by concept and ranks by matched terms", () => {
|
|
27
|
+
const results = findNodes(GRAPH, "pipeline clone");
|
|
28
|
+
expect(results[0]?.path).toBe("src/pipelines/utils/clone-pipeline.ts");
|
|
29
|
+
expect(results[0]?.matched.sort()).toEqual(["clone", "pipeline"]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("ranks pipeline-variables highest for that query", () => {
|
|
33
|
+
const results = findNodes(GRAPH, "pipeline variables store");
|
|
34
|
+
expect(results[0]?.path).toContain("pipeline-variables-store.ts");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("drops stopwords and short tokens from the query", () => {
|
|
38
|
+
const results = findNodes(GRAPH, "the clone of a pipeline");
|
|
39
|
+
expect(results[0]?.path).toBe("src/pipelines/utils/clone-pipeline.ts");
|
|
40
|
+
// "the", "of", "a" must not have matched anything on their own
|
|
41
|
+
expect(results.every((r) => !r.matched.includes("the"))).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("returns empty for a query that matches no path", () => {
|
|
45
|
+
expect(findNodes(GRAPH, "kubernetes helm chart")).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("fan-in breaks ties (more-depended-on file ranks higher)", () => {
|
|
49
|
+
// both match "pipeline api" equally; pipeline-api has 2 dependents
|
|
50
|
+
const results = findNodes(GRAPH, "pipeline");
|
|
51
|
+
const apiIdx = results.findIndex((r) => r.path.endsWith("pipeline-api.ts"));
|
|
52
|
+
expect(results[apiIdx]?.dependents).toBe(2);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
function sym(id: string, name: string, path: string, line: number): SymbolNode {
|
|
56
|
+
return { id, kind: "function", path, name, container: null, startLine: line, endLine: line + 2, language: "typescript" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const SYMBOL_GRAPH: GraphData = {
|
|
60
|
+
nodes: [],
|
|
61
|
+
edges: [],
|
|
62
|
+
symbols: [
|
|
63
|
+
sym("a#clonePipeline", "clonePipeline", "src/a.ts", 12),
|
|
64
|
+
sym("b#clonePipelineDeep", "clonePipelineDeep", "src/b.ts", 30),
|
|
65
|
+
sym("c#unrelated", "unrelated", "src/c.ts", 1),
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
test("findSymbols ranks an exact name match above a substring match", () => {
|
|
70
|
+
const results = findSymbols(SYMBOL_GRAPH, "clonePipeline");
|
|
71
|
+
expect(results[0]?.name).toBe("clonePipeline"); // exact-name bonus wins
|
|
72
|
+
expect(results.map((r) => r.name)).toContain("clonePipelineDeep");
|
|
73
|
+
expect(results.every((r) => r.name !== "unrelated")).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("findSymbols returns [] when the symbol layer is absent", () => {
|
|
77
|
+
expect(findSymbols({ nodes: [], edges: [] }, "clonePipeline")).toEqual([]);
|
|
78
|
+
});
|