octocode-cli 1.2.8 → 1.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/README.md +42 -35
- package/out/octocode-cli.js +36 -11767
- package/package.json +36 -36
- package/skills/README.md +42 -114
- package/skills/{octocode-code-engineer → octocode-engineer}/.claude/settings.local.json +2 -1
- package/skills/octocode-engineer/README.md +99 -0
- package/skills/octocode-engineer/SKILL.md +499 -0
- package/skills/octocode-engineer/build.mjs +29 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/eslint.config.mjs +3 -13
- package/skills/{octocode-code-engineer → octocode-engineer}/package.json +28 -27
- package/skills/octocode-engineer/references/ast-reference.md +166 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/references/cli-reference.md +80 -6
- package/skills/octocode-engineer/references/externals.md +86 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/references/output-files.md +46 -6
- package/skills/octocode-engineer/references/quality-indicators.md +202 -0
- package/skills/octocode-engineer/references/tool-workflows.md +298 -0
- package/skills/octocode-engineer/references/validation-playbooks.md +99 -0
- package/skills/octocode-engineer/scripts/ast/search.js +45 -0
- package/skills/octocode-engineer/scripts/ast/tree-search.js +27 -0
- package/skills/octocode-engineer/scripts/index.js +173 -0
- package/skills/octocode-engineer/scripts/run.js +179 -0
- package/skills/octocode-engineer/src/analysis/dependencies.ts +378 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/discovery.test.ts +57 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/discovery.ts +43 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/search.test.ts +113 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/search.ts +64 -1
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-sitter.test.ts +118 -2
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-sitter.ts +65 -3
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/ts-analyzer.test.ts +281 -1
- package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/ts-analyzer.ts +173 -3
- package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/security.test.ts +73 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/security.ts +62 -4
- package/skills/octocode-engineer/src/detector-gating.test.ts +59 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/code-quality.ts +342 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/index.ts +8 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/index.test.ts +565 -11
- package/skills/octocode-engineer/src/index.ts +468 -0
- package/skills/octocode-engineer/src/pipeline/affected.test.ts +147 -0
- package/skills/octocode-engineer/src/pipeline/affected.ts +68 -0
- package/skills/octocode-engineer/src/pipeline/baseline.test.ts +276 -0
- package/skills/octocode-engineer/src/pipeline/baseline.ts +76 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cli.test.ts +300 -53
- package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cli.ts +180 -36
- package/skills/octocode-engineer/src/pipeline/config-loader.test.ts +264 -0
- package/skills/octocode-engineer/src/pipeline/config-loader.ts +109 -0
- package/skills/octocode-engineer/src/pipeline/create-options.ts +55 -0
- package/skills/octocode-engineer/src/pipeline/health-score.test.ts +65 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/main.ts +130 -17
- package/skills/octocode-engineer/src/pipeline/progress.ts +51 -0
- package/skills/octocode-engineer/src/pipeline/reporters.test.ts +155 -0
- package/skills/octocode-engineer/src/pipeline/reporters.ts +64 -0
- package/skills/octocode-engineer/src/reporting/graph-features.test.ts +279 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/output-contract.test.ts +6 -0
- package/skills/octocode-engineer/src/reporting/summary-md.test.ts +1066 -0
- package/skills/octocode-engineer/src/reporting/summary-md.ts +1604 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/writer.ts +136 -13
- package/skills/octocode-engineer/src/run.ts +78 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/sanity.test.ts +1 -1
- package/skills/octocode-engineer/src/types/analysis.ts +25 -0
- package/skills/octocode-engineer/src/types/collectors.ts +134 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/types/constants.ts +75 -41
- package/skills/octocode-engineer/src/types/core.ts +203 -0
- package/skills/octocode-engineer/src/types/dependency.ts +215 -0
- package/skills/octocode-engineer/src/types/file-entry.ts +108 -0
- package/skills/octocode-engineer/src/types/findings.ts +105 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/src/types/index.ts +60 -30
- package/skills/octocode-engineer/src/types/tree-sitter.ts +38 -0
- package/skills/{octocode-code-engineer → octocode-engineer}/tsconfig.json +1 -0
- package/skills/octocode-research/.octocode/scan/.cache/analysis-cache.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/architecture.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/ast-trees.txt +5566 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/code-quality.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/dead-code.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/file-inventory.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/findings.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/graph.md +189 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/security.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/summary.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/summary.md +265 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/architecture.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/ast-trees.txt +5555 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/code-quality.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/dead-code.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/file-inventory.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/findings.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/graph.md +190 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/security.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/summary.json +1 -0
- package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/summary.md +265 -0
- package/skills/octocode-research/CHANGELOG.md +60 -0
- package/skills/octocode-research/README.md +102 -388
- package/skills/octocode-research/SKILL.md +169 -498
- package/skills/octocode-research/package.json +19 -31
- package/skills/octocode-research/references/PARALLEL_AGENT_PROTOCOL.md +19 -0
- package/skills/octocode-research/references/SESSION_MANAGEMENT.md +38 -0
- package/skills/octocode-research/scripts/server-init.js +1 -1
- package/skills/octocode-research/scripts/server.d.ts +2 -1
- package/skills/octocode-research/scripts/server.js +329 -233
- package/skills/octocode-research/src/__tests__/integration/promptsRoutes.test.ts +180 -0
- package/skills/octocode-research/src/__tests__/integration/serverHttp.test.ts +221 -0
- package/skills/octocode-research/src/__tests__/integration/serverLifecycle.test.ts +194 -0
- package/skills/octocode-research/src/__tests__/integration/toolsRoutes.test.ts +501 -0
- package/skills/octocode-research/src/__tests__/unit/readiness.test.ts +61 -0
- package/skills/octocode-research/src/__tests__/unit/resilience.test.ts +192 -0
- package/skills/octocode-research/src/__tests__/unit/responseFactory.test.ts +172 -0
- package/skills/octocode-research/src/__tests__/unit/responseParser.test.ts +288 -0
- package/skills/octocode-research/src/__tests__/unit/schemas.test.ts +509 -0
- package/skills/octocode-research/src/index.ts +4 -124
- package/skills/octocode-research/src/middleware/queryParser.ts +0 -26
- package/skills/octocode-research/src/routes/lsp.ts +58 -59
- package/skills/octocode-research/src/routes/package.ts +35 -65
- package/skills/octocode-research/src/routes/prompts.ts +3 -3
- package/skills/octocode-research/src/routes/tools.ts +8 -20
- package/skills/octocode-research/src/server-init.ts +30 -237
- package/skills/octocode-research/src/server.ts +50 -23
- package/skills/octocode-research/src/types/errorGuards.ts +9 -80
- package/skills/octocode-research/src/types/guards.ts +0 -28
- package/skills/octocode-research/src/types/mcp.ts +11 -66
- package/skills/octocode-research/src/types/responses.ts +11 -129
- package/skills/octocode-research/src/utils/circuitBreaker.ts +0 -21
- package/skills/octocode-research/src/utils/logger.ts +1 -97
- package/skills/octocode-research/src/utils/resilience.ts +2 -12
- package/skills/octocode-research/src/utils/responseFactory.ts +0 -42
- package/skills/octocode-research/src/utils/responseParser.ts +3 -25
- package/skills/octocode-research/src/utils/retry.ts +0 -63
- package/skills/octocode-research/src/utils/routeFactory.ts +1 -1
- package/skills/octocode-research/src/validation/httpPreprocess.ts +0 -3
- package/skills/octocode-research/src/validation/index.ts +0 -1
- package/skills/octocode-research/src/validation/schemas.ts +0 -63
- package/skills/octocode-research/src/validation/toolCallSchema.ts +3 -3
- package/skills/octocode-research/tsdown.config.ts +4 -0
- package/skills/octocode-research/vitest.config.ts +3 -0
- package/skills/octocode-code-engineer/.plan/VALIDATED_PLAN.md +0 -223
- package/skills/octocode-code-engineer/README.md +0 -178
- package/skills/octocode-code-engineer/SKILL.md +0 -418
- package/skills/octocode-code-engineer/minify-scripts.mjs +0 -32
- package/skills/octocode-code-engineer/references/agent-ast-reading-rfc.md +0 -95
- package/skills/octocode-code-engineer/references/architecture-techniques.md +0 -121
- package/skills/octocode-code-engineer/references/ast-search.md +0 -210
- package/skills/octocode-code-engineer/references/ast-tree-search.md +0 -151
- package/skills/octocode-code-engineer/references/concepts.md +0 -107
- package/skills/octocode-code-engineer/references/finding-categories.md +0 -128
- package/skills/octocode-code-engineer/references/improvement-roadmap.md +0 -304
- package/skills/octocode-code-engineer/references/playbooks.md +0 -204
- package/skills/octocode-code-engineer/references/present-results.md +0 -136
- package/skills/octocode-code-engineer/references/tool-workflows.md +0 -566
- package/skills/octocode-code-engineer/references/validate-investigate.md +0 -225
- package/skills/octocode-code-engineer/scripts/analysis/dependencies.js +0 -1
- package/skills/octocode-code-engineer/scripts/analysis/dependency-summary.js +0 -1
- package/skills/octocode-code-engineer/scripts/analysis/discovery.js +0 -1
- package/skills/octocode-code-engineer/scripts/analysis/graph-analytics.js +0 -1
- package/skills/octocode-code-engineer/scripts/analysis/semantic.js +0 -1
- package/skills/octocode-code-engineer/scripts/ast/helpers.js +0 -1
- package/skills/octocode-code-engineer/scripts/ast/metrics.js +0 -1
- package/skills/octocode-code-engineer/scripts/ast/search.js +0 -2
- package/skills/octocode-code-engineer/scripts/ast/tree-search.js +0 -2
- package/skills/octocode-code-engineer/scripts/ast/tree-sitter.js +0 -1
- package/skills/octocode-code-engineer/scripts/ast/ts-analyzer.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/chains.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/effects.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/input-sources.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/performance.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/prototype-pollution.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/security.js +0 -1
- package/skills/octocode-code-engineer/scripts/collectors/test-profile.js +0 -1
- package/skills/octocode-code-engineer/scripts/common/is-direct-run.js +0 -1
- package/skills/octocode-code-engineer/scripts/common/utils.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/code-quality.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/cohesion.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/coupling.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/cycle.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/dead-code.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/import-style.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/index.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/security.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/semantic.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/shared.js +0 -1
- package/skills/octocode-code-engineer/scripts/detectors/test-quality.js +0 -1
- package/skills/octocode-code-engineer/scripts/index.js +0 -1
- package/skills/octocode-code-engineer/scripts/pipeline/cache.js +0 -1
- package/skills/octocode-code-engineer/scripts/pipeline/cli.js +0 -1
- package/skills/octocode-code-engineer/scripts/pipeline/main.js +0 -2
- package/skills/octocode-code-engineer/scripts/reporting/analysis.js +0 -1
- package/skills/octocode-code-engineer/scripts/reporting/summary-md.js +0 -1
- package/skills/octocode-code-engineer/scripts/reporting/writer.js +0 -1
- package/skills/octocode-code-engineer/scripts/types/constants.js +0 -1
- package/skills/octocode-code-engineer/scripts/types/index.js +0 -1
- package/skills/octocode-code-engineer/scripts/types/interfaces.js +0 -1
- package/skills/octocode-code-engineer/src/analysis/dependencies.ts +0 -406
- package/skills/octocode-code-engineer/src/index.ts +0 -403
- package/skills/octocode-code-engineer/src/reporting/summary-md.test.ts +0 -421
- package/skills/octocode-code-engineer/src/reporting/summary-md.ts +0 -714
- package/skills/octocode-code-engineer/src/types/interfaces.ts +0 -682
- package/skills/octocode-research/src/types/toolTypes.ts +0 -33
- package/skills/octocode-research/src/utils/logEmoji.ts +0 -103
- /package/skills/{octocode-code-engineer → octocode-engineer}/.octocode/rfc/RFC-code-engineer-weakness-fixes.md +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/architecture.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ast-helpers.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ast-search.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/base.css +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/block-navigation.js +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/cache.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/cli.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/clover.xml +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-effects.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-input-sources.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-performance.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-prototype-pollution.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-security.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-test-profile.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/coverage-final.json +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/dependencies.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/dependency-summary.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/discovery.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/favicon.png +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/graph-analytics.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/index.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/index.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/metrics.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/pipeline.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/prettify.css +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/prettify.js +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/report-analysis.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/report-writer.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/security-detectors.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/semantic-detectors.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/semantic.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/sort-arrow-sprite.png +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/sorter.js +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/summary-md.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/test-quality-detectors.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/tree-sitter-analyzer.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ts-analyzer.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/types.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/utils.ts.html +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependencies.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependency-summary.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependency-summary.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/graph-analytics.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/graph-analytics.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/semantic.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/semantic.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/helpers.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/helpers.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/metrics.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/metrics.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-search.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-search.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/chains.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/effects.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/effects.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/input-sources.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/input-sources.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/performance.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/performance.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/prototype-pollution.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/prototype-pollution.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/test-profile.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/test-profile.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/is-direct-run.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/is-direct-run.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/utils.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/utils.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/cohesion.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/coupling.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/cycle.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/dead-code.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/import-style.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/index.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/security.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/security.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/semantic.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/shared.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/test-quality.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/test-quality.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cache.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cache.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/main.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/analysis.test.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/analysis.ts +0 -0
- /package/skills/{octocode-code-engineer → octocode-engineer}/vitest.config.ts +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
import { ALL_CATEGORIES, DEFAULT_OPTS, PILLAR_CATEGORIES } from '../types/index.js';
|
|
4
|
+
import { OptionsError, resolveExcludeToFeatures } from './create-options.js';
|
|
4
5
|
|
|
5
|
-
import type { AnalysisOptions } from '../types/index.js';
|
|
6
|
+
import type { AnalysisOptions, Thresholds } from '../types/index.js';
|
|
6
7
|
|
|
7
8
|
function parseNumeric(raw: string | undefined, fallback: number): number {
|
|
8
9
|
const n = parseInt(raw ?? '', 10);
|
|
@@ -14,6 +15,24 @@ function parseDecimal(raw: string | undefined, fallback: number): number {
|
|
|
14
15
|
return Number.isNaN(n) ? fallback : n;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
function setIntOpt(
|
|
19
|
+
target: Record<string, number>,
|
|
20
|
+
key: string,
|
|
21
|
+
raw: string,
|
|
22
|
+
defaults: Record<string, number>
|
|
23
|
+
): void {
|
|
24
|
+
target[key] = parseNumeric(raw, defaults[key]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function setFloatOpt(
|
|
28
|
+
target: Record<string, number>,
|
|
29
|
+
key: string,
|
|
30
|
+
raw: string,
|
|
31
|
+
defaults: Record<string, number>
|
|
32
|
+
): void {
|
|
33
|
+
target[key] = parseDecimal(raw, defaults[key]);
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
function resolveCategories(val: string, flagName: string): Set<string> {
|
|
18
37
|
const tokens = val
|
|
19
38
|
.split(',')
|
|
@@ -39,22 +58,35 @@ function parseScope(
|
|
|
39
58
|
val: string,
|
|
40
59
|
root: string
|
|
41
60
|
): { paths: string[]; symbols: Map<string, string[]> } {
|
|
61
|
+
const splitScopeToken = (
|
|
62
|
+
token: string
|
|
63
|
+
): { filePath: string; symbolName: string | null } => {
|
|
64
|
+
const colonIdx = token.lastIndexOf(':');
|
|
65
|
+
if (colonIdx <= 0 || colonIdx === token.length - 1) {
|
|
66
|
+
return { filePath: token, symbolName: null };
|
|
67
|
+
}
|
|
68
|
+
const symbolName = token.substring(colonIdx + 1);
|
|
69
|
+
if (symbolName.includes('/') || symbolName.includes('\\')) {
|
|
70
|
+
return { filePath: token, symbolName: null };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
filePath: token.substring(0, colonIdx),
|
|
74
|
+
symbolName,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
42
78
|
const paths: string[] = [];
|
|
43
79
|
const symbols = new Map<string, string[]>();
|
|
44
80
|
for (const token of val
|
|
45
81
|
.split(',')
|
|
46
82
|
.map(s => s.trim())
|
|
47
83
|
.filter(Boolean)) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const absFile = path.resolve(root, filePart);
|
|
53
|
-
paths.push(absFile);
|
|
84
|
+
const { filePath, symbolName } = splitScopeToken(token);
|
|
85
|
+
const absFile = path.resolve(root, filePath);
|
|
86
|
+
paths.push(absFile);
|
|
87
|
+
if (symbolName) {
|
|
54
88
|
if (!symbols.has(absFile)) symbols.set(absFile, []);
|
|
55
|
-
symbols.get(absFile)!.push(
|
|
56
|
-
} else {
|
|
57
|
-
paths.push(path.resolve(root, token));
|
|
89
|
+
symbols.get(absFile)!.push(symbolName);
|
|
58
90
|
}
|
|
59
91
|
}
|
|
60
92
|
return { paths, symbols };
|
|
@@ -103,15 +135,23 @@ const BOOL_FLAGS: Record<
|
|
|
103
135
|
o.includeTests = true;
|
|
104
136
|
o.semantic = true;
|
|
105
137
|
},
|
|
138
|
+
'--save-baseline': o => {
|
|
139
|
+
o.saveBaseline = true;
|
|
140
|
+
},
|
|
106
141
|
};
|
|
107
142
|
|
|
108
|
-
const
|
|
143
|
+
const CORE_INT_FLAGS: Record<string, keyof AnalysisOptions> = {
|
|
109
144
|
'--findings-limit': 'findingsLimit',
|
|
145
|
+
'--deep-link-topn': 'deepLinkTopN',
|
|
146
|
+
'--tree-depth': 'treeDepth',
|
|
147
|
+
'--max-recs-per-category': 'maxRecsPerCategory',
|
|
148
|
+
'--focus-depth': 'focusDepth',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const THRESHOLD_INT_FLAGS: Record<string, keyof Thresholds> = {
|
|
110
152
|
'--min-function-statements': 'minFunctionStatements',
|
|
111
153
|
'--min-flow-statements': 'minFlowStatements',
|
|
112
154
|
'--critical-complexity-threshold': 'criticalComplexityThreshold',
|
|
113
|
-
'--deep-link-topn': 'deepLinkTopN',
|
|
114
|
-
'--tree-depth': 'treeDepth',
|
|
115
155
|
'--coupling-threshold': 'couplingThreshold',
|
|
116
156
|
'--fan-in-threshold': 'fanInThreshold',
|
|
117
157
|
'--fan-out-threshold': 'fanOutThreshold',
|
|
@@ -126,14 +166,17 @@ const INT_FLAGS: Record<string, keyof AnalysisOptions> = {
|
|
|
126
166
|
'--maintainability-index-threshold': 'maintainabilityIndexThreshold',
|
|
127
167
|
'--any-threshold': 'anyThreshold',
|
|
128
168
|
'--flow-dup-threshold': 'flowDupThreshold',
|
|
129
|
-
'--max-recs-per-category': 'maxRecsPerCategory',
|
|
130
169
|
'--override-chain-threshold': 'overrideChainThreshold',
|
|
131
170
|
'--shotgun-threshold': 'shotgunThreshold',
|
|
132
171
|
'--secret-min-length': 'secretMinLength',
|
|
133
172
|
'--mock-threshold': 'mockThreshold',
|
|
173
|
+
'--deep-nesting-threshold': 'deepNestingThreshold',
|
|
174
|
+
'--multiple-return-threshold': 'multipleReturnThreshold',
|
|
175
|
+
'--magic-string-min-occurrences': 'magicStringMinOccurrences',
|
|
176
|
+
'--boolean-param-threshold': 'booleanParamThreshold',
|
|
134
177
|
};
|
|
135
178
|
|
|
136
|
-
const
|
|
179
|
+
const THRESHOLD_FLOAT_FLAGS: Record<string, keyof Thresholds> = {
|
|
137
180
|
'--secret-entropy-threshold': 'secretEntropyThreshold',
|
|
138
181
|
'--similarity-threshold': 'similarityThreshold',
|
|
139
182
|
'--sdp-min-delta': 'sdpMinDelta',
|
|
@@ -161,7 +204,20 @@ const SPECIAL_FLAGS: Record<string, FlagHandler> = {
|
|
|
161
204
|
return i + 1;
|
|
162
205
|
},
|
|
163
206
|
'--layer-order': (opts, argv, i) => {
|
|
164
|
-
opts.layerOrder = argv[i + 1].split(',').map(s => s.trim());
|
|
207
|
+
opts.thresholds.layerOrder = argv[i + 1].split(',').map(s => s.trim());
|
|
208
|
+
return i + 1;
|
|
209
|
+
},
|
|
210
|
+
'--reporter': (opts, argv, i) => {
|
|
211
|
+
const next = argv[i + 1];
|
|
212
|
+
if (!['default', 'compact', 'github-actions'].includes(next)) {
|
|
213
|
+
console.error(`Unsupported reporter: ${next}. Use default|compact|github-actions`);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
opts.reporter = next as AnalysisOptions['reporter'];
|
|
217
|
+
return i + 1;
|
|
218
|
+
},
|
|
219
|
+
'--config': (opts, argv, i) => {
|
|
220
|
+
opts.configFile = argv[i + 1];
|
|
165
221
|
return i + 1;
|
|
166
222
|
},
|
|
167
223
|
'--help': () => {
|
|
@@ -175,7 +231,7 @@ const SPECIAL_FLAGS: Record<string, FlagHandler> = {
|
|
|
175
231
|
};
|
|
176
232
|
|
|
177
233
|
export function parseArgs(argv: string[]): AnalysisOptions {
|
|
178
|
-
const opts: AnalysisOptions = { ...DEFAULT_OPTS };
|
|
234
|
+
const opts: AnalysisOptions = { ...DEFAULT_OPTS, thresholds: { ...DEFAULT_OPTS.thresholds } };
|
|
179
235
|
let excludeSet: Set<string> | null = null;
|
|
180
236
|
|
|
181
237
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -186,17 +242,33 @@ export function parseArgs(argv: string[]): AnalysisOptions {
|
|
|
186
242
|
continue;
|
|
187
243
|
}
|
|
188
244
|
|
|
189
|
-
if (
|
|
190
|
-
const key =
|
|
191
|
-
|
|
192
|
-
|
|
245
|
+
if (CORE_INT_FLAGS[arg]) {
|
|
246
|
+
const key = CORE_INT_FLAGS[arg];
|
|
247
|
+
setIntOpt(
|
|
248
|
+
opts as unknown as Record<string, number>,
|
|
249
|
+
key, argv[++i],
|
|
250
|
+
DEFAULT_OPTS as unknown as Record<string, number>
|
|
251
|
+
);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (THRESHOLD_INT_FLAGS[arg]) {
|
|
256
|
+
const key = THRESHOLD_INT_FLAGS[arg];
|
|
257
|
+
setIntOpt(
|
|
258
|
+
opts.thresholds as unknown as Record<string, number>,
|
|
259
|
+
key, argv[++i],
|
|
260
|
+
DEFAULT_OPTS.thresholds as unknown as Record<string, number>
|
|
261
|
+
);
|
|
193
262
|
continue;
|
|
194
263
|
}
|
|
195
264
|
|
|
196
|
-
if (
|
|
197
|
-
const key =
|
|
198
|
-
|
|
199
|
-
|
|
265
|
+
if (THRESHOLD_FLOAT_FLAGS[arg]) {
|
|
266
|
+
const key = THRESHOLD_FLOAT_FLAGS[arg];
|
|
267
|
+
setFloatOpt(
|
|
268
|
+
opts.thresholds as unknown as Record<string, number>,
|
|
269
|
+
key, argv[++i],
|
|
270
|
+
DEFAULT_OPTS.thresholds as unknown as Record<string, number>
|
|
271
|
+
);
|
|
200
272
|
continue;
|
|
201
273
|
}
|
|
202
274
|
|
|
@@ -211,7 +283,9 @@ export function parseArgs(argv: string[]): AnalysisOptions {
|
|
|
211
283
|
}
|
|
212
284
|
|
|
213
285
|
if (arg === '--scope' || arg.startsWith('--scope=')) {
|
|
214
|
-
const val = arg.
|
|
286
|
+
const val = arg.startsWith('--scope=')
|
|
287
|
+
? arg.slice('--scope='.length)
|
|
288
|
+
: argv[++i];
|
|
215
289
|
const { paths, symbols } = parseScope(val, opts.root);
|
|
216
290
|
opts.scope = paths;
|
|
217
291
|
if (symbols.size > 0) opts.scopeSymbols = symbols;
|
|
@@ -233,20 +307,58 @@ export function parseArgs(argv: string[]): AnalysisOptions {
|
|
|
233
307
|
excludeSet = resolveCategories(val, 'exclude');
|
|
234
308
|
continue;
|
|
235
309
|
}
|
|
310
|
+
|
|
311
|
+
if (arg === '--affected' || arg.startsWith('--affected=')) {
|
|
312
|
+
opts.affected = arg.startsWith('--affected=')
|
|
313
|
+
? arg.slice('--affected='.length)
|
|
314
|
+
: (argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : 'HEAD');
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (arg === '--ignore-known' || arg.startsWith('--ignore-known=')) {
|
|
319
|
+
opts.ignoreKnown = arg.startsWith('--ignore-known=')
|
|
320
|
+
? arg.slice('--ignore-known='.length)
|
|
321
|
+
: (argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : '.octocode/baseline.json');
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (arg === '--focus' || arg.startsWith('--focus=')) {
|
|
326
|
+
opts.focus = arg.startsWith('--focus=')
|
|
327
|
+
? arg.slice('--focus='.length)
|
|
328
|
+
: argv[++i];
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (arg === '--collapse' || arg.startsWith('--collapse=')) {
|
|
333
|
+
const val = arg.startsWith('--collapse=')
|
|
334
|
+
? arg.slice('--collapse='.length)
|
|
335
|
+
: argv[++i];
|
|
336
|
+
opts.collapse = parseNumeric(val, 2);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (arg === '--at-least' || arg.startsWith('--at-least=')) {
|
|
341
|
+
const val = arg.startsWith('--at-least=')
|
|
342
|
+
? arg.slice('--at-least='.length)
|
|
343
|
+
: argv[++i];
|
|
344
|
+
opts.atLeast = parseNumeric(val, 0);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (arg.startsWith('--')) {
|
|
349
|
+
console.warn(`Warning: unknown flag "${arg}" — ignored.`);
|
|
350
|
+
}
|
|
236
351
|
}
|
|
237
352
|
|
|
238
353
|
opts.packageRoot = path.join(opts.root, 'packages');
|
|
239
354
|
|
|
240
355
|
if (opts.features !== null && excludeSet !== null) {
|
|
241
|
-
|
|
356
|
+
throw new OptionsError(
|
|
242
357
|
'--features and --exclude are mutually exclusive. Use one or the other.'
|
|
243
358
|
);
|
|
244
|
-
process.exit(1);
|
|
245
359
|
}
|
|
246
360
|
if (excludeSet !== null) {
|
|
247
|
-
opts.features =
|
|
248
|
-
[...ALL_CATEGORIES].filter(c => !excludeSet!.has(c))
|
|
249
|
-
);
|
|
361
|
+
opts.features = resolveExcludeToFeatures(excludeSet);
|
|
250
362
|
}
|
|
251
363
|
|
|
252
364
|
if (opts.features !== null) {
|
|
@@ -259,10 +371,9 @@ export function parseArgs(argv: string[]): AnalysisOptions {
|
|
|
259
371
|
return opts;
|
|
260
372
|
}
|
|
261
373
|
|
|
262
|
-
export
|
|
263
|
-
console.log(`
|
|
374
|
+
export const HELP_TEXT = `
|
|
264
375
|
Usage:
|
|
265
|
-
node scripts/
|
|
376
|
+
node scripts/run.js [options]
|
|
266
377
|
|
|
267
378
|
Options:
|
|
268
379
|
--root <path> Analyze a different repo root (default: cwd)
|
|
@@ -320,7 +431,7 @@ Options:
|
|
|
320
431
|
Examples: --exclude=architecture
|
|
321
432
|
--exclude=dead-export,unsafe-any
|
|
322
433
|
--semantic Enable semantic analysis phase (TypeChecker + LanguageService).
|
|
323
|
-
Adds
|
|
434
|
+
Adds 12 categories: over-abstraction, concrete-dependency,
|
|
324
435
|
circular-type-dependency, unused-parameter,
|
|
325
436
|
deep-override-chain, interface-compliance, unused-import,
|
|
326
437
|
orphan-implementation, shotgun-surgery, move-to-caller,
|
|
@@ -332,6 +443,11 @@ Options:
|
|
|
332
443
|
--secret-entropy-threshold N Shannon entropy threshold for secret detection (default 4.5)
|
|
333
444
|
--secret-min-length N Min string length for entropy-based secret detection (default 20)
|
|
334
445
|
--similarity-threshold N Jaccard similarity threshold for near-clone detection (default 0.85)
|
|
446
|
+
--deep-nesting-threshold N Max branch/loop nesting depth before flagging (default 5)
|
|
447
|
+
--multiple-return-threshold N Max return/throw paths per function before flagging (default 6)
|
|
448
|
+
--magic-string-min-occurrences N
|
|
449
|
+
Min repeated string comparisons to flag as magic string (default 3)
|
|
450
|
+
--boolean-param-threshold N Min boolean params per function to flag as cluster (default 3)
|
|
335
451
|
--mock-threshold N Max mock/spy calls per test file (default 10)
|
|
336
452
|
--no-diversify Disable category-aware diversification when truncating findings.
|
|
337
453
|
By default, --findings-limit interleaves categories so the
|
|
@@ -339,6 +455,34 @@ Options:
|
|
|
339
455
|
--no-cache Disable incremental cache; re-parse all files
|
|
340
456
|
--clear-cache Delete the analysis cache and exit (no scan)
|
|
341
457
|
--all Enable all features: --include-tests --semantic
|
|
458
|
+
|
|
459
|
+
--affected [revision] Scope to files changed since git revision (default: HEAD) plus
|
|
460
|
+
their transitive dependents. Like dep-cruiser's --affected flag.
|
|
461
|
+
Examples: --affected
|
|
462
|
+
--affected HEAD~3
|
|
463
|
+
--affected main
|
|
464
|
+
--save-baseline Save current findings to .octocode/baseline.json for future
|
|
465
|
+
comparison. Use with --ignore-known for progressive adoption.
|
|
466
|
+
--ignore-known [file] Suppress findings matching a baseline file (default:
|
|
467
|
+
.octocode/baseline.json). Findings are matched by (category, file).
|
|
468
|
+
--reporter <format> Output format: default|compact|github-actions (default: default)
|
|
469
|
+
compact: one-line per finding for terminal/CI logs
|
|
470
|
+
github-actions: ::warning annotations for GitHub Actions
|
|
471
|
+
--focus <module> Show only this module and its neighbors in the dependency graph.
|
|
472
|
+
Requires --graph. Use with --focus-depth to control neighbor hops.
|
|
473
|
+
Examples: --focus src/session.ts
|
|
474
|
+
--focus=src/session.ts
|
|
475
|
+
--focus packages/octocode-mcp/src/tools
|
|
476
|
+
--focus-depth N Neighbor depth for --focus (default 1). 2 = friends-of-friends.
|
|
477
|
+
--collapse N Collapse graph nodes to folder depth N. Reduces large graphs to
|
|
478
|
+
high-level architecture view. Example: --collapse 2
|
|
479
|
+
--at-least N Fail (exit 1) if health score drops below N (0-100). Use in CI
|
|
480
|
+
to enforce a quality floor. Example: --at-least 60
|
|
481
|
+
--config <file> Path to config file. Also auto-discovers .octocode-scan.json,
|
|
482
|
+
.octocode-scan.jsonc, or package.json#octocode in the project root.
|
|
342
483
|
--help Show this message
|
|
343
|
-
|
|
484
|
+
`;
|
|
485
|
+
|
|
486
|
+
export function printHelp(): void {
|
|
487
|
+
console.log(HELP_TEXT);
|
|
344
488
|
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { loadConfigFile, mergeConfigIntoDefaults } from './config-loader.js';
|
|
8
|
+
import { DEFAULT_OPTS } from '../types/index.js';
|
|
9
|
+
|
|
10
|
+
describe('config-loader', () => {
|
|
11
|
+
const tmpDirs: string[] = [];
|
|
12
|
+
|
|
13
|
+
function makeTmpDir(): string {
|
|
14
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), 'config-test-'));
|
|
15
|
+
tmpDirs.push(d);
|
|
16
|
+
return d;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
for (const d of tmpDirs) {
|
|
21
|
+
fs.rmSync(d, { recursive: true, force: true });
|
|
22
|
+
}
|
|
23
|
+
tmpDirs.length = 0;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('loadConfigFile', () => {
|
|
27
|
+
it('loads explicit config file', () => {
|
|
28
|
+
const root = makeTmpDir();
|
|
29
|
+
const cfgPath = path.join(root, 'my-config.json');
|
|
30
|
+
fs.writeFileSync(cfgPath, JSON.stringify({ graph: true, semantic: true }));
|
|
31
|
+
|
|
32
|
+
const config = loadConfigFile(root, cfgPath);
|
|
33
|
+
expect(config).toBeDefined();
|
|
34
|
+
expect(config!.graph).toBe(true);
|
|
35
|
+
expect(config!.semantic).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('auto-discovers .octocode-scan.json', () => {
|
|
39
|
+
const root = makeTmpDir();
|
|
40
|
+
fs.writeFileSync(
|
|
41
|
+
path.join(root, '.octocode-scan.json'),
|
|
42
|
+
JSON.stringify({ flow: true })
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const config = loadConfigFile(root, null);
|
|
46
|
+
expect(config).toBeDefined();
|
|
47
|
+
expect(config!.flow).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('auto-discovers .octocode-scan.jsonc', () => {
|
|
51
|
+
const root = makeTmpDir();
|
|
52
|
+
fs.writeFileSync(
|
|
53
|
+
path.join(root, '.octocode-scan.jsonc'),
|
|
54
|
+
'// comment\n{ "graph": true }\n'
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const config = loadConfigFile(root, null);
|
|
58
|
+
expect(config).toBeDefined();
|
|
59
|
+
expect(config!.graph).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('reads from package.json#octocode', () => {
|
|
63
|
+
const root = makeTmpDir();
|
|
64
|
+
fs.writeFileSync(
|
|
65
|
+
path.join(root, 'package.json'),
|
|
66
|
+
JSON.stringify({ name: 'test', octocode: { includeTests: true } })
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const config = loadConfigFile(root, null);
|
|
70
|
+
expect(config).toBeDefined();
|
|
71
|
+
expect(config!.includeTests).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('returns null when no config found', () => {
|
|
75
|
+
const root = makeTmpDir();
|
|
76
|
+
expect(loadConfigFile(root, null)).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('converts kebab-case keys to camelCase', () => {
|
|
80
|
+
const root = makeTmpDir();
|
|
81
|
+
fs.writeFileSync(
|
|
82
|
+
path.join(root, '.octocode-scan.json'),
|
|
83
|
+
JSON.stringify({ 'include-tests': true, 'graph-advanced': true })
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const config = loadConfigFile(root, null);
|
|
87
|
+
expect(config!.includeTests).toBe(true);
|
|
88
|
+
expect(config!.graphAdvanced).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('prefers .octocode-scan.json over package.json', () => {
|
|
92
|
+
const root = makeTmpDir();
|
|
93
|
+
fs.writeFileSync(
|
|
94
|
+
path.join(root, '.octocode-scan.json'),
|
|
95
|
+
JSON.stringify({ graph: true })
|
|
96
|
+
);
|
|
97
|
+
fs.writeFileSync(
|
|
98
|
+
path.join(root, 'package.json'),
|
|
99
|
+
JSON.stringify({ name: 'x', octocode: { graph: false, flow: true } })
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const config = loadConfigFile(root, null);
|
|
103
|
+
expect(config!.graph).toBe(true);
|
|
104
|
+
expect(config!.flow).toBeUndefined();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('converts features string to Set', () => {
|
|
108
|
+
const root = makeTmpDir();
|
|
109
|
+
fs.writeFileSync(
|
|
110
|
+
path.join(root, '.octocode-scan.json'),
|
|
111
|
+
JSON.stringify({ features: 'architecture, dead-code' })
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const config = loadConfigFile(root, null);
|
|
115
|
+
expect(config!.features).toBeInstanceOf(Set);
|
|
116
|
+
expect((config!.features as Set<string>).has('architecture')).toBe(true);
|
|
117
|
+
expect((config!.features as Set<string>).has('dead-code')).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('converts scope string to array', () => {
|
|
121
|
+
const root = makeTmpDir();
|
|
122
|
+
fs.writeFileSync(
|
|
123
|
+
path.join(root, '.octocode-scan.json'),
|
|
124
|
+
JSON.stringify({ scope: 'packages/foo,packages/bar' })
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const config = loadConfigFile(root, null);
|
|
128
|
+
expect(config!.scope).toEqual(['packages/foo', 'packages/bar']);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('converts ignoreDirs array to Set', () => {
|
|
132
|
+
const root = makeTmpDir();
|
|
133
|
+
fs.writeFileSync(
|
|
134
|
+
path.join(root, '.octocode-scan.json'),
|
|
135
|
+
JSON.stringify({ 'ignore-dirs': ['vendor', 'generated'] })
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const config = loadConfigFile(root, null);
|
|
139
|
+
const dirs = config!.ignoreDirs as Set<string>;
|
|
140
|
+
expect(dirs).toBeInstanceOf(Set);
|
|
141
|
+
expect(dirs.has('vendor')).toBe(true);
|
|
142
|
+
expect(dirs.has('generated')).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('returns null for invalid JSON', () => {
|
|
146
|
+
const root = makeTmpDir();
|
|
147
|
+
fs.writeFileSync(
|
|
148
|
+
path.join(root, '.octocode-scan.json'),
|
|
149
|
+
'not { valid json !!!'
|
|
150
|
+
);
|
|
151
|
+
expect(loadConfigFile(root, null)).toBeNull();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('resolves relative explicit path against root', () => {
|
|
155
|
+
const root = makeTmpDir();
|
|
156
|
+
const cfgPath = path.join(root, 'configs', 'scan.json');
|
|
157
|
+
fs.mkdirSync(path.dirname(cfgPath), { recursive: true });
|
|
158
|
+
fs.writeFileSync(cfgPath, JSON.stringify({ semantic: true }));
|
|
159
|
+
|
|
160
|
+
const config = loadConfigFile(root, 'configs/scan.json');
|
|
161
|
+
expect(config).toBeDefined();
|
|
162
|
+
expect(config!.semantic).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('strips single-line comments in JSONC', () => {
|
|
166
|
+
const root = makeTmpDir();
|
|
167
|
+
fs.writeFileSync(
|
|
168
|
+
path.join(root, '.octocode-scan.json'),
|
|
169
|
+
`{
|
|
170
|
+
// Enable graph
|
|
171
|
+
"graph": true,
|
|
172
|
+
"flow": false // Not yet
|
|
173
|
+
}`
|
|
174
|
+
);
|
|
175
|
+
const config = loadConfigFile(root, null);
|
|
176
|
+
expect(config!.graph).toBe(true);
|
|
177
|
+
expect(config!.flow).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('strips block comments in JSONC', () => {
|
|
181
|
+
const root = makeTmpDir();
|
|
182
|
+
fs.writeFileSync(
|
|
183
|
+
path.join(root, '.octocode-scan.json'),
|
|
184
|
+
`{
|
|
185
|
+
/* This enables the semantic phase */
|
|
186
|
+
"semantic": true
|
|
187
|
+
}`
|
|
188
|
+
);
|
|
189
|
+
const config = loadConfigFile(root, null);
|
|
190
|
+
expect(config!.semantic).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('passes through threshold objects', () => {
|
|
194
|
+
const root = makeTmpDir();
|
|
195
|
+
fs.writeFileSync(
|
|
196
|
+
path.join(root, '.octocode-scan.json'),
|
|
197
|
+
JSON.stringify({ thresholds: { minFunctionStatements: 10 } })
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const config = loadConfigFile(root, null);
|
|
201
|
+
const t = config!.thresholds as Record<string, number>;
|
|
202
|
+
expect(t.minFunctionStatements).toBe(10);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('ignores package.json without octocode key', () => {
|
|
206
|
+
const root = makeTmpDir();
|
|
207
|
+
fs.writeFileSync(
|
|
208
|
+
path.join(root, 'package.json'),
|
|
209
|
+
JSON.stringify({ name: 'test', version: '1.0.0' })
|
|
210
|
+
);
|
|
211
|
+
expect(loadConfigFile(root, null)).toBeNull();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('mergeConfigIntoDefaults', () => {
|
|
216
|
+
it('config values override defaults', () => {
|
|
217
|
+
const config = { graph: true, semantic: true };
|
|
218
|
+
const cliArgs = { ...DEFAULT_OPTS };
|
|
219
|
+
|
|
220
|
+
const result = mergeConfigIntoDefaults(DEFAULT_OPTS, config, cliArgs);
|
|
221
|
+
expect(result.graph).toBe(true);
|
|
222
|
+
expect(result.semantic).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('CLI args override config when they differ from defaults', () => {
|
|
226
|
+
const config = { graph: true, semantic: true };
|
|
227
|
+
const cliArgs = { ...DEFAULT_OPTS, findingsLimit: 50 };
|
|
228
|
+
|
|
229
|
+
const result = mergeConfigIntoDefaults(DEFAULT_OPTS, config, cliArgs);
|
|
230
|
+
expect(result.graph).toBe(true);
|
|
231
|
+
expect(result.semantic).toBe(true);
|
|
232
|
+
expect(result.findingsLimit).toBe(50);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('merges threshold overrides', () => {
|
|
236
|
+
const config = { thresholds: { minFunctionStatements: 10 } };
|
|
237
|
+
const cliArgs = { ...DEFAULT_OPTS };
|
|
238
|
+
|
|
239
|
+
const result = mergeConfigIntoDefaults(DEFAULT_OPTS, config, cliArgs);
|
|
240
|
+
expect(result.thresholds.minFunctionStatements).toBe(10);
|
|
241
|
+
expect(result.thresholds.minFlowStatements).toBe(
|
|
242
|
+
DEFAULT_OPTS.thresholds.minFlowStatements
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('preserves defaults when config and CLI are empty', () => {
|
|
247
|
+
const result = mergeConfigIntoDefaults(
|
|
248
|
+
DEFAULT_OPTS,
|
|
249
|
+
{},
|
|
250
|
+
{ ...DEFAULT_OPTS }
|
|
251
|
+
);
|
|
252
|
+
expect(result).toEqual(DEFAULT_OPTS);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('config does not override root or packageRoot', () => {
|
|
256
|
+
const config = { json: true };
|
|
257
|
+
const cliArgs = { ...DEFAULT_OPTS };
|
|
258
|
+
|
|
259
|
+
const result = mergeConfigIntoDefaults(DEFAULT_OPTS, config, cliArgs);
|
|
260
|
+
expect(result.root).toBe(DEFAULT_OPTS.root);
|
|
261
|
+
expect(result.json).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|