agentic-qe 3.7.15 → 3.7.17
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/.claude/agents/v3/qe-devils-advocate.md +20 -0
- package/.claude/agents/v3/qe-gap-detector.md +25 -0
- package/.claude/agents/v3/qe-quality-gate.md +8 -0
- package/.claude/agents/v3/qe-requirements-validator.md +25 -0
- package/.claude/agents/v3/subagents/qe-code-reviewer.md +11 -0
- package/.claude/agents/v3/subagents/qe-integration-reviewer.md +11 -0
- package/.claude/agents/v3/subagents/qe-performance-reviewer.md +11 -0
- package/.claude/agents/v3/subagents/qe-security-reviewer.md +11 -0
- package/.claude/helpers/adr-compliance.sh +10 -10
- package/.claude/helpers/auto-memory-hook.mjs +24 -9
- package/.claude/helpers/brain-checkpoint.cjs +55 -134
- package/.claude/helpers/ddd-tracker.sh +2 -2
- package/.claude/helpers/guidance-hooks.sh +2 -2
- package/.claude/helpers/hook-handler.cjs +57 -18
- package/.claude/helpers/statusline.cjs +414 -595
- package/.claude/helpers/v3/quality-criteria/evidence-classification.md +116 -116
- package/.claude/helpers/v3/quality-criteria/htsm-categories.md +139 -139
- package/.claude/skills/README.md +8 -11
- package/.claude/skills/brutal-honesty-review/SKILL.md +3 -0
- package/.claude/skills/code-review-quality/SKILL.md +3 -0
- package/.claude/skills/qcsd-cicd-swarm/SKILL.md +79 -2075
- package/.claude/skills/qcsd-cicd-swarm/steps/01-flag-detection.md +62 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/02-core-agents.md +33 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/03-batch1-results.md +21 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/04-conditional-agents.md +23 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/05-decision-synthesis.md +30 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/06-report-generation.md +17 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/07-learning-persistence.md +27 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/08-deployment-advisor.md +25 -0
- package/.claude/skills/qcsd-cicd-swarm/steps/09-final-output.md +16 -0
- package/.claude/skills/qcsd-development-swarm/SKILL.md +79 -2027
- package/.claude/skills/qcsd-development-swarm/steps/01-flag-detection.md +50 -0
- package/.claude/skills/qcsd-development-swarm/steps/02-core-agents.md +29 -0
- package/.claude/skills/qcsd-development-swarm/steps/03-batch1-results.md +14 -0
- package/.claude/skills/qcsd-development-swarm/steps/04-conditional-agents.md +23 -0
- package/.claude/skills/qcsd-development-swarm/steps/05-decision-synthesis.md +30 -0
- package/.claude/skills/qcsd-development-swarm/steps/06-report-generation.md +16 -0
- package/.claude/skills/qcsd-development-swarm/steps/07-learning-persistence.md +25 -0
- package/.claude/skills/qcsd-development-swarm/steps/08-defect-predictor.md +25 -0
- package/.claude/skills/qcsd-development-swarm/steps/09-final-output.md +16 -0
- package/.claude/skills/qcsd-ideation-swarm/SKILL.md +94 -1894
- package/.claude/skills/qcsd-ideation-swarm/steps/01-flag-detection.md +57 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/02-core-agents.md +29 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/03-batch1-results.md +15 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/04-conditional-agents.md +23 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/05-decision-synthesis.md +29 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/06-report-generation.md +18 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/07-learning-persistence.md +29 -0
- package/.claude/skills/qcsd-ideation-swarm/steps/08-final-output.md +18 -0
- package/.claude/skills/qcsd-production-swarm/SKILL.md +88 -2663
- package/.claude/skills/qcsd-production-swarm/steps/01-flag-detection.md +206 -0
- package/.claude/skills/qcsd-production-swarm/steps/02-core-agents.md +428 -0
- package/.claude/skills/qcsd-production-swarm/steps/03-batch1-results.md +101 -0
- package/.claude/skills/qcsd-production-swarm/steps/04-conditional-agents.md +125 -0
- package/.claude/skills/qcsd-production-swarm/steps/05-decision-synthesis.md +136 -0
- package/.claude/skills/qcsd-production-swarm/steps/06-report-generation.md +181 -0
- package/.claude/skills/qcsd-production-swarm/steps/07-learning-persistence.md +185 -0
- package/.claude/skills/qcsd-production-swarm/steps/08-feedback-loop.md +122 -0
- package/.claude/skills/qcsd-production-swarm/steps/09-final-output.md +140 -0
- package/.claude/skills/qcsd-refinement-swarm/SKILL.md +59 -2312
- package/.claude/skills/qcsd-refinement-swarm/steps/01-flag-detection.md +91 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/02-core-agents.md +40 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/03-batch1-results.md +40 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/04-conditional-agents.md +35 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/05-decision-synthesis.md +43 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/06-report-generation.md +42 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/07-learning-persistence.md +53 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/08-transformation.md +36 -0
- package/.claude/skills/qcsd-refinement-swarm/steps/09-final-output.md +46 -0
- package/.claude/skills/sherlock-review/SKILL.md +3 -0
- package/.claude/skills/skill-builder/SKILL.md +103 -0
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +44 -0
- package/assets/agents/v3/qe-devils-advocate.md +20 -0
- package/assets/agents/v3/qe-gap-detector.md +25 -0
- package/assets/agents/v3/qe-quality-gate.md +8 -0
- package/assets/agents/v3/qe-requirements-validator.md +25 -0
- package/assets/agents/v3/subagents/qe-code-reviewer.md +11 -0
- package/assets/agents/v3/subagents/qe-integration-reviewer.md +11 -0
- package/assets/agents/v3/subagents/qe-performance-reviewer.md +11 -0
- package/assets/agents/v3/subagents/qe-security-reviewer.md +11 -0
- package/assets/helpers/statusline-v3.cjs +693 -0
- package/assets/skills/brutal-honesty-review/SKILL.md +3 -0
- package/assets/skills/code-review-quality/SKILL.md +3 -0
- package/assets/skills/qcsd-cicd-swarm/SKILL.md +79 -2075
- package/assets/skills/qcsd-cicd-swarm/steps/01-flag-detection.md +62 -0
- package/assets/skills/qcsd-cicd-swarm/steps/02-core-agents.md +33 -0
- package/assets/skills/qcsd-cicd-swarm/steps/03-batch1-results.md +21 -0
- package/assets/skills/qcsd-cicd-swarm/steps/04-conditional-agents.md +23 -0
- package/assets/skills/qcsd-cicd-swarm/steps/05-decision-synthesis.md +30 -0
- package/assets/skills/qcsd-cicd-swarm/steps/06-report-generation.md +17 -0
- package/assets/skills/qcsd-cicd-swarm/steps/07-learning-persistence.md +27 -0
- package/assets/skills/qcsd-cicd-swarm/steps/08-deployment-advisor.md +25 -0
- package/assets/skills/qcsd-cicd-swarm/steps/09-final-output.md +16 -0
- package/assets/skills/qcsd-development-swarm/SKILL.md +79 -2027
- package/assets/skills/qcsd-development-swarm/steps/01-flag-detection.md +50 -0
- package/assets/skills/qcsd-development-swarm/steps/02-core-agents.md +29 -0
- package/assets/skills/qcsd-development-swarm/steps/03-batch1-results.md +14 -0
- package/assets/skills/qcsd-development-swarm/steps/04-conditional-agents.md +23 -0
- package/assets/skills/qcsd-development-swarm/steps/05-decision-synthesis.md +30 -0
- package/assets/skills/qcsd-development-swarm/steps/06-report-generation.md +16 -0
- package/assets/skills/qcsd-development-swarm/steps/07-learning-persistence.md +25 -0
- package/assets/skills/qcsd-development-swarm/steps/08-defect-predictor.md +25 -0
- package/assets/skills/qcsd-development-swarm/steps/09-final-output.md +16 -0
- package/assets/skills/qcsd-ideation-swarm/SKILL.md +94 -1894
- package/assets/skills/qcsd-ideation-swarm/steps/01-flag-detection.md +57 -0
- package/assets/skills/qcsd-ideation-swarm/steps/02-core-agents.md +29 -0
- package/assets/skills/qcsd-ideation-swarm/steps/03-batch1-results.md +15 -0
- package/assets/skills/qcsd-ideation-swarm/steps/04-conditional-agents.md +23 -0
- package/assets/skills/qcsd-ideation-swarm/steps/05-decision-synthesis.md +29 -0
- package/assets/skills/qcsd-ideation-swarm/steps/06-report-generation.md +18 -0
- package/assets/skills/qcsd-ideation-swarm/steps/07-learning-persistence.md +29 -0
- package/assets/skills/qcsd-ideation-swarm/steps/08-final-output.md +18 -0
- package/assets/skills/qcsd-production-swarm/SKILL.md +88 -2663
- package/assets/skills/qcsd-production-swarm/steps/01-flag-detection.md +206 -0
- package/assets/skills/qcsd-production-swarm/steps/02-core-agents.md +428 -0
- package/assets/skills/qcsd-production-swarm/steps/03-batch1-results.md +101 -0
- package/assets/skills/qcsd-production-swarm/steps/04-conditional-agents.md +125 -0
- package/assets/skills/qcsd-production-swarm/steps/05-decision-synthesis.md +136 -0
- package/assets/skills/qcsd-production-swarm/steps/06-report-generation.md +181 -0
- package/assets/skills/qcsd-production-swarm/steps/07-learning-persistence.md +185 -0
- package/assets/skills/qcsd-production-swarm/steps/08-feedback-loop.md +122 -0
- package/assets/skills/qcsd-production-swarm/steps/09-final-output.md +140 -0
- package/assets/skills/qcsd-refinement-swarm/SKILL.md +59 -2312
- package/assets/skills/qcsd-refinement-swarm/steps/01-flag-detection.md +91 -0
- package/assets/skills/qcsd-refinement-swarm/steps/02-core-agents.md +40 -0
- package/assets/skills/qcsd-refinement-swarm/steps/03-batch1-results.md +40 -0
- package/assets/skills/qcsd-refinement-swarm/steps/04-conditional-agents.md +35 -0
- package/assets/skills/qcsd-refinement-swarm/steps/05-decision-synthesis.md +43 -0
- package/assets/skills/qcsd-refinement-swarm/steps/06-report-generation.md +42 -0
- package/assets/skills/qcsd-refinement-swarm/steps/07-learning-persistence.md +53 -0
- package/assets/skills/qcsd-refinement-swarm/steps/08-transformation.md +36 -0
- package/assets/skills/qcsd-refinement-swarm/steps/09-final-output.md +46 -0
- package/assets/skills/sherlock-review/SKILL.md +3 -0
- package/assets/templates/agent-override-example.yaml +39 -0
- package/dist/agents/devils-advocate/agent.d.ts +25 -1
- package/dist/agents/devils-advocate/agent.js +108 -4
- package/dist/agents/devils-advocate/types.d.ts +54 -0
- package/dist/agents/devils-advocate/types.js +14 -0
- package/dist/agents/overlay-loader.d.ts +28 -0
- package/dist/agents/overlay-loader.js +232 -0
- package/dist/agents/overlay-schema.d.ts +56 -0
- package/dist/agents/overlay-schema.js +77 -0
- package/dist/analysis/branch-enumerator.d.ts +68 -0
- package/dist/analysis/branch-enumerator.js +393 -0
- package/dist/analysis/index.d.ts +2 -0
- package/dist/analysis/index.js +2 -0
- package/dist/cli/bundle.js +2469 -634
- package/dist/cli/commands/coverage.js +50 -0
- package/dist/cli/handlers/brain-handler.js +2 -1
- package/dist/context/compiler.d.ts +62 -0
- package/dist/context/compiler.js +143 -0
- package/dist/context/index.d.ts +8 -0
- package/dist/context/index.js +6 -0
- package/dist/context/sources/coverage-source.d.ts +15 -0
- package/dist/context/sources/coverage-source.js +77 -0
- package/dist/context/sources/git-source.d.ts +12 -0
- package/dist/context/sources/git-source.js +33 -0
- package/dist/context/sources/index.d.ts +6 -0
- package/dist/context/sources/index.js +5 -0
- package/dist/context/sources/memory-source.d.ts +17 -0
- package/dist/context/sources/memory-source.js +94 -0
- package/dist/context/sources/test-source.d.ts +13 -0
- package/dist/context/sources/test-source.js +53 -0
- package/dist/context/sources/types.d.ts +42 -0
- package/dist/context/sources/types.js +5 -0
- package/dist/domains/test-generation/coordinator.js +6 -4
- package/dist/feedback/feedback-loop.d.ts +5 -0
- package/dist/feedback/feedback-loop.js +12 -0
- package/dist/feedback/index.d.ts +1 -1
- package/dist/feedback/index.js +1 -1
- package/dist/init/agents-installer.d.ts +9 -0
- package/dist/init/agents-installer.js +72 -0
- package/dist/init/phases/07-hooks.d.ts +11 -0
- package/dist/init/phases/07-hooks.js +67 -0
- package/dist/init/phases/09-assets.js +3 -0
- package/dist/init/settings-merge.js +1 -1
- package/dist/kernel/hnsw-adapter.d.ts +3 -0
- package/dist/kernel/hnsw-adapter.js +11 -1
- package/dist/kernel/unified-memory-schemas.d.ts +1 -1
- package/dist/kernel/unified-memory-schemas.js +2 -0
- package/dist/kernel/unified-memory.js +25 -0
- package/dist/learning/experience-capture-middleware.js +24 -0
- package/dist/learning/sqlite-persistence.d.ts +3 -0
- package/dist/learning/sqlite-persistence.js +9 -0
- package/dist/learning/token-tracker.js +4 -0
- package/dist/mcp/bundle.js +3694 -3101
- package/dist/mcp/handlers/handler-factory.js +92 -11
- package/dist/mcp/services/task-router.d.ts +11 -0
- package/dist/mcp/services/task-router.js +26 -0
- package/dist/routing/qe-agent-registry.d.ts +11 -0
- package/dist/routing/qe-agent-registry.js +34 -0
- package/dist/routing/qe-task-router.d.ts +1 -0
- package/dist/routing/qe-task-router.js +34 -2
- package/dist/routing/routing-feedback.d.ts +5 -0
- package/dist/routing/routing-feedback.js +29 -3
- package/dist/routing/types.d.ts +2 -0
- package/dist/sync/pull-agent.js +2 -1
- package/dist/test-scheduling/pipeline.d.ts +7 -0
- package/dist/test-scheduling/pipeline.js +9 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +10 -0
- package/dist/validation/pipeline.d.ts +80 -0
- package/dist/validation/pipeline.js +173 -0
- package/dist/validation/steps/requirements.d.ts +32 -0
- package/dist/validation/steps/requirements.js +596 -0
- package/package.json +6 -6
- package/.claude/agents/consensus/README.md +0 -253
- package/.claude/agents/deprecated/qe-api-contract-validator.md.v2 +0 -162
- package/.claude/agents/deprecated/qe-coverage-analyzer.md.v2 +0 -208
- package/.claude/agents/deprecated/qe-test-generator.md.v2 +0 -212
- package/.claude/agents/deprecated/qe-visual-tester.md.v2 +0 -216
- package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +0 -130
- package/.claude/agents/hive-mind/queen-coordinator.md +0 -203
- package/.claude/agents/hive-mind/scout-explorer.md +0 -242
- package/.claude/agents/hive-mind/swarm-memory-manager.md +0 -193
- package/.claude/agents/hive-mind/worker-specialist.md +0 -217
- package/.claude/agents/neural/safla-neural.md +0 -74
- package/.claude/agents/optimization/README.md +0 -250
- package/.claude/agents/reasoning/agent.md +0 -816
- package/.claude/agents/reasoning/goal-planner.md +0 -73
- package/.claude/agents/subagents/qe-code-reviewer.md +0 -76
- package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +0 -76
- package/.claude/agents/subagents/qe-data-generator.md +0 -77
- package/.claude/agents/subagents/qe-flaky-investigator.md +0 -91
- package/.claude/agents/subagents/qe-integration-tester.md +0 -90
- package/.claude/agents/subagents/qe-performance-validator.md +0 -92
- package/.claude/agents/subagents/qe-security-auditor.md +0 -94
- package/.claude/agents/subagents/qe-test-data-architect-sub.md +0 -93
- package/.claude/agents/subagents/qe-test-implementer.md +0 -106
- package/.claude/agents/subagents/qe-test-refactorer.md +0 -117
- package/.claude/agents/subagents/qe-test-writer.md +0 -112
- package/.claude/agents/swarm/README.md +0 -190
- package/.claude/agents/templates/migration-plan.md +0 -746
- package/.claude/agents/testing/unit/tdd-london-swarm.md +0 -244
- package/.claude/agents/testing/validation/production-validator.md +0 -395
- package/.claude/agents/v3/README.md +0 -39
- package/.claude/agents/v3/typescript-specialist.yaml +0 -21
- package/.claude/agents/v3/v3-memory-specialist.md +0 -318
- package/.claude/agents/v3/v3-performance-engineer.md +0 -397
- package/.claude/agents/v3/v3-queen-coordinator.md +0 -98
- package/.claude/agents/v3/v3-security-architect.md +0 -174
- package/.claude/commands/README.md +0 -106
- package/.claude/commands/agents/README.md +0 -10
- package/.claude/commands/agents/agent-capabilities.md +0 -21
- package/.claude/commands/agents/agent-coordination.md +0 -28
- package/.claude/commands/agents/agent-spawning.md +0 -28
- package/.claude/commands/agents/agent-types.md +0 -26
- package/.claude/commands/coordination/README.md +0 -9
- package/.claude/commands/coordination/agent-spawn.md +0 -25
- package/.claude/commands/coordination/init.md +0 -44
- package/.claude/commands/coordination/orchestrate.md +0 -43
- package/.claude/commands/coordination/spawn.md +0 -45
- package/.claude/commands/coordination/swarm-init.md +0 -85
- package/.claude/commands/coordination/task-orchestrate.md +0 -25
- package/.claude/commands/hive-mind/README.md +0 -17
- package/.claude/commands/hive-mind/hive-mind-consensus.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-init.md +0 -18
- package/.claude/commands/hive-mind/hive-mind-memory.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-metrics.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-resume.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-sessions.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-spawn.md +0 -21
- package/.claude/commands/hive-mind/hive-mind-status.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-stop.md +0 -8
- package/.claude/commands/hive-mind/hive-mind-wizard.md +0 -8
- package/.claude/commands/hive-mind/hive-mind.md +0 -27
- package/.claude/commands/memory/README.md +0 -9
- package/.claude/commands/memory/memory-persist.md +0 -25
- package/.claude/commands/memory/memory-search.md +0 -25
- package/.claude/commands/memory/memory-usage.md +0 -25
- package/.claude/commands/memory/neural.md +0 -47
- package/.claude/commands/swarm/README.md +0 -15
- package/.claude/commands/swarm/swarm-analysis.md +0 -8
- package/.claude/commands/swarm/swarm-background.md +0 -8
- package/.claude/commands/swarm/swarm-init.md +0 -19
- package/.claude/commands/swarm/swarm-modes.md +0 -8
- package/.claude/commands/swarm/swarm-monitor.md +0 -8
- package/.claude/commands/swarm/swarm-spawn.md +0 -19
- package/.claude/commands/swarm/swarm-status.md +0 -8
- package/.claude/commands/swarm/swarm-strategies.md +0 -8
- package/.claude/commands/swarm/swarm.md +0 -27
- package/.claude/commands/training/README.md +0 -9
- package/.claude/commands/training/model-update.md +0 -25
- package/.claude/commands/training/neural-patterns.md +0 -74
- package/.claude/commands/training/neural-train.md +0 -25
- package/.claude/commands/training/pattern-learn.md +0 -25
- package/.claude/commands/training/specialization.md +0 -63
- package/.claude/commands/workflows/README.md +0 -9
- package/.claude/commands/workflows/development.md +0 -78
- package/.claude/commands/workflows/research.md +0 -63
- package/.claude/commands/workflows/workflow-create.md +0 -25
- package/.claude/commands/workflows/workflow-execute.md +0 -25
- package/.claude/commands/workflows/workflow-export.md +0 -25
- package/.claude/skills/agentic-jujutsu/SKILL.md +0 -645
- package/.claude/skills/hive-mind-advanced/SKILL.md +0 -712
- package/.claude/skills/iterative-loop/SKILL.md +0 -371
- package/.claude/skills/performance-analysis/SKILL.md +0 -569
- package/.claude/skills/performance-analysis/evals/performance-analysis.yaml +0 -144
- package/.claude/skills/performance-analysis/schemas/output.json +0 -588
- package/.claude/skills/performance-analysis/scripts/validate-config.json +0 -36
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch Enumerator Utility (BMAD-004)
|
|
3
|
+
*
|
|
4
|
+
* Mechanically enumerates all branching constructs in TypeScript/JavaScript files
|
|
5
|
+
* without subjective risk scoring. Reports every unhandled path for completeness.
|
|
6
|
+
*
|
|
7
|
+
* Design: Strategy pattern (BranchEnumerator interface) for future multi-language support.
|
|
8
|
+
* Uses regex-based pattern matching (NOT AST parsing) to keep the utility lightweight
|
|
9
|
+
* and avoid parser version issues (Gap 5).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* TypeScript/JavaScript branch enumerator.
|
|
13
|
+
* Uses line-by-line pattern matching for reliability.
|
|
14
|
+
*/
|
|
15
|
+
export class TSBranchEnumerator {
|
|
16
|
+
language;
|
|
17
|
+
constructor(language = 'typescript') {
|
|
18
|
+
this.language = language;
|
|
19
|
+
}
|
|
20
|
+
enumerate(sourceCode, filePath) {
|
|
21
|
+
const branches = [];
|
|
22
|
+
const lines = sourceCode.split('\n');
|
|
23
|
+
// Track context for multi-line comment detection
|
|
24
|
+
let inBlockComment = false;
|
|
25
|
+
for (let i = 0; i < lines.length; i++) {
|
|
26
|
+
const line = lines[i];
|
|
27
|
+
const trimmed = line.trim();
|
|
28
|
+
const lineNum = i + 1;
|
|
29
|
+
const col = line.length - line.trimStart().length + 1;
|
|
30
|
+
// Skip block comments
|
|
31
|
+
if (inBlockComment) {
|
|
32
|
+
if (trimmed.includes('*/'))
|
|
33
|
+
inBlockComment = false;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (trimmed.startsWith('/*')) {
|
|
37
|
+
inBlockComment = !trimmed.includes('*/');
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Skip line comments
|
|
41
|
+
if (trimmed.startsWith('//'))
|
|
42
|
+
continue;
|
|
43
|
+
// 1. if-without-else
|
|
44
|
+
if (/^\s*if\s*\(/.test(line)) {
|
|
45
|
+
const hasElse = this.findMatchingElse(lines, i);
|
|
46
|
+
if (!hasElse) {
|
|
47
|
+
branches.push({
|
|
48
|
+
file: filePath,
|
|
49
|
+
line: lineNum,
|
|
50
|
+
column: col,
|
|
51
|
+
language: this.language,
|
|
52
|
+
construct: 'if-without-else',
|
|
53
|
+
triggerCondition: 'when condition is false',
|
|
54
|
+
currentHandling: 'falls through — no else branch',
|
|
55
|
+
suggestedGuard: 'Add else branch or document why falsy path is safe',
|
|
56
|
+
severity: 'medium',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 2. switch-no-default and switch-missing-break
|
|
61
|
+
if (/^\s*switch\s*\(/.test(line)) {
|
|
62
|
+
const switchBlock = this.extractBlock(lines, i);
|
|
63
|
+
if (switchBlock && !switchBlock.includes('default:') && !switchBlock.includes('default :')) {
|
|
64
|
+
branches.push({
|
|
65
|
+
file: filePath,
|
|
66
|
+
line: lineNum,
|
|
67
|
+
column: col,
|
|
68
|
+
language: this.language,
|
|
69
|
+
construct: 'switch-no-default',
|
|
70
|
+
triggerCondition: 'when value matches no case',
|
|
71
|
+
currentHandling: 'falls through — no default case',
|
|
72
|
+
suggestedGuard: 'Add default case with error handling or exhaustive check',
|
|
73
|
+
severity: 'high',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// 2b. switch-missing-break
|
|
77
|
+
if (switchBlock) {
|
|
78
|
+
const caseBlocks = switchBlock.match(/case\s+[^:]+:/g) || [];
|
|
79
|
+
const breakStatements = switchBlock.match(/\b(break|return|throw|continue)\b/g) || [];
|
|
80
|
+
if (caseBlocks.length > 0 && breakStatements.length < caseBlocks.length) {
|
|
81
|
+
branches.push({
|
|
82
|
+
file: filePath,
|
|
83
|
+
line: lineNum,
|
|
84
|
+
column: col,
|
|
85
|
+
language: this.language,
|
|
86
|
+
construct: 'switch-missing-break',
|
|
87
|
+
triggerCondition: 'when case falls through to next case',
|
|
88
|
+
currentHandling: 'fall-through — may execute unintended cases',
|
|
89
|
+
suggestedGuard: 'Add break/return to each case or add explicit // falls through comment',
|
|
90
|
+
severity: 'medium',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 3. try-empty-catch
|
|
96
|
+
if (/\bcatch\s*\(/.test(trimmed) || /\bcatch\s*\{/.test(trimmed)) {
|
|
97
|
+
const catchBody = this.extractBlock(lines, i);
|
|
98
|
+
if (catchBody !== null) {
|
|
99
|
+
const bodyContent = catchBody.replace(/[{}]/g, '').trim();
|
|
100
|
+
if (bodyContent.length === 0 || /^\s*\/\//.test(bodyContent)) {
|
|
101
|
+
branches.push({
|
|
102
|
+
file: filePath,
|
|
103
|
+
line: lineNum,
|
|
104
|
+
column: col,
|
|
105
|
+
language: this.language,
|
|
106
|
+
construct: 'try-empty-catch',
|
|
107
|
+
triggerCondition: 'when exception is thrown',
|
|
108
|
+
currentHandling: 'exception silently swallowed',
|
|
109
|
+
suggestedGuard: 'Log the error or rethrow with context',
|
|
110
|
+
severity: 'high',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 3b. try-no-finally
|
|
116
|
+
if (/\btry\s*\{/.test(trimmed)) {
|
|
117
|
+
const tryBlock = this.extractBlock(lines, i);
|
|
118
|
+
if (tryBlock) {
|
|
119
|
+
const afterTry = lines.slice(i, Math.min(i + 30, lines.length)).join('\n');
|
|
120
|
+
if (!afterTry.includes('finally')) {
|
|
121
|
+
branches.push({
|
|
122
|
+
file: filePath,
|
|
123
|
+
line: lineNum,
|
|
124
|
+
column: col,
|
|
125
|
+
language: this.language,
|
|
126
|
+
construct: 'try-no-finally',
|
|
127
|
+
triggerCondition: 'when cleanup is needed regardless of success/failure',
|
|
128
|
+
currentHandling: 'no finally block — cleanup may be skipped on exception',
|
|
129
|
+
suggestedGuard: 'Add finally block for resource cleanup if applicable',
|
|
130
|
+
severity: 'low',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// 4. Optional chaining ?.
|
|
136
|
+
if (trimmed.includes('?.')) {
|
|
137
|
+
const chainMatches = trimmed.match(/(\w+(?:\.\w+)*)\?\./g) || [];
|
|
138
|
+
for (const match of chainMatches) {
|
|
139
|
+
// Check if the result is used without null check
|
|
140
|
+
if (!trimmed.includes('??') && !trimmed.includes('|| ') && !trimmed.includes('if')) {
|
|
141
|
+
branches.push({
|
|
142
|
+
file: filePath,
|
|
143
|
+
line: lineNum,
|
|
144
|
+
column: col,
|
|
145
|
+
language: this.language,
|
|
146
|
+
construct: 'optional-chaining-null-path',
|
|
147
|
+
triggerCondition: `when ${match.replace('?.', '')} is null/undefined`,
|
|
148
|
+
currentHandling: 'returns undefined — may propagate',
|
|
149
|
+
suggestedGuard: 'Add ?? fallback or explicit null check',
|
|
150
|
+
severity: 'low',
|
|
151
|
+
});
|
|
152
|
+
break; // One per line
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// 5. Nullish coalescing ??
|
|
157
|
+
if (trimmed.includes('??') && !trimmed.includes('?.')) {
|
|
158
|
+
branches.push({
|
|
159
|
+
file: filePath,
|
|
160
|
+
line: lineNum,
|
|
161
|
+
column: col,
|
|
162
|
+
language: this.language,
|
|
163
|
+
construct: 'nullish-coalescing-fallback',
|
|
164
|
+
triggerCondition: 'when left side is null/undefined',
|
|
165
|
+
currentHandling: 'uses fallback value',
|
|
166
|
+
suggestedGuard: 'Verify fallback value is appropriate for all null cases',
|
|
167
|
+
severity: 'low',
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// 6. Promise without .catch
|
|
171
|
+
if (/\.\s*then\s*\(/.test(trimmed) && !trimmed.includes('.catch') && !trimmed.includes('await')) {
|
|
172
|
+
// Look ahead a few lines for .catch
|
|
173
|
+
const nextLines = lines.slice(i, Math.min(i + 5, lines.length)).join(' ');
|
|
174
|
+
if (!nextLines.includes('.catch') && !nextLines.includes('try')) {
|
|
175
|
+
branches.push({
|
|
176
|
+
file: filePath,
|
|
177
|
+
line: lineNum,
|
|
178
|
+
column: col,
|
|
179
|
+
language: this.language,
|
|
180
|
+
construct: 'promise-no-catch',
|
|
181
|
+
triggerCondition: 'when promise rejects',
|
|
182
|
+
currentHandling: 'unhandled rejection — may crash process',
|
|
183
|
+
suggestedGuard: 'Add .catch() handler or use try/catch with await',
|
|
184
|
+
severity: 'high',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// 7. Array methods with callbacks (empty array case)
|
|
189
|
+
const arrayMethods = ['map', 'filter', 'reduce', 'forEach', 'find', 'some', 'every', 'flatMap'];
|
|
190
|
+
for (const method of arrayMethods) {
|
|
191
|
+
const pattern = new RegExp(`\\.${method}\\s*\\(`);
|
|
192
|
+
if (pattern.test(trimmed)) {
|
|
193
|
+
// Check if there's an empty array check before
|
|
194
|
+
const prevLines = lines.slice(Math.max(0, i - 3), i).join(' ');
|
|
195
|
+
if (!prevLines.includes('.length') && !prevLines.includes('if (') && !prevLines.includes('?.')) {
|
|
196
|
+
branches.push({
|
|
197
|
+
file: filePath,
|
|
198
|
+
line: lineNum,
|
|
199
|
+
column: col,
|
|
200
|
+
language: this.language,
|
|
201
|
+
construct: 'array-callback-empty',
|
|
202
|
+
triggerCondition: `when array is empty before .${method}()`,
|
|
203
|
+
currentHandling: method === 'reduce'
|
|
204
|
+
? 'may throw without initial value'
|
|
205
|
+
: 'returns empty result — may cause downstream issues',
|
|
206
|
+
suggestedGuard: method === 'reduce'
|
|
207
|
+
? 'Provide initial value or check array length'
|
|
208
|
+
: 'Check array length or handle empty result',
|
|
209
|
+
severity: method === 'reduce' ? 'high' : 'low',
|
|
210
|
+
});
|
|
211
|
+
break; // One per line
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// 8. Logical OR for defaults (falsy trap)
|
|
216
|
+
if (/\|\|\s*['"`\d]/.test(trimmed) && !trimmed.includes('??')) {
|
|
217
|
+
branches.push({
|
|
218
|
+
file: filePath,
|
|
219
|
+
line: lineNum,
|
|
220
|
+
column: col,
|
|
221
|
+
language: this.language,
|
|
222
|
+
construct: 'logical-or-falsy',
|
|
223
|
+
triggerCondition: 'when left side is falsy (0, "", false, null, undefined)',
|
|
224
|
+
currentHandling: 'uses fallback — may unintentionally override 0, "", or false',
|
|
225
|
+
suggestedGuard: 'Use ?? instead of || if only null/undefined should trigger fallback',
|
|
226
|
+
severity: 'medium',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
// 9. Logical AND short-circuit
|
|
230
|
+
if (/&&\s*\w+\s*\(/.test(trimmed) && !trimmed.includes('if') && !trimmed.includes('while')) {
|
|
231
|
+
branches.push({
|
|
232
|
+
file: filePath,
|
|
233
|
+
line: lineNum,
|
|
234
|
+
column: col,
|
|
235
|
+
language: this.language,
|
|
236
|
+
construct: 'logical-and-short-circuit',
|
|
237
|
+
triggerCondition: 'when left side is falsy — right side never executes',
|
|
238
|
+
currentHandling: 'short-circuits — function call skipped silently',
|
|
239
|
+
suggestedGuard: 'Use explicit if-statement for clarity when side effects matter',
|
|
240
|
+
severity: 'low',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// 10. Complex ternary (nested or very long)
|
|
244
|
+
const ternaryMatches = trimmed.match(/\?/g) || [];
|
|
245
|
+
if (ternaryMatches.length >= 2 && trimmed.includes(':')) {
|
|
246
|
+
branches.push({
|
|
247
|
+
file: filePath,
|
|
248
|
+
line: lineNum,
|
|
249
|
+
column: col,
|
|
250
|
+
language: this.language,
|
|
251
|
+
construct: 'ternary-complex',
|
|
252
|
+
triggerCondition: 'when nested ternary conditions interact',
|
|
253
|
+
currentHandling: 'nested ternary — hard to read and maintain',
|
|
254
|
+
suggestedGuard: 'Refactor to if/else or switch for readability',
|
|
255
|
+
severity: 'medium',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// 11. Type guard without exhaustive handling
|
|
259
|
+
if (/\btypeof\s+\w+\s*===?\s*['"]/.test(trimmed) || /\binstanceof\b/.test(trimmed)) {
|
|
260
|
+
if (!trimmed.includes('else') && !this.findMatchingElse(lines, i)) {
|
|
261
|
+
branches.push({
|
|
262
|
+
file: filePath,
|
|
263
|
+
line: lineNum,
|
|
264
|
+
column: col,
|
|
265
|
+
language: this.language,
|
|
266
|
+
construct: 'type-guard-unhandled',
|
|
267
|
+
triggerCondition: 'when value does not match the guarded type',
|
|
268
|
+
currentHandling: 'unguarded type path — may cause runtime type errors',
|
|
269
|
+
suggestedGuard: 'Add else branch or exhaustive type checking',
|
|
270
|
+
severity: 'medium',
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return branches;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Check if an if-statement has a matching else.
|
|
279
|
+
* Simple heuristic: look for 'else' at same or lower indentation within ~30 lines.
|
|
280
|
+
*/
|
|
281
|
+
findMatchingElse(lines, ifLineIndex) {
|
|
282
|
+
const braceCount = { depth: 0 };
|
|
283
|
+
for (let i = ifLineIndex; i < Math.min(ifLineIndex + 30, lines.length); i++) {
|
|
284
|
+
const line = lines[i];
|
|
285
|
+
for (const ch of line) {
|
|
286
|
+
if (ch === '{')
|
|
287
|
+
braceCount.depth++;
|
|
288
|
+
if (ch === '}')
|
|
289
|
+
braceCount.depth--;
|
|
290
|
+
}
|
|
291
|
+
// After the if block closes, check for else
|
|
292
|
+
if (braceCount.depth === 0 && i > ifLineIndex) {
|
|
293
|
+
const nextLine = lines[i + 1]?.trim() || '';
|
|
294
|
+
if (nextLine.startsWith('else') ||
|
|
295
|
+
lines[i].trim().endsWith('else') ||
|
|
296
|
+
lines[i].trim().endsWith('else {')) {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
// Also check same line (e.g., "} else {")
|
|
300
|
+
if (lines[i].includes('} else'))
|
|
301
|
+
return true;
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Extract the block (curly braces content) starting near a line.
|
|
309
|
+
*/
|
|
310
|
+
extractBlock(lines, startIndex) {
|
|
311
|
+
let braceDepth = 0;
|
|
312
|
+
let started = false;
|
|
313
|
+
const blockLines = [];
|
|
314
|
+
for (let i = startIndex; i < Math.min(startIndex + 50, lines.length); i++) {
|
|
315
|
+
const line = lines[i];
|
|
316
|
+
for (const ch of line) {
|
|
317
|
+
if (ch === '{') {
|
|
318
|
+
braceDepth++;
|
|
319
|
+
started = true;
|
|
320
|
+
}
|
|
321
|
+
if (ch === '}')
|
|
322
|
+
braceDepth--;
|
|
323
|
+
}
|
|
324
|
+
if (started) {
|
|
325
|
+
blockLines.push(line);
|
|
326
|
+
if (braceDepth === 0) {
|
|
327
|
+
return blockLines.join('\n');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Enumerate branches in a source file.
|
|
336
|
+
*/
|
|
337
|
+
export function enumerateBranches(sourceCode, filePath, language) {
|
|
338
|
+
const start = Date.now();
|
|
339
|
+
// Detect language from file extension
|
|
340
|
+
const detectedLang = language ||
|
|
341
|
+
(filePath.endsWith('.ts') || filePath.endsWith('.tsx') ? 'typescript' : 'javascript');
|
|
342
|
+
const enumerator = new TSBranchEnumerator(detectedLang);
|
|
343
|
+
const branches = enumerator.enumerate(sourceCode, filePath);
|
|
344
|
+
return {
|
|
345
|
+
file: filePath,
|
|
346
|
+
language: detectedLang,
|
|
347
|
+
branches,
|
|
348
|
+
totalConstructs: branches.length,
|
|
349
|
+
unhandledCount: branches.length,
|
|
350
|
+
duration: Date.now() - start,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Format enumeration result as markdown.
|
|
355
|
+
*/
|
|
356
|
+
export function formatBranchReport(result) {
|
|
357
|
+
const lines = [];
|
|
358
|
+
lines.push(`# Branch Enumeration Report: ${result.file}`);
|
|
359
|
+
lines.push('');
|
|
360
|
+
lines.push(`**Language**: ${result.language} | **Branches**: ${result.unhandledCount} | **Duration**: ${result.duration}ms`);
|
|
361
|
+
lines.push('');
|
|
362
|
+
if (result.branches.length === 0) {
|
|
363
|
+
lines.push('No unhandled branches detected.');
|
|
364
|
+
return lines.join('\n');
|
|
365
|
+
}
|
|
366
|
+
// Group by severity
|
|
367
|
+
const bySeverity = { high: [], medium: [], low: [] };
|
|
368
|
+
for (const branch of result.branches) {
|
|
369
|
+
bySeverity[branch.severity].push(branch);
|
|
370
|
+
}
|
|
371
|
+
for (const severity of ['high', 'medium', 'low']) {
|
|
372
|
+
const group = bySeverity[severity];
|
|
373
|
+
if (group.length === 0)
|
|
374
|
+
continue;
|
|
375
|
+
lines.push(`## ${severity.toUpperCase()} Severity (${group.length})`);
|
|
376
|
+
lines.push('');
|
|
377
|
+
for (const branch of group) {
|
|
378
|
+
lines.push(`### ${branch.construct} — Line ${branch.line}`);
|
|
379
|
+
lines.push(`- **Trigger**: ${branch.triggerCondition}`);
|
|
380
|
+
lines.push(`- **Current**: ${branch.currentHandling}`);
|
|
381
|
+
lines.push(`- **Suggested**: ${branch.suggestedGuard}`);
|
|
382
|
+
lines.push('');
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return lines.join('\n');
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Format enumeration result as JSON.
|
|
389
|
+
*/
|
|
390
|
+
export function formatBranchJSON(result) {
|
|
391
|
+
return JSON.stringify(result, null, 2);
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=branch-enumerator.js.map
|