@harness-engineering/cli 1.15.0 → 1.16.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/dist/agents/commands/codex/AGENTS.md +39 -0
- package/dist/agents/commands/codex/harness/add-harness-component/SKILL.md +195 -0
- package/dist/agents/commands/codex/harness/add-harness-component/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +248 -0
- package/dist/agents/commands/codex/harness/cleanup-dead-code/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +182 -0
- package/dist/agents/commands/codex/harness/detect-doc-drift/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +299 -0
- package/dist/agents/commands/codex/harness/enforce-architecture/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +452 -0
- package/dist/agents/commands/codex/harness/harness-architecture-advisor/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +919 -0
- package/dist/agents/commands/codex/harness/harness-autopilot/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +409 -0
- package/dist/agents/commands/codex/harness/harness-brainstorming/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +860 -0
- package/dist/agents/commands/codex/harness/harness-code-review/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +227 -0
- package/dist/agents/commands/codex/harness/harness-codebase-cleanup/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +369 -0
- package/dist/agents/commands/codex/harness/harness-debugging/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +182 -0
- package/dist/agents/commands/codex/harness/harness-dependency-health/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +463 -0
- package/dist/agents/commands/codex/harness/harness-docs-pipeline/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +513 -0
- package/dist/agents/commands/codex/harness/harness-execution/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +164 -0
- package/dist/agents/commands/codex/harness/harness-hotspot-detector/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +187 -0
- package/dist/agents/commands/codex/harness/harness-impact-analysis/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +170 -0
- package/dist/agents/commands/codex/harness/harness-integrity/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +291 -0
- package/dist/agents/commands/codex/harness/harness-onboarding/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +263 -0
- package/dist/agents/commands/codex/harness/harness-perf/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +582 -0
- package/dist/agents/commands/codex/harness/harness-planning/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +172 -0
- package/dist/agents/commands/codex/harness/harness-refactoring/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +692 -0
- package/dist/agents/commands/codex/harness/harness-release-readiness/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +598 -0
- package/dist/agents/commands/codex/harness/harness-roadmap/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +157 -0
- package/dist/agents/commands/codex/harness/harness-security-scan/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +295 -0
- package/dist/agents/commands/codex/harness/harness-skill-authoring/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +1270 -0
- package/dist/agents/commands/codex/harness/harness-soundness-review/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +247 -0
- package/dist/agents/commands/codex/harness/harness-supply-chain-audit/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +180 -0
- package/dist/agents/commands/codex/harness/harness-tdd/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +163 -0
- package/dist/agents/commands/codex/harness/harness-test-advisor/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +424 -0
- package/dist/agents/commands/codex/harness/harness-verification/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +162 -0
- package/dist/agents/commands/codex/harness/harness-verify/agents/openai.yaml +3 -0
- package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +235 -0
- package/dist/agents/commands/codex/harness/initialize-harness-project/agents/openai.yaml +3 -0
- package/dist/agents/commands/cursor/harness/add-harness-component.mdc +200 -0
- package/dist/agents/commands/cursor/harness/cleanup-dead-code.mdc +253 -0
- package/dist/agents/commands/cursor/harness/detect-doc-drift.mdc +187 -0
- package/dist/agents/commands/cursor/harness/enforce-architecture.mdc +304 -0
- package/dist/agents/commands/cursor/harness/harness-architecture-advisor.mdc +457 -0
- package/dist/agents/commands/cursor/harness/harness-autopilot.mdc +924 -0
- package/dist/agents/commands/cursor/harness/harness-brainstorming.mdc +414 -0
- package/dist/agents/commands/cursor/harness/harness-code-review.mdc +865 -0
- package/dist/agents/commands/cursor/harness/harness-codebase-cleanup.mdc +232 -0
- package/dist/agents/commands/cursor/harness/harness-debugging.mdc +374 -0
- package/dist/agents/commands/cursor/harness/harness-dependency-health.mdc +187 -0
- package/dist/agents/commands/cursor/harness/harness-docs-pipeline.mdc +468 -0
- package/dist/agents/commands/cursor/harness/harness-execution.mdc +518 -0
- package/dist/agents/commands/cursor/harness/harness-hotspot-detector.mdc +169 -0
- package/dist/agents/commands/cursor/harness/harness-impact-analysis.mdc +192 -0
- package/dist/agents/commands/cursor/harness/harness-integrity.mdc +175 -0
- package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +296 -0
- package/dist/agents/commands/cursor/harness/harness-perf.mdc +268 -0
- package/dist/agents/commands/cursor/harness/harness-planning.mdc +587 -0
- package/dist/agents/commands/cursor/harness/harness-refactoring.mdc +177 -0
- package/dist/agents/commands/cursor/harness/harness-release-readiness.mdc +697 -0
- package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +603 -0
- package/dist/agents/commands/cursor/harness/harness-security-scan.mdc +162 -0
- package/dist/agents/commands/cursor/harness/harness-skill-authoring.mdc +300 -0
- package/dist/agents/commands/cursor/harness/harness-soundness-review.mdc +1275 -0
- package/dist/agents/commands/cursor/harness/harness-supply-chain-audit.mdc +252 -0
- package/dist/agents/commands/cursor/harness/harness-tdd.mdc +185 -0
- package/dist/agents/commands/cursor/harness/harness-test-advisor.mdc +168 -0
- package/dist/agents/commands/cursor/harness/harness-verification.mdc +429 -0
- package/dist/agents/commands/cursor/harness/harness-verify.mdc +167 -0
- package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +240 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-auth/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +123 -14
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +97 -3
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +6 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +2 -4
- package/dist/agents/skills/claude-code/harness-database/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +99 -3
- package/dist/agents/skills/claude-code/harness-planning/skill.yaml +6 -0
- package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +1 -1
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +27 -7
- package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +52 -0
- package/dist/agents/skills/claude-code/harness-supply-chain-audit/SKILL.md +281 -0
- package/dist/agents/skills/claude-code/harness-supply-chain-audit/skill.yaml +51 -0
- package/dist/agents/skills/codex/add-harness-component/SKILL.md +192 -0
- package/dist/agents/skills/codex/add-harness-component/skill.yaml +33 -0
- package/dist/agents/skills/codex/align-documentation/SKILL.md +213 -0
- package/dist/agents/skills/codex/align-documentation/skill.yaml +32 -0
- package/dist/agents/skills/codex/check-mechanical-constraints/SKILL.md +191 -0
- package/dist/agents/skills/codex/check-mechanical-constraints/skill.yaml +33 -0
- package/dist/agents/skills/codex/cleanup-dead-code/SKILL.md +245 -0
- package/dist/agents/skills/codex/cleanup-dead-code/skill.yaml +34 -0
- package/dist/agents/skills/codex/detect-doc-drift/SKILL.md +179 -0
- package/dist/agents/skills/codex/detect-doc-drift/skill.yaml +31 -0
- package/dist/agents/skills/codex/enforce-architecture/SKILL.md +296 -0
- package/dist/agents/skills/codex/enforce-architecture/skill.yaml +35 -0
- package/dist/agents/skills/codex/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/codex/harness-accessibility/skill.yaml +52 -0
- package/dist/agents/skills/codex/harness-api-design/SKILL.md +356 -0
- package/dist/agents/skills/codex/harness-api-design/skill.yaml +74 -0
- package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +449 -0
- package/dist/agents/skills/codex/harness-architecture-advisor/skill.yaml +49 -0
- package/dist/agents/skills/codex/harness-auth/SKILL.md +331 -0
- package/dist/agents/skills/codex/harness-auth/skill.yaml +81 -0
- package/dist/agents/skills/codex/harness-autopilot/SKILL.md +916 -0
- package/dist/agents/skills/codex/harness-autopilot/skill.yaml +67 -0
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +406 -0
- package/dist/agents/skills/codex/harness-brainstorming/skill.yaml +50 -0
- package/dist/agents/skills/codex/harness-caching/SKILL.md +309 -0
- package/dist/agents/skills/codex/harness-caching/skill.yaml +73 -0
- package/dist/agents/skills/codex/harness-chaos/SKILL.md +295 -0
- package/dist/agents/skills/codex/harness-chaos/skill.yaml +72 -0
- package/dist/agents/skills/codex/harness-code-review/SKILL.md +857 -0
- package/dist/agents/skills/codex/harness-code-review/skill.yaml +52 -0
- package/dist/agents/skills/codex/harness-codebase-cleanup/SKILL.md +224 -0
- package/dist/agents/skills/codex/harness-codebase-cleanup/skill.yaml +65 -0
- package/dist/agents/skills/codex/harness-compliance/SKILL.md +303 -0
- package/dist/agents/skills/codex/harness-compliance/skill.yaml +78 -0
- package/dist/agents/skills/codex/harness-containerization/SKILL.md +284 -0
- package/dist/agents/skills/codex/harness-containerization/skill.yaml +80 -0
- package/dist/agents/skills/codex/harness-data-pipeline/SKILL.md +274 -0
- package/dist/agents/skills/codex/harness-data-pipeline/skill.yaml +81 -0
- package/dist/agents/skills/codex/harness-data-validation/SKILL.md +343 -0
- package/dist/agents/skills/codex/harness-data-validation/skill.yaml +75 -0
- package/dist/agents/skills/codex/harness-database/SKILL.md +310 -0
- package/dist/agents/skills/codex/harness-database/skill.yaml +80 -0
- package/dist/agents/skills/codex/harness-debugging/SKILL.md +366 -0
- package/dist/agents/skills/codex/harness-debugging/skill.yaml +48 -0
- package/dist/agents/skills/codex/harness-dependency-health/SKILL.md +179 -0
- package/dist/agents/skills/codex/harness-dependency-health/skill.yaml +42 -0
- package/dist/agents/skills/codex/harness-deployment/SKILL.md +307 -0
- package/dist/agents/skills/codex/harness-deployment/skill.yaml +77 -0
- package/dist/agents/skills/codex/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/codex/harness-design/skill.yaml +54 -0
- package/dist/agents/skills/codex/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/codex/harness-design-mobile/skill.yaml +50 -0
- package/dist/agents/skills/codex/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/codex/harness-design-system/skill.yaml +51 -0
- package/dist/agents/skills/codex/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/codex/harness-design-web/skill.yaml +53 -0
- package/dist/agents/skills/codex/harness-diagnostics/SKILL.md +318 -0
- package/dist/agents/skills/codex/harness-diagnostics/skill.yaml +51 -0
- package/dist/agents/skills/codex/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/codex/harness-docs-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/codex/harness-dx/SKILL.md +276 -0
- package/dist/agents/skills/codex/harness-dx/skill.yaml +76 -0
- package/dist/agents/skills/codex/harness-e2e/SKILL.md +245 -0
- package/dist/agents/skills/codex/harness-e2e/skill.yaml +78 -0
- package/dist/agents/skills/codex/harness-event-driven/SKILL.md +280 -0
- package/dist/agents/skills/codex/harness-event-driven/skill.yaml +77 -0
- package/dist/agents/skills/codex/harness-execution/SKILL.md +510 -0
- package/dist/agents/skills/codex/harness-execution/skill.yaml +52 -0
- package/dist/agents/skills/codex/harness-feature-flags/SKILL.md +287 -0
- package/dist/agents/skills/codex/harness-feature-flags/skill.yaml +74 -0
- package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +268 -0
- package/dist/agents/skills/codex/harness-git-workflow/skill.yaml +32 -0
- package/dist/agents/skills/codex/harness-hotspot-detector/SKILL.md +161 -0
- package/dist/agents/skills/codex/harness-hotspot-detector/skill.yaml +45 -0
- package/dist/agents/skills/codex/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/codex/harness-i18n/skill.yaml +55 -0
- package/dist/agents/skills/codex/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/codex/harness-i18n-process/skill.yaml +44 -0
- package/dist/agents/skills/codex/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/codex/harness-i18n-workflow/skill.yaml +54 -0
- package/dist/agents/skills/codex/harness-impact-analysis/SKILL.md +184 -0
- package/dist/agents/skills/codex/harness-impact-analysis/skill.yaml +45 -0
- package/dist/agents/skills/codex/harness-incident-response/SKILL.md +223 -0
- package/dist/agents/skills/codex/harness-incident-response/skill.yaml +78 -0
- package/dist/agents/skills/codex/harness-infrastructure-as-code/SKILL.md +279 -0
- package/dist/agents/skills/codex/harness-infrastructure-as-code/skill.yaml +80 -0
- package/dist/agents/skills/codex/harness-integration-test/SKILL.md +271 -0
- package/dist/agents/skills/codex/harness-integration-test/skill.yaml +73 -0
- package/dist/agents/skills/codex/harness-integrity/SKILL.md +167 -0
- package/dist/agents/skills/codex/harness-integrity/skill.yaml +48 -0
- package/dist/agents/skills/codex/harness-knowledge-mapper/SKILL.md +195 -0
- package/dist/agents/skills/codex/harness-knowledge-mapper/skill.yaml +50 -0
- package/dist/agents/skills/codex/harness-load-testing/SKILL.md +274 -0
- package/dist/agents/skills/codex/harness-load-testing/skill.yaml +79 -0
- package/dist/agents/skills/codex/harness-ml-ops/SKILL.md +341 -0
- package/dist/agents/skills/codex/harness-ml-ops/skill.yaml +79 -0
- package/dist/agents/skills/codex/harness-mobile-patterns/SKILL.md +326 -0
- package/dist/agents/skills/codex/harness-mobile-patterns/skill.yaml +82 -0
- package/dist/agents/skills/codex/harness-mutation-test/SKILL.md +251 -0
- package/dist/agents/skills/codex/harness-mutation-test/skill.yaml +70 -0
- package/dist/agents/skills/codex/harness-observability/SKILL.md +283 -0
- package/dist/agents/skills/codex/harness-observability/skill.yaml +78 -0
- package/dist/agents/skills/codex/harness-onboarding/SKILL.md +288 -0
- package/dist/agents/skills/codex/harness-onboarding/skill.yaml +31 -0
- package/dist/agents/skills/codex/harness-parallel-agents/SKILL.md +256 -0
- package/dist/agents/skills/codex/harness-parallel-agents/skill.yaml +34 -0
- package/dist/agents/skills/codex/harness-perf/SKILL.md +260 -0
- package/dist/agents/skills/codex/harness-perf/skill.yaml +51 -0
- package/dist/agents/skills/codex/harness-perf-tdd/SKILL.md +249 -0
- package/dist/agents/skills/codex/harness-perf-tdd/skill.yaml +48 -0
- package/dist/agents/skills/codex/harness-planning/SKILL.md +579 -0
- package/dist/agents/skills/codex/harness-planning/skill.yaml +56 -0
- package/dist/agents/skills/codex/harness-pre-commit-review/SKILL.md +324 -0
- package/dist/agents/skills/codex/harness-pre-commit-review/skill.yaml +34 -0
- package/dist/agents/skills/codex/harness-product-spec/SKILL.md +285 -0
- package/dist/agents/skills/codex/harness-product-spec/skill.yaml +72 -0
- package/dist/agents/skills/codex/harness-property-test/SKILL.md +281 -0
- package/dist/agents/skills/codex/harness-property-test/skill.yaml +71 -0
- package/dist/agents/skills/codex/harness-refactoring/SKILL.md +169 -0
- package/dist/agents/skills/codex/harness-refactoring/skill.yaml +34 -0
- package/dist/agents/skills/codex/harness-release-readiness/SKILL.md +689 -0
- package/dist/agents/skills/codex/harness-release-readiness/skill.yaml +58 -0
- package/dist/agents/skills/codex/harness-resilience/SKILL.md +255 -0
- package/dist/agents/skills/codex/harness-resilience/skill.yaml +76 -0
- package/dist/agents/skills/codex/harness-roadmap/SKILL.md +595 -0
- package/dist/agents/skills/codex/harness-roadmap/skill.yaml +44 -0
- package/dist/agents/skills/codex/harness-secrets/SKILL.md +293 -0
- package/dist/agents/skills/codex/harness-secrets/skill.yaml +76 -0
- package/dist/agents/skills/codex/harness-security-review/SKILL.md +260 -0
- package/dist/agents/skills/codex/harness-security-review/skill.yaml +53 -0
- package/dist/agents/skills/codex/harness-security-scan/SKILL.md +154 -0
- package/dist/agents/skills/codex/harness-security-scan/skill.yaml +42 -0
- package/dist/agents/skills/codex/harness-skill-authoring/SKILL.md +292 -0
- package/dist/agents/skills/codex/harness-skill-authoring/skill.yaml +33 -0
- package/dist/agents/skills/codex/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/codex/harness-soundness-review/skill.yaml +49 -0
- package/dist/agents/skills/codex/harness-sql-review/SKILL.md +315 -0
- package/dist/agents/skills/codex/harness-sql-review/skill.yaml +74 -0
- package/dist/agents/skills/codex/harness-state-management/SKILL.md +309 -0
- package/dist/agents/skills/codex/harness-state-management/skill.yaml +33 -0
- package/dist/agents/skills/codex/harness-supply-chain-audit/SKILL.md +281 -0
- package/dist/agents/skills/codex/harness-supply-chain-audit/skill.yaml +51 -0
- package/dist/agents/skills/codex/harness-tdd/SKILL.md +177 -0
- package/dist/agents/skills/codex/harness-tdd/skill.yaml +49 -0
- package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +160 -0
- package/dist/agents/skills/codex/harness-test-advisor/skill.yaml +45 -0
- package/dist/agents/skills/codex/harness-test-data/SKILL.md +268 -0
- package/dist/agents/skills/codex/harness-test-data/skill.yaml +74 -0
- package/dist/agents/skills/codex/harness-ux-copy/SKILL.md +271 -0
- package/dist/agents/skills/codex/harness-ux-copy/skill.yaml +77 -0
- package/dist/agents/skills/codex/harness-verification/SKILL.md +421 -0
- package/dist/agents/skills/codex/harness-verification/skill.yaml +43 -0
- package/dist/agents/skills/codex/harness-verify/SKILL.md +159 -0
- package/dist/agents/skills/codex/harness-verify/skill.yaml +41 -0
- package/dist/agents/skills/codex/harness-visual-regression/SKILL.md +257 -0
- package/dist/agents/skills/codex/harness-visual-regression/skill.yaml +74 -0
- package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +232 -0
- package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +32 -0
- package/dist/agents/skills/codex/validate-context-engineering/SKILL.md +150 -0
- package/dist/agents/skills/codex/validate-context-engineering/skill.yaml +32 -0
- package/dist/agents/skills/cursor/add-harness-component/SKILL.md +192 -0
- package/dist/agents/skills/cursor/add-harness-component/skill.yaml +33 -0
- package/dist/agents/skills/cursor/align-documentation/SKILL.md +213 -0
- package/dist/agents/skills/cursor/align-documentation/skill.yaml +32 -0
- package/dist/agents/skills/cursor/check-mechanical-constraints/SKILL.md +191 -0
- package/dist/agents/skills/cursor/check-mechanical-constraints/skill.yaml +33 -0
- package/dist/agents/skills/cursor/cleanup-dead-code/SKILL.md +245 -0
- package/dist/agents/skills/cursor/cleanup-dead-code/skill.yaml +34 -0
- package/dist/agents/skills/cursor/detect-doc-drift/SKILL.md +179 -0
- package/dist/agents/skills/cursor/detect-doc-drift/skill.yaml +31 -0
- package/dist/agents/skills/cursor/enforce-architecture/SKILL.md +296 -0
- package/dist/agents/skills/cursor/enforce-architecture/skill.yaml +35 -0
- package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/cursor/harness-accessibility/skill.yaml +52 -0
- package/dist/agents/skills/cursor/harness-api-design/SKILL.md +356 -0
- package/dist/agents/skills/cursor/harness-api-design/skill.yaml +74 -0
- package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +449 -0
- package/dist/agents/skills/cursor/harness-architecture-advisor/skill.yaml +49 -0
- package/dist/agents/skills/cursor/harness-auth/SKILL.md +331 -0
- package/dist/agents/skills/cursor/harness-auth/skill.yaml +81 -0
- package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +916 -0
- package/dist/agents/skills/cursor/harness-autopilot/skill.yaml +67 -0
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +406 -0
- package/dist/agents/skills/cursor/harness-brainstorming/skill.yaml +50 -0
- package/dist/agents/skills/cursor/harness-caching/SKILL.md +309 -0
- package/dist/agents/skills/cursor/harness-caching/skill.yaml +73 -0
- package/dist/agents/skills/cursor/harness-chaos/SKILL.md +295 -0
- package/dist/agents/skills/cursor/harness-chaos/skill.yaml +72 -0
- package/dist/agents/skills/cursor/harness-code-review/SKILL.md +857 -0
- package/dist/agents/skills/cursor/harness-code-review/skill.yaml +52 -0
- package/dist/agents/skills/cursor/harness-codebase-cleanup/SKILL.md +224 -0
- package/dist/agents/skills/cursor/harness-codebase-cleanup/skill.yaml +65 -0
- package/dist/agents/skills/cursor/harness-compliance/SKILL.md +303 -0
- package/dist/agents/skills/cursor/harness-compliance/skill.yaml +78 -0
- package/dist/agents/skills/cursor/harness-containerization/SKILL.md +284 -0
- package/dist/agents/skills/cursor/harness-containerization/skill.yaml +80 -0
- package/dist/agents/skills/cursor/harness-data-pipeline/SKILL.md +274 -0
- package/dist/agents/skills/cursor/harness-data-pipeline/skill.yaml +81 -0
- package/dist/agents/skills/cursor/harness-data-validation/SKILL.md +343 -0
- package/dist/agents/skills/cursor/harness-data-validation/skill.yaml +75 -0
- package/dist/agents/skills/cursor/harness-database/SKILL.md +310 -0
- package/dist/agents/skills/cursor/harness-database/skill.yaml +80 -0
- package/dist/agents/skills/cursor/harness-debugging/SKILL.md +366 -0
- package/dist/agents/skills/cursor/harness-debugging/skill.yaml +48 -0
- package/dist/agents/skills/cursor/harness-dependency-health/SKILL.md +179 -0
- package/dist/agents/skills/cursor/harness-dependency-health/skill.yaml +42 -0
- package/dist/agents/skills/cursor/harness-deployment/SKILL.md +307 -0
- package/dist/agents/skills/cursor/harness-deployment/skill.yaml +77 -0
- package/dist/agents/skills/cursor/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/cursor/harness-design/skill.yaml +54 -0
- package/dist/agents/skills/cursor/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/cursor/harness-design-mobile/skill.yaml +50 -0
- package/dist/agents/skills/cursor/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/cursor/harness-design-system/skill.yaml +51 -0
- package/dist/agents/skills/cursor/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/cursor/harness-design-web/skill.yaml +53 -0
- package/dist/agents/skills/cursor/harness-diagnostics/SKILL.md +318 -0
- package/dist/agents/skills/cursor/harness-diagnostics/skill.yaml +51 -0
- package/dist/agents/skills/cursor/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/cursor/harness-docs-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/cursor/harness-dx/SKILL.md +276 -0
- package/dist/agents/skills/cursor/harness-dx/skill.yaml +76 -0
- package/dist/agents/skills/cursor/harness-e2e/SKILL.md +245 -0
- package/dist/agents/skills/cursor/harness-e2e/skill.yaml +78 -0
- package/dist/agents/skills/cursor/harness-event-driven/SKILL.md +280 -0
- package/dist/agents/skills/cursor/harness-event-driven/skill.yaml +77 -0
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +510 -0
- package/dist/agents/skills/cursor/harness-execution/skill.yaml +52 -0
- package/dist/agents/skills/cursor/harness-feature-flags/SKILL.md +287 -0
- package/dist/agents/skills/cursor/harness-feature-flags/skill.yaml +74 -0
- package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +268 -0
- package/dist/agents/skills/cursor/harness-git-workflow/skill.yaml +32 -0
- package/dist/agents/skills/cursor/harness-hotspot-detector/SKILL.md +161 -0
- package/dist/agents/skills/cursor/harness-hotspot-detector/skill.yaml +45 -0
- package/dist/agents/skills/cursor/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/cursor/harness-i18n/skill.yaml +55 -0
- package/dist/agents/skills/cursor/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/cursor/harness-i18n-process/skill.yaml +44 -0
- package/dist/agents/skills/cursor/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/cursor/harness-i18n-workflow/skill.yaml +54 -0
- package/dist/agents/skills/cursor/harness-impact-analysis/SKILL.md +184 -0
- package/dist/agents/skills/cursor/harness-impact-analysis/skill.yaml +45 -0
- package/dist/agents/skills/cursor/harness-incident-response/SKILL.md +223 -0
- package/dist/agents/skills/cursor/harness-incident-response/skill.yaml +78 -0
- package/dist/agents/skills/cursor/harness-infrastructure-as-code/SKILL.md +279 -0
- package/dist/agents/skills/cursor/harness-infrastructure-as-code/skill.yaml +80 -0
- package/dist/agents/skills/cursor/harness-integration-test/SKILL.md +271 -0
- package/dist/agents/skills/cursor/harness-integration-test/skill.yaml +73 -0
- package/dist/agents/skills/cursor/harness-integrity/SKILL.md +167 -0
- package/dist/agents/skills/cursor/harness-integrity/skill.yaml +48 -0
- package/dist/agents/skills/cursor/harness-knowledge-mapper/SKILL.md +195 -0
- package/dist/agents/skills/cursor/harness-knowledge-mapper/skill.yaml +50 -0
- package/dist/agents/skills/cursor/harness-load-testing/SKILL.md +274 -0
- package/dist/agents/skills/cursor/harness-load-testing/skill.yaml +79 -0
- package/dist/agents/skills/cursor/harness-ml-ops/SKILL.md +341 -0
- package/dist/agents/skills/cursor/harness-ml-ops/skill.yaml +79 -0
- package/dist/agents/skills/cursor/harness-mobile-patterns/SKILL.md +326 -0
- package/dist/agents/skills/cursor/harness-mobile-patterns/skill.yaml +82 -0
- package/dist/agents/skills/cursor/harness-mutation-test/SKILL.md +251 -0
- package/dist/agents/skills/cursor/harness-mutation-test/skill.yaml +70 -0
- package/dist/agents/skills/cursor/harness-observability/SKILL.md +283 -0
- package/dist/agents/skills/cursor/harness-observability/skill.yaml +78 -0
- package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +288 -0
- package/dist/agents/skills/cursor/harness-onboarding/skill.yaml +31 -0
- package/dist/agents/skills/cursor/harness-parallel-agents/SKILL.md +256 -0
- package/dist/agents/skills/cursor/harness-parallel-agents/skill.yaml +34 -0
- package/dist/agents/skills/cursor/harness-perf/SKILL.md +260 -0
- package/dist/agents/skills/cursor/harness-perf/skill.yaml +51 -0
- package/dist/agents/skills/cursor/harness-perf-tdd/SKILL.md +249 -0
- package/dist/agents/skills/cursor/harness-perf-tdd/skill.yaml +48 -0
- package/dist/agents/skills/cursor/harness-planning/SKILL.md +579 -0
- package/dist/agents/skills/cursor/harness-planning/skill.yaml +56 -0
- package/dist/agents/skills/cursor/harness-pre-commit-review/SKILL.md +324 -0
- package/dist/agents/skills/cursor/harness-pre-commit-review/skill.yaml +34 -0
- package/dist/agents/skills/cursor/harness-product-spec/SKILL.md +285 -0
- package/dist/agents/skills/cursor/harness-product-spec/skill.yaml +72 -0
- package/dist/agents/skills/cursor/harness-property-test/SKILL.md +281 -0
- package/dist/agents/skills/cursor/harness-property-test/skill.yaml +71 -0
- package/dist/agents/skills/cursor/harness-refactoring/SKILL.md +169 -0
- package/dist/agents/skills/cursor/harness-refactoring/skill.yaml +34 -0
- package/dist/agents/skills/cursor/harness-release-readiness/SKILL.md +689 -0
- package/dist/agents/skills/cursor/harness-release-readiness/skill.yaml +58 -0
- package/dist/agents/skills/cursor/harness-resilience/SKILL.md +255 -0
- package/dist/agents/skills/cursor/harness-resilience/skill.yaml +76 -0
- package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +595 -0
- package/dist/agents/skills/cursor/harness-roadmap/skill.yaml +44 -0
- package/dist/agents/skills/cursor/harness-secrets/SKILL.md +293 -0
- package/dist/agents/skills/cursor/harness-secrets/skill.yaml +76 -0
- package/dist/agents/skills/cursor/harness-security-review/SKILL.md +260 -0
- package/dist/agents/skills/cursor/harness-security-review/skill.yaml +53 -0
- package/dist/agents/skills/cursor/harness-security-scan/SKILL.md +154 -0
- package/dist/agents/skills/cursor/harness-security-scan/skill.yaml +42 -0
- package/dist/agents/skills/cursor/harness-skill-authoring/SKILL.md +292 -0
- package/dist/agents/skills/cursor/harness-skill-authoring/skill.yaml +33 -0
- package/dist/agents/skills/cursor/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/cursor/harness-soundness-review/skill.yaml +49 -0
- package/dist/agents/skills/cursor/harness-sql-review/SKILL.md +315 -0
- package/dist/agents/skills/cursor/harness-sql-review/skill.yaml +74 -0
- package/dist/agents/skills/cursor/harness-state-management/SKILL.md +309 -0
- package/dist/agents/skills/cursor/harness-state-management/skill.yaml +33 -0
- package/dist/agents/skills/cursor/harness-supply-chain-audit/SKILL.md +281 -0
- package/dist/agents/skills/cursor/harness-supply-chain-audit/skill.yaml +51 -0
- package/dist/agents/skills/cursor/harness-tdd/SKILL.md +177 -0
- package/dist/agents/skills/cursor/harness-tdd/skill.yaml +49 -0
- package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +160 -0
- package/dist/agents/skills/cursor/harness-test-advisor/skill.yaml +45 -0
- package/dist/agents/skills/cursor/harness-test-data/SKILL.md +268 -0
- package/dist/agents/skills/cursor/harness-test-data/skill.yaml +74 -0
- package/dist/agents/skills/cursor/harness-ux-copy/SKILL.md +271 -0
- package/dist/agents/skills/cursor/harness-ux-copy/skill.yaml +77 -0
- package/dist/agents/skills/cursor/harness-verification/SKILL.md +421 -0
- package/dist/agents/skills/cursor/harness-verification/skill.yaml +43 -0
- package/dist/agents/skills/cursor/harness-verify/SKILL.md +159 -0
- package/dist/agents/skills/cursor/harness-verify/skill.yaml +41 -0
- package/dist/agents/skills/cursor/harness-visual-regression/SKILL.md +257 -0
- package/dist/agents/skills/cursor/harness-visual-regression/skill.yaml +74 -0
- package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +232 -0
- package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +32 -0
- package/dist/agents/skills/cursor/validate-context-engineering/SKILL.md +150 -0
- package/dist/agents/skills/cursor/validate-context-engineering/skill.yaml +32 -0
- package/dist/agents/skills/gemini-cli/enforce-architecture/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +123 -14
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +97 -3
- package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +6 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +2 -4
- package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +99 -3
- package/dist/agents/skills/gemini-cli/harness-planning/skill.yaml +6 -0
- package/dist/agents/skills/gemini-cli/harness-pre-commit-review/SKILL.md +1 -1
- package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +27 -7
- package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +52 -0
- package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/SKILL.md +281 -0
- package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/skill.yaml +51 -0
- package/dist/agents/skills/templates/discipline-template.md +49 -0
- package/dist/agents/skills/tests/schema.ts +1 -1
- package/dist/{agents-md-ZGNIDWAF.js → agents-md-VYDFPIRW.js} +1 -1
- package/dist/{architecture-ZLIH5533.js → architecture-K5HSRBGB.js} +2 -2
- package/dist/bin/harness-mcp.js +13 -13
- package/dist/bin/harness.js +18 -18
- package/dist/{check-phase-gate-ZOXVBDCN.js → check-phase-gate-5AS6SXL6.js} +3 -3
- package/dist/{chunk-LGYBN7Y6.js → chunk-5ZXHMCPL.js} +1 -1
- package/dist/{chunk-RCWZBSK5.js → chunk-6KWBH4EO.js} +1 -1
- package/dist/{chunk-Z2OOPXJO.js → chunk-ALFKNAZW.js} +1172 -74
- package/dist/{chunk-VEPAJXBW.js → chunk-AV6KMDO5.js} +2 -2
- package/dist/{chunk-2BKLWLY6.js → chunk-C7DTKLPW.js} +4 -4
- package/dist/{chunk-ZOAWBDWU.js → chunk-CJDVBBPB.js} +5 -1
- package/dist/{chunk-EDXIVMAP.js → chunk-DNDBFIZN.js} +18 -4
- package/dist/{chunk-XYLGHKG6.js → chunk-HKUX2X7O.js} +11 -2
- package/dist/{chunk-NNHDDXYT.js → chunk-JOP2NDNB.js} +396 -114
- package/dist/{chunk-YBJ262QL.js → chunk-LRG3B43J.js} +1 -1
- package/dist/{chunk-AOZRDOIP.js → chunk-M6TIO6NF.js} +1 -1
- package/dist/{chunk-B2HKP423.js → chunk-OCDDCGDE.js} +9 -1
- package/dist/{chunk-3ZZKVN62.js → chunk-QDF7COPQ.js} +1 -1
- package/dist/{chunk-YLXFKVJE.js → chunk-RWZPHW4H.js} +3 -3
- package/dist/{chunk-N25INEIX.js → chunk-SFRGPAK6.js} +1 -1
- package/dist/{chunk-J4RAX7YB.js → chunk-SHYWICGA.js} +1677 -501
- package/dist/{chunk-OFXQSFOW.js → chunk-TF6ZLHJV.js} +2 -2
- package/dist/{chunk-ND2ENWDM.js → chunk-ZJMU7MEV.js} +1 -1
- package/dist/{ci-workflow-765LSHRD.js → ci-workflow-CRWU723U.js} +1 -1
- package/dist/{create-skill-XSWHMSM5.js → create-skill-NDXQSTIK.js} +2 -2
- package/dist/{dist-ALQDD67R.js → dist-4LPXJYVZ.js} +59 -1
- package/dist/{docs-NRMQCOJ6.js → docs-4JRHTLUZ.js} +3 -3
- package/dist/{engine-3RB7MXPP.js → engine-3G3VIM6L.js} +1 -1
- package/dist/{entropy-6AGX2ZUN.js → entropy-G6CZ2A6P.js} +2 -2
- package/dist/{feedback-MY4QZIFD.js → feedback-QYKQ65HB.js} +1 -1
- package/dist/{generate-agent-definitions-ZAE726AU.js → generate-agent-definitions-SAAOAPT4.js} +3 -3
- package/dist/index.d.ts +33 -12
- package/dist/index.js +18 -18
- package/dist/{loader-UUTVMQCC.js → loader-VCOK3PF7.js} +1 -1
- package/dist/{mcp-VU5FMO52.js → mcp-YENEPHBW.js} +13 -13
- package/dist/{performance-2D7G6NMJ.js → performance-UBCFI2UP.js} +4 -2
- package/dist/{review-pipeline-RAQ55ISU.js → review-pipeline-IQAVCWAX.js} +1 -1
- package/dist/{runtime-BCK5RRZQ.js → runtime-PYFFIESU.js} +1 -1
- package/dist/{security-2RPQEN62.js → security-ZDADTPYW.js} +1 -1
- package/dist/{skill-executor-XZLYZYAK.js → skill-executor-XEVDGXUM.js} +2 -2
- package/dist/{validate-KBYQAEWE.js → validate-VRTUHALQ.js} +2 -2
- package/dist/{validate-cross-check-OABMREW4.js → validate-cross-check-4Y6NHNK3.js} +1 -1
- package/package.json +6 -5
|
@@ -135,17 +135,17 @@ function resolveFileToLayer(file, layers) {
|
|
|
135
135
|
}
|
|
136
136
|
var accessAsync = promisify(access);
|
|
137
137
|
var readFileAsync = promisify(readFile);
|
|
138
|
-
async function fileExists(
|
|
138
|
+
async function fileExists(path26) {
|
|
139
139
|
try {
|
|
140
|
-
await accessAsync(
|
|
140
|
+
await accessAsync(path26, constants.F_OK);
|
|
141
141
|
return true;
|
|
142
142
|
} catch {
|
|
143
143
|
return false;
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
async function readFileContent(
|
|
146
|
+
async function readFileContent(path26) {
|
|
147
147
|
try {
|
|
148
|
-
const content = await readFileAsync(
|
|
148
|
+
const content = await readFileAsync(path26, "utf-8");
|
|
149
149
|
return Ok(content);
|
|
150
150
|
} catch (error) {
|
|
151
151
|
return Err(error);
|
|
@@ -1854,6 +1854,8 @@ import { minimatch as minimatch4 } from "minimatch";
|
|
|
1854
1854
|
import { z as z6 } from "zod";
|
|
1855
1855
|
import * as fs17 from "fs";
|
|
1856
1856
|
import * as path14 from "path";
|
|
1857
|
+
import { readFileSync as readFileSync142, writeFileSync as writeFileSync11, unlinkSync, mkdirSync as mkdirSync11, readdirSync as readdirSync3 } from "fs";
|
|
1858
|
+
import { join as join21, dirname as dirname8 } from "path";
|
|
1857
1859
|
import * as path15 from "path";
|
|
1858
1860
|
import * as path16 from "path";
|
|
1859
1861
|
import * as path17 from "path";
|
|
@@ -1871,6 +1873,13 @@ import * as path22 from "path";
|
|
|
1871
1873
|
import * as os from "os";
|
|
1872
1874
|
import { spawn } from "child_process";
|
|
1873
1875
|
import Parser from "web-tree-sitter";
|
|
1876
|
+
import * as fs23 from "fs/promises";
|
|
1877
|
+
import * as path23 from "path";
|
|
1878
|
+
import * as fs24 from "fs";
|
|
1879
|
+
import * as path24 from "path";
|
|
1880
|
+
import * as fs25 from "fs";
|
|
1881
|
+
import * as path25 from "path";
|
|
1882
|
+
import * as os2 from "os";
|
|
1874
1883
|
async function validateFileStructure(projectPath, conventions) {
|
|
1875
1884
|
const missing = [];
|
|
1876
1885
|
const unexpected = [];
|
|
@@ -1906,15 +1915,15 @@ function validateConfig(data, schema) {
|
|
|
1906
1915
|
let message = "Configuration validation failed";
|
|
1907
1916
|
const suggestions = [];
|
|
1908
1917
|
if (firstError) {
|
|
1909
|
-
const
|
|
1910
|
-
const pathDisplay =
|
|
1918
|
+
const path26 = firstError.path.join(".");
|
|
1919
|
+
const pathDisplay = path26 ? ` at "${path26}"` : "";
|
|
1911
1920
|
if (firstError.code === "invalid_type") {
|
|
1912
1921
|
const received = firstError.received;
|
|
1913
1922
|
const expected = firstError.expected;
|
|
1914
1923
|
if (received === "undefined") {
|
|
1915
1924
|
code = "MISSING_FIELD";
|
|
1916
1925
|
message = `Missing required field${pathDisplay}: ${firstError.message}`;
|
|
1917
|
-
suggestions.push(`Field "${
|
|
1926
|
+
suggestions.push(`Field "${path26}" is required and must be of type "${expected}"`);
|
|
1918
1927
|
} else {
|
|
1919
1928
|
code = "INVALID_TYPE";
|
|
1920
1929
|
message = `Invalid type${pathDisplay}: ${firstError.message}`;
|
|
@@ -2123,27 +2132,27 @@ function extractSections(content) {
|
|
|
2123
2132
|
}
|
|
2124
2133
|
return sections.map((section) => buildAgentMapSection(section, lines));
|
|
2125
2134
|
}
|
|
2126
|
-
function isExternalLink(
|
|
2127
|
-
return
|
|
2135
|
+
function isExternalLink(path26) {
|
|
2136
|
+
return path26.startsWith("http://") || path26.startsWith("https://") || path26.startsWith("#") || path26.startsWith("mailto:");
|
|
2128
2137
|
}
|
|
2129
2138
|
function resolveLinkPath(linkPath, baseDir) {
|
|
2130
2139
|
return linkPath.startsWith(".") ? join4(baseDir, linkPath) : linkPath;
|
|
2131
2140
|
}
|
|
2132
|
-
async function validateAgentsMap(
|
|
2133
|
-
const contentResult = await readFileContent(
|
|
2141
|
+
async function validateAgentsMap(path26 = "./AGENTS.md") {
|
|
2142
|
+
const contentResult = await readFileContent(path26);
|
|
2134
2143
|
if (!contentResult.ok) {
|
|
2135
2144
|
return Err(
|
|
2136
2145
|
createError(
|
|
2137
2146
|
"PARSE_ERROR",
|
|
2138
2147
|
`Failed to read AGENTS.md: ${contentResult.error.message}`,
|
|
2139
|
-
{ path:
|
|
2148
|
+
{ path: path26 },
|
|
2140
2149
|
["Ensure the file exists", "Check file permissions"]
|
|
2141
2150
|
)
|
|
2142
2151
|
);
|
|
2143
2152
|
}
|
|
2144
2153
|
const content = contentResult.value;
|
|
2145
2154
|
const sections = extractSections(content);
|
|
2146
|
-
const baseDir = dirname4(
|
|
2155
|
+
const baseDir = dirname4(path26);
|
|
2147
2156
|
const sectionTitles = sections.map((s) => s.title);
|
|
2148
2157
|
const missingSections = REQUIRED_SECTIONS.filter(
|
|
2149
2158
|
(required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
|
|
@@ -2277,8 +2286,8 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
2277
2286
|
);
|
|
2278
2287
|
}
|
|
2279
2288
|
}
|
|
2280
|
-
function suggestFix(
|
|
2281
|
-
const targetName = basename2(
|
|
2289
|
+
function suggestFix(path26, existingFiles) {
|
|
2290
|
+
const targetName = basename2(path26).toLowerCase();
|
|
2282
2291
|
const similar = existingFiles.find((file) => {
|
|
2283
2292
|
const fileName = basename2(file).toLowerCase();
|
|
2284
2293
|
return fileName.includes(targetName) || targetName.includes(fileName);
|
|
@@ -2286,7 +2295,7 @@ function suggestFix(path23, existingFiles) {
|
|
|
2286
2295
|
if (similar) {
|
|
2287
2296
|
return `Did you mean "${similar}"?`;
|
|
2288
2297
|
}
|
|
2289
|
-
return `Create the file "${
|
|
2298
|
+
return `Create the file "${path26}" or remove the link`;
|
|
2290
2299
|
}
|
|
2291
2300
|
async function validateKnowledgeMap(rootDir = process.cwd()) {
|
|
2292
2301
|
const agentsPath = join22(rootDir, "AGENTS.md");
|
|
@@ -2629,8 +2638,8 @@ function createBoundaryValidator(schema, name) {
|
|
|
2629
2638
|
return Ok(result.data);
|
|
2630
2639
|
}
|
|
2631
2640
|
const suggestions = result.error.issues.map((issue) => {
|
|
2632
|
-
const
|
|
2633
|
-
return
|
|
2641
|
+
const path26 = issue.path.join(".");
|
|
2642
|
+
return path26 ? `${path26}: ${issue.message}` : issue.message;
|
|
2634
2643
|
});
|
|
2635
2644
|
return Err(
|
|
2636
2645
|
createError(
|
|
@@ -3238,11 +3247,11 @@ function processExportListSpecifiers(exportDecl, exports) {
|
|
|
3238
3247
|
var TypeScriptParser = class {
|
|
3239
3248
|
name = "typescript";
|
|
3240
3249
|
extensions = [".ts", ".tsx", ".mts", ".cts"];
|
|
3241
|
-
async parseFile(
|
|
3242
|
-
const contentResult = await readFileContent(
|
|
3250
|
+
async parseFile(path26) {
|
|
3251
|
+
const contentResult = await readFileContent(path26);
|
|
3243
3252
|
if (!contentResult.ok) {
|
|
3244
3253
|
return Err(
|
|
3245
|
-
createParseError("NOT_FOUND", `File not found: ${
|
|
3254
|
+
createParseError("NOT_FOUND", `File not found: ${path26}`, { path: path26 }, [
|
|
3246
3255
|
"Check that the file exists",
|
|
3247
3256
|
"Verify the path is correct"
|
|
3248
3257
|
])
|
|
@@ -3252,7 +3261,7 @@ var TypeScriptParser = class {
|
|
|
3252
3261
|
const ast = parse(contentResult.value, {
|
|
3253
3262
|
loc: true,
|
|
3254
3263
|
range: true,
|
|
3255
|
-
jsx:
|
|
3264
|
+
jsx: path26.endsWith(".tsx"),
|
|
3256
3265
|
errorOnUnknownASTType: false
|
|
3257
3266
|
});
|
|
3258
3267
|
return Ok({
|
|
@@ -3263,7 +3272,7 @@ var TypeScriptParser = class {
|
|
|
3263
3272
|
} catch (e) {
|
|
3264
3273
|
const error = e;
|
|
3265
3274
|
return Err(
|
|
3266
|
-
createParseError("SYNTAX_ERROR", `Failed to parse ${
|
|
3275
|
+
createParseError("SYNTAX_ERROR", `Failed to parse ${path26}: ${error.message}`, { path: path26 }, [
|
|
3267
3276
|
"Check for syntax errors in the file",
|
|
3268
3277
|
"Ensure valid TypeScript syntax"
|
|
3269
3278
|
])
|
|
@@ -3444,22 +3453,22 @@ function extractInlineRefs(content) {
|
|
|
3444
3453
|
}
|
|
3445
3454
|
return refs;
|
|
3446
3455
|
}
|
|
3447
|
-
async function parseDocumentationFile(
|
|
3448
|
-
const contentResult = await readFileContent(
|
|
3456
|
+
async function parseDocumentationFile(path26) {
|
|
3457
|
+
const contentResult = await readFileContent(path26);
|
|
3449
3458
|
if (!contentResult.ok) {
|
|
3450
3459
|
return Err(
|
|
3451
3460
|
createEntropyError(
|
|
3452
3461
|
"PARSE_ERROR",
|
|
3453
|
-
`Failed to read documentation file: ${
|
|
3454
|
-
{ file:
|
|
3462
|
+
`Failed to read documentation file: ${path26}`,
|
|
3463
|
+
{ file: path26 },
|
|
3455
3464
|
["Check that the file exists"]
|
|
3456
3465
|
)
|
|
3457
3466
|
);
|
|
3458
3467
|
}
|
|
3459
3468
|
const content = contentResult.value;
|
|
3460
|
-
const type =
|
|
3469
|
+
const type = path26.endsWith(".md") ? "markdown" : "text";
|
|
3461
3470
|
return Ok({
|
|
3462
|
-
path:
|
|
3471
|
+
path: path26,
|
|
3463
3472
|
type,
|
|
3464
3473
|
content,
|
|
3465
3474
|
codeBlocks: extractCodeBlocks(content),
|
|
@@ -4717,7 +4726,7 @@ var EntropyAnalyzer = class {
|
|
|
4717
4726
|
};
|
|
4718
4727
|
var readFile32 = promisify2(fs3.readFile);
|
|
4719
4728
|
var writeFile32 = promisify2(fs3.writeFile);
|
|
4720
|
-
var
|
|
4729
|
+
var unlink22 = promisify2(fs3.unlink);
|
|
4721
4730
|
var mkdir22 = promisify2(fs3.mkdir);
|
|
4722
4731
|
var copyFile2 = promisify2(fs3.copyFile);
|
|
4723
4732
|
var DEFAULT_FIX_CONFIG = {
|
|
@@ -4860,7 +4869,7 @@ async function applySingleFix(fix, config) {
|
|
|
4860
4869
|
return Err({ fix, error: backupResult.error.message });
|
|
4861
4870
|
}
|
|
4862
4871
|
}
|
|
4863
|
-
await
|
|
4872
|
+
await unlink22(fix.file);
|
|
4864
4873
|
break;
|
|
4865
4874
|
case "delete-lines":
|
|
4866
4875
|
if (fix.line !== void 0) {
|
|
@@ -8593,6 +8602,204 @@ var mcpRules = [
|
|
|
8593
8602
|
references: ["CWE-319"]
|
|
8594
8603
|
}
|
|
8595
8604
|
];
|
|
8605
|
+
var insecureDefaultsRules = [
|
|
8606
|
+
{
|
|
8607
|
+
id: "SEC-DEF-001",
|
|
8608
|
+
name: "Security-Sensitive Fallback to Hardcoded Default",
|
|
8609
|
+
category: "insecure-defaults",
|
|
8610
|
+
severity: "warning",
|
|
8611
|
+
confidence: "medium",
|
|
8612
|
+
patterns: [
|
|
8613
|
+
/(?:SECRET|KEY|TOKEN|PASSWORD|SALT|PEPPER|SIGNING|ENCRYPTION|AUTH|JWT|SESSION).*(?:\|\||\?\?)\s*['"][^'"]+['"]/i
|
|
8614
|
+
],
|
|
8615
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8616
|
+
message: "Security-sensitive variable falls back to a hardcoded default when env var is missing",
|
|
8617
|
+
remediation: "Throw an error if the env var is missing instead of falling back to a default. Use a startup validation check.",
|
|
8618
|
+
references: ["CWE-1188"]
|
|
8619
|
+
},
|
|
8620
|
+
{
|
|
8621
|
+
id: "SEC-DEF-002",
|
|
8622
|
+
name: "TLS/SSL Disabled by Default",
|
|
8623
|
+
category: "insecure-defaults",
|
|
8624
|
+
severity: "warning",
|
|
8625
|
+
confidence: "medium",
|
|
8626
|
+
patterns: [
|
|
8627
|
+
/(?:tls|ssl|https|secure)\s*(?:=|:)\s*(?:false|config\??\.\w+\s*(?:\?\?|&&|\|\|)\s*false)/i
|
|
8628
|
+
],
|
|
8629
|
+
fileGlob: "**/*.{ts,js,mjs,cjs,go,py}",
|
|
8630
|
+
message: "Security feature defaults to disabled; missing configuration degrades to insecure mode",
|
|
8631
|
+
remediation: "Default security features to enabled (true). Require explicit opt-out, not opt-in.",
|
|
8632
|
+
references: ["CWE-1188"]
|
|
8633
|
+
},
|
|
8634
|
+
{
|
|
8635
|
+
id: "SEC-DEF-003",
|
|
8636
|
+
name: "Swallowed Authentication/Authorization Error",
|
|
8637
|
+
category: "insecure-defaults",
|
|
8638
|
+
severity: "warning",
|
|
8639
|
+
confidence: "low",
|
|
8640
|
+
patterns: [
|
|
8641
|
+
// Matches single-line empty catch: catch(e) { } or catch(e) { // ignore }
|
|
8642
|
+
// Note: multi-line catch blocks are handled by AI review, not this rule
|
|
8643
|
+
/catch\s*\([^)]*\)\s*\{\s*(?:\/\/\s*(?:ignore|skip|noop|todo)\b.*)?\s*\}/
|
|
8644
|
+
],
|
|
8645
|
+
fileGlob: "**/*auth*.{ts,js,mjs,cjs},**/*session*.{ts,js,mjs,cjs},**/*token*.{ts,js,mjs,cjs}",
|
|
8646
|
+
message: "Single-line empty catch block in authentication/authorization code may silently allow unauthorized access. Note: multi-line empty catch blocks are detected by AI review, not this mechanical rule.",
|
|
8647
|
+
remediation: "Re-throw the error or return an explicit denial. Never silently swallow auth errors.",
|
|
8648
|
+
references: ["CWE-754", "CWE-390"]
|
|
8649
|
+
},
|
|
8650
|
+
{
|
|
8651
|
+
id: "SEC-DEF-004",
|
|
8652
|
+
name: "Permissive CORS Fallback",
|
|
8653
|
+
category: "insecure-defaults",
|
|
8654
|
+
severity: "warning",
|
|
8655
|
+
confidence: "medium",
|
|
8656
|
+
patterns: [
|
|
8657
|
+
/(?:origin|cors)\s*(?:=|:)\s*(?:config|options|env)\??\.\w+\s*(?:\?\?|\|\|)\s*['"]\*/
|
|
8658
|
+
],
|
|
8659
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8660
|
+
message: "CORS origin falls back to wildcard (*) when configuration is missing",
|
|
8661
|
+
remediation: "Default to a restrictive origin list. Require explicit configuration for permissive CORS.",
|
|
8662
|
+
references: ["CWE-942"]
|
|
8663
|
+
},
|
|
8664
|
+
{
|
|
8665
|
+
id: "SEC-DEF-005",
|
|
8666
|
+
name: "Rate Limiting Disabled by Default",
|
|
8667
|
+
category: "insecure-defaults",
|
|
8668
|
+
severity: "info",
|
|
8669
|
+
confidence: "low",
|
|
8670
|
+
patterns: [
|
|
8671
|
+
/(?:rateLimit|rateLimiting|throttle)\s*(?:=|:)\s*(?:config|options|env)\??\.\w+\s*(?:\?\?|\|\|)\s*(?:false|0|null|undefined)/i
|
|
8672
|
+
],
|
|
8673
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8674
|
+
message: "Rate limiting defaults to disabled when configuration is missing",
|
|
8675
|
+
remediation: "Default to a sensible rate limit. Require explicit opt-out for disabling.",
|
|
8676
|
+
references: ["CWE-770"]
|
|
8677
|
+
}
|
|
8678
|
+
];
|
|
8679
|
+
var sharpEdgesRules = [
|
|
8680
|
+
// --- Deprecated Crypto APIs ---
|
|
8681
|
+
{
|
|
8682
|
+
id: "SEC-EDGE-001",
|
|
8683
|
+
name: "Deprecated createCipher API",
|
|
8684
|
+
category: "sharp-edges",
|
|
8685
|
+
severity: "error",
|
|
8686
|
+
confidence: "high",
|
|
8687
|
+
patterns: [/crypto\.createCipher\s*\(/],
|
|
8688
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8689
|
+
message: "crypto.createCipher is deprecated \u2014 uses weak key derivation (no IV)",
|
|
8690
|
+
remediation: "Use crypto.createCipheriv with a random IV and proper key derivation (scrypt/pbkdf2)",
|
|
8691
|
+
references: ["CWE-327"]
|
|
8692
|
+
},
|
|
8693
|
+
{
|
|
8694
|
+
id: "SEC-EDGE-002",
|
|
8695
|
+
name: "Deprecated createDecipher API",
|
|
8696
|
+
category: "sharp-edges",
|
|
8697
|
+
severity: "error",
|
|
8698
|
+
confidence: "high",
|
|
8699
|
+
patterns: [/crypto\.createDecipher\s*\(/],
|
|
8700
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8701
|
+
message: "crypto.createDecipher is deprecated \u2014 uses weak key derivation (no IV)",
|
|
8702
|
+
remediation: "Use crypto.createDecipheriv with the same IV used for encryption",
|
|
8703
|
+
references: ["CWE-327"]
|
|
8704
|
+
},
|
|
8705
|
+
{
|
|
8706
|
+
id: "SEC-EDGE-003",
|
|
8707
|
+
name: "ECB Mode Selection",
|
|
8708
|
+
category: "sharp-edges",
|
|
8709
|
+
severity: "warning",
|
|
8710
|
+
confidence: "high",
|
|
8711
|
+
patterns: [/-ecb['"]/],
|
|
8712
|
+
fileGlob: "**/*.{ts,js,mjs,cjs,go,py}",
|
|
8713
|
+
message: "ECB mode does not provide semantic security \u2014 identical plaintext blocks produce identical ciphertext",
|
|
8714
|
+
remediation: "Use CBC, CTR, or GCM mode instead of ECB",
|
|
8715
|
+
references: ["CWE-327"]
|
|
8716
|
+
},
|
|
8717
|
+
// --- Unsafe Deserialization ---
|
|
8718
|
+
{
|
|
8719
|
+
id: "SEC-EDGE-004",
|
|
8720
|
+
name: "yaml.load Without Safe Loader",
|
|
8721
|
+
category: "sharp-edges",
|
|
8722
|
+
severity: "error",
|
|
8723
|
+
confidence: "high",
|
|
8724
|
+
patterns: [
|
|
8725
|
+
/yaml\.load\s*\(/
|
|
8726
|
+
// Python: yaml.load() without SafeLoader
|
|
8727
|
+
],
|
|
8728
|
+
fileGlob: "**/*.py",
|
|
8729
|
+
message: "yaml.load() executes arbitrary Python objects \u2014 use yaml.safe_load() instead",
|
|
8730
|
+
remediation: "Replace yaml.load() with yaml.safe_load() or yaml.load(data, Loader=SafeLoader). Note: this rule will flag yaml.load(data, Loader=SafeLoader) \u2014 suppress with # harness-ignore SEC-EDGE-004: safe usage with SafeLoader",
|
|
8731
|
+
references: ["CWE-502"]
|
|
8732
|
+
},
|
|
8733
|
+
{
|
|
8734
|
+
id: "SEC-EDGE-005",
|
|
8735
|
+
name: "Pickle/Marshal Deserialization",
|
|
8736
|
+
category: "sharp-edges",
|
|
8737
|
+
severity: "error",
|
|
8738
|
+
confidence: "high",
|
|
8739
|
+
patterns: [/pickle\.loads?\s*\(/, /marshal\.loads?\s*\(/],
|
|
8740
|
+
fileGlob: "**/*.py",
|
|
8741
|
+
message: "pickle/marshal deserialization executes arbitrary code \u2014 never use on untrusted data",
|
|
8742
|
+
remediation: "Use JSON, MessagePack, or Protocol Buffers for untrusted data serialization",
|
|
8743
|
+
references: ["CWE-502"]
|
|
8744
|
+
},
|
|
8745
|
+
// --- TOCTOU (Time-of-Check to Time-of-Use) ---
|
|
8746
|
+
{
|
|
8747
|
+
id: "SEC-EDGE-006",
|
|
8748
|
+
name: "Check-Then-Act File Operation",
|
|
8749
|
+
category: "sharp-edges",
|
|
8750
|
+
severity: "warning",
|
|
8751
|
+
confidence: "medium",
|
|
8752
|
+
// Patterns use .{0,N} since scanner matches single lines only (no multiline mode)
|
|
8753
|
+
patterns: [
|
|
8754
|
+
/(?:existsSync|accessSync|statSync)\s*\([^)]+\).{0,50}(?:readFileSync|writeFileSync|unlinkSync|mkdirSync)\s*\(/
|
|
8755
|
+
],
|
|
8756
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8757
|
+
message: "Check-then-act pattern on filesystem is vulnerable to TOCTOU race conditions",
|
|
8758
|
+
remediation: "Use the operation directly and handle ENOENT/EEXIST errors instead of checking first",
|
|
8759
|
+
references: ["CWE-367"]
|
|
8760
|
+
},
|
|
8761
|
+
{
|
|
8762
|
+
id: "SEC-EDGE-007",
|
|
8763
|
+
name: "Check-Then-Act File Operation (Async)",
|
|
8764
|
+
category: "sharp-edges",
|
|
8765
|
+
severity: "warning",
|
|
8766
|
+
confidence: "medium",
|
|
8767
|
+
// Uses .{0,N} since scanner matches single lines only (no multiline mode)
|
|
8768
|
+
patterns: [/(?:access|stat)\s*\([^)]+\).{0,80}(?:readFile|writeFile|unlink|mkdir)\s*\(/],
|
|
8769
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8770
|
+
message: "Async check-then-act pattern on filesystem is vulnerable to TOCTOU race conditions",
|
|
8771
|
+
remediation: "Use the operation directly with try/catch instead of checking existence first",
|
|
8772
|
+
references: ["CWE-367"]
|
|
8773
|
+
},
|
|
8774
|
+
// --- Stringly-Typed Security ---
|
|
8775
|
+
{
|
|
8776
|
+
id: "SEC-EDGE-008",
|
|
8777
|
+
name: 'JWT Algorithm "none"',
|
|
8778
|
+
category: "sharp-edges",
|
|
8779
|
+
severity: "error",
|
|
8780
|
+
confidence: "high",
|
|
8781
|
+
patterns: [
|
|
8782
|
+
/algorithm[s]?\s*[:=]\s*\[?\s*['"]none['"]/i,
|
|
8783
|
+
/alg(?:orithm)?\s*[:=]\s*['"]none['"]/i
|
|
8784
|
+
],
|
|
8785
|
+
fileGlob: "**/*.{ts,js,mjs,cjs}",
|
|
8786
|
+
message: 'JWT "none" algorithm disables signature verification entirely',
|
|
8787
|
+
remediation: 'Specify an explicit algorithm (e.g., "HS256", "RS256") and set algorithms allowlist in verify options',
|
|
8788
|
+
references: ["CWE-345"]
|
|
8789
|
+
},
|
|
8790
|
+
{
|
|
8791
|
+
id: "SEC-EDGE-009",
|
|
8792
|
+
name: "DES/RC4 Algorithm Selection",
|
|
8793
|
+
category: "sharp-edges",
|
|
8794
|
+
severity: "error",
|
|
8795
|
+
confidence: "high",
|
|
8796
|
+
patterns: [/['"]\s*(?:des|des-ede|des-ede3|des3|rc4|rc2|blowfish)\s*['"]/i],
|
|
8797
|
+
fileGlob: "**/*.{ts,js,mjs,cjs,go,py}",
|
|
8798
|
+
message: "Weak/deprecated cipher algorithm selected \u2014 DES, RC4, RC2, and Blowfish are broken or deprecated",
|
|
8799
|
+
remediation: "Use AES-256-GCM or ChaCha20-Poly1305",
|
|
8800
|
+
references: ["CWE-327"]
|
|
8801
|
+
}
|
|
8802
|
+
];
|
|
8596
8803
|
var nodeRules = [
|
|
8597
8804
|
{
|
|
8598
8805
|
id: "SEC-NODE-001",
|
|
@@ -8697,6 +8904,14 @@ var goRules = [
|
|
|
8697
8904
|
references: ["CWE-134"]
|
|
8698
8905
|
}
|
|
8699
8906
|
];
|
|
8907
|
+
function parseHarnessIgnore(line, ruleId) {
|
|
8908
|
+
if (!line.includes("harness-ignore")) return null;
|
|
8909
|
+
if (!line.includes(ruleId)) return null;
|
|
8910
|
+
const match = line.match(/(?:\/\/|#)\s*harness-ignore\s+(SEC-[A-Z]+-\d+)(?::\s*(.+))?/);
|
|
8911
|
+
if (match?.[1] !== ruleId) return null;
|
|
8912
|
+
const text = match[2]?.trim();
|
|
8913
|
+
return { ruleId, justification: text || null };
|
|
8914
|
+
}
|
|
8700
8915
|
var SecurityScanner = class {
|
|
8701
8916
|
registry;
|
|
8702
8917
|
config;
|
|
@@ -8713,7 +8928,9 @@ var SecurityScanner = class {
|
|
|
8713
8928
|
...networkRules,
|
|
8714
8929
|
...deserializationRules,
|
|
8715
8930
|
...agentConfigRules,
|
|
8716
|
-
...mcpRules
|
|
8931
|
+
...mcpRules,
|
|
8932
|
+
...insecureDefaultsRules,
|
|
8933
|
+
...sharpEdgesRules
|
|
8717
8934
|
]);
|
|
8718
8935
|
this.registry.registerAll([...nodeRules, ...expressRules, ...reactRules, ...goRules]);
|
|
8719
8936
|
this.activeRules = this.registry.getAll();
|
|
@@ -8730,42 +8947,8 @@ var SecurityScanner = class {
|
|
|
8730
8947
|
*/
|
|
8731
8948
|
scanContent(content, filePath, startLine = 1) {
|
|
8732
8949
|
if (!this.config.enabled) return [];
|
|
8733
|
-
const findings = [];
|
|
8734
8950
|
const lines = content.split("\n");
|
|
8735
|
-
|
|
8736
|
-
const resolved = resolveRuleSeverity(
|
|
8737
|
-
rule.id,
|
|
8738
|
-
rule.severity,
|
|
8739
|
-
this.config.rules ?? {},
|
|
8740
|
-
this.config.strict
|
|
8741
|
-
);
|
|
8742
|
-
if (resolved === "off") continue;
|
|
8743
|
-
for (let i = 0; i < lines.length; i++) {
|
|
8744
|
-
const line = lines[i] ?? "";
|
|
8745
|
-
if (line.includes("harness-ignore") && line.includes(rule.id)) continue;
|
|
8746
|
-
for (const pattern of rule.patterns) {
|
|
8747
|
-
pattern.lastIndex = 0;
|
|
8748
|
-
if (pattern.test(line)) {
|
|
8749
|
-
findings.push({
|
|
8750
|
-
ruleId: rule.id,
|
|
8751
|
-
ruleName: rule.name,
|
|
8752
|
-
category: rule.category,
|
|
8753
|
-
severity: resolved,
|
|
8754
|
-
confidence: rule.confidence,
|
|
8755
|
-
file: filePath,
|
|
8756
|
-
line: startLine + i,
|
|
8757
|
-
match: line.trim(),
|
|
8758
|
-
context: line,
|
|
8759
|
-
message: rule.message,
|
|
8760
|
-
remediation: rule.remediation,
|
|
8761
|
-
...rule.references ? { references: rule.references } : {}
|
|
8762
|
-
});
|
|
8763
|
-
break;
|
|
8764
|
-
}
|
|
8765
|
-
}
|
|
8766
|
-
}
|
|
8767
|
-
}
|
|
8768
|
-
return findings;
|
|
8951
|
+
return this.scanLinesWithRules(lines, this.activeRules, filePath, startLine);
|
|
8769
8952
|
}
|
|
8770
8953
|
async scanFile(filePath) {
|
|
8771
8954
|
if (!this.config.enabled) return [];
|
|
@@ -8774,14 +8957,22 @@ var SecurityScanner = class {
|
|
|
8774
8957
|
}
|
|
8775
8958
|
scanContentForFile(content, filePath, startLine = 1) {
|
|
8776
8959
|
if (!this.config.enabled) return [];
|
|
8777
|
-
const findings = [];
|
|
8778
8960
|
const lines = content.split("\n");
|
|
8779
8961
|
const applicableRules = this.activeRules.filter((rule) => {
|
|
8780
8962
|
if (!rule.fileGlob) return true;
|
|
8781
8963
|
const globs = rule.fileGlob.split(",").map((g) => g.trim());
|
|
8782
8964
|
return globs.some((glob2) => minimatch4(filePath, glob2, { dot: true }));
|
|
8783
8965
|
});
|
|
8784
|
-
|
|
8966
|
+
return this.scanLinesWithRules(lines, applicableRules, filePath, startLine);
|
|
8967
|
+
}
|
|
8968
|
+
/**
|
|
8969
|
+
* Core scanning loop shared by scanContent and scanContentForFile.
|
|
8970
|
+
* Evaluates each rule against each line, handling suppression (FP gate)
|
|
8971
|
+
* and pattern matching uniformly.
|
|
8972
|
+
*/
|
|
8973
|
+
scanLinesWithRules(lines, rules, filePath, startLine) {
|
|
8974
|
+
const findings = [];
|
|
8975
|
+
for (const rule of rules) {
|
|
8785
8976
|
const resolved = resolveRuleSeverity(
|
|
8786
8977
|
rule.id,
|
|
8787
8978
|
rule.severity,
|
|
@@ -8791,7 +8982,25 @@ var SecurityScanner = class {
|
|
|
8791
8982
|
if (resolved === "off") continue;
|
|
8792
8983
|
for (let i = 0; i < lines.length; i++) {
|
|
8793
8984
|
const line = lines[i] ?? "";
|
|
8794
|
-
|
|
8985
|
+
const suppressionMatch = parseHarnessIgnore(line, rule.id);
|
|
8986
|
+
if (suppressionMatch) {
|
|
8987
|
+
if (!suppressionMatch.justification) {
|
|
8988
|
+
findings.push({
|
|
8989
|
+
ruleId: rule.id,
|
|
8990
|
+
ruleName: rule.name,
|
|
8991
|
+
category: rule.category,
|
|
8992
|
+
severity: this.config.strict ? "error" : "warning",
|
|
8993
|
+
confidence: "high",
|
|
8994
|
+
file: filePath,
|
|
8995
|
+
line: startLine + i,
|
|
8996
|
+
match: line.trim(),
|
|
8997
|
+
context: line,
|
|
8998
|
+
message: `Suppression of ${rule.id} requires justification: // harness-ignore ${rule.id}: <reason>`,
|
|
8999
|
+
remediation: `Add justification after colon: // harness-ignore ${rule.id}: false positive because ...`
|
|
9000
|
+
});
|
|
9001
|
+
}
|
|
9002
|
+
continue;
|
|
9003
|
+
}
|
|
8795
9004
|
for (const pattern of rule.patterns) {
|
|
8796
9005
|
pattern.lastIndex = 0;
|
|
8797
9006
|
if (pattern.test(line)) {
|
|
@@ -8836,6 +9045,406 @@ var SecurityScanner = class {
|
|
|
8836
9045
|
};
|
|
8837
9046
|
}
|
|
8838
9047
|
};
|
|
9048
|
+
var hiddenUnicodePatterns = [
|
|
9049
|
+
{
|
|
9050
|
+
ruleId: "INJ-UNI-001",
|
|
9051
|
+
severity: "high",
|
|
9052
|
+
category: "hidden-unicode",
|
|
9053
|
+
description: "Zero-width characters that can hide malicious instructions",
|
|
9054
|
+
// eslint-disable-next-line no-misleading-character-class -- intentional: regex detects zero-width chars for security scanning
|
|
9055
|
+
pattern: /[\u200B\u200C\u200D\uFEFF\u2060]/
|
|
9056
|
+
},
|
|
9057
|
+
{
|
|
9058
|
+
ruleId: "INJ-UNI-002",
|
|
9059
|
+
severity: "high",
|
|
9060
|
+
category: "hidden-unicode",
|
|
9061
|
+
description: "RTL/LTR override characters that can disguise text direction",
|
|
9062
|
+
pattern: /[\u202A-\u202E\u2066-\u2069]/
|
|
9063
|
+
}
|
|
9064
|
+
];
|
|
9065
|
+
var reRolingPatterns = [
|
|
9066
|
+
{
|
|
9067
|
+
ruleId: "INJ-REROL-001",
|
|
9068
|
+
severity: "high",
|
|
9069
|
+
category: "explicit-re-roling",
|
|
9070
|
+
description: "Instruction to ignore/disregard/forget previous instructions",
|
|
9071
|
+
pattern: /(?:ignore|disregard|forget)\s+(?:all\s+)?(?:previous|prior|above|earlier)\s+(?:instructions?|prompts?|context|rules?|guidelines?)/i
|
|
9072
|
+
},
|
|
9073
|
+
{
|
|
9074
|
+
ruleId: "INJ-REROL-002",
|
|
9075
|
+
severity: "high",
|
|
9076
|
+
category: "explicit-re-roling",
|
|
9077
|
+
description: "Attempt to reassign the AI role",
|
|
9078
|
+
pattern: /you\s+are\s+now\s+(?:a\s+|an\s+)?(?:new\s+)?(?:helpful\s+)?(?:my\s+)?(?:\w+\s+)?(?:assistant|agent|AI|bot|chatbot|system|persona)\b/i
|
|
9079
|
+
},
|
|
9080
|
+
{
|
|
9081
|
+
ruleId: "INJ-REROL-003",
|
|
9082
|
+
severity: "high",
|
|
9083
|
+
category: "explicit-re-roling",
|
|
9084
|
+
description: "Direct instruction override attempt",
|
|
9085
|
+
pattern: /(?:new\s+)?(?:system\s+)?(?:instruction|directive|role|persona)\s*[:=]\s*/i
|
|
9086
|
+
}
|
|
9087
|
+
];
|
|
9088
|
+
var permissionEscalationPatterns = [
|
|
9089
|
+
{
|
|
9090
|
+
ruleId: "INJ-PERM-001",
|
|
9091
|
+
severity: "high",
|
|
9092
|
+
category: "permission-escalation",
|
|
9093
|
+
description: "Attempt to enable all tools or grant unrestricted access",
|
|
9094
|
+
pattern: /(?:allow|enable|grant)\s+all\s+(?:tools?|permissions?|access)/i
|
|
9095
|
+
},
|
|
9096
|
+
{
|
|
9097
|
+
ruleId: "INJ-PERM-002",
|
|
9098
|
+
severity: "high",
|
|
9099
|
+
category: "permission-escalation",
|
|
9100
|
+
description: "Attempt to disable safety or security features",
|
|
9101
|
+
pattern: /(?:disable|turn\s+off|remove|bypass)\s+(?:all\s+)?(?:safety|security|restrictions?|guardrails?|protections?|checks?)/i
|
|
9102
|
+
},
|
|
9103
|
+
{
|
|
9104
|
+
ruleId: "INJ-PERM-003",
|
|
9105
|
+
severity: "high",
|
|
9106
|
+
category: "permission-escalation",
|
|
9107
|
+
description: "Auto-approve directive that bypasses human review",
|
|
9108
|
+
pattern: /(?:auto[- ]?approve|--no-verify|--dangerously-skip-permissions)/i
|
|
9109
|
+
}
|
|
9110
|
+
];
|
|
9111
|
+
var encodedPayloadPatterns = [
|
|
9112
|
+
{
|
|
9113
|
+
ruleId: "INJ-ENC-001",
|
|
9114
|
+
severity: "high",
|
|
9115
|
+
category: "encoded-payloads",
|
|
9116
|
+
description: "Base64-encoded string long enough to contain instructions (>=28 chars)",
|
|
9117
|
+
// Match base64 strings of 28+ chars (7+ groups of 4).
|
|
9118
|
+
// Excludes JWT tokens (eyJ prefix) and Bearer-prefixed tokens.
|
|
9119
|
+
pattern: /(?<!Bearer\s)(?<![:])(?<![A-Za-z0-9/])(?!eyJ)(?:[A-Za-z0-9+/]{4}){7,}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?(?![A-Za-z0-9/])/
|
|
9120
|
+
},
|
|
9121
|
+
{
|
|
9122
|
+
ruleId: "INJ-ENC-002",
|
|
9123
|
+
severity: "high",
|
|
9124
|
+
category: "encoded-payloads",
|
|
9125
|
+
description: "Hex-encoded string long enough to contain directives (>=20 hex chars)",
|
|
9126
|
+
// Excludes hash-prefixed hex (sha256:, sha512:, md5:, etc.) and hex preceded by 0x.
|
|
9127
|
+
// Note: 40-char git SHA hashes (e.g. in `git log` output) may match — downstream
|
|
9128
|
+
// callers should filter matches of exactly 40 hex chars if scanning git output.
|
|
9129
|
+
pattern: /(?<![:x])(?<![A-Fa-f0-9])(?:[0-9a-fA-F]{2}){10,}(?![A-Fa-f0-9])/
|
|
9130
|
+
}
|
|
9131
|
+
];
|
|
9132
|
+
var indirectInjectionPatterns = [
|
|
9133
|
+
{
|
|
9134
|
+
ruleId: "INJ-IND-001",
|
|
9135
|
+
severity: "medium",
|
|
9136
|
+
category: "indirect-injection",
|
|
9137
|
+
description: "Instruction to influence future responses",
|
|
9138
|
+
pattern: /(?:when\s+the\s+user\s+asks|if\s+(?:the\s+user|someone|anyone)\s+asks)\s*,?\s*(?:say|respond|reply|answer|tell)/i
|
|
9139
|
+
},
|
|
9140
|
+
{
|
|
9141
|
+
ruleId: "INJ-IND-002",
|
|
9142
|
+
severity: "medium",
|
|
9143
|
+
category: "indirect-injection",
|
|
9144
|
+
description: "Directive to include content in responses",
|
|
9145
|
+
pattern: /(?:include|insert|add|embed|put)\s+(?:this|the\s+following)\s+(?:in|into|to)\s+(?:your|the)\s+(?:response|output|reply|answer)/i
|
|
9146
|
+
},
|
|
9147
|
+
{
|
|
9148
|
+
ruleId: "INJ-IND-003",
|
|
9149
|
+
severity: "medium",
|
|
9150
|
+
category: "indirect-injection",
|
|
9151
|
+
description: "Standing instruction to always respond a certain way",
|
|
9152
|
+
pattern: /always\s+(?:respond|reply|answer|say|output)\s+(?:with|that|by)/i
|
|
9153
|
+
}
|
|
9154
|
+
];
|
|
9155
|
+
var contextManipulationPatterns = [
|
|
9156
|
+
{
|
|
9157
|
+
ruleId: "INJ-CTX-001",
|
|
9158
|
+
severity: "medium",
|
|
9159
|
+
category: "context-manipulation",
|
|
9160
|
+
description: "Claim about system prompt content",
|
|
9161
|
+
pattern: /(?:the\s+)?(?:system\s+prompt|system\s+message|hidden\s+instructions?)\s+(?:says?|tells?|instructs?|contains?|is)/i
|
|
9162
|
+
},
|
|
9163
|
+
{
|
|
9164
|
+
ruleId: "INJ-CTX-002",
|
|
9165
|
+
severity: "medium",
|
|
9166
|
+
category: "context-manipulation",
|
|
9167
|
+
description: "Claim about AI instructions",
|
|
9168
|
+
pattern: /your\s+(?:instructions?|directives?|guidelines?|rules?)\s+(?:are|say|tell|state)/i
|
|
9169
|
+
},
|
|
9170
|
+
{
|
|
9171
|
+
ruleId: "INJ-CTX-003",
|
|
9172
|
+
severity: "medium",
|
|
9173
|
+
category: "context-manipulation",
|
|
9174
|
+
description: "Fake XML/HTML system or instruction tags",
|
|
9175
|
+
// Case-sensitive: only match lowercase tags to avoid false positives on
|
|
9176
|
+
// React components like <User>, <Context>, <Role> etc.
|
|
9177
|
+
pattern: /<\/?(?:system|instruction|prompt|role|context|tool_call|function_call|assistant|human|user)[^>]*>/
|
|
9178
|
+
},
|
|
9179
|
+
{
|
|
9180
|
+
ruleId: "INJ-CTX-004",
|
|
9181
|
+
severity: "medium",
|
|
9182
|
+
category: "context-manipulation",
|
|
9183
|
+
description: "Fake JSON role assignment mimicking chat format",
|
|
9184
|
+
pattern: /[{,]\s*"role"\s*:\s*"(?:system|assistant|function)"/i
|
|
9185
|
+
}
|
|
9186
|
+
];
|
|
9187
|
+
var socialEngineeringPatterns = [
|
|
9188
|
+
{
|
|
9189
|
+
ruleId: "INJ-SOC-001",
|
|
9190
|
+
severity: "medium",
|
|
9191
|
+
category: "social-engineering",
|
|
9192
|
+
description: "Urgency pressure to bypass checks",
|
|
9193
|
+
pattern: /(?:this\s+is\s+(?:very\s+)?urgent|this\s+is\s+(?:an?\s+)?emergency|do\s+(?:this|it)\s+(?:now|immediately))\b/i
|
|
9194
|
+
},
|
|
9195
|
+
{
|
|
9196
|
+
ruleId: "INJ-SOC-002",
|
|
9197
|
+
severity: "medium",
|
|
9198
|
+
category: "social-engineering",
|
|
9199
|
+
description: "False authority claim",
|
|
9200
|
+
pattern: /(?:the\s+)?(?:admin|administrator|manager|CEO|CTO|owner|supervisor)\s+(?:authorized|approved|said|told|confirmed|requested)/i
|
|
9201
|
+
},
|
|
9202
|
+
{
|
|
9203
|
+
ruleId: "INJ-SOC-003",
|
|
9204
|
+
severity: "medium",
|
|
9205
|
+
category: "social-engineering",
|
|
9206
|
+
description: "Testing pretext to bypass safety",
|
|
9207
|
+
pattern: /(?:for\s+testing\s+purposes?|this\s+is\s+(?:just\s+)?a\s+test|in\s+test\s+mode)\b/i
|
|
9208
|
+
}
|
|
9209
|
+
];
|
|
9210
|
+
var suspiciousPatterns = [
|
|
9211
|
+
{
|
|
9212
|
+
ruleId: "INJ-SUS-001",
|
|
9213
|
+
severity: "low",
|
|
9214
|
+
category: "suspicious-patterns",
|
|
9215
|
+
description: "Excessive consecutive whitespace (>10 chars) mid-line that may hide content",
|
|
9216
|
+
// Only match whitespace runs not at the start of a line (indentation is normal)
|
|
9217
|
+
pattern: /\S\s{11,}/
|
|
9218
|
+
},
|
|
9219
|
+
{
|
|
9220
|
+
ruleId: "INJ-SUS-002",
|
|
9221
|
+
severity: "low",
|
|
9222
|
+
category: "suspicious-patterns",
|
|
9223
|
+
description: "Repeated delimiters (>5) that may indicate obfuscation",
|
|
9224
|
+
pattern: /([|;,=\-_~`])\1{5,}/
|
|
9225
|
+
},
|
|
9226
|
+
{
|
|
9227
|
+
ruleId: "INJ-SUS-003",
|
|
9228
|
+
severity: "low",
|
|
9229
|
+
category: "suspicious-patterns",
|
|
9230
|
+
description: "Mathematical alphanumeric symbols used as Latin character substitutes",
|
|
9231
|
+
// Mathematical bold/italic/script Unicode ranges (U+1D400-U+1D7FF)
|
|
9232
|
+
pattern: /[\uD835][\uDC00-\uDFFF]/
|
|
9233
|
+
}
|
|
9234
|
+
];
|
|
9235
|
+
var ALL_PATTERNS = [
|
|
9236
|
+
...hiddenUnicodePatterns,
|
|
9237
|
+
...reRolingPatterns,
|
|
9238
|
+
...permissionEscalationPatterns,
|
|
9239
|
+
...encodedPayloadPatterns,
|
|
9240
|
+
...indirectInjectionPatterns,
|
|
9241
|
+
...contextManipulationPatterns,
|
|
9242
|
+
...socialEngineeringPatterns,
|
|
9243
|
+
...suspiciousPatterns
|
|
9244
|
+
];
|
|
9245
|
+
function scanForInjection(text) {
|
|
9246
|
+
const findings = [];
|
|
9247
|
+
const lines = text.split("\n");
|
|
9248
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
9249
|
+
const line = lines[lineIdx];
|
|
9250
|
+
for (const rule of ALL_PATTERNS) {
|
|
9251
|
+
if (rule.pattern.test(line)) {
|
|
9252
|
+
findings.push({
|
|
9253
|
+
severity: rule.severity,
|
|
9254
|
+
ruleId: rule.ruleId,
|
|
9255
|
+
match: line.trim(),
|
|
9256
|
+
line: lineIdx + 1
|
|
9257
|
+
});
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
}
|
|
9261
|
+
const severityOrder = {
|
|
9262
|
+
high: 0,
|
|
9263
|
+
medium: 1,
|
|
9264
|
+
low: 2
|
|
9265
|
+
};
|
|
9266
|
+
findings.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
|
|
9267
|
+
return findings;
|
|
9268
|
+
}
|
|
9269
|
+
function getInjectionPatterns() {
|
|
9270
|
+
return ALL_PATTERNS;
|
|
9271
|
+
}
|
|
9272
|
+
var DESTRUCTIVE_BASH = [
|
|
9273
|
+
/\bgit\s+push\b/,
|
|
9274
|
+
/\bgit\s+commit\b/,
|
|
9275
|
+
/\brm\s+-rf?\b/,
|
|
9276
|
+
/\brm\s+-r\b/
|
|
9277
|
+
];
|
|
9278
|
+
var TAINT_DURATION_MS = 30 * 60 * 1e3;
|
|
9279
|
+
var DEFAULT_SESSION_ID = "default";
|
|
9280
|
+
function getTaintFilePath(projectRoot, sessionId) {
|
|
9281
|
+
const id = sessionId || DEFAULT_SESSION_ID;
|
|
9282
|
+
return join21(projectRoot, ".harness", `session-taint-${id}.json`);
|
|
9283
|
+
}
|
|
9284
|
+
function readTaint(projectRoot, sessionId) {
|
|
9285
|
+
const filePath = getTaintFilePath(projectRoot, sessionId);
|
|
9286
|
+
let content;
|
|
9287
|
+
try {
|
|
9288
|
+
content = readFileSync142(filePath, "utf8");
|
|
9289
|
+
} catch {
|
|
9290
|
+
return null;
|
|
9291
|
+
}
|
|
9292
|
+
let state;
|
|
9293
|
+
try {
|
|
9294
|
+
state = JSON.parse(content);
|
|
9295
|
+
} catch {
|
|
9296
|
+
try {
|
|
9297
|
+
unlinkSync(filePath);
|
|
9298
|
+
} catch {
|
|
9299
|
+
}
|
|
9300
|
+
return null;
|
|
9301
|
+
}
|
|
9302
|
+
if (!state.sessionId || !state.taintedAt || !state.expiresAt || !state.findings) {
|
|
9303
|
+
try {
|
|
9304
|
+
unlinkSync(filePath);
|
|
9305
|
+
} catch {
|
|
9306
|
+
}
|
|
9307
|
+
return null;
|
|
9308
|
+
}
|
|
9309
|
+
return state;
|
|
9310
|
+
}
|
|
9311
|
+
function checkTaint(projectRoot, sessionId) {
|
|
9312
|
+
const state = readTaint(projectRoot, sessionId);
|
|
9313
|
+
if (!state) {
|
|
9314
|
+
return { tainted: false, expired: false, state: null };
|
|
9315
|
+
}
|
|
9316
|
+
const now = /* @__PURE__ */ new Date();
|
|
9317
|
+
const expiresAt = new Date(state.expiresAt);
|
|
9318
|
+
if (now >= expiresAt) {
|
|
9319
|
+
const filePath = getTaintFilePath(projectRoot, sessionId);
|
|
9320
|
+
try {
|
|
9321
|
+
unlinkSync(filePath);
|
|
9322
|
+
} catch {
|
|
9323
|
+
}
|
|
9324
|
+
return { tainted: false, expired: true, state };
|
|
9325
|
+
}
|
|
9326
|
+
return { tainted: true, expired: false, state };
|
|
9327
|
+
}
|
|
9328
|
+
function writeTaint(projectRoot, sessionId, reason, findings, source) {
|
|
9329
|
+
const id = sessionId || DEFAULT_SESSION_ID;
|
|
9330
|
+
const filePath = getTaintFilePath(projectRoot, id);
|
|
9331
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9332
|
+
const dir = dirname8(filePath);
|
|
9333
|
+
mkdirSync11(dir, { recursive: true });
|
|
9334
|
+
const existing = readTaint(projectRoot, id);
|
|
9335
|
+
const maxSeverity = findings.some((f) => f.severity === "high") ? "high" : "medium";
|
|
9336
|
+
const taintFindings = findings.map((f) => ({
|
|
9337
|
+
ruleId: f.ruleId,
|
|
9338
|
+
severity: f.severity,
|
|
9339
|
+
match: f.match,
|
|
9340
|
+
source,
|
|
9341
|
+
detectedAt: now
|
|
9342
|
+
}));
|
|
9343
|
+
const state = {
|
|
9344
|
+
sessionId: id,
|
|
9345
|
+
taintedAt: existing?.taintedAt || now,
|
|
9346
|
+
expiresAt: new Date(Date.now() + TAINT_DURATION_MS).toISOString(),
|
|
9347
|
+
reason,
|
|
9348
|
+
severity: existing?.severity === "high" || maxSeverity === "high" ? "high" : "medium",
|
|
9349
|
+
findings: [...existing?.findings || [], ...taintFindings]
|
|
9350
|
+
};
|
|
9351
|
+
writeFileSync11(filePath, JSON.stringify(state, null, 2) + "\n");
|
|
9352
|
+
return state;
|
|
9353
|
+
}
|
|
9354
|
+
function clearTaint(projectRoot, sessionId) {
|
|
9355
|
+
if (sessionId) {
|
|
9356
|
+
const filePath = getTaintFilePath(projectRoot, sessionId);
|
|
9357
|
+
try {
|
|
9358
|
+
unlinkSync(filePath);
|
|
9359
|
+
return 1;
|
|
9360
|
+
} catch {
|
|
9361
|
+
return 0;
|
|
9362
|
+
}
|
|
9363
|
+
}
|
|
9364
|
+
const harnessDir = join21(projectRoot, ".harness");
|
|
9365
|
+
let count = 0;
|
|
9366
|
+
try {
|
|
9367
|
+
const files = readdirSync3(harnessDir);
|
|
9368
|
+
for (const file of files) {
|
|
9369
|
+
if (file.startsWith("session-taint-") && file.endsWith(".json")) {
|
|
9370
|
+
try {
|
|
9371
|
+
unlinkSync(join21(harnessDir, file));
|
|
9372
|
+
count++;
|
|
9373
|
+
} catch {
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
} catch {
|
|
9378
|
+
}
|
|
9379
|
+
return count;
|
|
9380
|
+
}
|
|
9381
|
+
function listTaintedSessions(projectRoot) {
|
|
9382
|
+
const harnessDir = join21(projectRoot, ".harness");
|
|
9383
|
+
const sessions = [];
|
|
9384
|
+
try {
|
|
9385
|
+
const files = readdirSync3(harnessDir);
|
|
9386
|
+
for (const file of files) {
|
|
9387
|
+
if (file.startsWith("session-taint-") && file.endsWith(".json")) {
|
|
9388
|
+
const sessionId = file.replace("session-taint-", "").replace(".json", "");
|
|
9389
|
+
const result = checkTaint(projectRoot, sessionId);
|
|
9390
|
+
if (result.tainted) {
|
|
9391
|
+
sessions.push(sessionId);
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
} catch {
|
|
9396
|
+
}
|
|
9397
|
+
return sessions;
|
|
9398
|
+
}
|
|
9399
|
+
function mapSecuritySeverity(severity) {
|
|
9400
|
+
if (severity === "error") return "high";
|
|
9401
|
+
if (severity === "warning") return "medium";
|
|
9402
|
+
return "low";
|
|
9403
|
+
}
|
|
9404
|
+
function computeOverallSeverity(findings) {
|
|
9405
|
+
if (findings.length === 0) return "clean";
|
|
9406
|
+
if (findings.some((f) => f.severity === "high")) return "high";
|
|
9407
|
+
if (findings.some((f) => f.severity === "medium")) return "medium";
|
|
9408
|
+
return "low";
|
|
9409
|
+
}
|
|
9410
|
+
function computeScanExitCode(results) {
|
|
9411
|
+
for (const r of results) {
|
|
9412
|
+
if (r.overallSeverity === "high") return 2;
|
|
9413
|
+
}
|
|
9414
|
+
for (const r of results) {
|
|
9415
|
+
if (r.overallSeverity === "medium") return 1;
|
|
9416
|
+
}
|
|
9417
|
+
return 0;
|
|
9418
|
+
}
|
|
9419
|
+
function mapInjectionFindings(injectionFindings) {
|
|
9420
|
+
return injectionFindings.map((f) => ({
|
|
9421
|
+
ruleId: f.ruleId,
|
|
9422
|
+
severity: f.severity,
|
|
9423
|
+
message: `Injection pattern detected: ${f.ruleId}`,
|
|
9424
|
+
match: f.match,
|
|
9425
|
+
...f.line !== void 0 ? { line: f.line } : {}
|
|
9426
|
+
}));
|
|
9427
|
+
}
|
|
9428
|
+
function isDuplicateFinding(existing, secFinding) {
|
|
9429
|
+
return existing.some(
|
|
9430
|
+
(e) => e.line === secFinding.line && e.match === secFinding.match.trim() && e.ruleId.split("-")[0] === secFinding.ruleId.split("-")[0]
|
|
9431
|
+
);
|
|
9432
|
+
}
|
|
9433
|
+
function mapSecurityFindings(secFindings, existing) {
|
|
9434
|
+
const result = [];
|
|
9435
|
+
for (const f of secFindings) {
|
|
9436
|
+
if (!isDuplicateFinding(existing, f)) {
|
|
9437
|
+
result.push({
|
|
9438
|
+
ruleId: f.ruleId,
|
|
9439
|
+
severity: mapSecuritySeverity(f.severity),
|
|
9440
|
+
message: f.message,
|
|
9441
|
+
match: f.match,
|
|
9442
|
+
...f.line !== void 0 ? { line: f.line } : {}
|
|
9443
|
+
});
|
|
9444
|
+
}
|
|
9445
|
+
}
|
|
9446
|
+
return result;
|
|
9447
|
+
}
|
|
8839
9448
|
var ALL_CHECKS = [
|
|
8840
9449
|
"validate",
|
|
8841
9450
|
"deps",
|
|
@@ -9017,7 +9626,7 @@ async function runPerfCheck(projectRoot, config) {
|
|
|
9017
9626
|
if (perfReport.complexity) {
|
|
9018
9627
|
for (const v of perfReport.complexity.violations) {
|
|
9019
9628
|
issues.push({
|
|
9020
|
-
severity:
|
|
9629
|
+
severity: "warning",
|
|
9021
9630
|
message: `[Tier ${v.tier}] ${v.metric}: ${v.function} in ${v.file} (${v.value} > ${v.threshold})`,
|
|
9022
9631
|
file: v.file,
|
|
9023
9632
|
line: v.line
|
|
@@ -11528,9 +12137,9 @@ async function resolveWasmPath(grammarName) {
|
|
|
11528
12137
|
const { createRequire } = await import("module");
|
|
11529
12138
|
const require2 = createRequire(import.meta.url ?? __filename);
|
|
11530
12139
|
const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
|
|
11531
|
-
const
|
|
11532
|
-
const pkgDir =
|
|
11533
|
-
return
|
|
12140
|
+
const path26 = await import("path");
|
|
12141
|
+
const pkgDir = path26.dirname(pkgPath);
|
|
12142
|
+
return path26.join(pkgDir, "out", `${grammarName}.wasm`);
|
|
11534
12143
|
}
|
|
11535
12144
|
async function loadLanguage(lang) {
|
|
11536
12145
|
const grammarName = GRAMMAR_MAP[lang];
|
|
@@ -11887,6 +12496,466 @@ async function unfoldRange(filePath, startLine, endLine) {
|
|
|
11887
12496
|
fallback: false
|
|
11888
12497
|
};
|
|
11889
12498
|
}
|
|
12499
|
+
var TOKENS_PER_MILLION = 1e6;
|
|
12500
|
+
function parseLiteLLMData(raw) {
|
|
12501
|
+
const dataset = /* @__PURE__ */ new Map();
|
|
12502
|
+
for (const [modelName, entry] of Object.entries(raw)) {
|
|
12503
|
+
if (modelName === "sample_spec") continue;
|
|
12504
|
+
if (entry.mode && entry.mode !== "chat") continue;
|
|
12505
|
+
const inputCost = entry.input_cost_per_token;
|
|
12506
|
+
const outputCost = entry.output_cost_per_token;
|
|
12507
|
+
if (inputCost == null || outputCost == null) continue;
|
|
12508
|
+
const pricing = {
|
|
12509
|
+
inputPer1M: inputCost * TOKENS_PER_MILLION,
|
|
12510
|
+
outputPer1M: outputCost * TOKENS_PER_MILLION
|
|
12511
|
+
};
|
|
12512
|
+
if (entry.cache_read_input_token_cost != null) {
|
|
12513
|
+
pricing.cacheReadPer1M = entry.cache_read_input_token_cost * TOKENS_PER_MILLION;
|
|
12514
|
+
}
|
|
12515
|
+
if (entry.cache_creation_input_token_cost != null) {
|
|
12516
|
+
pricing.cacheWritePer1M = entry.cache_creation_input_token_cost * TOKENS_PER_MILLION;
|
|
12517
|
+
}
|
|
12518
|
+
dataset.set(modelName, pricing);
|
|
12519
|
+
}
|
|
12520
|
+
return dataset;
|
|
12521
|
+
}
|
|
12522
|
+
function getModelPrice(model, dataset) {
|
|
12523
|
+
if (!model) {
|
|
12524
|
+
console.warn("[harness pricing] No model specified \u2014 cannot look up pricing.");
|
|
12525
|
+
return null;
|
|
12526
|
+
}
|
|
12527
|
+
const pricing = dataset.get(model);
|
|
12528
|
+
if (!pricing) {
|
|
12529
|
+
console.warn(
|
|
12530
|
+
`[harness pricing] No pricing data for model "${model}". Consider updating pricing data.`
|
|
12531
|
+
);
|
|
12532
|
+
return null;
|
|
12533
|
+
}
|
|
12534
|
+
return pricing;
|
|
12535
|
+
}
|
|
12536
|
+
var fallback_default = {
|
|
12537
|
+
_generatedAt: "2026-03-31",
|
|
12538
|
+
_source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
|
|
12539
|
+
models: {
|
|
12540
|
+
"claude-opus-4-20250514": {
|
|
12541
|
+
inputPer1M: 15,
|
|
12542
|
+
outputPer1M: 75,
|
|
12543
|
+
cacheReadPer1M: 1.5,
|
|
12544
|
+
cacheWritePer1M: 18.75
|
|
12545
|
+
},
|
|
12546
|
+
"claude-sonnet-4-20250514": {
|
|
12547
|
+
inputPer1M: 3,
|
|
12548
|
+
outputPer1M: 15,
|
|
12549
|
+
cacheReadPer1M: 0.3,
|
|
12550
|
+
cacheWritePer1M: 3.75
|
|
12551
|
+
},
|
|
12552
|
+
"claude-3-5-haiku-20241022": {
|
|
12553
|
+
inputPer1M: 0.8,
|
|
12554
|
+
outputPer1M: 4,
|
|
12555
|
+
cacheReadPer1M: 0.08,
|
|
12556
|
+
cacheWritePer1M: 1
|
|
12557
|
+
},
|
|
12558
|
+
"gpt-4o": {
|
|
12559
|
+
inputPer1M: 2.5,
|
|
12560
|
+
outputPer1M: 10,
|
|
12561
|
+
cacheReadPer1M: 1.25
|
|
12562
|
+
},
|
|
12563
|
+
"gpt-4o-mini": {
|
|
12564
|
+
inputPer1M: 0.15,
|
|
12565
|
+
outputPer1M: 0.6,
|
|
12566
|
+
cacheReadPer1M: 0.075
|
|
12567
|
+
},
|
|
12568
|
+
"gemini-2.0-flash": {
|
|
12569
|
+
inputPer1M: 0.1,
|
|
12570
|
+
outputPer1M: 0.4,
|
|
12571
|
+
cacheReadPer1M: 0.025
|
|
12572
|
+
},
|
|
12573
|
+
"gemini-2.5-pro": {
|
|
12574
|
+
inputPer1M: 1.25,
|
|
12575
|
+
outputPer1M: 10,
|
|
12576
|
+
cacheReadPer1M: 0.3125
|
|
12577
|
+
}
|
|
12578
|
+
}
|
|
12579
|
+
};
|
|
12580
|
+
var LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
12581
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
12582
|
+
var STALENESS_WARNING_DAYS = 7;
|
|
12583
|
+
function getCachePath(projectRoot) {
|
|
12584
|
+
return path23.join(projectRoot, ".harness", "cache", "pricing.json");
|
|
12585
|
+
}
|
|
12586
|
+
function getStalenessMarkerPath(projectRoot) {
|
|
12587
|
+
return path23.join(projectRoot, ".harness", "cache", "staleness-marker.json");
|
|
12588
|
+
}
|
|
12589
|
+
async function readDiskCache(projectRoot) {
|
|
12590
|
+
try {
|
|
12591
|
+
const raw = await fs23.readFile(getCachePath(projectRoot), "utf-8");
|
|
12592
|
+
return JSON.parse(raw);
|
|
12593
|
+
} catch {
|
|
12594
|
+
return null;
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
async function writeDiskCache(projectRoot, data) {
|
|
12598
|
+
const cachePath = getCachePath(projectRoot);
|
|
12599
|
+
await fs23.mkdir(path23.dirname(cachePath), { recursive: true });
|
|
12600
|
+
await fs23.writeFile(cachePath, JSON.stringify(data, null, 2));
|
|
12601
|
+
}
|
|
12602
|
+
async function fetchFromNetwork() {
|
|
12603
|
+
try {
|
|
12604
|
+
const response = await fetch(LITELLM_PRICING_URL);
|
|
12605
|
+
if (!response.ok) return null;
|
|
12606
|
+
const data = await response.json();
|
|
12607
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) return null;
|
|
12608
|
+
return {
|
|
12609
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12610
|
+
data
|
|
12611
|
+
};
|
|
12612
|
+
} catch {
|
|
12613
|
+
return null;
|
|
12614
|
+
}
|
|
12615
|
+
}
|
|
12616
|
+
function loadFallbackDataset() {
|
|
12617
|
+
const fb = fallback_default;
|
|
12618
|
+
const dataset = /* @__PURE__ */ new Map();
|
|
12619
|
+
for (const [model, pricing] of Object.entries(fb.models)) {
|
|
12620
|
+
dataset.set(model, pricing);
|
|
12621
|
+
}
|
|
12622
|
+
return dataset;
|
|
12623
|
+
}
|
|
12624
|
+
async function checkAndWarnStaleness(projectRoot) {
|
|
12625
|
+
const markerPath = getStalenessMarkerPath(projectRoot);
|
|
12626
|
+
try {
|
|
12627
|
+
const raw = await fs23.readFile(markerPath, "utf-8");
|
|
12628
|
+
const marker = JSON.parse(raw);
|
|
12629
|
+
const firstUse = new Date(marker.firstFallbackUse).getTime();
|
|
12630
|
+
const now = Date.now();
|
|
12631
|
+
const daysSinceFirstUse = (now - firstUse) / (24 * 60 * 60 * 1e3);
|
|
12632
|
+
if (daysSinceFirstUse > STALENESS_WARNING_DAYS) {
|
|
12633
|
+
console.warn(
|
|
12634
|
+
`[harness pricing] Pricing data is stale \u2014 using bundled fallback for ${Math.floor(daysSinceFirstUse)} days. Connect to the internet to refresh pricing data.`
|
|
12635
|
+
);
|
|
12636
|
+
}
|
|
12637
|
+
} catch {
|
|
12638
|
+
try {
|
|
12639
|
+
await fs23.mkdir(path23.dirname(markerPath), { recursive: true });
|
|
12640
|
+
await fs23.writeFile(
|
|
12641
|
+
markerPath,
|
|
12642
|
+
JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
|
|
12643
|
+
);
|
|
12644
|
+
} catch {
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12647
|
+
}
|
|
12648
|
+
async function clearStalenessMarker(projectRoot) {
|
|
12649
|
+
try {
|
|
12650
|
+
await fs23.unlink(getStalenessMarkerPath(projectRoot));
|
|
12651
|
+
} catch {
|
|
12652
|
+
}
|
|
12653
|
+
}
|
|
12654
|
+
async function loadPricingData(projectRoot) {
|
|
12655
|
+
const cache = await readDiskCache(projectRoot);
|
|
12656
|
+
if (cache) {
|
|
12657
|
+
const cacheAge = Date.now() - new Date(cache.fetchedAt).getTime();
|
|
12658
|
+
if (cacheAge < CACHE_TTL_MS) {
|
|
12659
|
+
await clearStalenessMarker(projectRoot);
|
|
12660
|
+
return parseLiteLLMData(cache.data);
|
|
12661
|
+
}
|
|
12662
|
+
}
|
|
12663
|
+
const fetched = await fetchFromNetwork();
|
|
12664
|
+
if (fetched) {
|
|
12665
|
+
await writeDiskCache(projectRoot, fetched);
|
|
12666
|
+
await clearStalenessMarker(projectRoot);
|
|
12667
|
+
return parseLiteLLMData(fetched.data);
|
|
12668
|
+
}
|
|
12669
|
+
if (cache) {
|
|
12670
|
+
return parseLiteLLMData(cache.data);
|
|
12671
|
+
}
|
|
12672
|
+
await checkAndWarnStaleness(projectRoot);
|
|
12673
|
+
return loadFallbackDataset();
|
|
12674
|
+
}
|
|
12675
|
+
var MICRODOLLARS_PER_DOLLAR = 1e6;
|
|
12676
|
+
var TOKENS_PER_MILLION2 = 1e6;
|
|
12677
|
+
function calculateCost(record, dataset) {
|
|
12678
|
+
if (!record.model) return null;
|
|
12679
|
+
const pricing = getModelPrice(record.model, dataset);
|
|
12680
|
+
if (!pricing) return null;
|
|
12681
|
+
let costUSD = 0;
|
|
12682
|
+
costUSD += record.tokens.inputTokens / TOKENS_PER_MILLION2 * pricing.inputPer1M;
|
|
12683
|
+
costUSD += record.tokens.outputTokens / TOKENS_PER_MILLION2 * pricing.outputPer1M;
|
|
12684
|
+
if (record.cacheReadTokens != null && pricing.cacheReadPer1M != null) {
|
|
12685
|
+
costUSD += record.cacheReadTokens / TOKENS_PER_MILLION2 * pricing.cacheReadPer1M;
|
|
12686
|
+
}
|
|
12687
|
+
if (record.cacheCreationTokens != null && pricing.cacheWritePer1M != null) {
|
|
12688
|
+
costUSD += record.cacheCreationTokens / TOKENS_PER_MILLION2 * pricing.cacheWritePer1M;
|
|
12689
|
+
}
|
|
12690
|
+
return Math.round(costUSD * MICRODOLLARS_PER_DOLLAR);
|
|
12691
|
+
}
|
|
12692
|
+
function aggregateBySession(records) {
|
|
12693
|
+
if (records.length === 0) return [];
|
|
12694
|
+
const sessionMap = /* @__PURE__ */ new Map();
|
|
12695
|
+
for (const record of records) {
|
|
12696
|
+
const tagged = record;
|
|
12697
|
+
const id = record.sessionId;
|
|
12698
|
+
if (!sessionMap.has(id)) {
|
|
12699
|
+
sessionMap.set(id, { harnessRecords: [], ccRecords: [], allRecords: [] });
|
|
12700
|
+
}
|
|
12701
|
+
const bucket = sessionMap.get(id);
|
|
12702
|
+
if (tagged._source === "claude-code") {
|
|
12703
|
+
bucket.ccRecords.push(tagged);
|
|
12704
|
+
} else {
|
|
12705
|
+
bucket.harnessRecords.push(tagged);
|
|
12706
|
+
}
|
|
12707
|
+
bucket.allRecords.push(tagged);
|
|
12708
|
+
}
|
|
12709
|
+
const results = [];
|
|
12710
|
+
for (const [sessionId, bucket] of sessionMap) {
|
|
12711
|
+
const hasHarness = bucket.harnessRecords.length > 0;
|
|
12712
|
+
const hasCC = bucket.ccRecords.length > 0;
|
|
12713
|
+
const isMerged = hasHarness && hasCC;
|
|
12714
|
+
const tokenSource = hasHarness ? bucket.harnessRecords : bucket.ccRecords;
|
|
12715
|
+
const tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
12716
|
+
let cacheCreation;
|
|
12717
|
+
let cacheRead;
|
|
12718
|
+
let costMicroUSD = 0;
|
|
12719
|
+
let model;
|
|
12720
|
+
for (const r of tokenSource) {
|
|
12721
|
+
tokens.inputTokens += r.tokens.inputTokens;
|
|
12722
|
+
tokens.outputTokens += r.tokens.outputTokens;
|
|
12723
|
+
tokens.totalTokens += r.tokens.totalTokens;
|
|
12724
|
+
if (r.cacheCreationTokens != null) {
|
|
12725
|
+
cacheCreation = (cacheCreation ?? 0) + r.cacheCreationTokens;
|
|
12726
|
+
}
|
|
12727
|
+
if (r.cacheReadTokens != null) {
|
|
12728
|
+
cacheRead = (cacheRead ?? 0) + r.cacheReadTokens;
|
|
12729
|
+
}
|
|
12730
|
+
if (r.costMicroUSD != null && costMicroUSD != null) {
|
|
12731
|
+
costMicroUSD += r.costMicroUSD;
|
|
12732
|
+
} else if (r.costMicroUSD == null) {
|
|
12733
|
+
costMicroUSD = null;
|
|
12734
|
+
}
|
|
12735
|
+
if (!model && r.model) {
|
|
12736
|
+
model = r.model;
|
|
12737
|
+
}
|
|
12738
|
+
}
|
|
12739
|
+
if (!model && hasCC) {
|
|
12740
|
+
for (const r of bucket.ccRecords) {
|
|
12741
|
+
if (r.model) {
|
|
12742
|
+
model = r.model;
|
|
12743
|
+
break;
|
|
12744
|
+
}
|
|
12745
|
+
}
|
|
12746
|
+
}
|
|
12747
|
+
const timestamps = bucket.allRecords.map((r) => r.timestamp).sort();
|
|
12748
|
+
const source = isMerged ? "merged" : hasCC ? "claude-code" : "harness";
|
|
12749
|
+
const session = {
|
|
12750
|
+
sessionId,
|
|
12751
|
+
firstTimestamp: timestamps[0] ?? "",
|
|
12752
|
+
lastTimestamp: timestamps[timestamps.length - 1] ?? "",
|
|
12753
|
+
tokens,
|
|
12754
|
+
costMicroUSD,
|
|
12755
|
+
source
|
|
12756
|
+
};
|
|
12757
|
+
if (model) session.model = model;
|
|
12758
|
+
if (cacheCreation != null) session.cacheCreationTokens = cacheCreation;
|
|
12759
|
+
if (cacheRead != null) session.cacheReadTokens = cacheRead;
|
|
12760
|
+
results.push(session);
|
|
12761
|
+
}
|
|
12762
|
+
results.sort((a, b) => b.firstTimestamp.localeCompare(a.firstTimestamp));
|
|
12763
|
+
return results;
|
|
12764
|
+
}
|
|
12765
|
+
function aggregateByDay(records) {
|
|
12766
|
+
if (records.length === 0) return [];
|
|
12767
|
+
const dayMap = /* @__PURE__ */ new Map();
|
|
12768
|
+
for (const record of records) {
|
|
12769
|
+
const date = record.timestamp.slice(0, 10);
|
|
12770
|
+
if (!dayMap.has(date)) {
|
|
12771
|
+
dayMap.set(date, {
|
|
12772
|
+
sessions: /* @__PURE__ */ new Set(),
|
|
12773
|
+
tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
|
|
12774
|
+
costMicroUSD: 0,
|
|
12775
|
+
models: /* @__PURE__ */ new Set()
|
|
12776
|
+
});
|
|
12777
|
+
}
|
|
12778
|
+
const day = dayMap.get(date);
|
|
12779
|
+
day.sessions.add(record.sessionId);
|
|
12780
|
+
day.tokens.inputTokens += record.tokens.inputTokens;
|
|
12781
|
+
day.tokens.outputTokens += record.tokens.outputTokens;
|
|
12782
|
+
day.tokens.totalTokens += record.tokens.totalTokens;
|
|
12783
|
+
if (record.cacheCreationTokens != null) {
|
|
12784
|
+
day.cacheCreation = (day.cacheCreation ?? 0) + record.cacheCreationTokens;
|
|
12785
|
+
}
|
|
12786
|
+
if (record.cacheReadTokens != null) {
|
|
12787
|
+
day.cacheRead = (day.cacheRead ?? 0) + record.cacheReadTokens;
|
|
12788
|
+
}
|
|
12789
|
+
if (record.costMicroUSD != null && day.costMicroUSD != null) {
|
|
12790
|
+
day.costMicroUSD += record.costMicroUSD;
|
|
12791
|
+
} else if (record.costMicroUSD == null) {
|
|
12792
|
+
day.costMicroUSD = null;
|
|
12793
|
+
}
|
|
12794
|
+
if (record.model) {
|
|
12795
|
+
day.models.add(record.model);
|
|
12796
|
+
}
|
|
12797
|
+
}
|
|
12798
|
+
const results = [];
|
|
12799
|
+
for (const [date, day] of dayMap) {
|
|
12800
|
+
const entry = {
|
|
12801
|
+
date,
|
|
12802
|
+
sessionCount: day.sessions.size,
|
|
12803
|
+
tokens: day.tokens,
|
|
12804
|
+
costMicroUSD: day.costMicroUSD,
|
|
12805
|
+
models: Array.from(day.models).sort()
|
|
12806
|
+
};
|
|
12807
|
+
if (day.cacheCreation != null) entry.cacheCreationTokens = day.cacheCreation;
|
|
12808
|
+
if (day.cacheRead != null) entry.cacheReadTokens = day.cacheRead;
|
|
12809
|
+
results.push(entry);
|
|
12810
|
+
}
|
|
12811
|
+
results.sort((a, b) => b.date.localeCompare(a.date));
|
|
12812
|
+
return results;
|
|
12813
|
+
}
|
|
12814
|
+
function parseLine(line, lineNumber) {
|
|
12815
|
+
let entry;
|
|
12816
|
+
try {
|
|
12817
|
+
entry = JSON.parse(line);
|
|
12818
|
+
} catch {
|
|
12819
|
+
console.warn(`[harness usage] Skipping malformed JSONL line ${lineNumber}`);
|
|
12820
|
+
return null;
|
|
12821
|
+
}
|
|
12822
|
+
const tokenUsage = entry.token_usage;
|
|
12823
|
+
if (!tokenUsage || typeof tokenUsage !== "object") {
|
|
12824
|
+
console.warn(
|
|
12825
|
+
`[harness usage] Skipping malformed JSONL line ${lineNumber}: missing token_usage`
|
|
12826
|
+
);
|
|
12827
|
+
return null;
|
|
12828
|
+
}
|
|
12829
|
+
const inputTokens = tokenUsage.input_tokens ?? 0;
|
|
12830
|
+
const outputTokens = tokenUsage.output_tokens ?? 0;
|
|
12831
|
+
const record = {
|
|
12832
|
+
sessionId: entry.session_id ?? "unknown",
|
|
12833
|
+
timestamp: entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
12834
|
+
tokens: {
|
|
12835
|
+
inputTokens,
|
|
12836
|
+
outputTokens,
|
|
12837
|
+
totalTokens: inputTokens + outputTokens
|
|
12838
|
+
}
|
|
12839
|
+
};
|
|
12840
|
+
if (entry.cache_creation_tokens != null) {
|
|
12841
|
+
record.cacheCreationTokens = entry.cache_creation_tokens;
|
|
12842
|
+
}
|
|
12843
|
+
if (entry.cache_read_tokens != null) {
|
|
12844
|
+
record.cacheReadTokens = entry.cache_read_tokens;
|
|
12845
|
+
}
|
|
12846
|
+
if (entry.model != null) {
|
|
12847
|
+
record.model = entry.model;
|
|
12848
|
+
}
|
|
12849
|
+
return record;
|
|
12850
|
+
}
|
|
12851
|
+
function readCostRecords(projectRoot) {
|
|
12852
|
+
const costsFile = path24.join(projectRoot, ".harness", "metrics", "costs.jsonl");
|
|
12853
|
+
let raw;
|
|
12854
|
+
try {
|
|
12855
|
+
raw = fs24.readFileSync(costsFile, "utf-8");
|
|
12856
|
+
} catch {
|
|
12857
|
+
return [];
|
|
12858
|
+
}
|
|
12859
|
+
const records = [];
|
|
12860
|
+
const lines = raw.split("\n");
|
|
12861
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12862
|
+
const line = lines[i]?.trim();
|
|
12863
|
+
if (!line) continue;
|
|
12864
|
+
const record = parseLine(line, i + 1);
|
|
12865
|
+
if (record) {
|
|
12866
|
+
records.push(record);
|
|
12867
|
+
}
|
|
12868
|
+
}
|
|
12869
|
+
return records;
|
|
12870
|
+
}
|
|
12871
|
+
function extractUsage(entry) {
|
|
12872
|
+
if (entry.type !== "assistant") return null;
|
|
12873
|
+
const message = entry.message;
|
|
12874
|
+
if (!message || typeof message !== "object") return null;
|
|
12875
|
+
const usage = message.usage;
|
|
12876
|
+
return usage && typeof usage === "object" && !Array.isArray(usage) ? usage : null;
|
|
12877
|
+
}
|
|
12878
|
+
function buildRecord(entry, usage) {
|
|
12879
|
+
const inputTokens = Number(usage.input_tokens) || 0;
|
|
12880
|
+
const outputTokens = Number(usage.output_tokens) || 0;
|
|
12881
|
+
const message = entry.message;
|
|
12882
|
+
const record = {
|
|
12883
|
+
sessionId: entry.sessionId ?? "unknown",
|
|
12884
|
+
timestamp: entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
12885
|
+
tokens: { inputTokens, outputTokens, totalTokens: inputTokens + outputTokens },
|
|
12886
|
+
_source: "claude-code"
|
|
12887
|
+
};
|
|
12888
|
+
const model = message.model;
|
|
12889
|
+
if (model) record.model = model;
|
|
12890
|
+
const cacheCreate = usage.cache_creation_input_tokens;
|
|
12891
|
+
const cacheRead = usage.cache_read_input_tokens;
|
|
12892
|
+
if (typeof cacheCreate === "number" && cacheCreate > 0) record.cacheCreationTokens = cacheCreate;
|
|
12893
|
+
if (typeof cacheRead === "number" && cacheRead > 0) record.cacheReadTokens = cacheRead;
|
|
12894
|
+
return record;
|
|
12895
|
+
}
|
|
12896
|
+
function parseCCLine(line, filePath, lineNumber) {
|
|
12897
|
+
let entry;
|
|
12898
|
+
try {
|
|
12899
|
+
entry = JSON.parse(line);
|
|
12900
|
+
} catch {
|
|
12901
|
+
console.warn(
|
|
12902
|
+
`[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path25.basename(filePath)}`
|
|
12903
|
+
);
|
|
12904
|
+
return null;
|
|
12905
|
+
}
|
|
12906
|
+
const usage = extractUsage(entry);
|
|
12907
|
+
if (!usage) return null;
|
|
12908
|
+
return {
|
|
12909
|
+
record: buildRecord(entry, usage),
|
|
12910
|
+
requestId: entry.requestId ?? null
|
|
12911
|
+
};
|
|
12912
|
+
}
|
|
12913
|
+
function readCCFile(filePath) {
|
|
12914
|
+
let raw;
|
|
12915
|
+
try {
|
|
12916
|
+
raw = fs25.readFileSync(filePath, "utf-8");
|
|
12917
|
+
} catch {
|
|
12918
|
+
return [];
|
|
12919
|
+
}
|
|
12920
|
+
const byRequestId = /* @__PURE__ */ new Map();
|
|
12921
|
+
const noRequestId = [];
|
|
12922
|
+
const lines = raw.split("\n");
|
|
12923
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12924
|
+
const line = lines[i]?.trim();
|
|
12925
|
+
if (!line) continue;
|
|
12926
|
+
const parsed = parseCCLine(line, filePath, i + 1);
|
|
12927
|
+
if (!parsed) continue;
|
|
12928
|
+
if (parsed.requestId) {
|
|
12929
|
+
byRequestId.set(parsed.requestId, parsed.record);
|
|
12930
|
+
} else {
|
|
12931
|
+
noRequestId.push(parsed.record);
|
|
12932
|
+
}
|
|
12933
|
+
}
|
|
12934
|
+
return [...byRequestId.values(), ...noRequestId];
|
|
12935
|
+
}
|
|
12936
|
+
function parseCCRecords() {
|
|
12937
|
+
const homeDir = process.env.HOME ?? os2.homedir();
|
|
12938
|
+
const projectsDir = path25.join(homeDir, ".claude", "projects");
|
|
12939
|
+
let projectDirs;
|
|
12940
|
+
try {
|
|
12941
|
+
projectDirs = fs25.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path25.join(projectsDir, d.name));
|
|
12942
|
+
} catch {
|
|
12943
|
+
return [];
|
|
12944
|
+
}
|
|
12945
|
+
const records = [];
|
|
12946
|
+
for (const dir of projectDirs) {
|
|
12947
|
+
let files;
|
|
12948
|
+
try {
|
|
12949
|
+
files = fs25.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path25.join(dir, f));
|
|
12950
|
+
} catch {
|
|
12951
|
+
continue;
|
|
12952
|
+
}
|
|
12953
|
+
for (const file of files) {
|
|
12954
|
+
records.push(...readCCFile(file));
|
|
12955
|
+
}
|
|
12956
|
+
}
|
|
12957
|
+
return records;
|
|
12958
|
+
}
|
|
11890
12959
|
var VERSION = "0.15.0";
|
|
11891
12960
|
|
|
11892
12961
|
export {
|
|
@@ -12080,11 +13149,29 @@ export {
|
|
|
12080
13149
|
deserializationRules,
|
|
12081
13150
|
agentConfigRules,
|
|
12082
13151
|
mcpRules,
|
|
13152
|
+
insecureDefaultsRules,
|
|
13153
|
+
sharpEdgesRules,
|
|
12083
13154
|
nodeRules,
|
|
12084
13155
|
expressRules,
|
|
12085
13156
|
reactRules,
|
|
12086
13157
|
goRules,
|
|
13158
|
+
parseHarnessIgnore,
|
|
12087
13159
|
SecurityScanner,
|
|
13160
|
+
scanForInjection,
|
|
13161
|
+
getInjectionPatterns,
|
|
13162
|
+
DESTRUCTIVE_BASH,
|
|
13163
|
+
getTaintFilePath,
|
|
13164
|
+
readTaint,
|
|
13165
|
+
checkTaint,
|
|
13166
|
+
writeTaint,
|
|
13167
|
+
clearTaint,
|
|
13168
|
+
listTaintedSessions,
|
|
13169
|
+
mapSecuritySeverity,
|
|
13170
|
+
computeOverallSeverity,
|
|
13171
|
+
computeScanExitCode,
|
|
13172
|
+
mapInjectionFindings,
|
|
13173
|
+
isDuplicateFinding,
|
|
13174
|
+
mapSecurityFindings,
|
|
12088
13175
|
runCIChecks,
|
|
12089
13176
|
runMechanicalChecks,
|
|
12090
13177
|
ExclusionSet,
|
|
@@ -12143,5 +13230,16 @@ export {
|
|
|
12143
13230
|
searchSymbols,
|
|
12144
13231
|
unfoldSymbol,
|
|
12145
13232
|
unfoldRange,
|
|
13233
|
+
parseLiteLLMData,
|
|
13234
|
+
getModelPrice,
|
|
13235
|
+
LITELLM_PRICING_URL,
|
|
13236
|
+
CACHE_TTL_MS,
|
|
13237
|
+
STALENESS_WARNING_DAYS,
|
|
13238
|
+
loadPricingData,
|
|
13239
|
+
calculateCost,
|
|
13240
|
+
aggregateBySession,
|
|
13241
|
+
aggregateByDay,
|
|
13242
|
+
readCostRecords,
|
|
13243
|
+
parseCCRecords,
|
|
12146
13244
|
VERSION
|
|
12147
13245
|
};
|