agentsys 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agnix.toml +49 -0
- package/.claude-plugin/marketplace.json +110 -0
- package/.claude-plugin/plugin.json +20 -0
- package/AGENTS.md +260 -0
- package/CHANGELOG.md +190 -0
- package/LICENSE +21 -0
- package/README.md +916 -0
- package/SECURITY.md +45 -0
- package/adapters/README.md +258 -0
- package/adapters/codex/README.md +273 -0
- package/adapters/codex/install.sh +260 -0
- package/adapters/codex/skills/agnix/SKILL.md +138 -0
- package/adapters/codex/skills/audit-project/SKILL.md +334 -0
- package/adapters/codex/skills/audit-project-agents/SKILL.md +459 -0
- package/adapters/codex/skills/audit-project-github/SKILL.md +146 -0
- package/adapters/codex/skills/consult/SKILL.md +245 -0
- package/adapters/codex/skills/delivery-approval/SKILL.md +339 -0
- package/adapters/codex/skills/deslop/SKILL.md +167 -0
- package/adapters/codex/skills/drift-detect/SKILL.md +268 -0
- package/adapters/codex/skills/enhance/SKILL.md +177 -0
- package/adapters/codex/skills/learn/SKILL.md +188 -0
- package/adapters/codex/skills/next-task/SKILL.md +546 -0
- package/adapters/codex/skills/perf/SKILL.md +469 -0
- package/adapters/codex/skills/repo-map/SKILL.md +132 -0
- package/adapters/codex/skills/ship/SKILL.md +491 -0
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +473 -0
- package/adapters/codex/skills/ship-deployment/SKILL.md +336 -0
- package/adapters/codex/skills/ship-error-handling/SKILL.md +260 -0
- package/adapters/codex/skills/sync-docs/SKILL.md +186 -0
- package/adapters/opencode/README.md +302 -0
- package/adapters/opencode/agents/agent-enhancer.md +65 -0
- package/adapters/opencode/agents/agnix-agent.md +56 -0
- package/adapters/opencode/agents/ci-fixer.md +104 -0
- package/adapters/opencode/agents/ci-monitor.md +127 -0
- package/adapters/opencode/agents/claudemd-enhancer.md +66 -0
- package/adapters/opencode/agents/consult-agent.md +124 -0
- package/adapters/opencode/agents/cross-file-enhancer.md +54 -0
- package/adapters/opencode/agents/delivery-validator.md +115 -0
- package/adapters/opencode/agents/deslop-agent.md +88 -0
- package/adapters/opencode/agents/docs-enhancer.md +65 -0
- package/adapters/opencode/agents/exploration-agent.md +143 -0
- package/adapters/opencode/agents/hooks-enhancer.md +66 -0
- package/adapters/opencode/agents/implementation-agent.md +206 -0
- package/adapters/opencode/agents/learn-agent.md +279 -0
- package/adapters/opencode/agents/map-validator.md +65 -0
- package/adapters/opencode/agents/perf-analyzer.md +40 -0
- package/adapters/opencode/agents/perf-code-paths.md +12 -0
- package/adapters/opencode/agents/perf-investigation-logger.md +44 -0
- package/adapters/opencode/agents/perf-orchestrator.md +147 -0
- package/adapters/opencode/agents/perf-theory-gatherer.md +18 -0
- package/adapters/opencode/agents/perf-theory-tester.md +43 -0
- package/adapters/opencode/agents/plan-synthesizer.md +229 -0
- package/adapters/opencode/agents/planning-agent.md +235 -0
- package/adapters/opencode/agents/plugin-enhancer.md +64 -0
- package/adapters/opencode/agents/prompt-enhancer.md +58 -0
- package/adapters/opencode/agents/simple-fixer.md +107 -0
- package/adapters/opencode/agents/skills-enhancer.md +66 -0
- package/adapters/opencode/agents/sync-docs-agent.md +153 -0
- package/adapters/opencode/agents/task-discoverer.md +80 -0
- package/adapters/opencode/agents/test-coverage-checker.md +144 -0
- package/adapters/opencode/agents/worktree-manager.md +209 -0
- package/adapters/opencode/commands/agnix.md +106 -0
- package/adapters/opencode/commands/audit-project-agents.md +125 -0
- package/adapters/opencode/commands/audit-project-github.md +145 -0
- package/adapters/opencode/commands/audit-project.md +268 -0
- package/adapters/opencode/commands/consult.md +252 -0
- package/adapters/opencode/commands/delivery-approval.md +212 -0
- package/adapters/opencode/commands/deslop.md +132 -0
- package/adapters/opencode/commands/drift-detect.md +173 -0
- package/adapters/opencode/commands/enhance.md +183 -0
- package/adapters/opencode/commands/learn.md +116 -0
- package/adapters/opencode/commands/next-task.md +393 -0
- package/adapters/opencode/commands/perf.md +49 -0
- package/adapters/opencode/commands/repo-map.md +69 -0
- package/adapters/opencode/commands/ship-ci-review-loop.md +334 -0
- package/adapters/opencode/commands/ship-deployment.md +336 -0
- package/adapters/opencode/commands/ship-error-handling.md +248 -0
- package/adapters/opencode/commands/ship.md +371 -0
- package/adapters/opencode/commands/sync-docs.md +108 -0
- package/adapters/opencode/install.sh +322 -0
- package/adapters/opencode/skills/agnix/SKILL.md +139 -0
- package/adapters/opencode/skills/consult/SKILL.md +292 -0
- package/adapters/opencode/skills/deslop/SKILL.md +169 -0
- package/adapters/opencode/skills/discover-tasks/SKILL.md +102 -0
- package/adapters/opencode/skills/drift-analysis/SKILL.md +279 -0
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +279 -0
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +390 -0
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +112 -0
- package/adapters/opencode/skills/enhance-docs/SKILL.md +288 -0
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +557 -0
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +114 -0
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +314 -0
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +341 -0
- package/adapters/opencode/skills/enhance-skills/SKILL.md +443 -0
- package/adapters/opencode/skills/learn/SKILL.md +352 -0
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +95 -0
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +38 -0
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +31 -0
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +49 -0
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +33 -0
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +42 -0
- package/adapters/opencode/skills/perf-profiler/SKILL.md +39 -0
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +36 -0
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +37 -0
- package/adapters/opencode/skills/repo-mapping/SKILL.md +86 -0
- package/adapters/opencode/skills/sync-docs/SKILL.md +246 -0
- package/adapters/opencode/skills/validate-delivery/SKILL.md +112 -0
- package/adapters/opencode-plugin/index.ts +346 -0
- package/adapters/opencode-plugin/package.json +21 -0
- package/agent-knowledge/AGENTS.md +62 -0
- package/agent-knowledge/ai-cli-advanced-integration-patterns.md +670 -0
- package/agent-knowledge/ai-cli-non-interactive-programmatic-usage.md +1394 -0
- package/agent-knowledge/resources/ai-cli-non-interactive-programmatic-usage-sources.json +500 -0
- package/bin/cli.js +719 -0
- package/bin/dev-cli.js +587 -0
- package/lib/adapter-transforms.js +278 -0
- package/lib/collectors/codebase.js +392 -0
- package/lib/collectors/docs-patterns.js +713 -0
- package/lib/collectors/documentation.js +219 -0
- package/lib/collectors/github.js +266 -0
- package/lib/collectors/index.js +126 -0
- package/lib/config/index.js +14 -0
- package/lib/cross-platform/index.js +539 -0
- package/lib/discovery/index.js +352 -0
- package/lib/drift-detect/collectors.js +37 -0
- package/lib/enhance/agent-analyzer.js +421 -0
- package/lib/enhance/agent-patterns.js +571 -0
- package/lib/enhance/auto-suppression.js +622 -0
- package/lib/enhance/benchmark.js +417 -0
- package/lib/enhance/cross-file-analyzer.js +930 -0
- package/lib/enhance/cross-file-patterns.js +370 -0
- package/lib/enhance/docs-analyzer.js +325 -0
- package/lib/enhance/docs-patterns.js +671 -0
- package/lib/enhance/fixer.js +721 -0
- package/lib/enhance/hook-analyzer.js +135 -0
- package/lib/enhance/hook-patterns.js +40 -0
- package/lib/enhance/index.js +127 -0
- package/lib/enhance/plugin-analyzer.js +402 -0
- package/lib/enhance/plugin-patterns.js +326 -0
- package/lib/enhance/projectmemory-analyzer.js +551 -0
- package/lib/enhance/projectmemory-patterns.js +617 -0
- package/lib/enhance/prompt-analyzer.js +457 -0
- package/lib/enhance/prompt-patterns.js +1484 -0
- package/lib/enhance/reporter.js +1348 -0
- package/lib/enhance/security-patterns.js +284 -0
- package/lib/enhance/skill-analyzer.js +182 -0
- package/lib/enhance/skill-patterns.js +147 -0
- package/lib/enhance/suppression.js +352 -0
- package/lib/enhance/tool-patterns.js +373 -0
- package/lib/index.js +270 -0
- package/lib/package.json +25 -0
- package/lib/patterns/cli-enhancers.js +611 -0
- package/lib/patterns/pipeline.js +948 -0
- package/lib/patterns/review-patterns.js +558 -0
- package/lib/patterns/slop-analyzers.js +2305 -0
- package/lib/patterns/slop-patterns.js +1187 -0
- package/lib/perf/analyzer/index.js +22 -0
- package/lib/perf/argument-parser.js +105 -0
- package/lib/perf/baseline-comparator.js +50 -0
- package/lib/perf/baseline-store.js +127 -0
- package/lib/perf/benchmark-runner.js +399 -0
- package/lib/perf/breaking-point-finder.js +52 -0
- package/lib/perf/breaking-point-runner.js +60 -0
- package/lib/perf/checkpoint.js +123 -0
- package/lib/perf/code-paths.js +86 -0
- package/lib/perf/consolidation.js +37 -0
- package/lib/perf/constraint-runner.js +71 -0
- package/lib/perf/experiment-runner.js +32 -0
- package/lib/perf/index.js +41 -0
- package/lib/perf/investigation-state.js +875 -0
- package/lib/perf/optimization-runner.js +79 -0
- package/lib/perf/profilers/go.js +22 -0
- package/lib/perf/profilers/index.js +46 -0
- package/lib/perf/profilers/java.js +23 -0
- package/lib/perf/profilers/node.js +27 -0
- package/lib/perf/profilers/python.js +23 -0
- package/lib/perf/profilers/rust.js +23 -0
- package/lib/perf/profiling-runner.js +56 -0
- package/lib/perf/schemas.js +140 -0
- package/lib/platform/detect-platform.js +413 -0
- package/lib/platform/detection-configs.js +93 -0
- package/lib/platform/state-dir.js +132 -0
- package/lib/platform/verify-tools.js +182 -0
- package/lib/repo-map/cache.js +152 -0
- package/lib/repo-map/index.js +222 -0
- package/lib/repo-map/installer.js +212 -0
- package/lib/repo-map/queries/go.js +27 -0
- package/lib/repo-map/queries/index.js +100 -0
- package/lib/repo-map/queries/java.js +38 -0
- package/lib/repo-map/queries/javascript.js +55 -0
- package/lib/repo-map/queries/python.js +24 -0
- package/lib/repo-map/queries/rust.js +73 -0
- package/lib/repo-map/queries/typescript.js +38 -0
- package/lib/repo-map/runner.js +1165 -0
- package/lib/repo-map/updater.js +474 -0
- package/lib/repo-map/usage-analyzer.js +407 -0
- package/lib/schemas/plugin-manifest.schema.json +57 -0
- package/lib/schemas/validator.js +247 -0
- package/lib/sources/custom-handler.js +199 -0
- package/lib/sources/policy-questions.js +246 -0
- package/lib/sources/source-cache.js +165 -0
- package/lib/state/workflow-state.js +575 -0
- package/lib/types/agent-frontmatter.d.ts +134 -0
- package/lib/types/command-frontmatter.d.ts +107 -0
- package/lib/types/hook-frontmatter.d.ts +115 -0
- package/lib/types/index.d.ts +84 -0
- package/lib/types/plugin-manifest.d.ts +102 -0
- package/lib/types/skill-frontmatter.d.ts +89 -0
- package/lib/utils/atomic-write.js +94 -0
- package/lib/utils/cache-manager.js +159 -0
- package/lib/utils/context-optimizer.js +300 -0
- package/lib/utils/deprecation.js +37 -0
- package/lib/utils/shell-escape.js +88 -0
- package/meta/skills/maintain-cross-platform/SKILL.md +1022 -0
- package/package.json +92 -0
- package/plugins/agnix/.claude-plugin/plugin.json +22 -0
- package/plugins/agnix/agents/agnix-agent.md +56 -0
- package/plugins/agnix/commands/agnix.md +139 -0
- package/plugins/agnix/skills/agnix/SKILL.md +138 -0
- package/plugins/audit-project/.claude-plugin/plugin.json +20 -0
- package/plugins/audit-project/commands/audit-project-agents.md +458 -0
- package/plugins/audit-project/commands/audit-project-github.md +144 -0
- package/plugins/audit-project/commands/audit-project.md +336 -0
- package/plugins/audit-project/lib/adapter-transforms.js +278 -0
- package/plugins/audit-project/lib/collectors/codebase.js +392 -0
- package/plugins/audit-project/lib/collectors/docs-patterns.js +713 -0
- package/plugins/audit-project/lib/collectors/documentation.js +219 -0
- package/plugins/audit-project/lib/collectors/github.js +266 -0
- package/plugins/audit-project/lib/collectors/index.js +126 -0
- package/plugins/audit-project/lib/config/index.js +14 -0
- package/plugins/audit-project/lib/cross-platform/index.js +539 -0
- package/plugins/audit-project/lib/discovery/index.js +352 -0
- package/plugins/audit-project/lib/drift-detect/collectors.js +37 -0
- package/plugins/audit-project/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/audit-project/lib/enhance/agent-patterns.js +571 -0
- package/plugins/audit-project/lib/enhance/auto-suppression.js +622 -0
- package/plugins/audit-project/lib/enhance/benchmark.js +417 -0
- package/plugins/audit-project/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/audit-project/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/audit-project/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/audit-project/lib/enhance/docs-patterns.js +671 -0
- package/plugins/audit-project/lib/enhance/fixer.js +721 -0
- package/plugins/audit-project/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/audit-project/lib/enhance/hook-patterns.js +40 -0
- package/plugins/audit-project/lib/enhance/index.js +127 -0
- package/plugins/audit-project/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/audit-project/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/audit-project/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/audit-project/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/audit-project/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/audit-project/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/audit-project/lib/enhance/reporter.js +1348 -0
- package/plugins/audit-project/lib/enhance/security-patterns.js +284 -0
- package/plugins/audit-project/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/audit-project/lib/enhance/skill-patterns.js +147 -0
- package/plugins/audit-project/lib/enhance/suppression.js +352 -0
- package/plugins/audit-project/lib/enhance/tool-patterns.js +373 -0
- package/plugins/audit-project/lib/index.js +270 -0
- package/plugins/audit-project/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/audit-project/lib/patterns/pipeline.js +948 -0
- package/plugins/audit-project/lib/patterns/review-patterns.js +558 -0
- package/plugins/audit-project/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/audit-project/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/audit-project/lib/perf/analyzer/index.js +22 -0
- package/plugins/audit-project/lib/perf/argument-parser.js +105 -0
- package/plugins/audit-project/lib/perf/baseline-comparator.js +50 -0
- package/plugins/audit-project/lib/perf/baseline-store.js +127 -0
- package/plugins/audit-project/lib/perf/benchmark-runner.js +399 -0
- package/plugins/audit-project/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/audit-project/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/audit-project/lib/perf/checkpoint.js +123 -0
- package/plugins/audit-project/lib/perf/code-paths.js +86 -0
- package/plugins/audit-project/lib/perf/consolidation.js +37 -0
- package/plugins/audit-project/lib/perf/constraint-runner.js +71 -0
- package/plugins/audit-project/lib/perf/experiment-runner.js +32 -0
- package/plugins/audit-project/lib/perf/index.js +41 -0
- package/plugins/audit-project/lib/perf/investigation-state.js +875 -0
- package/plugins/audit-project/lib/perf/optimization-runner.js +79 -0
- package/plugins/audit-project/lib/perf/profilers/go.js +22 -0
- package/plugins/audit-project/lib/perf/profilers/index.js +46 -0
- package/plugins/audit-project/lib/perf/profilers/java.js +23 -0
- package/plugins/audit-project/lib/perf/profilers/node.js +27 -0
- package/plugins/audit-project/lib/perf/profilers/python.js +23 -0
- package/plugins/audit-project/lib/perf/profilers/rust.js +23 -0
- package/plugins/audit-project/lib/perf/profiling-runner.js +56 -0
- package/plugins/audit-project/lib/perf/schemas.js +140 -0
- package/plugins/audit-project/lib/platform/detect-platform.js +413 -0
- package/plugins/audit-project/lib/platform/detection-configs.js +93 -0
- package/plugins/audit-project/lib/platform/state-dir.js +132 -0
- package/plugins/audit-project/lib/platform/verify-tools.js +182 -0
- package/plugins/audit-project/lib/repo-map/cache.js +152 -0
- package/plugins/audit-project/lib/repo-map/index.js +222 -0
- package/plugins/audit-project/lib/repo-map/installer.js +212 -0
- package/plugins/audit-project/lib/repo-map/queries/go.js +27 -0
- package/plugins/audit-project/lib/repo-map/queries/index.js +100 -0
- package/plugins/audit-project/lib/repo-map/queries/java.js +38 -0
- package/plugins/audit-project/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/audit-project/lib/repo-map/queries/python.js +24 -0
- package/plugins/audit-project/lib/repo-map/queries/rust.js +73 -0
- package/plugins/audit-project/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/audit-project/lib/repo-map/runner.js +1165 -0
- package/plugins/audit-project/lib/repo-map/updater.js +474 -0
- package/plugins/audit-project/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/audit-project/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/audit-project/lib/schemas/validator.js +247 -0
- package/plugins/audit-project/lib/sources/custom-handler.js +199 -0
- package/plugins/audit-project/lib/sources/policy-questions.js +246 -0
- package/plugins/audit-project/lib/sources/source-cache.js +165 -0
- package/plugins/audit-project/lib/state/workflow-state.js +575 -0
- package/plugins/audit-project/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/audit-project/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/audit-project/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/audit-project/lib/types/index.d.ts +84 -0
- package/plugins/audit-project/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/audit-project/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/audit-project/lib/utils/atomic-write.js +94 -0
- package/plugins/audit-project/lib/utils/cache-manager.js +159 -0
- package/plugins/audit-project/lib/utils/context-optimizer.js +300 -0
- package/plugins/audit-project/lib/utils/deprecation.js +37 -0
- package/plugins/audit-project/lib/utils/shell-escape.js +88 -0
- package/plugins/consult/.claude-plugin/plugin.json +24 -0
- package/plugins/consult/agents/consult-agent.md +129 -0
- package/plugins/consult/commands/consult.md +248 -0
- package/plugins/consult/skills/consult/SKILL.md +285 -0
- package/plugins/deslop/.claude-plugin/plugin.json +20 -0
- package/plugins/deslop/agents/deslop-agent.md +88 -0
- package/plugins/deslop/commands/deslop.md +168 -0
- package/plugins/deslop/lib/adapter-transforms.js +278 -0
- package/plugins/deslop/lib/collectors/codebase.js +392 -0
- package/plugins/deslop/lib/collectors/docs-patterns.js +713 -0
- package/plugins/deslop/lib/collectors/documentation.js +219 -0
- package/plugins/deslop/lib/collectors/github.js +266 -0
- package/plugins/deslop/lib/collectors/index.js +126 -0
- package/plugins/deslop/lib/config/index.js +14 -0
- package/plugins/deslop/lib/cross-platform/index.js +539 -0
- package/plugins/deslop/lib/discovery/index.js +352 -0
- package/plugins/deslop/lib/drift-detect/collectors.js +37 -0
- package/plugins/deslop/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/deslop/lib/enhance/agent-patterns.js +571 -0
- package/plugins/deslop/lib/enhance/auto-suppression.js +622 -0
- package/plugins/deslop/lib/enhance/benchmark.js +417 -0
- package/plugins/deslop/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/deslop/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/deslop/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/deslop/lib/enhance/docs-patterns.js +671 -0
- package/plugins/deslop/lib/enhance/fixer.js +721 -0
- package/plugins/deslop/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/deslop/lib/enhance/hook-patterns.js +40 -0
- package/plugins/deslop/lib/enhance/index.js +127 -0
- package/plugins/deslop/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/deslop/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/deslop/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/deslop/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/deslop/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/deslop/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/deslop/lib/enhance/reporter.js +1348 -0
- package/plugins/deslop/lib/enhance/security-patterns.js +284 -0
- package/plugins/deslop/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/deslop/lib/enhance/skill-patterns.js +147 -0
- package/plugins/deslop/lib/enhance/suppression.js +352 -0
- package/plugins/deslop/lib/enhance/tool-patterns.js +373 -0
- package/plugins/deslop/lib/index.js +270 -0
- package/plugins/deslop/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/deslop/lib/patterns/pipeline.js +948 -0
- package/plugins/deslop/lib/patterns/review-patterns.js +558 -0
- package/plugins/deslop/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/deslop/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/deslop/lib/perf/analyzer/index.js +22 -0
- package/plugins/deslop/lib/perf/argument-parser.js +105 -0
- package/plugins/deslop/lib/perf/baseline-comparator.js +50 -0
- package/plugins/deslop/lib/perf/baseline-store.js +127 -0
- package/plugins/deslop/lib/perf/benchmark-runner.js +399 -0
- package/plugins/deslop/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/deslop/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/deslop/lib/perf/checkpoint.js +123 -0
- package/plugins/deslop/lib/perf/code-paths.js +86 -0
- package/plugins/deslop/lib/perf/consolidation.js +37 -0
- package/plugins/deslop/lib/perf/constraint-runner.js +71 -0
- package/plugins/deslop/lib/perf/experiment-runner.js +32 -0
- package/plugins/deslop/lib/perf/index.js +41 -0
- package/plugins/deslop/lib/perf/investigation-state.js +875 -0
- package/plugins/deslop/lib/perf/optimization-runner.js +79 -0
- package/plugins/deslop/lib/perf/profilers/go.js +22 -0
- package/plugins/deslop/lib/perf/profilers/index.js +46 -0
- package/plugins/deslop/lib/perf/profilers/java.js +23 -0
- package/plugins/deslop/lib/perf/profilers/node.js +27 -0
- package/plugins/deslop/lib/perf/profilers/python.js +23 -0
- package/plugins/deslop/lib/perf/profilers/rust.js +23 -0
- package/plugins/deslop/lib/perf/profiling-runner.js +56 -0
- package/plugins/deslop/lib/perf/schemas.js +140 -0
- package/plugins/deslop/lib/platform/detect-platform.js +413 -0
- package/plugins/deslop/lib/platform/detection-configs.js +93 -0
- package/plugins/deslop/lib/platform/state-dir.js +132 -0
- package/plugins/deslop/lib/platform/verify-tools.js +182 -0
- package/plugins/deslop/lib/repo-map/cache.js +152 -0
- package/plugins/deslop/lib/repo-map/index.js +222 -0
- package/plugins/deslop/lib/repo-map/installer.js +212 -0
- package/plugins/deslop/lib/repo-map/queries/go.js +27 -0
- package/plugins/deslop/lib/repo-map/queries/index.js +100 -0
- package/plugins/deslop/lib/repo-map/queries/java.js +38 -0
- package/plugins/deslop/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/deslop/lib/repo-map/queries/python.js +24 -0
- package/plugins/deslop/lib/repo-map/queries/rust.js +73 -0
- package/plugins/deslop/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/deslop/lib/repo-map/runner.js +1165 -0
- package/plugins/deslop/lib/repo-map/updater.js +474 -0
- package/plugins/deslop/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/deslop/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/deslop/lib/schemas/validator.js +247 -0
- package/plugins/deslop/lib/sources/custom-handler.js +199 -0
- package/plugins/deslop/lib/sources/policy-questions.js +246 -0
- package/plugins/deslop/lib/sources/source-cache.js +165 -0
- package/plugins/deslop/lib/state/workflow-state.js +575 -0
- package/plugins/deslop/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/deslop/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/deslop/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/deslop/lib/types/index.d.ts +84 -0
- package/plugins/deslop/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/deslop/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/deslop/lib/utils/atomic-write.js +94 -0
- package/plugins/deslop/lib/utils/cache-manager.js +159 -0
- package/plugins/deslop/lib/utils/context-optimizer.js +300 -0
- package/plugins/deslop/lib/utils/deprecation.js +37 -0
- package/plugins/deslop/lib/utils/shell-escape.js +88 -0
- package/plugins/deslop/references/slop-categories.md +122 -0
- package/plugins/deslop/scripts/detect.js +134 -0
- package/plugins/deslop/skills/deslop/SKILL.md +204 -0
- package/plugins/drift-detect/.claude-plugin/plugin.json +23 -0
- package/plugins/drift-detect/agents/plan-synthesizer.md +225 -0
- package/plugins/drift-detect/commands/drift-detect.md +269 -0
- package/plugins/drift-detect/lib/adapter-transforms.js +278 -0
- package/plugins/drift-detect/lib/collectors/codebase.js +392 -0
- package/plugins/drift-detect/lib/collectors/docs-patterns.js +713 -0
- package/plugins/drift-detect/lib/collectors/documentation.js +219 -0
- package/plugins/drift-detect/lib/collectors/github.js +266 -0
- package/plugins/drift-detect/lib/collectors/index.js +126 -0
- package/plugins/drift-detect/lib/config/index.js +14 -0
- package/plugins/drift-detect/lib/cross-platform/index.js +539 -0
- package/plugins/drift-detect/lib/discovery/index.js +352 -0
- package/plugins/drift-detect/lib/drift-detect/collectors.js +37 -0
- package/plugins/drift-detect/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/drift-detect/lib/enhance/agent-patterns.js +571 -0
- package/plugins/drift-detect/lib/enhance/auto-suppression.js +622 -0
- package/plugins/drift-detect/lib/enhance/benchmark.js +417 -0
- package/plugins/drift-detect/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/drift-detect/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/drift-detect/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/drift-detect/lib/enhance/docs-patterns.js +671 -0
- package/plugins/drift-detect/lib/enhance/fixer.js +721 -0
- package/plugins/drift-detect/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/drift-detect/lib/enhance/hook-patterns.js +40 -0
- package/plugins/drift-detect/lib/enhance/index.js +127 -0
- package/plugins/drift-detect/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/drift-detect/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/drift-detect/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/drift-detect/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/drift-detect/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/drift-detect/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/drift-detect/lib/enhance/reporter.js +1348 -0
- package/plugins/drift-detect/lib/enhance/security-patterns.js +284 -0
- package/plugins/drift-detect/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/drift-detect/lib/enhance/skill-patterns.js +147 -0
- package/plugins/drift-detect/lib/enhance/suppression.js +352 -0
- package/plugins/drift-detect/lib/enhance/tool-patterns.js +373 -0
- package/plugins/drift-detect/lib/index.js +270 -0
- package/plugins/drift-detect/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/drift-detect/lib/patterns/pipeline.js +948 -0
- package/plugins/drift-detect/lib/patterns/review-patterns.js +558 -0
- package/plugins/drift-detect/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/drift-detect/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/drift-detect/lib/perf/analyzer/index.js +22 -0
- package/plugins/drift-detect/lib/perf/argument-parser.js +105 -0
- package/plugins/drift-detect/lib/perf/baseline-comparator.js +50 -0
- package/plugins/drift-detect/lib/perf/baseline-store.js +127 -0
- package/plugins/drift-detect/lib/perf/benchmark-runner.js +399 -0
- package/plugins/drift-detect/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/drift-detect/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/drift-detect/lib/perf/checkpoint.js +123 -0
- package/plugins/drift-detect/lib/perf/code-paths.js +86 -0
- package/plugins/drift-detect/lib/perf/consolidation.js +37 -0
- package/plugins/drift-detect/lib/perf/constraint-runner.js +71 -0
- package/plugins/drift-detect/lib/perf/experiment-runner.js +32 -0
- package/plugins/drift-detect/lib/perf/index.js +41 -0
- package/plugins/drift-detect/lib/perf/investigation-state.js +875 -0
- package/plugins/drift-detect/lib/perf/optimization-runner.js +79 -0
- package/plugins/drift-detect/lib/perf/profilers/go.js +22 -0
- package/plugins/drift-detect/lib/perf/profilers/index.js +46 -0
- package/plugins/drift-detect/lib/perf/profilers/java.js +23 -0
- package/plugins/drift-detect/lib/perf/profilers/node.js +27 -0
- package/plugins/drift-detect/lib/perf/profilers/python.js +23 -0
- package/plugins/drift-detect/lib/perf/profilers/rust.js +23 -0
- package/plugins/drift-detect/lib/perf/profiling-runner.js +56 -0
- package/plugins/drift-detect/lib/perf/schemas.js +140 -0
- package/plugins/drift-detect/lib/platform/detect-platform.js +413 -0
- package/plugins/drift-detect/lib/platform/detection-configs.js +93 -0
- package/plugins/drift-detect/lib/platform/state-dir.js +132 -0
- package/plugins/drift-detect/lib/platform/verify-tools.js +182 -0
- package/plugins/drift-detect/lib/repo-map/cache.js +152 -0
- package/plugins/drift-detect/lib/repo-map/index.js +222 -0
- package/plugins/drift-detect/lib/repo-map/installer.js +212 -0
- package/plugins/drift-detect/lib/repo-map/queries/go.js +27 -0
- package/plugins/drift-detect/lib/repo-map/queries/index.js +100 -0
- package/plugins/drift-detect/lib/repo-map/queries/java.js +38 -0
- package/plugins/drift-detect/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/drift-detect/lib/repo-map/queries/python.js +24 -0
- package/plugins/drift-detect/lib/repo-map/queries/rust.js +73 -0
- package/plugins/drift-detect/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/drift-detect/lib/repo-map/runner.js +1165 -0
- package/plugins/drift-detect/lib/repo-map/updater.js +474 -0
- package/plugins/drift-detect/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/drift-detect/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/drift-detect/lib/schemas/validator.js +247 -0
- package/plugins/drift-detect/lib/sources/custom-handler.js +199 -0
- package/plugins/drift-detect/lib/sources/policy-questions.js +246 -0
- package/plugins/drift-detect/lib/sources/source-cache.js +165 -0
- package/plugins/drift-detect/lib/state/workflow-state.js +575 -0
- package/plugins/drift-detect/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/drift-detect/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/drift-detect/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/drift-detect/lib/types/index.d.ts +84 -0
- package/plugins/drift-detect/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/drift-detect/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/drift-detect/lib/utils/atomic-write.js +94 -0
- package/plugins/drift-detect/lib/utils/cache-manager.js +159 -0
- package/plugins/drift-detect/lib/utils/context-optimizer.js +300 -0
- package/plugins/drift-detect/lib/utils/deprecation.js +37 -0
- package/plugins/drift-detect/lib/utils/shell-escape.js +88 -0
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +324 -0
- package/plugins/enhance/.claude-plugin/plugin.json +20 -0
- package/plugins/enhance/agents/agent-enhancer.md +64 -0
- package/plugins/enhance/agents/claudemd-enhancer.md +65 -0
- package/plugins/enhance/agents/cross-file-enhancer.md +54 -0
- package/plugins/enhance/agents/docs-enhancer.md +64 -0
- package/plugins/enhance/agents/hooks-enhancer.md +64 -0
- package/plugins/enhance/agents/plugin-enhancer.md +63 -0
- package/plugins/enhance/agents/prompt-enhancer.md +58 -0
- package/plugins/enhance/agents/skills-enhancer.md +64 -0
- package/plugins/enhance/commands/enhance.md +178 -0
- package/plugins/enhance/lib/adapter-transforms.js +278 -0
- package/plugins/enhance/lib/collectors/codebase.js +392 -0
- package/plugins/enhance/lib/collectors/docs-patterns.js +713 -0
- package/plugins/enhance/lib/collectors/documentation.js +219 -0
- package/plugins/enhance/lib/collectors/github.js +266 -0
- package/plugins/enhance/lib/collectors/index.js +126 -0
- package/plugins/enhance/lib/config/index.js +14 -0
- package/plugins/enhance/lib/cross-platform/index.js +539 -0
- package/plugins/enhance/lib/discovery/index.js +352 -0
- package/plugins/enhance/lib/drift-detect/collectors.js +37 -0
- package/plugins/enhance/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/enhance/lib/enhance/agent-patterns.js +571 -0
- package/plugins/enhance/lib/enhance/auto-suppression.js +622 -0
- package/plugins/enhance/lib/enhance/benchmark.js +417 -0
- package/plugins/enhance/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/enhance/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/enhance/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/enhance/lib/enhance/docs-patterns.js +671 -0
- package/plugins/enhance/lib/enhance/fixer.js +721 -0
- package/plugins/enhance/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/enhance/lib/enhance/hook-patterns.js +40 -0
- package/plugins/enhance/lib/enhance/index.js +127 -0
- package/plugins/enhance/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/enhance/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/enhance/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/enhance/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/enhance/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/enhance/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/enhance/lib/enhance/reporter.js +1348 -0
- package/plugins/enhance/lib/enhance/security-patterns.js +284 -0
- package/plugins/enhance/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/enhance/lib/enhance/skill-patterns.js +147 -0
- package/plugins/enhance/lib/enhance/suppression.js +352 -0
- package/plugins/enhance/lib/enhance/tool-patterns.js +373 -0
- package/plugins/enhance/lib/index.js +270 -0
- package/plugins/enhance/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/enhance/lib/patterns/pipeline.js +948 -0
- package/plugins/enhance/lib/patterns/review-patterns.js +558 -0
- package/plugins/enhance/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/enhance/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/enhance/lib/perf/analyzer/index.js +22 -0
- package/plugins/enhance/lib/perf/argument-parser.js +105 -0
- package/plugins/enhance/lib/perf/baseline-comparator.js +50 -0
- package/plugins/enhance/lib/perf/baseline-store.js +127 -0
- package/plugins/enhance/lib/perf/benchmark-runner.js +399 -0
- package/plugins/enhance/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/enhance/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/enhance/lib/perf/checkpoint.js +123 -0
- package/plugins/enhance/lib/perf/code-paths.js +86 -0
- package/plugins/enhance/lib/perf/consolidation.js +37 -0
- package/plugins/enhance/lib/perf/constraint-runner.js +71 -0
- package/plugins/enhance/lib/perf/experiment-runner.js +32 -0
- package/plugins/enhance/lib/perf/index.js +41 -0
- package/plugins/enhance/lib/perf/investigation-state.js +875 -0
- package/plugins/enhance/lib/perf/optimization-runner.js +79 -0
- package/plugins/enhance/lib/perf/profilers/go.js +22 -0
- package/plugins/enhance/lib/perf/profilers/index.js +46 -0
- package/plugins/enhance/lib/perf/profilers/java.js +23 -0
- package/plugins/enhance/lib/perf/profilers/node.js +27 -0
- package/plugins/enhance/lib/perf/profilers/python.js +23 -0
- package/plugins/enhance/lib/perf/profilers/rust.js +23 -0
- package/plugins/enhance/lib/perf/profiling-runner.js +56 -0
- package/plugins/enhance/lib/perf/schemas.js +140 -0
- package/plugins/enhance/lib/platform/detect-platform.js +413 -0
- package/plugins/enhance/lib/platform/detection-configs.js +93 -0
- package/plugins/enhance/lib/platform/state-dir.js +132 -0
- package/plugins/enhance/lib/platform/verify-tools.js +182 -0
- package/plugins/enhance/lib/repo-map/cache.js +152 -0
- package/plugins/enhance/lib/repo-map/index.js +222 -0
- package/plugins/enhance/lib/repo-map/installer.js +212 -0
- package/plugins/enhance/lib/repo-map/queries/go.js +27 -0
- package/plugins/enhance/lib/repo-map/queries/index.js +100 -0
- package/plugins/enhance/lib/repo-map/queries/java.js +38 -0
- package/plugins/enhance/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/enhance/lib/repo-map/queries/python.js +24 -0
- package/plugins/enhance/lib/repo-map/queries/rust.js +73 -0
- package/plugins/enhance/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/enhance/lib/repo-map/runner.js +1165 -0
- package/plugins/enhance/lib/repo-map/updater.js +474 -0
- package/plugins/enhance/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/enhance/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/enhance/lib/schemas/validator.js +247 -0
- package/plugins/enhance/lib/sources/custom-handler.js +199 -0
- package/plugins/enhance/lib/sources/policy-questions.js +246 -0
- package/plugins/enhance/lib/sources/source-cache.js +165 -0
- package/plugins/enhance/lib/state/workflow-state.js +575 -0
- package/plugins/enhance/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/enhance/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/enhance/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/enhance/lib/types/index.d.ts +84 -0
- package/plugins/enhance/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/enhance/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/enhance/lib/utils/atomic-write.js +94 -0
- package/plugins/enhance/lib/utils/cache-manager.js +159 -0
- package/plugins/enhance/lib/utils/context-optimizer.js +300 -0
- package/plugins/enhance/lib/utils/deprecation.js +37 -0
- package/plugins/enhance/lib/utils/shell-escape.js +88 -0
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +277 -0
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +387 -0
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +110 -0
- package/plugins/enhance/skills/enhance-docs/SKILL.md +298 -0
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +554 -0
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +255 -0
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +319 -0
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +340 -0
- package/plugins/enhance/skills/enhance-skills/SKILL.md +436 -0
- package/plugins/learn/.claude-plugin/plugin.json +21 -0
- package/plugins/learn/agents/learn-agent.md +331 -0
- package/plugins/learn/commands/learn.md +190 -0
- package/plugins/learn/lib/adapter-transforms.js +278 -0
- package/plugins/learn/lib/collectors/codebase.js +392 -0
- package/plugins/learn/lib/collectors/docs-patterns.js +713 -0
- package/plugins/learn/lib/collectors/documentation.js +219 -0
- package/plugins/learn/lib/collectors/github.js +266 -0
- package/plugins/learn/lib/collectors/index.js +126 -0
- package/plugins/learn/lib/config/index.js +14 -0
- package/plugins/learn/lib/cross-platform/index.js +539 -0
- package/plugins/learn/lib/discovery/index.js +352 -0
- package/plugins/learn/lib/drift-detect/collectors.js +37 -0
- package/plugins/learn/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/learn/lib/enhance/agent-patterns.js +571 -0
- package/plugins/learn/lib/enhance/auto-suppression.js +622 -0
- package/plugins/learn/lib/enhance/benchmark.js +417 -0
- package/plugins/learn/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/learn/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/learn/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/learn/lib/enhance/docs-patterns.js +671 -0
- package/plugins/learn/lib/enhance/fixer.js +721 -0
- package/plugins/learn/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/learn/lib/enhance/hook-patterns.js +40 -0
- package/plugins/learn/lib/enhance/index.js +127 -0
- package/plugins/learn/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/learn/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/learn/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/learn/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/learn/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/learn/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/learn/lib/enhance/reporter.js +1348 -0
- package/plugins/learn/lib/enhance/security-patterns.js +284 -0
- package/plugins/learn/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/learn/lib/enhance/skill-patterns.js +147 -0
- package/plugins/learn/lib/enhance/suppression.js +352 -0
- package/plugins/learn/lib/enhance/tool-patterns.js +373 -0
- package/plugins/learn/lib/index.js +270 -0
- package/plugins/learn/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/learn/lib/patterns/pipeline.js +948 -0
- package/plugins/learn/lib/patterns/review-patterns.js +558 -0
- package/plugins/learn/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/learn/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/learn/lib/perf/analyzer/index.js +22 -0
- package/plugins/learn/lib/perf/argument-parser.js +105 -0
- package/plugins/learn/lib/perf/baseline-comparator.js +50 -0
- package/plugins/learn/lib/perf/baseline-store.js +127 -0
- package/plugins/learn/lib/perf/benchmark-runner.js +399 -0
- package/plugins/learn/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/learn/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/learn/lib/perf/checkpoint.js +123 -0
- package/plugins/learn/lib/perf/code-paths.js +86 -0
- package/plugins/learn/lib/perf/consolidation.js +37 -0
- package/plugins/learn/lib/perf/constraint-runner.js +71 -0
- package/plugins/learn/lib/perf/experiment-runner.js +32 -0
- package/plugins/learn/lib/perf/index.js +41 -0
- package/plugins/learn/lib/perf/investigation-state.js +875 -0
- package/plugins/learn/lib/perf/optimization-runner.js +79 -0
- package/plugins/learn/lib/perf/profilers/go.js +22 -0
- package/plugins/learn/lib/perf/profilers/index.js +46 -0
- package/plugins/learn/lib/perf/profilers/java.js +23 -0
- package/plugins/learn/lib/perf/profilers/node.js +27 -0
- package/plugins/learn/lib/perf/profilers/python.js +23 -0
- package/plugins/learn/lib/perf/profilers/rust.js +23 -0
- package/plugins/learn/lib/perf/profiling-runner.js +56 -0
- package/plugins/learn/lib/perf/schemas.js +140 -0
- package/plugins/learn/lib/platform/detect-platform.js +413 -0
- package/plugins/learn/lib/platform/detection-configs.js +93 -0
- package/plugins/learn/lib/platform/state-dir.js +132 -0
- package/plugins/learn/lib/platform/verify-tools.js +182 -0
- package/plugins/learn/lib/repo-map/cache.js +152 -0
- package/plugins/learn/lib/repo-map/index.js +222 -0
- package/plugins/learn/lib/repo-map/installer.js +212 -0
- package/plugins/learn/lib/repo-map/queries/go.js +27 -0
- package/plugins/learn/lib/repo-map/queries/index.js +100 -0
- package/plugins/learn/lib/repo-map/queries/java.js +38 -0
- package/plugins/learn/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/learn/lib/repo-map/queries/python.js +24 -0
- package/plugins/learn/lib/repo-map/queries/rust.js +73 -0
- package/plugins/learn/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/learn/lib/repo-map/runner.js +1165 -0
- package/plugins/learn/lib/repo-map/updater.js +474 -0
- package/plugins/learn/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/learn/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/learn/lib/schemas/validator.js +247 -0
- package/plugins/learn/lib/sources/custom-handler.js +199 -0
- package/plugins/learn/lib/sources/policy-questions.js +246 -0
- package/plugins/learn/lib/sources/source-cache.js +165 -0
- package/plugins/learn/lib/state/workflow-state.js +575 -0
- package/plugins/learn/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/learn/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/learn/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/learn/lib/types/index.d.ts +84 -0
- package/plugins/learn/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/learn/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/learn/lib/utils/atomic-write.js +94 -0
- package/plugins/learn/lib/utils/cache-manager.js +159 -0
- package/plugins/learn/lib/utils/context-optimizer.js +300 -0
- package/plugins/learn/lib/utils/deprecation.js +37 -0
- package/plugins/learn/lib/utils/shell-escape.js +88 -0
- package/plugins/learn/skills/learn/SKILL.md +349 -0
- package/plugins/next-task/.claude-plugin/plugin.json +24 -0
- package/plugins/next-task/agents/ci-fixer.md +259 -0
- package/plugins/next-task/agents/ci-monitor.md +342 -0
- package/plugins/next-task/agents/delivery-validator.md +115 -0
- package/plugins/next-task/agents/exploration-agent.md +316 -0
- package/plugins/next-task/agents/implementation-agent.md +465 -0
- package/plugins/next-task/agents/planning-agent.md +377 -0
- package/plugins/next-task/agents/simple-fixer.md +139 -0
- package/plugins/next-task/agents/task-discoverer.md +89 -0
- package/plugins/next-task/agents/test-coverage-checker.md +451 -0
- package/plugins/next-task/agents/worktree-manager.md +257 -0
- package/plugins/next-task/commands/delivery-approval.md +341 -0
- package/plugins/next-task/commands/next-task.md +547 -0
- package/plugins/next-task/hooks/hooks.json +14 -0
- package/plugins/next-task/lib/adapter-transforms.js +278 -0
- package/plugins/next-task/lib/collectors/codebase.js +392 -0
- package/plugins/next-task/lib/collectors/docs-patterns.js +713 -0
- package/plugins/next-task/lib/collectors/documentation.js +219 -0
- package/plugins/next-task/lib/collectors/github.js +266 -0
- package/plugins/next-task/lib/collectors/index.js +126 -0
- package/plugins/next-task/lib/config/index.js +14 -0
- package/plugins/next-task/lib/cross-platform/index.js +539 -0
- package/plugins/next-task/lib/discovery/index.js +352 -0
- package/plugins/next-task/lib/drift-detect/collectors.js +37 -0
- package/plugins/next-task/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/next-task/lib/enhance/agent-patterns.js +571 -0
- package/plugins/next-task/lib/enhance/auto-suppression.js +622 -0
- package/plugins/next-task/lib/enhance/benchmark.js +417 -0
- package/plugins/next-task/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/next-task/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/next-task/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/next-task/lib/enhance/docs-patterns.js +671 -0
- package/plugins/next-task/lib/enhance/fixer.js +721 -0
- package/plugins/next-task/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/next-task/lib/enhance/hook-patterns.js +40 -0
- package/plugins/next-task/lib/enhance/index.js +127 -0
- package/plugins/next-task/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/next-task/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/next-task/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/next-task/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/next-task/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/next-task/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/next-task/lib/enhance/reporter.js +1348 -0
- package/plugins/next-task/lib/enhance/security-patterns.js +284 -0
- package/plugins/next-task/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/next-task/lib/enhance/skill-patterns.js +147 -0
- package/plugins/next-task/lib/enhance/suppression.js +352 -0
- package/plugins/next-task/lib/enhance/tool-patterns.js +373 -0
- package/plugins/next-task/lib/index.js +270 -0
- package/plugins/next-task/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/next-task/lib/patterns/pipeline.js +948 -0
- package/plugins/next-task/lib/patterns/review-patterns.js +558 -0
- package/plugins/next-task/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/next-task/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/next-task/lib/perf/analyzer/index.js +22 -0
- package/plugins/next-task/lib/perf/argument-parser.js +105 -0
- package/plugins/next-task/lib/perf/baseline-comparator.js +50 -0
- package/plugins/next-task/lib/perf/baseline-store.js +127 -0
- package/plugins/next-task/lib/perf/benchmark-runner.js +399 -0
- package/plugins/next-task/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/next-task/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/next-task/lib/perf/checkpoint.js +123 -0
- package/plugins/next-task/lib/perf/code-paths.js +86 -0
- package/plugins/next-task/lib/perf/consolidation.js +37 -0
- package/plugins/next-task/lib/perf/constraint-runner.js +71 -0
- package/plugins/next-task/lib/perf/experiment-runner.js +32 -0
- package/plugins/next-task/lib/perf/index.js +41 -0
- package/plugins/next-task/lib/perf/investigation-state.js +875 -0
- package/plugins/next-task/lib/perf/optimization-runner.js +79 -0
- package/plugins/next-task/lib/perf/profilers/go.js +22 -0
- package/plugins/next-task/lib/perf/profilers/index.js +46 -0
- package/plugins/next-task/lib/perf/profilers/java.js +23 -0
- package/plugins/next-task/lib/perf/profilers/node.js +27 -0
- package/plugins/next-task/lib/perf/profilers/python.js +23 -0
- package/plugins/next-task/lib/perf/profilers/rust.js +23 -0
- package/plugins/next-task/lib/perf/profiling-runner.js +56 -0
- package/plugins/next-task/lib/perf/schemas.js +140 -0
- package/plugins/next-task/lib/platform/detect-platform.js +413 -0
- package/plugins/next-task/lib/platform/detection-configs.js +93 -0
- package/plugins/next-task/lib/platform/state-dir.js +132 -0
- package/plugins/next-task/lib/platform/verify-tools.js +182 -0
- package/plugins/next-task/lib/repo-map/cache.js +152 -0
- package/plugins/next-task/lib/repo-map/index.js +222 -0
- package/plugins/next-task/lib/repo-map/installer.js +212 -0
- package/plugins/next-task/lib/repo-map/queries/go.js +27 -0
- package/plugins/next-task/lib/repo-map/queries/index.js +100 -0
- package/plugins/next-task/lib/repo-map/queries/java.js +38 -0
- package/plugins/next-task/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/next-task/lib/repo-map/queries/python.js +24 -0
- package/plugins/next-task/lib/repo-map/queries/rust.js +73 -0
- package/plugins/next-task/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/next-task/lib/repo-map/runner.js +1165 -0
- package/plugins/next-task/lib/repo-map/updater.js +474 -0
- package/plugins/next-task/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/next-task/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/next-task/lib/schemas/validator.js +247 -0
- package/plugins/next-task/lib/sources/custom-handler.js +199 -0
- package/plugins/next-task/lib/sources/policy-questions.js +246 -0
- package/plugins/next-task/lib/sources/source-cache.js +165 -0
- package/plugins/next-task/lib/state/workflow-state.js +575 -0
- package/plugins/next-task/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/next-task/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/next-task/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/next-task/lib/types/index.d.ts +84 -0
- package/plugins/next-task/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/next-task/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/next-task/lib/utils/atomic-write.js +94 -0
- package/plugins/next-task/lib/utils/cache-manager.js +159 -0
- package/plugins/next-task/lib/utils/context-optimizer.js +300 -0
- package/plugins/next-task/lib/utils/deprecation.js +37 -0
- package/plugins/next-task/lib/utils/shell-escape.js +88 -0
- package/plugins/next-task/skills/discover-tasks/SKILL.md +191 -0
- package/plugins/next-task/skills/orchestrate-review/SKILL.md +239 -0
- package/plugins/next-task/skills/validate-delivery/SKILL.md +186 -0
- package/plugins/perf/.claude-plugin/plugin.json +20 -0
- package/plugins/perf/agents/perf-analyzer.md +43 -0
- package/plugins/perf/agents/perf-code-paths.md +16 -0
- package/plugins/perf/agents/perf-investigation-logger.md +47 -0
- package/plugins/perf/agents/perf-orchestrator.md +344 -0
- package/plugins/perf/agents/perf-theory-gatherer.md +25 -0
- package/plugins/perf/agents/perf-theory-tester.md +58 -0
- package/plugins/perf/commands/perf.md +470 -0
- package/plugins/perf/hooks/checkpoint.md +35 -0
- package/plugins/perf/hooks/constraint-tester.md +40 -0
- package/plugins/perf/lib/adapter-transforms.js +278 -0
- package/plugins/perf/lib/collectors/codebase.js +392 -0
- package/plugins/perf/lib/collectors/docs-patterns.js +713 -0
- package/plugins/perf/lib/collectors/documentation.js +219 -0
- package/plugins/perf/lib/collectors/github.js +266 -0
- package/plugins/perf/lib/collectors/index.js +126 -0
- package/plugins/perf/lib/config/index.js +14 -0
- package/plugins/perf/lib/cross-platform/index.js +539 -0
- package/plugins/perf/lib/discovery/index.js +352 -0
- package/plugins/perf/lib/drift-detect/collectors.js +37 -0
- package/plugins/perf/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/perf/lib/enhance/agent-patterns.js +571 -0
- package/plugins/perf/lib/enhance/auto-suppression.js +622 -0
- package/plugins/perf/lib/enhance/benchmark.js +417 -0
- package/plugins/perf/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/perf/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/perf/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/perf/lib/enhance/docs-patterns.js +671 -0
- package/plugins/perf/lib/enhance/fixer.js +721 -0
- package/plugins/perf/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/perf/lib/enhance/hook-patterns.js +40 -0
- package/plugins/perf/lib/enhance/index.js +127 -0
- package/plugins/perf/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/perf/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/perf/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/perf/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/perf/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/perf/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/perf/lib/enhance/reporter.js +1348 -0
- package/plugins/perf/lib/enhance/security-patterns.js +284 -0
- package/plugins/perf/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/perf/lib/enhance/skill-patterns.js +147 -0
- package/plugins/perf/lib/enhance/suppression.js +352 -0
- package/plugins/perf/lib/enhance/tool-patterns.js +373 -0
- package/plugins/perf/lib/index.js +270 -0
- package/plugins/perf/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/perf/lib/patterns/pipeline.js +948 -0
- package/plugins/perf/lib/patterns/review-patterns.js +558 -0
- package/plugins/perf/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/perf/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/perf/lib/perf/analyzer/index.js +22 -0
- package/plugins/perf/lib/perf/argument-parser.js +105 -0
- package/plugins/perf/lib/perf/baseline-comparator.js +50 -0
- package/plugins/perf/lib/perf/baseline-store.js +127 -0
- package/plugins/perf/lib/perf/benchmark-runner.js +399 -0
- package/plugins/perf/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/perf/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/perf/lib/perf/checkpoint.js +123 -0
- package/plugins/perf/lib/perf/code-paths.js +86 -0
- package/plugins/perf/lib/perf/consolidation.js +37 -0
- package/plugins/perf/lib/perf/constraint-runner.js +71 -0
- package/plugins/perf/lib/perf/experiment-runner.js +32 -0
- package/plugins/perf/lib/perf/index.js +41 -0
- package/plugins/perf/lib/perf/investigation-state.js +875 -0
- package/plugins/perf/lib/perf/optimization-runner.js +79 -0
- package/plugins/perf/lib/perf/profilers/go.js +22 -0
- package/plugins/perf/lib/perf/profilers/index.js +46 -0
- package/plugins/perf/lib/perf/profilers/java.js +23 -0
- package/plugins/perf/lib/perf/profilers/node.js +27 -0
- package/plugins/perf/lib/perf/profilers/python.js +23 -0
- package/plugins/perf/lib/perf/profilers/rust.js +23 -0
- package/plugins/perf/lib/perf/profiling-runner.js +56 -0
- package/plugins/perf/lib/perf/schemas.js +140 -0
- package/plugins/perf/lib/platform/detect-platform.js +413 -0
- package/plugins/perf/lib/platform/detection-configs.js +93 -0
- package/plugins/perf/lib/platform/state-dir.js +132 -0
- package/plugins/perf/lib/platform/verify-tools.js +182 -0
- package/plugins/perf/lib/repo-map/cache.js +152 -0
- package/plugins/perf/lib/repo-map/index.js +222 -0
- package/plugins/perf/lib/repo-map/installer.js +212 -0
- package/plugins/perf/lib/repo-map/queries/go.js +27 -0
- package/plugins/perf/lib/repo-map/queries/index.js +100 -0
- package/plugins/perf/lib/repo-map/queries/java.js +38 -0
- package/plugins/perf/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/perf/lib/repo-map/queries/python.js +24 -0
- package/plugins/perf/lib/repo-map/queries/rust.js +73 -0
- package/plugins/perf/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/perf/lib/repo-map/runner.js +1165 -0
- package/plugins/perf/lib/repo-map/updater.js +474 -0
- package/plugins/perf/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/perf/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/perf/lib/schemas/validator.js +247 -0
- package/plugins/perf/lib/sources/custom-handler.js +199 -0
- package/plugins/perf/lib/sources/policy-questions.js +246 -0
- package/plugins/perf/lib/sources/source-cache.js +165 -0
- package/plugins/perf/lib/state/workflow-state.js +575 -0
- package/plugins/perf/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/perf/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/perf/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/perf/lib/types/index.d.ts +84 -0
- package/plugins/perf/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/perf/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/perf/lib/utils/atomic-write.js +94 -0
- package/plugins/perf/lib/utils/cache-manager.js +159 -0
- package/plugins/perf/lib/utils/context-optimizer.js +300 -0
- package/plugins/perf/lib/utils/deprecation.js +37 -0
- package/plugins/perf/lib/utils/shell-escape.js +88 -0
- package/plugins/perf/skills/perf-analyzer/SKILL.md +37 -0
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +30 -0
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +52 -0
- package/plugins/perf/skills/perf-code-paths/SKILL.md +32 -0
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +41 -0
- package/plugins/perf/skills/perf-profiler/SKILL.md +42 -0
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +35 -0
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +36 -0
- package/plugins/repo-map/.claude-plugin/plugin.json +22 -0
- package/plugins/repo-map/agents/map-validator.md +60 -0
- package/plugins/repo-map/commands/repo-map.md +133 -0
- package/plugins/repo-map/lib/adapter-transforms.js +278 -0
- package/plugins/repo-map/lib/collectors/codebase.js +392 -0
- package/plugins/repo-map/lib/collectors/docs-patterns.js +713 -0
- package/plugins/repo-map/lib/collectors/documentation.js +219 -0
- package/plugins/repo-map/lib/collectors/github.js +266 -0
- package/plugins/repo-map/lib/collectors/index.js +126 -0
- package/plugins/repo-map/lib/config/index.js +14 -0
- package/plugins/repo-map/lib/cross-platform/index.js +539 -0
- package/plugins/repo-map/lib/discovery/index.js +352 -0
- package/plugins/repo-map/lib/drift-detect/collectors.js +37 -0
- package/plugins/repo-map/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/repo-map/lib/enhance/agent-patterns.js +571 -0
- package/plugins/repo-map/lib/enhance/auto-suppression.js +622 -0
- package/plugins/repo-map/lib/enhance/benchmark.js +417 -0
- package/plugins/repo-map/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/repo-map/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/repo-map/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/repo-map/lib/enhance/docs-patterns.js +671 -0
- package/plugins/repo-map/lib/enhance/fixer.js +721 -0
- package/plugins/repo-map/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/repo-map/lib/enhance/hook-patterns.js +40 -0
- package/plugins/repo-map/lib/enhance/index.js +127 -0
- package/plugins/repo-map/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/repo-map/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/repo-map/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/repo-map/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/repo-map/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/repo-map/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/repo-map/lib/enhance/reporter.js +1348 -0
- package/plugins/repo-map/lib/enhance/security-patterns.js +284 -0
- package/plugins/repo-map/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/repo-map/lib/enhance/skill-patterns.js +147 -0
- package/plugins/repo-map/lib/enhance/suppression.js +352 -0
- package/plugins/repo-map/lib/enhance/tool-patterns.js +373 -0
- package/plugins/repo-map/lib/index.js +270 -0
- package/plugins/repo-map/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/repo-map/lib/patterns/pipeline.js +948 -0
- package/plugins/repo-map/lib/patterns/review-patterns.js +558 -0
- package/plugins/repo-map/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/repo-map/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/repo-map/lib/perf/analyzer/index.js +22 -0
- package/plugins/repo-map/lib/perf/argument-parser.js +105 -0
- package/plugins/repo-map/lib/perf/baseline-comparator.js +50 -0
- package/plugins/repo-map/lib/perf/baseline-store.js +127 -0
- package/plugins/repo-map/lib/perf/benchmark-runner.js +399 -0
- package/plugins/repo-map/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/repo-map/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/repo-map/lib/perf/checkpoint.js +123 -0
- package/plugins/repo-map/lib/perf/code-paths.js +86 -0
- package/plugins/repo-map/lib/perf/consolidation.js +37 -0
- package/plugins/repo-map/lib/perf/constraint-runner.js +71 -0
- package/plugins/repo-map/lib/perf/experiment-runner.js +32 -0
- package/plugins/repo-map/lib/perf/index.js +41 -0
- package/plugins/repo-map/lib/perf/investigation-state.js +875 -0
- package/plugins/repo-map/lib/perf/optimization-runner.js +79 -0
- package/plugins/repo-map/lib/perf/profilers/go.js +22 -0
- package/plugins/repo-map/lib/perf/profilers/index.js +46 -0
- package/plugins/repo-map/lib/perf/profilers/java.js +23 -0
- package/plugins/repo-map/lib/perf/profilers/node.js +27 -0
- package/plugins/repo-map/lib/perf/profilers/python.js +23 -0
- package/plugins/repo-map/lib/perf/profilers/rust.js +23 -0
- package/plugins/repo-map/lib/perf/profiling-runner.js +56 -0
- package/plugins/repo-map/lib/perf/schemas.js +140 -0
- package/plugins/repo-map/lib/platform/detect-platform.js +413 -0
- package/plugins/repo-map/lib/platform/detection-configs.js +93 -0
- package/plugins/repo-map/lib/platform/state-dir.js +132 -0
- package/plugins/repo-map/lib/platform/verify-tools.js +182 -0
- package/plugins/repo-map/lib/repo-map/cache.js +152 -0
- package/plugins/repo-map/lib/repo-map/index.js +222 -0
- package/plugins/repo-map/lib/repo-map/installer.js +212 -0
- package/plugins/repo-map/lib/repo-map/queries/go.js +27 -0
- package/plugins/repo-map/lib/repo-map/queries/index.js +100 -0
- package/plugins/repo-map/lib/repo-map/queries/java.js +38 -0
- package/plugins/repo-map/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/repo-map/lib/repo-map/queries/python.js +24 -0
- package/plugins/repo-map/lib/repo-map/queries/rust.js +73 -0
- package/plugins/repo-map/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/repo-map/lib/repo-map/runner.js +1165 -0
- package/plugins/repo-map/lib/repo-map/updater.js +474 -0
- package/plugins/repo-map/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/repo-map/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/repo-map/lib/schemas/validator.js +247 -0
- package/plugins/repo-map/lib/sources/custom-handler.js +199 -0
- package/plugins/repo-map/lib/sources/policy-questions.js +246 -0
- package/plugins/repo-map/lib/sources/source-cache.js +165 -0
- package/plugins/repo-map/lib/state/workflow-state.js +575 -0
- package/plugins/repo-map/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/repo-map/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/repo-map/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/repo-map/lib/types/index.d.ts +84 -0
- package/plugins/repo-map/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/repo-map/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/repo-map/lib/utils/atomic-write.js +94 -0
- package/plugins/repo-map/lib/utils/cache-manager.js +159 -0
- package/plugins/repo-map/lib/utils/context-optimizer.js +300 -0
- package/plugins/repo-map/lib/utils/deprecation.js +37 -0
- package/plugins/repo-map/lib/utils/shell-escape.js +88 -0
- package/plugins/repo-map/skills/repo-mapping/SKILL.md +83 -0
- package/plugins/ship/.claude-plugin/plugin.json +21 -0
- package/plugins/ship/commands/ship-ci-review-loop.md +472 -0
- package/plugins/ship/commands/ship-deployment.md +335 -0
- package/plugins/ship/commands/ship-error-handling.md +258 -0
- package/plugins/ship/commands/ship.md +492 -0
- package/plugins/ship/lib/adapter-transforms.js +278 -0
- package/plugins/ship/lib/collectors/codebase.js +392 -0
- package/plugins/ship/lib/collectors/docs-patterns.js +713 -0
- package/plugins/ship/lib/collectors/documentation.js +219 -0
- package/plugins/ship/lib/collectors/github.js +266 -0
- package/plugins/ship/lib/collectors/index.js +126 -0
- package/plugins/ship/lib/config/index.js +14 -0
- package/plugins/ship/lib/cross-platform/index.js +539 -0
- package/plugins/ship/lib/discovery/index.js +352 -0
- package/plugins/ship/lib/drift-detect/collectors.js +37 -0
- package/plugins/ship/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/ship/lib/enhance/agent-patterns.js +571 -0
- package/plugins/ship/lib/enhance/auto-suppression.js +622 -0
- package/plugins/ship/lib/enhance/benchmark.js +417 -0
- package/plugins/ship/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/ship/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/ship/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/ship/lib/enhance/docs-patterns.js +671 -0
- package/plugins/ship/lib/enhance/fixer.js +721 -0
- package/plugins/ship/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/ship/lib/enhance/hook-patterns.js +40 -0
- package/plugins/ship/lib/enhance/index.js +127 -0
- package/plugins/ship/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/ship/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/ship/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/ship/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/ship/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/ship/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/ship/lib/enhance/reporter.js +1348 -0
- package/plugins/ship/lib/enhance/security-patterns.js +284 -0
- package/plugins/ship/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/ship/lib/enhance/skill-patterns.js +147 -0
- package/plugins/ship/lib/enhance/suppression.js +352 -0
- package/plugins/ship/lib/enhance/tool-patterns.js +373 -0
- package/plugins/ship/lib/index.js +270 -0
- package/plugins/ship/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/ship/lib/patterns/pipeline.js +948 -0
- package/plugins/ship/lib/patterns/review-patterns.js +558 -0
- package/plugins/ship/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/ship/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/ship/lib/perf/analyzer/index.js +22 -0
- package/plugins/ship/lib/perf/argument-parser.js +105 -0
- package/plugins/ship/lib/perf/baseline-comparator.js +50 -0
- package/plugins/ship/lib/perf/baseline-store.js +127 -0
- package/plugins/ship/lib/perf/benchmark-runner.js +399 -0
- package/plugins/ship/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/ship/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/ship/lib/perf/checkpoint.js +123 -0
- package/plugins/ship/lib/perf/code-paths.js +86 -0
- package/plugins/ship/lib/perf/consolidation.js +37 -0
- package/plugins/ship/lib/perf/constraint-runner.js +71 -0
- package/plugins/ship/lib/perf/experiment-runner.js +32 -0
- package/plugins/ship/lib/perf/index.js +41 -0
- package/plugins/ship/lib/perf/investigation-state.js +875 -0
- package/plugins/ship/lib/perf/optimization-runner.js +79 -0
- package/plugins/ship/lib/perf/profilers/go.js +22 -0
- package/plugins/ship/lib/perf/profilers/index.js +46 -0
- package/plugins/ship/lib/perf/profilers/java.js +23 -0
- package/plugins/ship/lib/perf/profilers/node.js +27 -0
- package/plugins/ship/lib/perf/profilers/python.js +23 -0
- package/plugins/ship/lib/perf/profilers/rust.js +23 -0
- package/plugins/ship/lib/perf/profiling-runner.js +56 -0
- package/plugins/ship/lib/perf/schemas.js +140 -0
- package/plugins/ship/lib/platform/detect-platform.js +413 -0
- package/plugins/ship/lib/platform/detection-configs.js +93 -0
- package/plugins/ship/lib/platform/state-dir.js +132 -0
- package/plugins/ship/lib/platform/verify-tools.js +182 -0
- package/plugins/ship/lib/repo-map/cache.js +152 -0
- package/plugins/ship/lib/repo-map/index.js +222 -0
- package/plugins/ship/lib/repo-map/installer.js +212 -0
- package/plugins/ship/lib/repo-map/queries/go.js +27 -0
- package/plugins/ship/lib/repo-map/queries/index.js +100 -0
- package/plugins/ship/lib/repo-map/queries/java.js +38 -0
- package/plugins/ship/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/ship/lib/repo-map/queries/python.js +24 -0
- package/plugins/ship/lib/repo-map/queries/rust.js +73 -0
- package/plugins/ship/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/ship/lib/repo-map/runner.js +1165 -0
- package/plugins/ship/lib/repo-map/updater.js +474 -0
- package/plugins/ship/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/ship/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/ship/lib/schemas/validator.js +247 -0
- package/plugins/ship/lib/sources/custom-handler.js +199 -0
- package/plugins/ship/lib/sources/policy-questions.js +246 -0
- package/plugins/ship/lib/sources/source-cache.js +165 -0
- package/plugins/ship/lib/state/workflow-state.js +575 -0
- package/plugins/ship/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/ship/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/ship/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/ship/lib/types/index.d.ts +84 -0
- package/plugins/ship/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/ship/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/ship/lib/utils/atomic-write.js +94 -0
- package/plugins/ship/lib/utils/cache-manager.js +159 -0
- package/plugins/ship/lib/utils/context-optimizer.js +300 -0
- package/plugins/ship/lib/utils/deprecation.js +37 -0
- package/plugins/ship/lib/utils/shell-escape.js +88 -0
- package/plugins/sync-docs/.claude-plugin/plugin.json +20 -0
- package/plugins/sync-docs/agents/sync-docs-agent.md +154 -0
- package/plugins/sync-docs/commands/sync-docs.md +186 -0
- package/plugins/sync-docs/lib/adapter-transforms.js +278 -0
- package/plugins/sync-docs/lib/collectors/codebase.js +392 -0
- package/plugins/sync-docs/lib/collectors/docs-patterns.js +713 -0
- package/plugins/sync-docs/lib/collectors/documentation.js +219 -0
- package/plugins/sync-docs/lib/collectors/github.js +266 -0
- package/plugins/sync-docs/lib/collectors/index.js +126 -0
- package/plugins/sync-docs/lib/config/index.js +14 -0
- package/plugins/sync-docs/lib/cross-platform/index.js +539 -0
- package/plugins/sync-docs/lib/discovery/index.js +352 -0
- package/plugins/sync-docs/lib/drift-detect/collectors.js +37 -0
- package/plugins/sync-docs/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/sync-docs/lib/enhance/agent-patterns.js +571 -0
- package/plugins/sync-docs/lib/enhance/auto-suppression.js +622 -0
- package/plugins/sync-docs/lib/enhance/benchmark.js +417 -0
- package/plugins/sync-docs/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/sync-docs/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/sync-docs/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/sync-docs/lib/enhance/docs-patterns.js +671 -0
- package/plugins/sync-docs/lib/enhance/fixer.js +721 -0
- package/plugins/sync-docs/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/sync-docs/lib/enhance/hook-patterns.js +40 -0
- package/plugins/sync-docs/lib/enhance/index.js +127 -0
- package/plugins/sync-docs/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/sync-docs/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/sync-docs/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/sync-docs/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/sync-docs/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/sync-docs/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/sync-docs/lib/enhance/reporter.js +1348 -0
- package/plugins/sync-docs/lib/enhance/security-patterns.js +284 -0
- package/plugins/sync-docs/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/sync-docs/lib/enhance/skill-patterns.js +147 -0
- package/plugins/sync-docs/lib/enhance/suppression.js +352 -0
- package/plugins/sync-docs/lib/enhance/tool-patterns.js +373 -0
- package/plugins/sync-docs/lib/index.js +270 -0
- package/plugins/sync-docs/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/sync-docs/lib/patterns/pipeline.js +948 -0
- package/plugins/sync-docs/lib/patterns/review-patterns.js +558 -0
- package/plugins/sync-docs/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/sync-docs/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/sync-docs/lib/perf/analyzer/index.js +22 -0
- package/plugins/sync-docs/lib/perf/argument-parser.js +105 -0
- package/plugins/sync-docs/lib/perf/baseline-comparator.js +50 -0
- package/plugins/sync-docs/lib/perf/baseline-store.js +127 -0
- package/plugins/sync-docs/lib/perf/benchmark-runner.js +399 -0
- package/plugins/sync-docs/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/sync-docs/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/sync-docs/lib/perf/checkpoint.js +123 -0
- package/plugins/sync-docs/lib/perf/code-paths.js +86 -0
- package/plugins/sync-docs/lib/perf/consolidation.js +37 -0
- package/plugins/sync-docs/lib/perf/constraint-runner.js +71 -0
- package/plugins/sync-docs/lib/perf/experiment-runner.js +32 -0
- package/plugins/sync-docs/lib/perf/index.js +41 -0
- package/plugins/sync-docs/lib/perf/investigation-state.js +875 -0
- package/plugins/sync-docs/lib/perf/optimization-runner.js +79 -0
- package/plugins/sync-docs/lib/perf/profilers/go.js +22 -0
- package/plugins/sync-docs/lib/perf/profilers/index.js +46 -0
- package/plugins/sync-docs/lib/perf/profilers/java.js +23 -0
- package/plugins/sync-docs/lib/perf/profilers/node.js +27 -0
- package/plugins/sync-docs/lib/perf/profilers/python.js +23 -0
- package/plugins/sync-docs/lib/perf/profilers/rust.js +23 -0
- package/plugins/sync-docs/lib/perf/profiling-runner.js +56 -0
- package/plugins/sync-docs/lib/perf/schemas.js +140 -0
- package/plugins/sync-docs/lib/platform/detect-platform.js +413 -0
- package/plugins/sync-docs/lib/platform/detection-configs.js +93 -0
- package/plugins/sync-docs/lib/platform/state-dir.js +132 -0
- package/plugins/sync-docs/lib/platform/verify-tools.js +182 -0
- package/plugins/sync-docs/lib/repo-map/cache.js +152 -0
- package/plugins/sync-docs/lib/repo-map/index.js +222 -0
- package/plugins/sync-docs/lib/repo-map/installer.js +212 -0
- package/plugins/sync-docs/lib/repo-map/queries/go.js +27 -0
- package/plugins/sync-docs/lib/repo-map/queries/index.js +100 -0
- package/plugins/sync-docs/lib/repo-map/queries/java.js +38 -0
- package/plugins/sync-docs/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/sync-docs/lib/repo-map/queries/python.js +24 -0
- package/plugins/sync-docs/lib/repo-map/queries/rust.js +73 -0
- package/plugins/sync-docs/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/sync-docs/lib/repo-map/runner.js +1165 -0
- package/plugins/sync-docs/lib/repo-map/updater.js +474 -0
- package/plugins/sync-docs/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/sync-docs/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/sync-docs/lib/schemas/validator.js +247 -0
- package/plugins/sync-docs/lib/sources/custom-handler.js +199 -0
- package/plugins/sync-docs/lib/sources/policy-questions.js +246 -0
- package/plugins/sync-docs/lib/sources/source-cache.js +165 -0
- package/plugins/sync-docs/lib/state/workflow-state.js +575 -0
- package/plugins/sync-docs/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/sync-docs/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/sync-docs/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/sync-docs/lib/types/index.d.ts +84 -0
- package/plugins/sync-docs/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/sync-docs/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/sync-docs/lib/utils/atomic-write.js +94 -0
- package/plugins/sync-docs/lib/utils/cache-manager.js +159 -0
- package/plugins/sync-docs/lib/utils/context-optimizer.js +300 -0
- package/plugins/sync-docs/lib/utils/deprecation.js +37 -0
- package/plugins/sync-docs/lib/utils/shell-escape.js +88 -0
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +351 -0
- package/scripts/bump-version.js +92 -0
- package/scripts/check-hardcoded-paths.js +199 -0
- package/scripts/dev-install.js +493 -0
- package/scripts/expand-templates.js +269 -0
- package/scripts/gen-adapters.js +323 -0
- package/scripts/generate-docs.js +558 -0
- package/scripts/generate-plugin-list.js +20 -0
- package/scripts/migrate-opencode.js +307 -0
- package/scripts/perf/repo-map-create.js +46 -0
- package/scripts/plugins.txt +12 -0
- package/scripts/preflight.js +1263 -0
- package/scripts/scaffold.js +490 -0
- package/scripts/setup-hooks.js +169 -0
- package/scripts/stamp-version.js +175 -0
- package/scripts/test-transform.js +85 -0
- package/scripts/validate-agent-skill-compliance.js +284 -0
- package/scripts/validate-counts.js +457 -0
- package/scripts/validate-cross-platform-docs.js +550 -0
- package/scripts/validate-opencode-install.js +182 -0
- package/site/assets/css/main.css +1525 -0
- package/site/assets/css/tokens.css +493 -0
- package/site/assets/favicon.svg +23 -0
- package/site/assets/js/main.js +801 -0
- package/site/assets/logo.png +0 -0
- package/site/assets/og-image.html +163 -0
- package/site/content.json +453 -0
- package/site/index.html +698 -0
- package/site/ux-spec.md +683 -0
- package/site/version.json +5 -0
- package/templates/agent-snippets/enhance-integration-points.md +6 -0
- package/templates/agent-snippets/enhance-skill-delegation.md +18 -0
- package/templates/agent-snippets/model-choice.md +6 -0
|
@@ -0,0 +1,2305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slop Analyzers - Multi-pass analysis functions for slop detection
|
|
3
|
+
*
|
|
4
|
+
* These analyzers handle patterns that require structural code analysis
|
|
5
|
+
* beyond simple regex matching (e.g., doc/code ratio computation).
|
|
6
|
+
*
|
|
7
|
+
* @author Avi Fenesh
|
|
8
|
+
* @license MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Analyze JSDoc-to-function ratio to detect excessive documentation
|
|
13
|
+
*
|
|
14
|
+
* Flags functions where JSDoc block lines exceed maxRatio times the function body lines.
|
|
15
|
+
* This pattern often indicates AI-generated code with verbose, unnecessary documentation.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} content - File content to analyze
|
|
18
|
+
* @param {Object} options - Analysis options
|
|
19
|
+
* @param {number} [options.minFunctionLines=3] - Minimum function body lines to analyze
|
|
20
|
+
* @param {number} [options.maxRatio=3.0] - Maximum allowed doc/code ratio
|
|
21
|
+
* @returns {Array<Object>} Array of violations: { line, docLines, codeLines, ratio }
|
|
22
|
+
*/
|
|
23
|
+
function analyzeDocCodeRatio(content, options = {}) {
|
|
24
|
+
const minFunctionLines = options.minFunctionLines || 3;
|
|
25
|
+
const maxRatio = options.maxRatio || 3.0;
|
|
26
|
+
const lang = detectLanguage(options.filePath || '.js');
|
|
27
|
+
const violations = [];
|
|
28
|
+
|
|
29
|
+
const config = getDocCodeConfig(lang);
|
|
30
|
+
if (!config) return violations;
|
|
31
|
+
|
|
32
|
+
if (config.useBraces) {
|
|
33
|
+
return analyzeDocCodeBraceLanguage(content, lang, config, minFunctionLines, maxRatio);
|
|
34
|
+
} else {
|
|
35
|
+
return analyzeDocCodePython(content, minFunctionLines, maxRatio);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get language-specific configuration for doc/code ratio detection
|
|
41
|
+
*/
|
|
42
|
+
function getDocCodeConfig(lang) {
|
|
43
|
+
const configs = {
|
|
44
|
+
js: {
|
|
45
|
+
useBraces: true,
|
|
46
|
+
// JSDoc: /** ... */ followed by function
|
|
47
|
+
docPatterns: [
|
|
48
|
+
/\/\*\*([\s\S]*?)\*\/\s*(export\s+)?(async\s+)?(?:function\s+(\w+)\s*\([^)]*\)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>)/g,
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
java: {
|
|
52
|
+
useBraces: true,
|
|
53
|
+
// Javadoc: /** ... */ followed by method
|
|
54
|
+
docPatterns: [
|
|
55
|
+
/\/\*\*([\s\S]*?)\*\/\s*(?:@\w+\s*)*(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?(?:\w+(?:<[^>]*>)?)\s+(\w+)\s*\([^)]*\)/g,
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
rust: {
|
|
59
|
+
useBraces: true,
|
|
60
|
+
// Rust doc comments: /// or //! lines before fn
|
|
61
|
+
docPatterns: [
|
|
62
|
+
/((?:^\s*\/\/[\/!].*\n)+)\s*(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/gm,
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
go: {
|
|
66
|
+
useBraces: true,
|
|
67
|
+
// Go doc comments: // lines before func
|
|
68
|
+
docPatterns: [
|
|
69
|
+
/((?:^\s*\/\/.*\n)+)\s*func\s+(?:\([^)]+\)\s+)?(\w+)/gm,
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
python: {
|
|
73
|
+
useBraces: false,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
return configs[lang];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Analyze doc/code ratio for brace-delimited languages (JS, Java, Rust, Go)
|
|
81
|
+
*/
|
|
82
|
+
function analyzeDocCodeBraceLanguage(content, lang, config, minFunctionLines, maxRatio) {
|
|
83
|
+
const violations = [];
|
|
84
|
+
|
|
85
|
+
for (const pattern of config.docPatterns) {
|
|
86
|
+
let match;
|
|
87
|
+
pattern.lastIndex = 0;
|
|
88
|
+
|
|
89
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
90
|
+
const docBlock = match[1];
|
|
91
|
+
const docLines = countNonEmptyLines(docBlock);
|
|
92
|
+
|
|
93
|
+
// Find the opening brace after the match
|
|
94
|
+
const afterMatch = match.index + match[0].length;
|
|
95
|
+
const openBraceOffset = content.substring(afterMatch).search(/\{/);
|
|
96
|
+
if (openBraceOffset === -1) continue;
|
|
97
|
+
|
|
98
|
+
const funcStart = afterMatch + openBraceOffset;
|
|
99
|
+
const closingBraceIndex = findMatchingBrace(content, funcStart);
|
|
100
|
+
if (closingBraceIndex === -1) continue;
|
|
101
|
+
|
|
102
|
+
const funcBody = content.substring(funcStart + 1, closingBraceIndex);
|
|
103
|
+
const funcLines = countNonEmptyLines(funcBody);
|
|
104
|
+
|
|
105
|
+
if (funcLines < minFunctionLines) continue;
|
|
106
|
+
|
|
107
|
+
const ratio = docLines / funcLines;
|
|
108
|
+
if (ratio > maxRatio) {
|
|
109
|
+
const lineNumber = countNewlines(content.substring(0, match.index)) + 1;
|
|
110
|
+
const funcName = match[4] || match[5] || 'unknown';
|
|
111
|
+
violations.push({
|
|
112
|
+
line: lineNumber,
|
|
113
|
+
docLines: docLines,
|
|
114
|
+
codeLines: funcLines,
|
|
115
|
+
ratio: parseFloat(ratio.toFixed(2)),
|
|
116
|
+
functionName: funcName
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return violations;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Analyze doc/code ratio for Python (indentation-based with docstrings)
|
|
127
|
+
*/
|
|
128
|
+
function analyzeDocCodePython(content, minFunctionLines, maxRatio) {
|
|
129
|
+
const violations = [];
|
|
130
|
+
const lines = content.split('\n');
|
|
131
|
+
|
|
132
|
+
const defPattern = /^(\s*)(?:async\s+)?def\s+(\w+)\s*\([^)]*\)\s*(?:->.*)?:\s*$/;
|
|
133
|
+
|
|
134
|
+
for (let i = 0; i < lines.length; i++) {
|
|
135
|
+
const match = defPattern.exec(lines[i]);
|
|
136
|
+
if (!match) continue;
|
|
137
|
+
|
|
138
|
+
const funcIndent = match[1].length;
|
|
139
|
+
const funcName = match[2];
|
|
140
|
+
|
|
141
|
+
// Look for docstring right after def
|
|
142
|
+
let docLines = 0;
|
|
143
|
+
let docEndLine = i + 1;
|
|
144
|
+
if (docEndLine < lines.length) {
|
|
145
|
+
const nextLine = lines[docEndLine].trim();
|
|
146
|
+
if (nextLine.startsWith('"""') || nextLine.startsWith("'''")) {
|
|
147
|
+
const quote = nextLine.substring(0, 3);
|
|
148
|
+
// Single-line docstring?
|
|
149
|
+
if (nextLine.length > 6 && nextLine.endsWith(quote)) {
|
|
150
|
+
docLines = 1;
|
|
151
|
+
docEndLine++;
|
|
152
|
+
} else {
|
|
153
|
+
// Multi-line docstring
|
|
154
|
+
docLines = 1;
|
|
155
|
+
docEndLine++;
|
|
156
|
+
while (docEndLine < lines.length) {
|
|
157
|
+
docLines++;
|
|
158
|
+
if (lines[docEndLine].includes(quote)) {
|
|
159
|
+
docEndLine++;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
docEndLine++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Count function body lines (after docstring)
|
|
169
|
+
let codeLines = 0;
|
|
170
|
+
for (let j = docEndLine; j < lines.length; j++) {
|
|
171
|
+
const line = lines[j];
|
|
172
|
+
const trimmed = line.trim();
|
|
173
|
+
if (!trimmed) continue;
|
|
174
|
+
|
|
175
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
176
|
+
if (lineIndent <= funcIndent && trimmed) break;
|
|
177
|
+
|
|
178
|
+
if (!trimmed.startsWith('#')) {
|
|
179
|
+
codeLines++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (codeLines < minFunctionLines) continue;
|
|
184
|
+
|
|
185
|
+
const ratio = docLines / codeLines;
|
|
186
|
+
if (ratio > maxRatio) {
|
|
187
|
+
violations.push({
|
|
188
|
+
line: i + 1,
|
|
189
|
+
docLines: docLines,
|
|
190
|
+
codeLines: codeLines,
|
|
191
|
+
ratio: parseFloat(ratio.toFixed(2)),
|
|
192
|
+
functionName: funcName
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return violations;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Count non-empty lines in a string
|
|
202
|
+
* @param {string} str - String to count lines in
|
|
203
|
+
* @returns {number} Number of non-empty lines
|
|
204
|
+
*/
|
|
205
|
+
function countNonEmptyLines(str) {
|
|
206
|
+
return str.split('\n').filter(line => line.trim().length > 0).length;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Count newlines in a string (for line number calculation)
|
|
211
|
+
* @param {string} str - String to count newlines in
|
|
212
|
+
* @returns {number} Number of newlines (lines - 1 for content before position)
|
|
213
|
+
*/
|
|
214
|
+
function countNewlines(str) {
|
|
215
|
+
if (!str) return 0;
|
|
216
|
+
return (str.match(/\n/g) || []).length;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Find matching closing brace (handles nested braces and string literals)
|
|
221
|
+
*
|
|
222
|
+
* Stops at 5000 characters to prevent runaway parsing on malformed code.
|
|
223
|
+
*
|
|
224
|
+
* @param {string} content - Full file content
|
|
225
|
+
* @param {number} openIndex - Index of opening brace
|
|
226
|
+
* @returns {number} Index of matching closing brace, or -1 if not found
|
|
227
|
+
*/
|
|
228
|
+
function findMatchingBrace(content, openIndex) {
|
|
229
|
+
let depth = 1;
|
|
230
|
+
let inString = false;
|
|
231
|
+
let stringChar = '';
|
|
232
|
+
let inTemplateExpr = false;
|
|
233
|
+
let templateExprDepth = 0;
|
|
234
|
+
|
|
235
|
+
// Limit search to prevent runaway parsing
|
|
236
|
+
const maxSearch = Math.min(content.length, openIndex + 5000);
|
|
237
|
+
|
|
238
|
+
for (let i = openIndex + 1; i < maxSearch; i++) {
|
|
239
|
+
const char = content[i];
|
|
240
|
+
const prevChar = i > 0 ? content[i - 1] : '';
|
|
241
|
+
|
|
242
|
+
// Skip single-line comments (must be checked before string handling)
|
|
243
|
+
// Quotes/apostrophes inside comments should not affect string state
|
|
244
|
+
if (!inString && char === '/' && content[i + 1] === '/') {
|
|
245
|
+
const eol = content.indexOf('\n', i);
|
|
246
|
+
i = eol === -1 ? maxSearch : eol;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Skip block comments
|
|
251
|
+
if (!inString && char === '/' && content[i + 1] === '*') {
|
|
252
|
+
const endComment = content.indexOf('*/', i + 2);
|
|
253
|
+
i = endComment === -1 ? maxSearch : endComment + 1;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Handle template literal expression ${...}
|
|
258
|
+
if (char === '$' && content[i + 1] === '{' && inString && stringChar === '`') {
|
|
259
|
+
inTemplateExpr = true;
|
|
260
|
+
templateExprDepth = 1;
|
|
261
|
+
i++; // Skip the {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Inside template expression, track braces separately
|
|
266
|
+
if (inTemplateExpr) {
|
|
267
|
+
if (char === '{') {
|
|
268
|
+
templateExprDepth++;
|
|
269
|
+
} else if (char === '}') {
|
|
270
|
+
templateExprDepth--;
|
|
271
|
+
if (templateExprDepth === 0) {
|
|
272
|
+
inTemplateExpr = false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Track string state (handle escaped quotes)
|
|
279
|
+
if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
|
|
280
|
+
if (inString && char === stringChar) {
|
|
281
|
+
inString = false;
|
|
282
|
+
stringChar = '';
|
|
283
|
+
} else if (!inString) {
|
|
284
|
+
inString = true;
|
|
285
|
+
stringChar = char;
|
|
286
|
+
}
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Count braces outside strings
|
|
291
|
+
if (!inString) {
|
|
292
|
+
if (char === '{') depth++;
|
|
293
|
+
if (char === '}') depth--;
|
|
294
|
+
if (depth === 0) return i;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return -1; // Not found within limit
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Verbosity Detection
|
|
303
|
+
// ============================================================================
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Comment syntax patterns for different languages
|
|
307
|
+
* blockLen: length of block comment delimiter (2 for /*, 3 for """)
|
|
308
|
+
*/
|
|
309
|
+
const COMMENT_SYNTAX = {
|
|
310
|
+
js: { line: /^\s*\/\//, block: { start: /\/\*/, end: /\*\//, len: 2 } },
|
|
311
|
+
python: { line: /^\s*#/, block: { start: /"""/, end: /"""/, len: 3 } },
|
|
312
|
+
rust: { line: /^\s*\/\//, block: { start: /\/\*/, end: /\*\//, len: 2 } },
|
|
313
|
+
go: { line: /^\s*\/\//, block: { start: /\/\*/, end: /\*\//, len: 2 } }
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Detect language from file extension for comment syntax
|
|
318
|
+
* @param {string} filePath - File path or extension
|
|
319
|
+
* @returns {string} Language key (js, python, rust, go)
|
|
320
|
+
*/
|
|
321
|
+
function detectCommentLanguage(filePath) {
|
|
322
|
+
if (!filePath) return 'js';
|
|
323
|
+
const ext = filePath.includes('.') ? filePath.substring(filePath.lastIndexOf('.')) : filePath;
|
|
324
|
+
if (['.py'].includes(ext)) return 'python';
|
|
325
|
+
if (['.rs'].includes(ext)) return 'rust';
|
|
326
|
+
if (['.go'].includes(ext)) return 'go';
|
|
327
|
+
return 'js'; // Default for .js, .ts, .jsx, .tsx, etc.
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Analyze inline comment-to-code ratio within functions
|
|
332
|
+
*
|
|
333
|
+
* Flags functions where inline comment lines exceed maxCommentRatio times the code lines.
|
|
334
|
+
* This pattern detects over-explained code where comments restate what the code does.
|
|
335
|
+
*
|
|
336
|
+
* Different from doc/code ratio:
|
|
337
|
+
* - doc/code ratio: counts JSDoc blocks ABOVE functions
|
|
338
|
+
* - verbosity ratio: counts inline comments WITHIN function bodies
|
|
339
|
+
*
|
|
340
|
+
* @param {string} content - File content to analyze
|
|
341
|
+
* @param {Object} options - Analysis options
|
|
342
|
+
* @param {number} [options.minCodeLines=3] - Minimum code lines to analyze
|
|
343
|
+
* @param {number} [options.maxCommentRatio=2.0] - Maximum allowed comment/code ratio
|
|
344
|
+
* @param {string} [options.filePath] - File path for language detection
|
|
345
|
+
* @returns {Array<Object>} Array of violations: { line, commentLines, codeLines, ratio }
|
|
346
|
+
*/
|
|
347
|
+
function analyzeVerbosityRatio(content, options = {}) {
|
|
348
|
+
const minCodeLines = options.minCodeLines || 3;
|
|
349
|
+
const maxCommentRatio = options.maxCommentRatio || 2.0;
|
|
350
|
+
const lang = detectCommentLanguage(options.filePath);
|
|
351
|
+
const violations = [];
|
|
352
|
+
|
|
353
|
+
// Pattern to find function declarations with opening brace
|
|
354
|
+
// Handles: function name(), async function name(), const name = () =>, arrow functions
|
|
355
|
+
const funcPattern = /(export\s+)?(async\s+)?(?:function\s+\w+\s*\([^)]*\)|(?:const|let|var)\s+\w+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?function\s*\([^)]*\))/g;
|
|
356
|
+
|
|
357
|
+
let match;
|
|
358
|
+
while ((match = funcPattern.exec(content)) !== null) {
|
|
359
|
+
// Find the opening brace after the function declaration
|
|
360
|
+
const afterMatch = match.index + match[0].length;
|
|
361
|
+
const searchRegion = content.substring(afterMatch, afterMatch + 200); // Look ahead
|
|
362
|
+
const braceMatch = searchRegion.match(/^\s*\{/);
|
|
363
|
+
|
|
364
|
+
if (!braceMatch) continue; // No opening brace found (might be expression body arrow)
|
|
365
|
+
|
|
366
|
+
const funcStart = afterMatch + searchRegion.indexOf('{');
|
|
367
|
+
const closingBraceIndex = findMatchingBrace(content, funcStart);
|
|
368
|
+
|
|
369
|
+
if (closingBraceIndex === -1) continue; // Parsing failed, skip
|
|
370
|
+
|
|
371
|
+
const funcBody = content.substring(funcStart + 1, closingBraceIndex);
|
|
372
|
+
|
|
373
|
+
// Count comment lines and code lines within function body
|
|
374
|
+
const lines = funcBody.split('\n');
|
|
375
|
+
let commentLines = 0;
|
|
376
|
+
let codeLines = 0;
|
|
377
|
+
let inBlockComment = false;
|
|
378
|
+
const commentSyntax = COMMENT_SYNTAX[lang] || COMMENT_SYNTAX.js;
|
|
379
|
+
|
|
380
|
+
for (const line of lines) {
|
|
381
|
+
const trimmed = line.trim();
|
|
382
|
+
if (!trimmed) continue; // Skip empty lines
|
|
383
|
+
|
|
384
|
+
// Handle block comments
|
|
385
|
+
if (inBlockComment) {
|
|
386
|
+
commentLines++;
|
|
387
|
+
if (commentSyntax.block.end.test(trimmed)) {
|
|
388
|
+
inBlockComment = false;
|
|
389
|
+
}
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (commentSyntax.block.start.test(trimmed)) {
|
|
394
|
+
commentLines++;
|
|
395
|
+
const delimLen = commentSyntax.block.len || 2;
|
|
396
|
+
if (!commentSyntax.block.end.test(trimmed.substring(trimmed.search(commentSyntax.block.start) + delimLen))) {
|
|
397
|
+
inBlockComment = true;
|
|
398
|
+
}
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Handle line comments
|
|
403
|
+
if (commentSyntax.line.test(trimmed)) {
|
|
404
|
+
commentLines++;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// It's code (may have trailing comment, but primary purpose is code)
|
|
409
|
+
codeLines++;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Skip if function is too small
|
|
413
|
+
if (codeLines < minCodeLines) continue;
|
|
414
|
+
|
|
415
|
+
const ratio = commentLines / codeLines;
|
|
416
|
+
if (ratio > maxCommentRatio) {
|
|
417
|
+
// Line number is 1-indexed: count newlines before match + 1
|
|
418
|
+
const lineNumber = countNewlines(content.substring(0, match.index)) + 1;
|
|
419
|
+
violations.push({
|
|
420
|
+
line: lineNumber,
|
|
421
|
+
commentLines,
|
|
422
|
+
codeLines,
|
|
423
|
+
ratio: parseFloat(ratio.toFixed(2))
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return violations;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ============================================================================
|
|
432
|
+
// Over-Engineering Detection
|
|
433
|
+
// ============================================================================
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Standard entry points per language ecosystem
|
|
437
|
+
* Libraries typically re-export from these files
|
|
438
|
+
*/
|
|
439
|
+
const ENTRY_POINTS = [
|
|
440
|
+
'index.js', 'index.ts', 'src/index.js', 'src/index.ts',
|
|
441
|
+
'lib/index.js', 'lib/index.ts', 'main.js', 'main.ts',
|
|
442
|
+
'lib.rs', 'src/lib.rs',
|
|
443
|
+
'main.go',
|
|
444
|
+
'__init__.py', 'src/__init__.py',
|
|
445
|
+
'Main.java', 'src/Main.java', 'src/main/java/Main.java',
|
|
446
|
+
'Application.java', 'src/main/java/Application.java',
|
|
447
|
+
'App.java', 'src/main/java/App.java'
|
|
448
|
+
];
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Export patterns per language (used by countExportsInContent)
|
|
452
|
+
*/
|
|
453
|
+
const EXPORT_PATTERNS = {
|
|
454
|
+
js: [
|
|
455
|
+
/export\s+(function|class|const|let|var|default|async\s+function)/g,
|
|
456
|
+
/export\s*\{[^}]+\}/g, // Named re-exports: export { Foo, Bar }
|
|
457
|
+
/export\s*\*\s*(as\s+\w+\s+)?from/g, // Star re-exports: export * from './foo'
|
|
458
|
+
/module\.exports\s*=/g,
|
|
459
|
+
/exports\.\w+\s*=/g
|
|
460
|
+
],
|
|
461
|
+
rust: [
|
|
462
|
+
/^pub\s+(fn|struct|enum|mod|type|trait|const|static)/gm
|
|
463
|
+
],
|
|
464
|
+
go: [
|
|
465
|
+
/^func\s+[A-Z]/gm,
|
|
466
|
+
/^type\s+[A-Z]\w*\s+(struct|interface)/gm,
|
|
467
|
+
/^var\s+[A-Z]/gm,
|
|
468
|
+
/^const\s+[A-Z]/gm
|
|
469
|
+
],
|
|
470
|
+
python: [
|
|
471
|
+
/__all__\s*=\s*\[/g,
|
|
472
|
+
/^def\s+(?!_)\w+\s*\(/gm, // Public functions (excludes _private)
|
|
473
|
+
/^class\s+[A-Z]\w*[\s:(]/gm
|
|
474
|
+
],
|
|
475
|
+
java: [
|
|
476
|
+
/^\s*public\s+(?:static\s+)?(?:final\s+)?(?:class|interface|enum)\s+\w+/gm,
|
|
477
|
+
/^\s*public\s+(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:\w+(?:<[^>]*>)?)\s+\w+\s*\(/gm
|
|
478
|
+
]
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Source file extensions per language
|
|
483
|
+
*/
|
|
484
|
+
const SOURCE_EXTENSIONS = {
|
|
485
|
+
js: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'],
|
|
486
|
+
rust: ['.rs'],
|
|
487
|
+
go: ['.go'],
|
|
488
|
+
python: ['.py'],
|
|
489
|
+
java: ['.java']
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Directories to exclude from analysis
|
|
494
|
+
*/
|
|
495
|
+
const EXCLUDE_DIRS = [
|
|
496
|
+
'node_modules', 'vendor', 'dist', 'build', 'out', 'target',
|
|
497
|
+
'.git', '.svn', '.hg', '__pycache__', '.pytest_cache',
|
|
498
|
+
'coverage', '.nyc_output', '.next', '.nuxt', '.cache'
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Parse .gitignore file and return a matcher function
|
|
503
|
+
* @param {string} repoPath - Repository root path
|
|
504
|
+
* @param {Object} fs - File system module
|
|
505
|
+
* @param {Object} path - Path module
|
|
506
|
+
* @returns {Function|null} Matcher function or null if no .gitignore
|
|
507
|
+
*/
|
|
508
|
+
function parseGitignore(repoPath, fs, path) {
|
|
509
|
+
const gitignorePath = path.join(repoPath, '.gitignore');
|
|
510
|
+
|
|
511
|
+
let content;
|
|
512
|
+
try {
|
|
513
|
+
content = fs.readFileSync(gitignorePath, 'utf8');
|
|
514
|
+
} catch {
|
|
515
|
+
return null; // No .gitignore file
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const patterns = content
|
|
519
|
+
.split('\n')
|
|
520
|
+
.map(line => line.trim())
|
|
521
|
+
.filter(line => line && !line.startsWith('#'))
|
|
522
|
+
.map(rawPattern => {
|
|
523
|
+
let pattern = rawPattern;
|
|
524
|
+
|
|
525
|
+
// Track if pattern is negated
|
|
526
|
+
const negated = pattern.startsWith('!');
|
|
527
|
+
if (negated) pattern = pattern.slice(1);
|
|
528
|
+
|
|
529
|
+
// Track if pattern is directory-only
|
|
530
|
+
const dirOnly = pattern.endsWith('/');
|
|
531
|
+
if (dirOnly) pattern = pattern.slice(0, -1);
|
|
532
|
+
|
|
533
|
+
// Track if pattern is anchored (explicit / at start)
|
|
534
|
+
const anchored = pattern.startsWith('/');
|
|
535
|
+
if (anchored) pattern = pattern.slice(1);
|
|
536
|
+
|
|
537
|
+
// Check if pattern starts with ** (matches any leading path)
|
|
538
|
+
const matchesAnywhere = pattern.startsWith('**/');
|
|
539
|
+
|
|
540
|
+
// Convert gitignore pattern to regex
|
|
541
|
+
// Step 1: Replace globstar patterns with placeholders (before escaping)
|
|
542
|
+
let regexStr = pattern
|
|
543
|
+
.replace(/^\*\*\//, '\x00LEADING\x00')
|
|
544
|
+
.replace(/\/\*\*$/, '\x00TRAILING\x00')
|
|
545
|
+
.replace(/\*\*\//g, '\x00ANYPATH\x00')
|
|
546
|
+
.replace(/\/\*\*/g, '\x00ANYPATH2\x00')
|
|
547
|
+
.replace(/\*\*/g, '\x00STAR2\x00');
|
|
548
|
+
|
|
549
|
+
// Step 2: Escape special regex chars (except * and ?) and handle remaining globs
|
|
550
|
+
regexStr = regexStr
|
|
551
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
552
|
+
.replace(/\*/g, '[^/]*')
|
|
553
|
+
.replace(/\?/g, '[^/]');
|
|
554
|
+
|
|
555
|
+
// Step 3: Restore globstar patterns with proper regex
|
|
556
|
+
regexStr = regexStr
|
|
557
|
+
.replace(/\x00LEADING\x00/g, '(?:.*/)?')
|
|
558
|
+
.replace(/\x00TRAILING\x00/g, '(?:/.*)?')
|
|
559
|
+
.replace(/\x00ANYPATH\x00/g, '(?:.*/)?')
|
|
560
|
+
.replace(/\x00ANYPATH2\x00/g, '(?:/.*)?')
|
|
561
|
+
.replace(/\x00STAR2\x00/g, '.*');
|
|
562
|
+
|
|
563
|
+
// Pattern matching rules:
|
|
564
|
+
// - Anchored (starts with /): match from root only
|
|
565
|
+
// - Starts with **: match anywhere (leading ** already handled in regex)
|
|
566
|
+
// - Contains /: match relative to root
|
|
567
|
+
// - Simple name: match anywhere in path
|
|
568
|
+
if (anchored) {
|
|
569
|
+
regexStr = '^' + regexStr;
|
|
570
|
+
} else if (matchesAnywhere) {
|
|
571
|
+
// Leading ** already allows matching anywhere via (?:.*/)? prefix
|
|
572
|
+
regexStr = '^' + regexStr;
|
|
573
|
+
} else if (pattern.includes('/')) {
|
|
574
|
+
regexStr = '^' + regexStr;
|
|
575
|
+
} else {
|
|
576
|
+
// Simple patterns match anywhere
|
|
577
|
+
regexStr = '(?:^|/)' + regexStr;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
regex: new RegExp(regexStr + '(?:$|/)'),
|
|
582
|
+
negated,
|
|
583
|
+
dirOnly
|
|
584
|
+
};
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
return function isIgnored(relativePath, isDirectory = false) {
|
|
588
|
+
// Normalize path separators
|
|
589
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
590
|
+
let ignored = false;
|
|
591
|
+
|
|
592
|
+
for (const { regex, negated, dirOnly } of patterns) {
|
|
593
|
+
// Skip directory-only patterns for files
|
|
594
|
+
if (dirOnly && !isDirectory) continue;
|
|
595
|
+
|
|
596
|
+
if (regex.test(normalized)) {
|
|
597
|
+
ignored = !negated;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return ignored;
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Detect language from file extension
|
|
607
|
+
* @param {string} filePath - Path to file
|
|
608
|
+
* @returns {string} Language key (js, rust, go, python)
|
|
609
|
+
*/
|
|
610
|
+
function detectLanguage(filePath) {
|
|
611
|
+
const ext = filePath.substring(filePath.lastIndexOf('.'));
|
|
612
|
+
for (const [lang, exts] of Object.entries(SOURCE_EXTENSIONS)) {
|
|
613
|
+
if (exts.includes(ext)) return lang;
|
|
614
|
+
}
|
|
615
|
+
return 'js'; // Default to JS patterns
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Count exports in file content based on language
|
|
620
|
+
* @param {string} content - File content
|
|
621
|
+
* @param {string} lang - Language key
|
|
622
|
+
* @returns {number} Number of exports detected
|
|
623
|
+
*/
|
|
624
|
+
function countExportsInContent(content, lang) {
|
|
625
|
+
const patterns = EXPORT_PATTERNS[lang] || EXPORT_PATTERNS.js;
|
|
626
|
+
let count = 0;
|
|
627
|
+
|
|
628
|
+
for (const pattern of patterns) {
|
|
629
|
+
// Clone pattern to reset lastIndex
|
|
630
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
631
|
+
const matches = content.match(regex);
|
|
632
|
+
if (matches) count += matches.length;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return count;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Check if path should be excluded from analysis
|
|
640
|
+
* @param {string} filePath - Path to check
|
|
641
|
+
* @param {string[]} excludeDirs - Directories to exclude
|
|
642
|
+
* @returns {boolean} True if should be excluded
|
|
643
|
+
*/
|
|
644
|
+
function shouldExclude(filePath, excludeDirs = EXCLUDE_DIRS) {
|
|
645
|
+
const parts = filePath.split(/[\\/]/);
|
|
646
|
+
return parts.some(part => excludeDirs.includes(part));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Check if file is a test file
|
|
651
|
+
* @param {string} filePath - Path to check
|
|
652
|
+
* @returns {boolean} True if test file
|
|
653
|
+
*/
|
|
654
|
+
function isTestFile(filePath) {
|
|
655
|
+
const testPatterns = [
|
|
656
|
+
/\.test\.[jt]sx?$/,
|
|
657
|
+
/\.spec\.[jt]sx?$/,
|
|
658
|
+
/_tests?\.(go|rs|py)$/,
|
|
659
|
+
/test_.*\.py$/,
|
|
660
|
+
/__tests__/,
|
|
661
|
+
/tests?\//i
|
|
662
|
+
];
|
|
663
|
+
return testPatterns.some(p => p.test(filePath));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Count source files in directory (recursive, excludes tests/vendor by default)
|
|
668
|
+
*
|
|
669
|
+
* @param {string} repoPath - Repository root path
|
|
670
|
+
* @param {Object} options - Options
|
|
671
|
+
* @param {Function} options.readdir - Directory reader (for testing)
|
|
672
|
+
* @param {Function} options.stat - Stat function (for testing)
|
|
673
|
+
* @param {number} options.maxFiles - Maximum files to count (default 10000)
|
|
674
|
+
* @param {boolean} options.includeTests - Include test files (default false)
|
|
675
|
+
* @param {boolean} options.respectGitignore - Respect .gitignore patterns (default true)
|
|
676
|
+
* @returns {Object} { count, files[] }
|
|
677
|
+
*/
|
|
678
|
+
function countSourceFiles(repoPath, options = {}) {
|
|
679
|
+
const fs = options.fs || require('fs');
|
|
680
|
+
const path = options.path || require('path');
|
|
681
|
+
const maxFiles = options.maxFiles || 10000;
|
|
682
|
+
const includeTests = options.includeTests || false;
|
|
683
|
+
const respectGitignore = options.respectGitignore !== false;
|
|
684
|
+
|
|
685
|
+
const files = [];
|
|
686
|
+
let count = 0;
|
|
687
|
+
// Pre-compute extension list for performance (avoid recalculation in loop)
|
|
688
|
+
const allExts = Object.values(SOURCE_EXTENSIONS).flat();
|
|
689
|
+
|
|
690
|
+
// Parse .gitignore if enabled
|
|
691
|
+
const isIgnored = respectGitignore ? parseGitignore(repoPath, fs, path) : null;
|
|
692
|
+
|
|
693
|
+
function walk(dir, depth = 0) {
|
|
694
|
+
if (count >= maxFiles) return;
|
|
695
|
+
if (depth > 10) return; // Prevent infinite recursion
|
|
696
|
+
|
|
697
|
+
let entries;
|
|
698
|
+
try {
|
|
699
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
700
|
+
} catch {
|
|
701
|
+
return; // Skip unreadable directories
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
for (const entry of entries) {
|
|
705
|
+
if (count >= maxFiles) break;
|
|
706
|
+
|
|
707
|
+
const fullPath = path.join(dir, entry.name);
|
|
708
|
+
const relativePath = path.relative(repoPath, fullPath);
|
|
709
|
+
|
|
710
|
+
if (shouldExclude(relativePath)) continue;
|
|
711
|
+
|
|
712
|
+
// Check gitignore
|
|
713
|
+
if (isIgnored && isIgnored(relativePath, entry.isDirectory())) continue;
|
|
714
|
+
|
|
715
|
+
if (entry.isDirectory()) {
|
|
716
|
+
walk(fullPath, depth + 1);
|
|
717
|
+
} else if (entry.isFile()) {
|
|
718
|
+
const ext = path.extname(entry.name);
|
|
719
|
+
|
|
720
|
+
if (allExts.includes(ext) && (includeTests || !isTestFile(relativePath))) {
|
|
721
|
+
files.push(relativePath);
|
|
722
|
+
count++;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
walk(repoPath);
|
|
729
|
+
return { count, files };
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Count source lines (excluding comments and blanks)
|
|
734
|
+
*
|
|
735
|
+
* Uses simple heuristics - not a full parser but good enough for metrics.
|
|
736
|
+
* Reads files asynchronously to avoid blocking I/O (PERF-007).
|
|
737
|
+
*
|
|
738
|
+
* @param {string} repoPath - Repository root path
|
|
739
|
+
* @param {Object} options - Options
|
|
740
|
+
* @param {string[]} options.files - Files to count (from countSourceFiles)
|
|
741
|
+
* @param {Object} options.fs - File system module (for testing)
|
|
742
|
+
* @returns {Promise<number>} Total source lines
|
|
743
|
+
*/
|
|
744
|
+
async function countSourceLines(repoPath, options = {}) {
|
|
745
|
+
const fs = options.fs || require('fs');
|
|
746
|
+
const fsPromises = fs.promises || require('fs').promises;
|
|
747
|
+
const path = options.path || require('path');
|
|
748
|
+
const files = options.files || countSourceFiles(repoPath, options).files;
|
|
749
|
+
|
|
750
|
+
// Process files in parallel batches to avoid overwhelming the system
|
|
751
|
+
const BATCH_SIZE = 50;
|
|
752
|
+
let totalLines = 0;
|
|
753
|
+
|
|
754
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
755
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
756
|
+
const results = await Promise.all(
|
|
757
|
+
batch.map(async (file) => {
|
|
758
|
+
try {
|
|
759
|
+
const content = await fsPromises.readFile(path.join(repoPath, file), 'utf8');
|
|
760
|
+
return countLinesInContent(content);
|
|
761
|
+
} catch {
|
|
762
|
+
// Skip unreadable files
|
|
763
|
+
return 0;
|
|
764
|
+
}
|
|
765
|
+
})
|
|
766
|
+
);
|
|
767
|
+
totalLines += results.reduce((sum, count) => sum + count, 0);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return totalLines;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Count source lines in file content (excluding comments and blanks)
|
|
775
|
+
*
|
|
776
|
+
* @param {string} content - File content
|
|
777
|
+
* @returns {number} Source line count
|
|
778
|
+
*/
|
|
779
|
+
function countLinesInContent(content) {
|
|
780
|
+
const lines = content.split('\n');
|
|
781
|
+
let count = 0;
|
|
782
|
+
let inBlockComment = false;
|
|
783
|
+
|
|
784
|
+
for (const line of lines) {
|
|
785
|
+
const trimmed = line.trim();
|
|
786
|
+
|
|
787
|
+
// Skip empty lines
|
|
788
|
+
if (!trimmed) continue;
|
|
789
|
+
|
|
790
|
+
// Process line for block comments (handles inline and multi-line)
|
|
791
|
+
let processedLine = trimmed;
|
|
792
|
+
|
|
793
|
+
// Handle block comment state transitions
|
|
794
|
+
if (inBlockComment) {
|
|
795
|
+
const endIdx = processedLine.indexOf('*/');
|
|
796
|
+
if (endIdx !== -1) {
|
|
797
|
+
// Comment ends on this line - keep anything after */
|
|
798
|
+
inBlockComment = false;
|
|
799
|
+
processedLine = processedLine.substring(endIdx + 2).trim();
|
|
800
|
+
} else {
|
|
801
|
+
// Still in block comment
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Check for block comment start (may also end on same line)
|
|
807
|
+
const startIdx = processedLine.indexOf('/*');
|
|
808
|
+
if (startIdx !== -1) {
|
|
809
|
+
const beforeComment = processedLine.substring(0, startIdx).trim();
|
|
810
|
+
const afterStart = processedLine.substring(startIdx + 2);
|
|
811
|
+
const endIdx = afterStart.indexOf('*/');
|
|
812
|
+
|
|
813
|
+
if (endIdx !== -1) {
|
|
814
|
+
// Single-line block comment: /* ... */
|
|
815
|
+
processedLine = beforeComment + ' ' + afterStart.substring(endIdx + 2).trim();
|
|
816
|
+
processedLine = processedLine.trim();
|
|
817
|
+
} else {
|
|
818
|
+
// Block comment starts but doesn't end
|
|
819
|
+
inBlockComment = true;
|
|
820
|
+
processedLine = beforeComment;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Skip if nothing left after removing comments
|
|
825
|
+
if (!processedLine) continue;
|
|
826
|
+
|
|
827
|
+
// Skip single-line comments
|
|
828
|
+
if (processedLine.startsWith('//') || processedLine.startsWith('#')) continue;
|
|
829
|
+
|
|
830
|
+
// Skip Python/Rust doc comments that span the whole line
|
|
831
|
+
if (processedLine.startsWith('///') || processedLine.startsWith('"""') || processedLine.startsWith("'''")) continue;
|
|
832
|
+
|
|
833
|
+
count++;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
return count;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Count exports from entry points
|
|
841
|
+
*
|
|
842
|
+
* Scans standard entry points (index.js, lib.rs, etc.) for export statements.
|
|
843
|
+
* Falls back to scanning all src/ if no entry points found.
|
|
844
|
+
*
|
|
845
|
+
* @param {string} repoPath - Repository root path
|
|
846
|
+
* @param {Object} options - Options
|
|
847
|
+
* @param {Function} options.readFile - File reader (for testing)
|
|
848
|
+
* @returns {Object} { count, method, entryPoints[] }
|
|
849
|
+
*/
|
|
850
|
+
function countEntryPointExports(repoPath, options = {}) {
|
|
851
|
+
const fs = options.fs || require('fs');
|
|
852
|
+
const path = options.path || require('path');
|
|
853
|
+
|
|
854
|
+
const foundEntries = [];
|
|
855
|
+
let count = 0;
|
|
856
|
+
|
|
857
|
+
// Try standard entry points
|
|
858
|
+
for (const entry of ENTRY_POINTS) {
|
|
859
|
+
const fullPath = path.join(repoPath, entry);
|
|
860
|
+
try {
|
|
861
|
+
const stat = fs.statSync(fullPath);
|
|
862
|
+
if (stat.isFile()) {
|
|
863
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
864
|
+
const lang = detectLanguage(entry);
|
|
865
|
+
const exports = countExportsInContent(content, lang);
|
|
866
|
+
if (exports > 0) {
|
|
867
|
+
foundEntries.push(entry);
|
|
868
|
+
count += exports;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} catch {
|
|
872
|
+
// File doesn't exist, try next
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (count > 0) {
|
|
877
|
+
return { count, method: 'entry-points', entryPoints: foundEntries };
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Fallback: scan src/ for all exports
|
|
881
|
+
const srcDir = path.join(repoPath, 'src');
|
|
882
|
+
try {
|
|
883
|
+
const srcStat = fs.statSync(srcDir);
|
|
884
|
+
if (srcStat.isDirectory()) {
|
|
885
|
+
const { files } = countSourceFiles(srcDir, options);
|
|
886
|
+
for (const file of files) {
|
|
887
|
+
try {
|
|
888
|
+
const content = fs.readFileSync(path.join(srcDir, file), 'utf8');
|
|
889
|
+
const lang = detectLanguage(file);
|
|
890
|
+
count += countExportsInContent(content, lang);
|
|
891
|
+
} catch {
|
|
892
|
+
// Skip unreadable
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (count > 0) {
|
|
896
|
+
return { count, method: 'src-scan', entryPoints: ['src/'] };
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} catch {
|
|
900
|
+
// No src/ directory
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Final fallback
|
|
904
|
+
return { count: 1, method: 'fallback', entryPoints: [] };
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Get maximum directory depth in a path
|
|
909
|
+
*
|
|
910
|
+
* @param {string} repoPath - Repository root path
|
|
911
|
+
* @param {string} startDir - Directory to start from (e.g., 'src')
|
|
912
|
+
* @param {Object} options - Options
|
|
913
|
+
* @returns {number} Maximum depth (0 if startDir doesn't exist)
|
|
914
|
+
*/
|
|
915
|
+
function getMaxDirectoryDepth(repoPath, startDir = 'src', options = {}) {
|
|
916
|
+
const fs = options.fs || require('fs');
|
|
917
|
+
const path = options.path || require('path');
|
|
918
|
+
|
|
919
|
+
const rootDir = path.join(repoPath, startDir);
|
|
920
|
+
let maxDepth = 0;
|
|
921
|
+
|
|
922
|
+
function walk(dir, depth) {
|
|
923
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
924
|
+
if (depth > 20) return; // Safety limit
|
|
925
|
+
|
|
926
|
+
try {
|
|
927
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
928
|
+
for (const entry of entries) {
|
|
929
|
+
if (entry.isDirectory() && !shouldExclude(entry.name)) {
|
|
930
|
+
walk(path.join(dir, entry.name), depth + 1);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
} catch {
|
|
934
|
+
// Skip unreadable
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
try {
|
|
939
|
+
const stat = fs.statSync(rootDir);
|
|
940
|
+
if (stat.isDirectory()) {
|
|
941
|
+
walk(rootDir, 1);
|
|
942
|
+
}
|
|
943
|
+
} catch {
|
|
944
|
+
return 0;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
return maxDepth;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Analyze over-engineering metrics for a repository
|
|
952
|
+
*
|
|
953
|
+
* Detects three signals of over-engineering:
|
|
954
|
+
* 1. File-to-export ratio > 20x
|
|
955
|
+
* 2. Lines-per-export > 500:1
|
|
956
|
+
* 3. Directory depth > 4 levels
|
|
957
|
+
*
|
|
958
|
+
* @param {string} repoPath - Repository root path
|
|
959
|
+
* @param {Object} options - Analysis options
|
|
960
|
+
* @param {number} [options.fileRatioThreshold=20] - Max files per export
|
|
961
|
+
* @param {number} [options.linesPerExportThreshold=500] - Max lines per export
|
|
962
|
+
* @param {number} [options.depthThreshold=4] - Max directory depth
|
|
963
|
+
* @returns {Promise<Object>} Analysis results with violations
|
|
964
|
+
*/
|
|
965
|
+
async function analyzeOverEngineering(repoPath, options = {}) {
|
|
966
|
+
const fileRatioThreshold = options.fileRatioThreshold || 20;
|
|
967
|
+
const linesPerExportThreshold = options.linesPerExportThreshold || 500;
|
|
968
|
+
const depthThreshold = options.depthThreshold || 4;
|
|
969
|
+
|
|
970
|
+
const violations = [];
|
|
971
|
+
|
|
972
|
+
// Count source files
|
|
973
|
+
const { count: sourceFileCount, files } = countSourceFiles(repoPath, options);
|
|
974
|
+
|
|
975
|
+
// Count exports from entry points
|
|
976
|
+
const { count: exportCount, method: exportMethod, entryPoints } = countEntryPointExports(repoPath, options);
|
|
977
|
+
|
|
978
|
+
// Calculate file-to-export ratio
|
|
979
|
+
const fileRatio = sourceFileCount / Math.max(exportCount, 1);
|
|
980
|
+
if (fileRatio > fileRatioThreshold) {
|
|
981
|
+
violations.push({
|
|
982
|
+
type: 'file_proliferation',
|
|
983
|
+
value: `${sourceFileCount} files / ${exportCount} exports = ${fileRatio.toFixed(1)}x`,
|
|
984
|
+
threshold: `${fileRatioThreshold}x`,
|
|
985
|
+
severity: fileRatio > fileRatioThreshold * 2 ? 'high' : 'medium',
|
|
986
|
+
details: { sourceFileCount, exportCount, fileRatio, exportMethod }
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// Count source lines (async to avoid blocking I/O - PERF-007)
|
|
991
|
+
const totalLines = await countSourceLines(repoPath, { ...options, files });
|
|
992
|
+
|
|
993
|
+
// Calculate lines-per-export ratio
|
|
994
|
+
const linesPerExport = totalLines / Math.max(exportCount, 1);
|
|
995
|
+
if (linesPerExport > linesPerExportThreshold) {
|
|
996
|
+
violations.push({
|
|
997
|
+
type: 'code_density',
|
|
998
|
+
value: `${totalLines} lines / ${exportCount} exports = ${Math.round(linesPerExport)}:1`,
|
|
999
|
+
threshold: `${linesPerExportThreshold}:1`,
|
|
1000
|
+
severity: linesPerExport > linesPerExportThreshold * 2 ? 'high' : 'medium',
|
|
1001
|
+
details: { totalLines, exportCount, linesPerExport }
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// Get directory depth
|
|
1006
|
+
const maxDepth = getMaxDirectoryDepth(repoPath, 'src', options);
|
|
1007
|
+
if (maxDepth > depthThreshold) {
|
|
1008
|
+
violations.push({
|
|
1009
|
+
type: 'directory_depth',
|
|
1010
|
+
value: `${maxDepth} levels`,
|
|
1011
|
+
threshold: `${depthThreshold} levels`,
|
|
1012
|
+
severity: maxDepth > depthThreshold + 2 ? 'high' : 'medium',
|
|
1013
|
+
details: { maxDepth }
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
return {
|
|
1018
|
+
metrics: {
|
|
1019
|
+
sourceFiles: sourceFileCount,
|
|
1020
|
+
exports: exportCount,
|
|
1021
|
+
exportMethod,
|
|
1022
|
+
entryPoints,
|
|
1023
|
+
totalLines,
|
|
1024
|
+
directoryDepth: maxDepth,
|
|
1025
|
+
fileRatio: parseFloat(fileRatio.toFixed(2)),
|
|
1026
|
+
linesPerExport: Math.round(linesPerExport)
|
|
1027
|
+
},
|
|
1028
|
+
violations,
|
|
1029
|
+
verdict: violations.length > 0
|
|
1030
|
+
? (violations.some(v => v.severity === 'high') ? 'HIGH' : 'MEDIUM')
|
|
1031
|
+
: 'OK'
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// ============================================================================
|
|
1036
|
+
// Infrastructure Without Implementation Detection
|
|
1037
|
+
// Detects infrastructure components that are set up but never used
|
|
1038
|
+
// ============================================================================
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Common infrastructure component suffixes that indicate setup/configuration
|
|
1042
|
+
* These naming patterns typically indicate infrastructure components
|
|
1043
|
+
*/
|
|
1044
|
+
const INFRASTRUCTURE_SUFFIXES = [
|
|
1045
|
+
'Client', 'Connection', 'Pool', 'Service', 'Provider',
|
|
1046
|
+
'Manager', 'Factory', 'Repository', 'Gateway', 'Adapter',
|
|
1047
|
+
'Handler', 'Broker', 'Queue', 'Cache', 'Store',
|
|
1048
|
+
'Transport', 'Channel', 'Socket', 'Server', 'Database'
|
|
1049
|
+
];
|
|
1050
|
+
|
|
1051
|
+
// Pattern for detecting overly generic variable names to skip
|
|
1052
|
+
const GENERIC_VAR_PATTERN = /^[ijkxy]$/;
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Common setup/initialization verbs that indicate infrastructure creation
|
|
1056
|
+
*/
|
|
1057
|
+
const SETUP_VERBS = [
|
|
1058
|
+
'create', 'connect', 'init', 'initialize', 'setup',
|
|
1059
|
+
'configure', 'establish', 'open', 'start', 'new',
|
|
1060
|
+
'build', 'make', 'construct', 'instantiate', 'spawn'
|
|
1061
|
+
];
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Language-specific patterns for instantiation/initialization
|
|
1065
|
+
* These patterns detect when infrastructure components are created
|
|
1066
|
+
*/
|
|
1067
|
+
const INSTANTIATION_PATTERNS = {
|
|
1068
|
+
js: [
|
|
1069
|
+
// new Class() instantiation
|
|
1070
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*new\s+(\w+(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))/g,
|
|
1071
|
+
// Factory/builder pattern: createXxx(), Xxx.create()
|
|
1072
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:await\s+)?(?:create|connect|init|initialize|setup)(\w+)/gi,
|
|
1073
|
+
// Method call pattern: thing.connect(), thing.initialize()
|
|
1074
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:await\s+)?\w+\.(?:create|connect|init|initialize|setup|open|start)\(/gi
|
|
1075
|
+
],
|
|
1076
|
+
python: [
|
|
1077
|
+
// Class instantiation: client = SomeClient()
|
|
1078
|
+
/(\w+)\s*=\s*(\w+(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))\(/gm,
|
|
1079
|
+
// Module.Class pattern: client = module.RedisClient()
|
|
1080
|
+
/(\w+)\s*=\s*\w+\.(\w+(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))\(/gm,
|
|
1081
|
+
// Factory pattern: client = create_client()
|
|
1082
|
+
/(\w+)\s*=\s*(?:create|connect|init|initialize|setup)_(\w+)\(/gm,
|
|
1083
|
+
// Async patterns: client = await create_client()
|
|
1084
|
+
/(\w+)\s*=\s*await\s+(?:create|connect|init|initialize|setup)_(\w+)\(/gm
|
|
1085
|
+
],
|
|
1086
|
+
go: [
|
|
1087
|
+
// New* function pattern: client := NewClient()
|
|
1088
|
+
/(\w+)\s*:=\s*(?:New|Create|Connect|Init|Setup)(\w+)\(/g,
|
|
1089
|
+
// Module.New* pattern: client := redis.NewClient()
|
|
1090
|
+
/(\w+)\s*:=\s*\w+\.(?:New|Create|Connect|Init|Setup)(\w+)\(/g,
|
|
1091
|
+
// Variable declaration: var client = NewClient()
|
|
1092
|
+
/var\s+(\w+)\s+.*=\s*(?:New|Create|Connect|Init|Setup)(\w+)\(/g,
|
|
1093
|
+
// Struct literal with suffix: client := &RedisClient{}
|
|
1094
|
+
/(\w+)\s*:=\s*&(\w+(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))\{/g
|
|
1095
|
+
],
|
|
1096
|
+
rust: [
|
|
1097
|
+
// ::new() constructor: let client = Client::new()
|
|
1098
|
+
/let\s+(?:mut\s+)?(\w+)\s*=\s*(\w*(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))::(?:new|create|connect|init|build)\(/g,
|
|
1099
|
+
// Builder pattern: let client = ClientBuilder::new().build()
|
|
1100
|
+
/let\s+(?:mut\s+)?(\w+)\s*=\s*(\w+Builder)::new\(\).*\.build\(\)/g,
|
|
1101
|
+
// From/into patterns: let client = Client::from()
|
|
1102
|
+
/let\s+(?:mut\s+)?(\w+)\s*=\s*(\w*(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))::from/g
|
|
1103
|
+
],
|
|
1104
|
+
java: [
|
|
1105
|
+
// Field/local var: Client client = new Client()
|
|
1106
|
+
/(?:\w+(?:<[^>]*>)?)\s+(\w+)\s*=\s*new\s+(\w+(?:Client|Connection|Pool|Service|Provider|Manager|Factory|Repository|Gateway|Adapter|Handler|Broker|Queue|Cache|Store|Transport|Channel|Socket|Server|Database))(?:<[^>]*>)?\s*\(/g,
|
|
1107
|
+
// Factory pattern: Client client = ClientFactory.create()
|
|
1108
|
+
/(?:\w+(?:<[^>]*>)?)\s+(\w+)\s*=\s*(\w+(?:Factory|Builder))\.(?:create|build|get|new)\w*\(/g,
|
|
1109
|
+
// Builder pattern: Client client = Client.builder().build()
|
|
1110
|
+
/(?:\w+(?:<[^>]*>)?)\s+(\w+)\s*=\s*(\w+)\.builder\(\).*\.build\(\)/g,
|
|
1111
|
+
// Spring/DI injection via constructor or field
|
|
1112
|
+
/@(?:Autowired|Inject)\s+(?:private\s+)?(?:\w+(?:<[^>]*>)?)\s+(\w+)/g
|
|
1113
|
+
]
|
|
1114
|
+
};
|
|
1115
|
+
|
|
1116
|
+
// ============================================================================
|
|
1117
|
+
// Buzzword Inflation Detection
|
|
1118
|
+
// Detects quality claims in docs/comments without supporting code evidence
|
|
1119
|
+
// ============================================================================
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Default buzzword categories and their associated terms
|
|
1123
|
+
*/
|
|
1124
|
+
const BUZZWORD_CATEGORIES = {
|
|
1125
|
+
production: ['production-ready', 'production-grade', 'prod-ready'],
|
|
1126
|
+
enterprise: ['enterprise-grade', 'enterprise-ready', 'enterprise-class'],
|
|
1127
|
+
security: ['secure', 'secure by default', 'security-focused'],
|
|
1128
|
+
scale: ['scalable', 'high-performance', 'performant', 'highly scalable'],
|
|
1129
|
+
reliability: ['battle-tested', 'robust', 'reliable', 'rock-solid'],
|
|
1130
|
+
completeness: ['comprehensive', 'complete', 'full-featured', 'feature-complete']
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Evidence patterns per buzzword category
|
|
1135
|
+
* Each category maps to evidence types, each with array of regex patterns
|
|
1136
|
+
*/
|
|
1137
|
+
const EVIDENCE_PATTERNS = {
|
|
1138
|
+
production: {
|
|
1139
|
+
tests: [/\.test\.[jt]sx?$|\.spec\.[jt]sx?$|__tests__|test_.*\.py$|_test\.go$|_test\.rs$/],
|
|
1140
|
+
errorHandling: [/try\s*\{|catch\s*\(|\.catch\s*\(|except\s*:|if\s+let\s+Err|match.*Err\(/],
|
|
1141
|
+
logging: [/logger\.|\.log\s*\(|console\.error|tracing::|slog\.|log\.(info|warn|error|debug)/i]
|
|
1142
|
+
},
|
|
1143
|
+
enterprise: {
|
|
1144
|
+
auth: [/authenticat|authorization|permission|rbac|acl|role/i],
|
|
1145
|
+
audit: [/audit|track.*event|event.*log|activity.*log/i],
|
|
1146
|
+
rateLimit: [/rate.?limit|throttle|limiter/i]
|
|
1147
|
+
},
|
|
1148
|
+
security: {
|
|
1149
|
+
validation: [/validat|sanitiz|escape|clean|htmlspecialchars/i],
|
|
1150
|
+
auth: [/\bauth\b|token|jwt|session|login|passport/i],
|
|
1151
|
+
encryption: [/encrypt|decrypt|hash|bcrypt|argon|crypto\./i]
|
|
1152
|
+
},
|
|
1153
|
+
scale: {
|
|
1154
|
+
async: [/async\s+|await\s+|Promise|Future|tokio|async_std|goroutine/],
|
|
1155
|
+
cache: [/\bcache\b|redis|memcache|lru/i],
|
|
1156
|
+
pool: [/pool|connection.?pool|thread.?pool/i]
|
|
1157
|
+
},
|
|
1158
|
+
reliability: {
|
|
1159
|
+
tests: [/\.test\.[jt]sx?$|\.spec\.[jt]sx?$|__tests__|test_.*\.py$|_test\.go$|_test\.rs$/],
|
|
1160
|
+
coverage: [/coverage|lcov|nyc|istanbul|codecov/i],
|
|
1161
|
+
errorHandling: [/try\s*\{|catch\s*\(|\.catch\s*\(|except\s*:|if\s+let\s+Err/]
|
|
1162
|
+
},
|
|
1163
|
+
completeness: {
|
|
1164
|
+
edgeCases: [/edge.?case|boundary|corner.?case/i],
|
|
1165
|
+
errorHandling: [/\b(handle|handles|handled|handling)\s+(all\s+)?(errors?|exceptions?|failures?)\b/i],
|
|
1166
|
+
documentation: [/\/\*\*|\/\/\/|"""|'''/]
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* Patterns indicating a positive claim (not TODO/aspirational)
|
|
1172
|
+
*/
|
|
1173
|
+
const CLAIM_INDICATORS = [
|
|
1174
|
+
/\bis\s+/i, // "is secure"
|
|
1175
|
+
/\bare\s+/i, // "are production-ready"
|
|
1176
|
+
/\bprovides?\s+/i, // "provides secure"
|
|
1177
|
+
/\boffers?\s+/i, // "offers robust"
|
|
1178
|
+
/\bfeatures?\s+/i, // "features comprehensive"
|
|
1179
|
+
/\bfully\s+/i, // "fully production-ready"
|
|
1180
|
+
/\b100%\s+/i, // "100% secure"
|
|
1181
|
+
/\bdesigned\s+(for|to\s+be)\s+/i // "designed for security"
|
|
1182
|
+
];
|
|
1183
|
+
|
|
1184
|
+
/**
|
|
1185
|
+
* Patterns indicating NOT a claim (aspirational/TODO)
|
|
1186
|
+
*/
|
|
1187
|
+
const NOT_CLAIM_INDICATORS = [
|
|
1188
|
+
/\bTODO\b/i,
|
|
1189
|
+
/\bFIXME\b/i,
|
|
1190
|
+
/\bshould\s+be\b/i,
|
|
1191
|
+
/\bwill\s+be\b/i,
|
|
1192
|
+
/\bmake\s+(?:it\s+(?:more|less|better)|this\b)/i,
|
|
1193
|
+
/\bneed(s)?\s+to\s+be\b/i,
|
|
1194
|
+
/\bplan(ning)?\s+to\b/i,
|
|
1195
|
+
/\bwant(s)?\s+to\b/i
|
|
1196
|
+
];
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Escape regex special characters in a string
|
|
1200
|
+
* @param {string} str - String to escape
|
|
1201
|
+
* @returns {string} Escaped string safe for regex
|
|
1202
|
+
*/
|
|
1203
|
+
function escapeRegex(str) {
|
|
1204
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Extract buzzword claims from file content
|
|
1209
|
+
*
|
|
1210
|
+
* @param {string} content - File content
|
|
1211
|
+
* @param {string} filePath - Path to file (for reporting)
|
|
1212
|
+
* @param {Object} buzzwordCategories - Buzzword category mappings
|
|
1213
|
+
* @returns {Array<Object>} Array of claims with line, buzzword, category, isPositiveClaim
|
|
1214
|
+
*/
|
|
1215
|
+
function extractClaims(content, filePath, buzzwordCategories = BUZZWORD_CATEGORIES) {
|
|
1216
|
+
const claims = [];
|
|
1217
|
+
const lines = content.split('\n');
|
|
1218
|
+
|
|
1219
|
+
// Build single regex from all buzzwords and reverse map for category lookup
|
|
1220
|
+
const allBuzzwords = [];
|
|
1221
|
+
const buzzwordToCategory = new Map();
|
|
1222
|
+
for (const [category, buzzwords] of Object.entries(buzzwordCategories)) {
|
|
1223
|
+
for (const buzzword of buzzwords) {
|
|
1224
|
+
allBuzzwords.push(escapeRegex(buzzword));
|
|
1225
|
+
buzzwordToCategory.set(buzzword.toLowerCase(), { category, buzzword });
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
const combinedRegex = new RegExp(`\\b(${allBuzzwords.join('|')})\\b`, 'gi');
|
|
1229
|
+
|
|
1230
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1231
|
+
const line = lines[i];
|
|
1232
|
+
|
|
1233
|
+
// Find all buzzword matches in this line
|
|
1234
|
+
const matches = [...line.matchAll(combinedRegex)];
|
|
1235
|
+
if (matches.length === 0) continue;
|
|
1236
|
+
|
|
1237
|
+
// Check claim indicators once per line (only if matches found)
|
|
1238
|
+
const hasNotClaimIndicator = NOT_CLAIM_INDICATORS.some(p => p.test(line));
|
|
1239
|
+
const hasClaimIndicator = CLAIM_INDICATORS.some(p => p.test(line));
|
|
1240
|
+
const isPositiveClaim = hasClaimIndicator && !hasNotClaimIndicator;
|
|
1241
|
+
|
|
1242
|
+
for (const match of matches) {
|
|
1243
|
+
const matchedText = match[1].toLowerCase();
|
|
1244
|
+
const mapping = buzzwordToCategory.get(matchedText);
|
|
1245
|
+
if (!mapping) continue;
|
|
1246
|
+
|
|
1247
|
+
claims.push({
|
|
1248
|
+
line: i + 1,
|
|
1249
|
+
column: match.index,
|
|
1250
|
+
buzzword: mapping.buzzword,
|
|
1251
|
+
category: mapping.category,
|
|
1252
|
+
text: line.trim(),
|
|
1253
|
+
isPositiveClaim,
|
|
1254
|
+
filePath
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
return claims;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Find files that may contain claims (docs, READMEs, code with comments)
|
|
1264
|
+
*
|
|
1265
|
+
* @param {string} repoPath - Repository root path
|
|
1266
|
+
* @param {Object} options - Options with fs/path overrides
|
|
1267
|
+
* @returns {Array<string>} Array of relative file paths
|
|
1268
|
+
*/
|
|
1269
|
+
function findClaimSourceFiles(repoPath, options = {}) {
|
|
1270
|
+
const fs = options.fs || require('fs');
|
|
1271
|
+
const path = options.path || require('path');
|
|
1272
|
+
|
|
1273
|
+
const files = [];
|
|
1274
|
+
const docPatterns = [
|
|
1275
|
+
/README/i,
|
|
1276
|
+
/\.md$/,
|
|
1277
|
+
/docs?\//i,
|
|
1278
|
+
/\.rst$/,
|
|
1279
|
+
/CHANGELOG/i,
|
|
1280
|
+
/\.[jt]sx?$/, // JS/TS files (JSDoc comments)
|
|
1281
|
+
/\.py$/, // Python (docstrings)
|
|
1282
|
+
/\.rs$/, // Rust (doc comments)
|
|
1283
|
+
/\.go$/ // Go (doc comments)
|
|
1284
|
+
];
|
|
1285
|
+
|
|
1286
|
+
function walk(dir, depth = 0) {
|
|
1287
|
+
if (depth > 5) return; // Limit depth
|
|
1288
|
+
if (files.length > 500) return; // Limit file count
|
|
1289
|
+
|
|
1290
|
+
let entries;
|
|
1291
|
+
try {
|
|
1292
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1293
|
+
} catch {
|
|
1294
|
+
return; // Skip unreadable directories
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
for (const entry of entries) {
|
|
1298
|
+
const fullPath = path.join(dir, entry.name);
|
|
1299
|
+
const relativePath = path.relative(repoPath, fullPath);
|
|
1300
|
+
|
|
1301
|
+
if (shouldExclude(relativePath)) continue;
|
|
1302
|
+
|
|
1303
|
+
if (entry.isDirectory()) {
|
|
1304
|
+
walk(fullPath, depth + 1);
|
|
1305
|
+
} else if (entry.isFile()) {
|
|
1306
|
+
if (docPatterns.some(p => p.test(relativePath))) {
|
|
1307
|
+
files.push(relativePath);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
walk(repoPath);
|
|
1314
|
+
return files;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/**
|
|
1318
|
+
* Check if a regex pattern is for matching file paths (vs file content)
|
|
1319
|
+
* File path patterns typically match file extensions or test directory structures
|
|
1320
|
+
*
|
|
1321
|
+
* @param {RegExp} regex - The pattern to check
|
|
1322
|
+
* @returns {boolean} True if this is a file path pattern
|
|
1323
|
+
*/
|
|
1324
|
+
function isFilePathPattern(regex) {
|
|
1325
|
+
const source = regex.source;
|
|
1326
|
+
// File path patterns match file extensions or test directories
|
|
1327
|
+
return (
|
|
1328
|
+
source.includes('\\.[jt]sx?$') || // .js, .ts, .jsx, .tsx
|
|
1329
|
+
source.includes('\\.py$') || // .py
|
|
1330
|
+
source.includes('\\.go$') || // .go
|
|
1331
|
+
source.includes('\\.rs$') || // .rs
|
|
1332
|
+
source.includes('__tests__') || // Jest test directory
|
|
1333
|
+
source.includes('_test\\.') || // Go/Rust test files
|
|
1334
|
+
source.includes('test_.*\\.') || // Python test files
|
|
1335
|
+
source.includes('\\.spec\\.') // Spec files
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Search for evidence supporting a buzzword category
|
|
1341
|
+
*
|
|
1342
|
+
* @param {string} repoPath - Repository root path
|
|
1343
|
+
* @param {string} category - Buzzword category to search evidence for
|
|
1344
|
+
* @param {Object} evidencePatterns - Evidence patterns mapping
|
|
1345
|
+
* @param {Array<string>} filesToSearch - Files to search
|
|
1346
|
+
* @param {Object} options - Options with fs/path overrides
|
|
1347
|
+
* @returns {Object} Evidence results: { found[], total, categories{} }
|
|
1348
|
+
*/
|
|
1349
|
+
function searchEvidence(repoPath, category, evidencePatterns, filesToSearch, options = {}) {
|
|
1350
|
+
const fs = options.fs || require('fs');
|
|
1351
|
+
const path = options.path || require('path');
|
|
1352
|
+
|
|
1353
|
+
const evidence = {
|
|
1354
|
+
found: [],
|
|
1355
|
+
total: 0,
|
|
1356
|
+
categories: {}
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
// Get evidence patterns for this category
|
|
1360
|
+
const patterns = evidencePatterns[category];
|
|
1361
|
+
if (!patterns) return evidence;
|
|
1362
|
+
|
|
1363
|
+
// Separate path patterns from content patterns for efficiency
|
|
1364
|
+
const pathPatterns = [];
|
|
1365
|
+
const contentPatterns = [];
|
|
1366
|
+
for (const [evidenceType, regexes] of Object.entries(patterns)) {
|
|
1367
|
+
for (const regex of regexes) {
|
|
1368
|
+
if (isFilePathPattern(regex)) {
|
|
1369
|
+
pathPatterns.push({ evidenceType, regex });
|
|
1370
|
+
} else {
|
|
1371
|
+
contentPatterns.push({ evidenceType, regex });
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
for (const file of filesToSearch) {
|
|
1377
|
+
// Check path patterns first (no file read needed)
|
|
1378
|
+
for (const { evidenceType, regex } of pathPatterns) {
|
|
1379
|
+
if (regex.test(file)) {
|
|
1380
|
+
if (!evidence.categories[evidenceType]) {
|
|
1381
|
+
evidence.categories[evidenceType] = [];
|
|
1382
|
+
}
|
|
1383
|
+
if (!evidence.categories[evidenceType].includes(file)) {
|
|
1384
|
+
evidence.categories[evidenceType].push(file);
|
|
1385
|
+
evidence.total++;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
// Only read content if there are content patterns to check
|
|
1391
|
+
if (contentPatterns.length > 0) {
|
|
1392
|
+
let content;
|
|
1393
|
+
try {
|
|
1394
|
+
const fullPath = path.isAbsolute(file) ? file : path.join(repoPath, file);
|
|
1395
|
+
content = fs.readFileSync(fullPath, 'utf8');
|
|
1396
|
+
} catch {
|
|
1397
|
+
continue; // Skip unreadable files
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
for (const { evidenceType, regex } of contentPatterns) {
|
|
1401
|
+
if (regex.test(content)) {
|
|
1402
|
+
if (!evidence.categories[evidenceType]) {
|
|
1403
|
+
evidence.categories[evidenceType] = [];
|
|
1404
|
+
}
|
|
1405
|
+
if (!evidence.categories[evidenceType].includes(file)) {
|
|
1406
|
+
evidence.categories[evidenceType].push(file);
|
|
1407
|
+
evidence.total++;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
evidence.found = Object.keys(evidence.categories);
|
|
1415
|
+
return evidence;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* Detect gaps between claims and evidence
|
|
1420
|
+
*
|
|
1421
|
+
* @param {Array<Object>} claims - Extracted claims
|
|
1422
|
+
* @param {string} repoPath - Repository root path
|
|
1423
|
+
* @param {Object} evidencePatterns - Evidence patterns
|
|
1424
|
+
* @param {number} minEvidenceMatches - Minimum evidence required
|
|
1425
|
+
* @param {Array<string>} filesToSearch - Files to search for evidence
|
|
1426
|
+
* @param {Object} options - Options
|
|
1427
|
+
* @returns {Array<Object>} Violations
|
|
1428
|
+
*/
|
|
1429
|
+
function detectGaps(claims, repoPath, evidencePatterns, minEvidenceMatches, filesToSearch, options = {}) {
|
|
1430
|
+
const violations = [];
|
|
1431
|
+
|
|
1432
|
+
// Cache evidence searches per category (avoid re-searching)
|
|
1433
|
+
const evidenceCache = new Map();
|
|
1434
|
+
|
|
1435
|
+
for (const claim of claims) {
|
|
1436
|
+
// Skip non-positive claims (TODOs, aspirational)
|
|
1437
|
+
if (!claim.isPositiveClaim) continue;
|
|
1438
|
+
|
|
1439
|
+
// Check cache first
|
|
1440
|
+
let evidence = evidenceCache.get(claim.category);
|
|
1441
|
+
if (!evidence) {
|
|
1442
|
+
evidence = searchEvidence(
|
|
1443
|
+
repoPath,
|
|
1444
|
+
claim.category,
|
|
1445
|
+
evidencePatterns,
|
|
1446
|
+
filesToSearch,
|
|
1447
|
+
options
|
|
1448
|
+
);
|
|
1449
|
+
evidenceCache.set(claim.category, evidence);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// Check if sufficient evidence exists
|
|
1453
|
+
if (evidence.total < minEvidenceMatches) {
|
|
1454
|
+
violations.push({
|
|
1455
|
+
type: 'buzzword_inflation',
|
|
1456
|
+
file: claim.filePath,
|
|
1457
|
+
line: claim.line,
|
|
1458
|
+
buzzword: claim.buzzword,
|
|
1459
|
+
category: claim.category,
|
|
1460
|
+
claim: claim.text,
|
|
1461
|
+
evidenceFound: evidence.found,
|
|
1462
|
+
evidenceCount: evidence.total,
|
|
1463
|
+
evidenceRequired: minEvidenceMatches,
|
|
1464
|
+
severity: evidence.total === 0 ? 'high' : 'medium',
|
|
1465
|
+
message: `Claim "${claim.buzzword}" without sufficient evidence (found ${evidence.total}/${minEvidenceMatches} required)`
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
return violations;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* Analyze buzzword inflation - quality claims without supporting code evidence
|
|
1475
|
+
*
|
|
1476
|
+
* Detects claims like "production-ready", "secure", "scalable" in documentation
|
|
1477
|
+
* and comments, then searches for supporting evidence in the codebase.
|
|
1478
|
+
* Flags claims that lack sufficient evidence.
|
|
1479
|
+
*
|
|
1480
|
+
* @param {string} repoPath - Repository root path
|
|
1481
|
+
* @param {Object} options - Analysis options
|
|
1482
|
+
* @param {Object} [options.buzzwordCategories] - Buzzword category mappings
|
|
1483
|
+
* @param {Object} [options.evidencePatterns] - Evidence patterns per category
|
|
1484
|
+
* @param {number} [options.minEvidenceMatches=2] - Minimum evidence matches required
|
|
1485
|
+
* @returns {Object} Analysis results with violations
|
|
1486
|
+
*/
|
|
1487
|
+
function analyzeBuzzwordInflation(repoPath, options = {}) {
|
|
1488
|
+
const fs = options.fs || require('fs');
|
|
1489
|
+
const path = options.path || require('path');
|
|
1490
|
+
|
|
1491
|
+
const buzzwordCategories = options.buzzwordCategories || BUZZWORD_CATEGORIES;
|
|
1492
|
+
const evidencePatterns = options.evidencePatterns || EVIDENCE_PATTERNS;
|
|
1493
|
+
const minEvidenceMatches = options.minEvidenceMatches || 2;
|
|
1494
|
+
|
|
1495
|
+
// Find files that may contain claims
|
|
1496
|
+
const claimSourceFiles = findClaimSourceFiles(repoPath, options);
|
|
1497
|
+
|
|
1498
|
+
// Find all source files for evidence searching (include tests - they're evidence)
|
|
1499
|
+
const { files: sourceFiles } = countSourceFiles(repoPath, { ...options, includeTests: true });
|
|
1500
|
+
|
|
1501
|
+
// Extract all claims from claim source files
|
|
1502
|
+
const allClaims = [];
|
|
1503
|
+
for (const file of claimSourceFiles) {
|
|
1504
|
+
let content;
|
|
1505
|
+
try {
|
|
1506
|
+
content = fs.readFileSync(path.join(repoPath, file), 'utf8');
|
|
1507
|
+
} catch {
|
|
1508
|
+
continue; // Skip unreadable files
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
const claims = extractClaims(content, file, buzzwordCategories);
|
|
1512
|
+
allClaims.push(...claims);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// Detect gaps (claims without evidence)
|
|
1516
|
+
const violations = detectGaps(
|
|
1517
|
+
allClaims,
|
|
1518
|
+
repoPath,
|
|
1519
|
+
evidencePatterns,
|
|
1520
|
+
minEvidenceMatches,
|
|
1521
|
+
sourceFiles,
|
|
1522
|
+
options
|
|
1523
|
+
);
|
|
1524
|
+
|
|
1525
|
+
return {
|
|
1526
|
+
claimsFound: allClaims.length,
|
|
1527
|
+
positiveClaimsFound: allClaims.filter(c => c.isPositiveClaim).length,
|
|
1528
|
+
violations,
|
|
1529
|
+
verdict: violations.length > 0
|
|
1530
|
+
? (violations.some(v => v.severity === 'high') ? 'HIGH' : 'MEDIUM')
|
|
1531
|
+
: 'OK'
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* Analyze infrastructure without implementation - setup without usage
|
|
1537
|
+
*
|
|
1538
|
+
* Detects infrastructure components (clients, connections, pools, services) that are
|
|
1539
|
+
* instantiated/configured but never actually used anywhere in the codebase.
|
|
1540
|
+
* This pattern often indicates dead code or incomplete implementations.
|
|
1541
|
+
*
|
|
1542
|
+
* @param {string} rootPath - Repository root path
|
|
1543
|
+
* @param {Object} options - Analysis options
|
|
1544
|
+
* @param {Array} [options.infrastructureSuffixes] - Component suffixes to detect
|
|
1545
|
+
* @param {Array} [options.setupVerbs] - Setup verbs to detect
|
|
1546
|
+
* @param {Object} [options.instantiationPatterns] - Language-specific patterns
|
|
1547
|
+
* @returns {Object} Analysis results: { setupsFound, usagesFound, violations, verdict }
|
|
1548
|
+
*/
|
|
1549
|
+
function analyzeInfrastructureWithoutImplementation(rootPath, options = {}) {
|
|
1550
|
+
const fs = options.fs || require('fs');
|
|
1551
|
+
const path = options.path || require('path');
|
|
1552
|
+
|
|
1553
|
+
const instantiationPatterns = options.instantiationPatterns || INSTANTIATION_PATTERNS;
|
|
1554
|
+
|
|
1555
|
+
// Collect all source files (excluding tests by default)
|
|
1556
|
+
const { files: sourceFiles } = countSourceFiles(rootPath, {
|
|
1557
|
+
...options,
|
|
1558
|
+
includeTests: false,
|
|
1559
|
+
maxFiles: 1000
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
// Track infrastructure setups and their usage
|
|
1563
|
+
const infrastructureSetups = new Map(); // varName -> { file, line, type, component }
|
|
1564
|
+
const infrastructureUsage = new Map(); // varName -> { count, files[] }
|
|
1565
|
+
|
|
1566
|
+
// Cache file contents to avoid O(N*M) file reads
|
|
1567
|
+
// Phase 1 reads N files, Phase 2 would read N*M without caching
|
|
1568
|
+
const fileContentCache = new Map(); // file -> { content, lines }
|
|
1569
|
+
|
|
1570
|
+
// Phase 1: Find all infrastructure setups (single pass through files)
|
|
1571
|
+
for (const file of sourceFiles) {
|
|
1572
|
+
if (shouldExclude(file) || isTestFile(file)) continue;
|
|
1573
|
+
|
|
1574
|
+
let content;
|
|
1575
|
+
try {
|
|
1576
|
+
content = fs.readFileSync(path.join(rootPath, file), 'utf8');
|
|
1577
|
+
} catch (err) {
|
|
1578
|
+
// Skip unreadable files (permissions, binary, etc.)
|
|
1579
|
+
// This is expected for some files in the repository
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// Cache content for Phase 2 usage search
|
|
1584
|
+
fileContentCache.set(file, { content, lines: content.split('\n') });
|
|
1585
|
+
|
|
1586
|
+
const lang = detectLanguage(file);
|
|
1587
|
+
const patterns = instantiationPatterns[lang] || instantiationPatterns.js;
|
|
1588
|
+
|
|
1589
|
+
for (const pattern of patterns) {
|
|
1590
|
+
// Reset regex state
|
|
1591
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
1592
|
+
let match;
|
|
1593
|
+
let matchCount = 0;
|
|
1594
|
+
const MAX_MATCHES_PER_FILE = 100; // Safety limit to prevent DoS
|
|
1595
|
+
|
|
1596
|
+
while ((match = regex.exec(content)) !== null && matchCount < MAX_MATCHES_PER_FILE) {
|
|
1597
|
+
matchCount++;
|
|
1598
|
+
const varName = match[1];
|
|
1599
|
+
const componentType = match[2] || 'Infrastructure';
|
|
1600
|
+
|
|
1601
|
+
// Skip if variable name is too generic (e.g., 'x', 'i', 'tmp')
|
|
1602
|
+
if (varName.length < 2 || GENERIC_VAR_PATTERN.test(varName)) continue;
|
|
1603
|
+
|
|
1604
|
+
const lineNumber = countNewlines(content.substring(0, match.index)) + 1;
|
|
1605
|
+
|
|
1606
|
+
// Store the setup location
|
|
1607
|
+
const key = `${file}:${varName}`;
|
|
1608
|
+
infrastructureSetups.set(key, {
|
|
1609
|
+
file,
|
|
1610
|
+
line: lineNumber,
|
|
1611
|
+
varName,
|
|
1612
|
+
type: componentType,
|
|
1613
|
+
content: content.split('\n')[lineNumber - 1].trim()
|
|
1614
|
+
});
|
|
1615
|
+
|
|
1616
|
+
// Initialize usage tracking
|
|
1617
|
+
if (!infrastructureUsage.has(key)) {
|
|
1618
|
+
infrastructureUsage.set(key, { count: 0, files: [] });
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// Phase 2: Search for usage of each setup variable (using cached content)
|
|
1625
|
+
for (const [key, setup] of infrastructureSetups.entries()) {
|
|
1626
|
+
const { varName, file: setupFile } = setup;
|
|
1627
|
+
|
|
1628
|
+
// Pre-compile usage patterns once per variable for performance
|
|
1629
|
+
const escapedVarName = escapeRegex(varName);
|
|
1630
|
+
const usagePatterns = [
|
|
1631
|
+
new RegExp(`\\b${escapedVarName}\\s*\\.\\w+`), // varName.method()
|
|
1632
|
+
new RegExp(`\\b${escapedVarName}\\s*\\[`), // varName[prop]
|
|
1633
|
+
new RegExp(`\\(.*\\b${escapedVarName}\\b.*\\)`), // func(varName)
|
|
1634
|
+
new RegExp(`\\b${escapedVarName}\\s*\\)`), // func(arg, varName)
|
|
1635
|
+
new RegExp(`return\\s+.*\\b${escapedVarName}\\b`) // return varName
|
|
1636
|
+
];
|
|
1637
|
+
|
|
1638
|
+
// Search for usage in all source files (using cache - O(N) instead of O(N*M))
|
|
1639
|
+
for (const [file, cached] of fileContentCache.entries()) {
|
|
1640
|
+
const { lines } = cached;
|
|
1641
|
+
|
|
1642
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1643
|
+
const line = lines[i];
|
|
1644
|
+
|
|
1645
|
+
// Skip the setup line itself
|
|
1646
|
+
if (file === setupFile && i === setup.line - 1) continue;
|
|
1647
|
+
|
|
1648
|
+
// Look for usage patterns (method calls, property access, passed as argument)
|
|
1649
|
+
// Using word boundaries to avoid false positives
|
|
1650
|
+
for (const pattern of usagePatterns) {
|
|
1651
|
+
if (pattern.test(line)) {
|
|
1652
|
+
const usage = infrastructureUsage.get(key);
|
|
1653
|
+
usage.count++;
|
|
1654
|
+
if (!usage.files.includes(file)) {
|
|
1655
|
+
usage.files.push(file);
|
|
1656
|
+
}
|
|
1657
|
+
break; // Count once per line
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
// Clear cache to free memory
|
|
1665
|
+
fileContentCache.clear();
|
|
1666
|
+
|
|
1667
|
+
// Phase 3: Detect violations (setups without usage)
|
|
1668
|
+
const violations = [];
|
|
1669
|
+
for (const [key, setup] of infrastructureSetups.entries()) {
|
|
1670
|
+
const usage = infrastructureUsage.get(key);
|
|
1671
|
+
|
|
1672
|
+
if (usage.count === 0) {
|
|
1673
|
+
// Check for false positives - might be exported or used in a way we didn't detect
|
|
1674
|
+
const setupContent = setup.content.toLowerCase();
|
|
1675
|
+
|
|
1676
|
+
// Skip if it's likely exported or part of a module.exports
|
|
1677
|
+
if (setupContent.includes('export') || setupContent.includes('module.exports')) {
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// Skip if it's a parameter or destructured assignment
|
|
1682
|
+
if (setupContent.includes('function') && setupContent.includes(setup.varName)) {
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
violations.push({
|
|
1687
|
+
file: setup.file,
|
|
1688
|
+
line: setup.line,
|
|
1689
|
+
varName: setup.varName,
|
|
1690
|
+
type: setup.type,
|
|
1691
|
+
content: setup.content,
|
|
1692
|
+
severity: 'high',
|
|
1693
|
+
message: `Infrastructure component "${setup.varName}" (${setup.type}) is created but never used`
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
return {
|
|
1699
|
+
setupsFound: infrastructureSetups.size,
|
|
1700
|
+
usagesFound: Array.from(infrastructureUsage.values()).filter(u => u.count > 0).length,
|
|
1701
|
+
violations,
|
|
1702
|
+
verdict: violations.length > 0 ? 'HIGH' : 'OK'
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// ============================================================================
|
|
1707
|
+
// Dead Code Detection
|
|
1708
|
+
// Detects unreachable code after return/throw/break/continue statements
|
|
1709
|
+
// ============================================================================
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Language-specific control flow termination patterns
|
|
1713
|
+
* These statements terminate the current execution path
|
|
1714
|
+
*/
|
|
1715
|
+
const TERMINATION_STATEMENTS = {
|
|
1716
|
+
js: [
|
|
1717
|
+
/\breturn\s*(?:[^;]*)?;/,
|
|
1718
|
+
/\bthrow\s+/,
|
|
1719
|
+
/\bbreak\s*;/,
|
|
1720
|
+
/\bcontinue\s*;/
|
|
1721
|
+
],
|
|
1722
|
+
python: [
|
|
1723
|
+
/^\s*return(?:\s+|$)/m,
|
|
1724
|
+
/^\s*raise\s+/m,
|
|
1725
|
+
/^\s*break\s*$/m,
|
|
1726
|
+
/^\s*continue\s*$/m
|
|
1727
|
+
],
|
|
1728
|
+
go: [
|
|
1729
|
+
/\breturn\b/,
|
|
1730
|
+
/\bpanic\s*\(/,
|
|
1731
|
+
/\bbreak\s*$/m,
|
|
1732
|
+
/\bcontinue\s*$/m
|
|
1733
|
+
],
|
|
1734
|
+
rust: [
|
|
1735
|
+
/\breturn\s*(?:[^;]*)?;/,
|
|
1736
|
+
/\bpanic!\s*\(/,
|
|
1737
|
+
/\bbreak\s*;/,
|
|
1738
|
+
/\bcontinue\s*;/
|
|
1739
|
+
],
|
|
1740
|
+
java: [
|
|
1741
|
+
/\breturn\s*(?:[^;]*)?;/,
|
|
1742
|
+
/\bthrow\s+/,
|
|
1743
|
+
/\bbreak\s*;/,
|
|
1744
|
+
/\bcontinue\s*;/
|
|
1745
|
+
]
|
|
1746
|
+
};
|
|
1747
|
+
|
|
1748
|
+
/**
|
|
1749
|
+
* Patterns for block start (opening braces/colons)
|
|
1750
|
+
*/
|
|
1751
|
+
const BLOCK_START_PATTERNS = {
|
|
1752
|
+
js: /\{[\s]*$/,
|
|
1753
|
+
python: /:[\s]*$/,
|
|
1754
|
+
go: /\{[\s]*$/,
|
|
1755
|
+
rust: /\{[\s]*$/
|
|
1756
|
+
};
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* Analyze dead code - unreachable statements after control flow terminators
|
|
1760
|
+
*
|
|
1761
|
+
* Detects code that appears after return, throw, break, or continue statements
|
|
1762
|
+
* within the same block scope. This is a common sign of incomplete refactoring
|
|
1763
|
+
* or copy-paste errors.
|
|
1764
|
+
*
|
|
1765
|
+
* @param {string} content - File content to analyze
|
|
1766
|
+
* @param {Object} options - Analysis options
|
|
1767
|
+
* @param {string} [options.filePath] - File path for language detection
|
|
1768
|
+
* @returns {Array<Object>} Array of violations: { line, terminatedBy, deadCode }
|
|
1769
|
+
*/
|
|
1770
|
+
function analyzeDeadCode(content, options = {}) {
|
|
1771
|
+
const lang = detectLanguage(options.filePath || '.js');
|
|
1772
|
+
const violations = [];
|
|
1773
|
+
const terminationPatterns = TERMINATION_STATEMENTS[lang] || TERMINATION_STATEMENTS.js;
|
|
1774
|
+
|
|
1775
|
+
const lines = content.split('\n');
|
|
1776
|
+
const lineCount = lines.length;
|
|
1777
|
+
|
|
1778
|
+
for (let i = 0; i < lineCount; i++) {
|
|
1779
|
+
const line = lines[i];
|
|
1780
|
+
const trimmed = line.trim();
|
|
1781
|
+
|
|
1782
|
+
// Skip empty lines, comments, and closing braces
|
|
1783
|
+
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('#') ||
|
|
1784
|
+
trimmed.startsWith('/*') || trimmed.startsWith('*') ||
|
|
1785
|
+
trimmed === '}' || trimmed === '},' || trimmed === '};') {
|
|
1786
|
+
continue;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
// Check if this line contains a termination statement
|
|
1790
|
+
let isTermination = false;
|
|
1791
|
+
let terminationType = '';
|
|
1792
|
+
|
|
1793
|
+
for (const pattern of terminationPatterns) {
|
|
1794
|
+
if (pattern.test(trimmed)) {
|
|
1795
|
+
isTermination = true;
|
|
1796
|
+
terminationType = trimmed.match(/\b(return|throw|break|continue|panic|raise)\b/i)?.[1] || 'terminator';
|
|
1797
|
+
break;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
if (!isTermination) continue;
|
|
1802
|
+
|
|
1803
|
+
// Skip if termination is part of a one-line conditional (e.g., "if (x) return;")
|
|
1804
|
+
// These don't make subsequent code unreachable
|
|
1805
|
+
if (/^\s*(if|elif|else\s+if)\s*\(/.test(trimmed) ||
|
|
1806
|
+
/^[ \t]*if\s[^:\n]*:/.test(trimmed)) {
|
|
1807
|
+
continue;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
// Check for multi-line statements (unbalanced brackets)
|
|
1811
|
+
// e.g., "throw new Error(" or "return [" continues on next lines
|
|
1812
|
+
const countBrackets = (str) => {
|
|
1813
|
+
const open = (str.match(/[\(\[\{]/g) || []).length;
|
|
1814
|
+
const close = (str.match(/[\)\]\}]/g) || []).length;
|
|
1815
|
+
return open - close;
|
|
1816
|
+
};
|
|
1817
|
+
let bracketBalance = countBrackets(trimmed);
|
|
1818
|
+
if (bracketBalance > 0) {
|
|
1819
|
+
// Statement continues on following lines - skip to where it ends
|
|
1820
|
+
for (let k = i + 1; k < lineCount && bracketBalance > 0; k++) {
|
|
1821
|
+
const contLine = lines[k].trim();
|
|
1822
|
+
bracketBalance += countBrackets(contLine);
|
|
1823
|
+
i = k; // Advance past continuation lines
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// Look for non-empty code after the termination (within same block)
|
|
1828
|
+
// Use different scope tracking for Python vs brace-based languages
|
|
1829
|
+
const isPython = lang === 'python';
|
|
1830
|
+
const currentIndent = isPython ? (line.match(/^\s*/)[0].length) : null;
|
|
1831
|
+
let braceDepth = 0;
|
|
1832
|
+
|
|
1833
|
+
for (let j = i + 1; j < lineCount; j++) {
|
|
1834
|
+
const nextLine = lines[j];
|
|
1835
|
+
const nextTrimmed = nextLine.trim();
|
|
1836
|
+
|
|
1837
|
+
// Skip empty lines and comments
|
|
1838
|
+
if (!nextTrimmed || nextTrimmed.startsWith('//') || nextTrimmed.startsWith('#') ||
|
|
1839
|
+
nextTrimmed.startsWith('/*') || nextTrimmed.startsWith('*')) {
|
|
1840
|
+
continue;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// Python: Check indentation level to detect scope exit
|
|
1844
|
+
if (isPython) {
|
|
1845
|
+
const nextIndent = nextLine.match(/^\s*/)[0].length;
|
|
1846
|
+
|
|
1847
|
+
// If dedented to LESS than current level, we've exited the block
|
|
1848
|
+
if (nextIndent < currentIndent) {
|
|
1849
|
+
break;
|
|
1850
|
+
}
|
|
1851
|
+
} else {
|
|
1852
|
+
// Brace-based languages: Track brace depth
|
|
1853
|
+
const openBraces = (nextTrimmed.match(/\{/g) || []).length;
|
|
1854
|
+
const closeBraces = (nextTrimmed.match(/\}/g) || []).length;
|
|
1855
|
+
braceDepth += openBraces - closeBraces;
|
|
1856
|
+
|
|
1857
|
+
// If we see a closing brace that takes us out of the current scope, stop
|
|
1858
|
+
if (braceDepth < 0) break;
|
|
1859
|
+
|
|
1860
|
+
// If we see only a closing brace, that's fine (not dead code)
|
|
1861
|
+
if (nextTrimmed === '}' || nextTrimmed === '},' || nextTrimmed === '};') {
|
|
1862
|
+
continue;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
// Skip case/default labels in switch statements
|
|
1867
|
+
if (/^(case\s+|default\s*:)/.test(nextTrimmed)) {
|
|
1868
|
+
break;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
// Skip else/elif/except/catch clauses (they're alternative paths, not dead code)
|
|
1872
|
+
// Handles: "} else {", "} catch {", "} catch (e) {", "catch {" (modern JS without binding)
|
|
1873
|
+
if (/^(else\s*[:{]?|elif\s+|else\s+if\s+|except\s*[:(]|catch\s*[({]|\}\s*else\s*|\}\s*catch\s*)/.test(nextTrimmed)) {
|
|
1874
|
+
break;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
// Found potential dead code
|
|
1878
|
+
violations.push({
|
|
1879
|
+
line: j + 1, // 1-indexed
|
|
1880
|
+
terminationType: terminationType,
|
|
1881
|
+
terminationLine: i + 1,
|
|
1882
|
+
content: nextTrimmed.substring(0, 50) + (nextTrimmed.length > 50 ? '...' : ''),
|
|
1883
|
+
severity: 'high'
|
|
1884
|
+
});
|
|
1885
|
+
|
|
1886
|
+
// Only report the first dead line per terminator (avoids noise)
|
|
1887
|
+
break;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
return violations;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// ============================================================================
|
|
1895
|
+
// Shotgun Surgery Detection
|
|
1896
|
+
// Detects files that frequently change together across commits
|
|
1897
|
+
// ============================================================================
|
|
1898
|
+
|
|
1899
|
+
/**
|
|
1900
|
+
* Analyze shotgun surgery - files that frequently change together
|
|
1901
|
+
*
|
|
1902
|
+
* Uses git log to find commits where multiple files change together,
|
|
1903
|
+
* indicating tight coupling that may need refactoring.
|
|
1904
|
+
*
|
|
1905
|
+
* @param {string} repoPath - Repository root path
|
|
1906
|
+
* @param {Object} options - Analysis options
|
|
1907
|
+
* @param {number} [options.commitLimit=100] - Number of commits to analyze
|
|
1908
|
+
* @param {number} [options.clusterThreshold=5] - Min files changed together to flag
|
|
1909
|
+
* @param {Function} [options.execFileSync] - Command executor (for testing)
|
|
1910
|
+
* @returns {Object} Analysis results: { clusters, violations, verdict }
|
|
1911
|
+
*/
|
|
1912
|
+
function analyzeShotgunSurgery(repoPath, options = {}) {
|
|
1913
|
+
// Validate commitLimit to prevent command injection
|
|
1914
|
+
let commitLimit = parseInt(options.commitLimit, 10) || 100;
|
|
1915
|
+
if (!Number.isInteger(commitLimit) || commitLimit < 1 || commitLimit > 10000) {
|
|
1916
|
+
commitLimit = 100;
|
|
1917
|
+
}
|
|
1918
|
+
const clusterThreshold = options.clusterThreshold || 5;
|
|
1919
|
+
const execFileSync = options.execFileSync || require('child_process').execFileSync;
|
|
1920
|
+
const path = options.path || require('path');
|
|
1921
|
+
|
|
1922
|
+
const violations = [];
|
|
1923
|
+
const fileClusters = new Map(); // "file1,file2" -> count
|
|
1924
|
+
|
|
1925
|
+
try {
|
|
1926
|
+
// Get commit hashes with file changes
|
|
1927
|
+
// maxBuffer: 2MB is sufficient for 100 commits (typical output is ~50-200KB)
|
|
1928
|
+
const logResult = execFileSync(
|
|
1929
|
+
'git',
|
|
1930
|
+
['log', '--name-only', '--pretty=format:COMMIT:%H', '-n', String(commitLimit)],
|
|
1931
|
+
{ cwd: repoPath, encoding: 'utf8', maxBuffer: 2 * 1024 * 1024 }
|
|
1932
|
+
);
|
|
1933
|
+
|
|
1934
|
+
// Parse commits and their files
|
|
1935
|
+
const commits = [];
|
|
1936
|
+
let currentCommit = null;
|
|
1937
|
+
|
|
1938
|
+
for (const line of logResult.split('\n')) {
|
|
1939
|
+
const trimmed = line.trim();
|
|
1940
|
+
if (!trimmed) continue;
|
|
1941
|
+
|
|
1942
|
+
if (trimmed.startsWith('COMMIT:')) {
|
|
1943
|
+
if (currentCommit && currentCommit.files.length > 1) {
|
|
1944
|
+
commits.push(currentCommit);
|
|
1945
|
+
}
|
|
1946
|
+
currentCommit = { hash: trimmed.substring(7), files: [] };
|
|
1947
|
+
} else if (currentCommit) {
|
|
1948
|
+
// Filter to source files only, exclude common uninteresting files
|
|
1949
|
+
const ext = path.extname(trimmed);
|
|
1950
|
+
if (['.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs', '.java'].includes(ext)) {
|
|
1951
|
+
// Skip test files, they often change with implementation
|
|
1952
|
+
if (!isTestFile(trimmed) && !shouldExclude(trimmed)) {
|
|
1953
|
+
currentCommit.files.push(trimmed);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
// Don't forget the last commit
|
|
1960
|
+
if (currentCommit && currentCommit.files.length > 1) {
|
|
1961
|
+
commits.push(currentCommit);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
// Build co-change matrix
|
|
1965
|
+
for (const commit of commits) {
|
|
1966
|
+
const files = commit.files;
|
|
1967
|
+
if (files.length < 2 || files.length > 20) continue; // Skip huge commits
|
|
1968
|
+
|
|
1969
|
+
// Count co-changes for each pair
|
|
1970
|
+
for (let i = 0; i < files.length; i++) {
|
|
1971
|
+
for (let j = i + 1; j < files.length; j++) {
|
|
1972
|
+
const pair = [files[i], files[j]].sort().join('|||');
|
|
1973
|
+
fileClusters.set(pair, (fileClusters.get(pair) || 0) + 1);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
// Find highly coupled file pairs (appear together in 3+ commits)
|
|
1979
|
+
const coupledPairs = [];
|
|
1980
|
+
for (const [pair, count] of fileClusters.entries()) {
|
|
1981
|
+
if (count >= 3) {
|
|
1982
|
+
const [file1, file2] = pair.split('|||');
|
|
1983
|
+
coupledPairs.push({ file1, file2, count });
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
// Sort by frequency
|
|
1988
|
+
coupledPairs.sort((a, b) => b.count - a.count);
|
|
1989
|
+
|
|
1990
|
+
// Find clusters of files that frequently change together
|
|
1991
|
+
// A cluster is when a file appears in multiple coupled pairs
|
|
1992
|
+
const fileFrequency = new Map(); // file -> number of coupled pairs it appears in
|
|
1993
|
+
for (const { file1, file2 } of coupledPairs) {
|
|
1994
|
+
fileFrequency.set(file1, (fileFrequency.get(file1) || 0) + 1);
|
|
1995
|
+
fileFrequency.set(file2, (fileFrequency.get(file2) || 0) + 1);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// Files that appear in many coupled pairs indicate shotgun surgery
|
|
1999
|
+
const frequentlyChangedFiles = Array.from(fileFrequency.entries())
|
|
2000
|
+
.filter(([_, count]) => count >= clusterThreshold)
|
|
2001
|
+
.sort((a, b) => b[1] - a[1]);
|
|
2002
|
+
|
|
2003
|
+
// Report violations
|
|
2004
|
+
for (const [file, coupledCount] of frequentlyChangedFiles) {
|
|
2005
|
+
// Find all files this one is coupled with
|
|
2006
|
+
const coupledWith = coupledPairs
|
|
2007
|
+
.filter(p => p.file1 === file || p.file2 === file)
|
|
2008
|
+
.map(p => p.file1 === file ? p.file2 : p.file1)
|
|
2009
|
+
.slice(0, 5); // Limit to top 5 for readability
|
|
2010
|
+
|
|
2011
|
+
violations.push({
|
|
2012
|
+
file,
|
|
2013
|
+
coupledCount,
|
|
2014
|
+
coupledWith,
|
|
2015
|
+
severity: coupledCount >= clusterThreshold * 2 ? 'high' : 'medium',
|
|
2016
|
+
message: `"${file}" changes with ${coupledCount} other files frequently (shotgun surgery indicator)`
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
return {
|
|
2021
|
+
commitsAnalyzed: commits.length,
|
|
2022
|
+
coupledPairs: coupledPairs.slice(0, 20), // Top 20 for report
|
|
2023
|
+
violations,
|
|
2024
|
+
verdict: violations.length > 0
|
|
2025
|
+
? (violations.some(v => v.severity === 'high') ? 'HIGH' : 'MEDIUM')
|
|
2026
|
+
: 'OK'
|
|
2027
|
+
};
|
|
2028
|
+
|
|
2029
|
+
} catch (err) {
|
|
2030
|
+
// Git command failed - likely not a git repo or no commits
|
|
2031
|
+
return {
|
|
2032
|
+
commitsAnalyzed: 0,
|
|
2033
|
+
coupledPairs: [],
|
|
2034
|
+
violations: [],
|
|
2035
|
+
verdict: 'SKIP',
|
|
2036
|
+
error: err.message
|
|
2037
|
+
};
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
// ============================================================================
|
|
2042
|
+
// Stub Function Detection
|
|
2043
|
+
// Detects functions that only return placeholder values without real logic
|
|
2044
|
+
// ============================================================================
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* Analyze stub functions - functions that only return placeholder values
|
|
2048
|
+
*
|
|
2049
|
+
* A stub function is one where:
|
|
2050
|
+
* - The body contains only a return statement (plus optional comments)
|
|
2051
|
+
* - The return value is a placeholder: 0, null, undefined, true, false, [], {}, "", ''
|
|
2052
|
+
*
|
|
2053
|
+
* Higher certainty when TODO/FIXME comments are present.
|
|
2054
|
+
*
|
|
2055
|
+
* @param {string} content - File content to analyze
|
|
2056
|
+
* @param {Object} options - Analysis options
|
|
2057
|
+
* @param {string} [options.filePath] - File path for language detection
|
|
2058
|
+
* @returns {Array<Object>} Array of violations: { line, functionName, returnValue, hasTodo, certainty }
|
|
2059
|
+
*/
|
|
2060
|
+
function analyzeStubFunctions(content, options = {}) {
|
|
2061
|
+
const violations = [];
|
|
2062
|
+
const lang = detectLanguage(options.filePath || '.js');
|
|
2063
|
+
|
|
2064
|
+
const langConfig = getStubFunctionConfig(lang);
|
|
2065
|
+
if (!langConfig) return violations;
|
|
2066
|
+
|
|
2067
|
+
if (langConfig.useBraces) {
|
|
2068
|
+
return analyzeStubFunctionsBraceLanguage(content, lang, langConfig);
|
|
2069
|
+
} else {
|
|
2070
|
+
return analyzeStubFunctionsPython(content);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
/**
|
|
2075
|
+
* Get language-specific configuration for stub detection
|
|
2076
|
+
*/
|
|
2077
|
+
function getStubFunctionConfig(lang) {
|
|
2078
|
+
const configs = {
|
|
2079
|
+
js: {
|
|
2080
|
+
useBraces: true,
|
|
2081
|
+
functionPatterns: [
|
|
2082
|
+
/(?:async\s+)?function\s+(\w+)\s*\([^)]*\)\s*\{/g,
|
|
2083
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>\s*\{/g,
|
|
2084
|
+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?function\s*\([^)]*\)\s*\{/g,
|
|
2085
|
+
/^\s*(?:async\s+)?(?!if\b|for\b|while\b|switch\b|catch\b|with\b|function\b)(\w+)\s*\([^)]*\)\s*\{/gm,
|
|
2086
|
+
],
|
|
2087
|
+
stubReturnPattern: /^\s*return\s+(0|null|undefined|true|false|\[\]|\{\}|""|''|``)\s*;?\s*$/,
|
|
2088
|
+
commentPatterns: [/^\s*\/\//, /^\s*\/\*/, /^\s*\*/, /^\s*\*\/$/],
|
|
2089
|
+
},
|
|
2090
|
+
rust: {
|
|
2091
|
+
useBraces: true,
|
|
2092
|
+
functionPatterns: [
|
|
2093
|
+
/(?:pub\s+)?(?:async\s+)?fn\s+(\w+)\s*(?:<[^>]*>)?\s*\([^)]*\)(?:\s*->\s*[^{]+)?\s*\{/g,
|
|
2094
|
+
],
|
|
2095
|
+
stubReturnPattern: /^\s*(?:return\s+)?(None|0|true|false|String::new\(\)|Vec::new\(\)|vec!\[\]|\(\)|""|Default::default\(\))\s*;?\s*$/,
|
|
2096
|
+
stubMacroPattern: /^\s*(todo!\(\)|unimplemented!\(\)|panic!\([^)]*\))\s*;?\s*$/,
|
|
2097
|
+
commentPatterns: [/^\s*\/\//, /^\s*\/\*/, /^\s*\*/, /^\s*\*\/$/],
|
|
2098
|
+
},
|
|
2099
|
+
java: {
|
|
2100
|
+
useBraces: true,
|
|
2101
|
+
functionPatterns: [
|
|
2102
|
+
/(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?(?:\w+(?:<[^>]*>)?)\s+(\w+)\s*\([^)]*\)\s*(?:throws\s+[^{]+)?\s*\{/g,
|
|
2103
|
+
],
|
|
2104
|
+
stubReturnPattern: /^\s*return\s+(null|0|0L|0\.0|0\.0f|true|false|""|Collections\.emptyList\(\)|Collections\.emptyMap\(\)|Optional\.empty\(\))\s*;\s*$/,
|
|
2105
|
+
throwStubPattern: /^\s*throw\s+new\s+(?:Unsupported(?:Operation)?Exception|NotImplementedException|IllegalStateException)\s*\([^)]*\)\s*;\s*$/,
|
|
2106
|
+
commentPatterns: [/^\s*\/\//, /^\s*\/\*/, /^\s*\*/, /^\s*\*\/$/],
|
|
2107
|
+
},
|
|
2108
|
+
go: {
|
|
2109
|
+
useBraces: true,
|
|
2110
|
+
functionPatterns: [
|
|
2111
|
+
/func\s+(?:\([^)]+\)\s+)?(\w+)\s*\([^)]*\)(?:\s*(?:\([^)]+\)|[^{]+))?\s*\{/g,
|
|
2112
|
+
],
|
|
2113
|
+
stubReturnPattern: /^\s*return\s+(nil|0|""|false|true|\[\][a-zA-Z_]\w*\{\}|map\[[^\]]+\][a-zA-Z_]\w*\{\}|\&?[A-Z]\w*\{\})\s*$/,
|
|
2114
|
+
panicPattern: /^\s*panic\s*\([^)]*\)\s*$/,
|
|
2115
|
+
commentPatterns: [/^\s*\/\//],
|
|
2116
|
+
},
|
|
2117
|
+
python: {
|
|
2118
|
+
useBraces: false,
|
|
2119
|
+
},
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2122
|
+
return configs[lang];
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* Analyze brace-delimited languages (JS, Rust, Java, Go)
|
|
2127
|
+
*/
|
|
2128
|
+
function analyzeStubFunctionsBraceLanguage(content, lang, config) {
|
|
2129
|
+
const violations = [];
|
|
2130
|
+
|
|
2131
|
+
for (const pattern of config.functionPatterns) {
|
|
2132
|
+
let match;
|
|
2133
|
+
pattern.lastIndex = 0;
|
|
2134
|
+
|
|
2135
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
2136
|
+
const funcName = match[1] || 'anonymous';
|
|
2137
|
+
const funcStart = match.index + match[0].length - 1;
|
|
2138
|
+
|
|
2139
|
+
const closingBrace = findMatchingBrace(content, funcStart);
|
|
2140
|
+
if (closingBrace === -1) continue;
|
|
2141
|
+
|
|
2142
|
+
const bodyContent = content.substring(funcStart + 1, closingBrace);
|
|
2143
|
+
const bodyLines = bodyContent.split('\n');
|
|
2144
|
+
|
|
2145
|
+
const significantLines = bodyLines.filter(line => {
|
|
2146
|
+
const trimmed = line.trim();
|
|
2147
|
+
if (!trimmed) return false;
|
|
2148
|
+
for (const commentPattern of config.commentPatterns) {
|
|
2149
|
+
if (commentPattern.test(trimmed)) return false;
|
|
2150
|
+
}
|
|
2151
|
+
return true;
|
|
2152
|
+
});
|
|
2153
|
+
|
|
2154
|
+
if (significantLines.length === 1) {
|
|
2155
|
+
const onlyLine = significantLines[0].trim();
|
|
2156
|
+
let stubMatch = config.stubReturnPattern.exec(onlyLine);
|
|
2157
|
+
let returnValue = stubMatch ? stubMatch[1] : null;
|
|
2158
|
+
|
|
2159
|
+
if (!stubMatch && config.stubMacroPattern) {
|
|
2160
|
+
stubMatch = config.stubMacroPattern.exec(onlyLine);
|
|
2161
|
+
returnValue = stubMatch ? stubMatch[1] : null;
|
|
2162
|
+
}
|
|
2163
|
+
if (!stubMatch && config.throwStubPattern) {
|
|
2164
|
+
stubMatch = config.throwStubPattern.exec(onlyLine);
|
|
2165
|
+
returnValue = stubMatch ? 'throw stub' : null;
|
|
2166
|
+
}
|
|
2167
|
+
if (!stubMatch && config.panicPattern) {
|
|
2168
|
+
stubMatch = config.panicPattern.exec(onlyLine);
|
|
2169
|
+
returnValue = stubMatch ? 'panic' : null;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
if (stubMatch && returnValue) {
|
|
2173
|
+
const hasTodo = /\b(TODO|FIXME|XXX|HACK|STUB)\b/i.test(bodyContent);
|
|
2174
|
+
const lineNumber = countNewlines(content.substring(0, funcStart)) + 1;
|
|
2175
|
+
|
|
2176
|
+
violations.push({
|
|
2177
|
+
line: lineNumber,
|
|
2178
|
+
functionName: funcName,
|
|
2179
|
+
returnValue: returnValue,
|
|
2180
|
+
hasTodo: hasTodo,
|
|
2181
|
+
certainty: hasTodo ? 'HIGH' : 'MEDIUM',
|
|
2182
|
+
content: `${funcName}() returns ${returnValue}`
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
return violations;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
/**
|
|
2193
|
+
* Analyze Python functions (indentation-based)
|
|
2194
|
+
*/
|
|
2195
|
+
function analyzeStubFunctionsPython(content) {
|
|
2196
|
+
const violations = [];
|
|
2197
|
+
const lines = content.split('\n');
|
|
2198
|
+
|
|
2199
|
+
const defPattern = /^(\s*)(?:async\s+)?def\s+(\w+)\s*\([^)]*\)\s*(?:->.*)?:\s*$/;
|
|
2200
|
+
const stubReturns = [
|
|
2201
|
+
/^\s*return\s+(None|0|True|False|\[\]|\{\}|"")\s*$/,
|
|
2202
|
+
/^\s*pass\s*$/,
|
|
2203
|
+
/^\s*raise\s+NotImplementedError\s*\([^)]*\)\s*$/,
|
|
2204
|
+
/^\s*\.\.\.\s*$/,
|
|
2205
|
+
];
|
|
2206
|
+
const commentPattern = /^\s*#/;
|
|
2207
|
+
|
|
2208
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2209
|
+
const match = defPattern.exec(lines[i]);
|
|
2210
|
+
if (!match) continue;
|
|
2211
|
+
|
|
2212
|
+
const funcIndent = match[1].length;
|
|
2213
|
+
const funcName = match[2];
|
|
2214
|
+
|
|
2215
|
+
const bodyLines = [];
|
|
2216
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
2217
|
+
const line = lines[j];
|
|
2218
|
+
const trimmed = line.trim();
|
|
2219
|
+
|
|
2220
|
+
if (!trimmed) continue;
|
|
2221
|
+
|
|
2222
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
2223
|
+
if (lineIndent <= funcIndent && trimmed) break;
|
|
2224
|
+
|
|
2225
|
+
if (!commentPattern.test(trimmed) && !trimmed.startsWith('"""') && !trimmed.startsWith("'''")) {
|
|
2226
|
+
bodyLines.push(trimmed);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
if (bodyLines.length === 1) {
|
|
2231
|
+
const onlyLine = bodyLines[0];
|
|
2232
|
+
for (const stubPattern of stubReturns) {
|
|
2233
|
+
const stubMatch = stubPattern.exec(onlyLine);
|
|
2234
|
+
if (stubMatch) {
|
|
2235
|
+
const returnValue = stubMatch[1] || onlyLine.trim();
|
|
2236
|
+
const hasTodo = /\b(TODO|FIXME|XXX|HACK|STUB)\b/i.test(
|
|
2237
|
+
lines.slice(i, Math.min(i + 10, lines.length)).join('\n')
|
|
2238
|
+
);
|
|
2239
|
+
|
|
2240
|
+
violations.push({
|
|
2241
|
+
line: i + 1,
|
|
2242
|
+
functionName: funcName,
|
|
2243
|
+
returnValue: returnValue,
|
|
2244
|
+
hasTodo: hasTodo,
|
|
2245
|
+
certainty: hasTodo ? 'HIGH' : 'MEDIUM',
|
|
2246
|
+
content: `def ${funcName}(): ${onlyLine}`
|
|
2247
|
+
});
|
|
2248
|
+
break;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
return violations;
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
module.exports = {
|
|
2258
|
+
analyzeDocCodeRatio,
|
|
2259
|
+
analyzeVerbosityRatio,
|
|
2260
|
+
analyzeOverEngineering,
|
|
2261
|
+
analyzeBuzzwordInflation,
|
|
2262
|
+
analyzeInfrastructureWithoutImplementation,
|
|
2263
|
+
analyzeDeadCode,
|
|
2264
|
+
analyzeShotgunSurgery,
|
|
2265
|
+
analyzeStubFunctions,
|
|
2266
|
+
// Export helpers for testing
|
|
2267
|
+
findMatchingBrace,
|
|
2268
|
+
countNonEmptyLines,
|
|
2269
|
+
countSourceFiles,
|
|
2270
|
+
countSourceLines,
|
|
2271
|
+
countEntryPointExports,
|
|
2272
|
+
countExportsInContent,
|
|
2273
|
+
getMaxDirectoryDepth,
|
|
2274
|
+
detectLanguage,
|
|
2275
|
+
detectCommentLanguage,
|
|
2276
|
+
shouldExclude,
|
|
2277
|
+
isTestFile,
|
|
2278
|
+
parseGitignore,
|
|
2279
|
+
// Buzzword inflation helpers (for testing)
|
|
2280
|
+
extractClaims,
|
|
2281
|
+
searchEvidence,
|
|
2282
|
+
detectGaps,
|
|
2283
|
+
findClaimSourceFiles,
|
|
2284
|
+
escapeRegex,
|
|
2285
|
+
isFilePathPattern,
|
|
2286
|
+
// Export constants for testing
|
|
2287
|
+
ENTRY_POINTS,
|
|
2288
|
+
EXPORT_PATTERNS,
|
|
2289
|
+
SOURCE_EXTENSIONS,
|
|
2290
|
+
EXCLUDE_DIRS,
|
|
2291
|
+
COMMENT_SYNTAX,
|
|
2292
|
+
// Buzzword inflation constants
|
|
2293
|
+
BUZZWORD_CATEGORIES,
|
|
2294
|
+
EVIDENCE_PATTERNS,
|
|
2295
|
+
CLAIM_INDICATORS,
|
|
2296
|
+
NOT_CLAIM_INDICATORS,
|
|
2297
|
+
// Infrastructure detection constants
|
|
2298
|
+
INFRASTRUCTURE_SUFFIXES,
|
|
2299
|
+
SETUP_VERBS,
|
|
2300
|
+
INSTANTIATION_PATTERNS,
|
|
2301
|
+
GENERIC_VAR_PATTERN,
|
|
2302
|
+
// Dead code detection constants
|
|
2303
|
+
TERMINATION_STATEMENTS,
|
|
2304
|
+
BLOCK_START_PATTERNS
|
|
2305
|
+
};
|