@harness-engineering/cli 1.23.1 → 1.23.2
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/harness/add-harness-component/SKILL.md +21 -12
- package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +5 -15
- package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +5 -15
- package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +10 -0
- package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +5 -15
- package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +18 -10
- package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +10 -0
- package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +10 -1
- package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +5 -15
- package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +20 -1
- package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +10 -0
- package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +9 -0
- package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +8 -0
- package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +22 -13
- package/dist/agents/commands/cursor/harness/add-harness-component.mdc +12 -12
- package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +10 -10
- package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +1 -1
- package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +13 -13
- package/dist/agents/skills/claude-code/add-harness-component/SKILL.md +21 -12
- package/dist/agents/skills/claude-code/align-documentation/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/check-mechanical-constraints/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-auth/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-caching/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-chaos/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/harness-compliance/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-containerization/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-data-pipeline/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-data-validation/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-database/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-debugging/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-design/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-design-system/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-design-web/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-diagnostics/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/harness-dx/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-e2e/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-event-driven/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-feature-flags/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-git-workflow/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-incident-response/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-infrastructure-as-code/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-integration-test/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-load-testing/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-ml-ops/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-mobile-patterns/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-mutation-test/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-observability/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +18 -10
- package/dist/agents/skills/claude-code/harness-parallel-agents/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-property-test/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-refactoring/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +11 -0
- package/dist/agents/skills/claude-code/harness-resilience/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +10 -1
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/claude-code/harness-secrets/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +5 -15
- package/dist/agents/skills/claude-code/harness-skill-authoring/SKILL.md +29 -1
- package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-sql-review/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-state-management/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-supply-chain-audit/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-tdd/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-test-data/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-ux-copy/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-verify/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-visual-regression/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +22 -13
- package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +9 -0
- package/dist/agents/skills/codex/add-harness-component/SKILL.md +21 -12
- package/dist/agents/skills/codex/align-documentation/SKILL.md +9 -0
- package/dist/agents/skills/codex/check-mechanical-constraints/SKILL.md +9 -0
- package/dist/agents/skills/codex/cleanup-dead-code/SKILL.md +11 -0
- package/dist/agents/skills/codex/detect-doc-drift/SKILL.md +9 -0
- package/dist/agents/skills/codex/enforce-architecture/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-api-design/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-auth/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-autopilot/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-caching/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-chaos/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-code-review/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-codebase-cleanup/SKILL.md +11 -0
- package/dist/agents/skills/codex/harness-compliance/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-containerization/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-data-pipeline/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-data-validation/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-database/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-debugging/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-dependency-health/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-deployment/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-design/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-design-mobile/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-design-system/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-design-web/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-diagnostics/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-docs-pipeline/SKILL.md +11 -0
- package/dist/agents/skills/codex/harness-dx/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-e2e/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-event-driven/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-execution/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-feature-flags/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-hotspot-detector/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-i18n/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-i18n-process/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-i18n-workflow/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-impact-analysis/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-incident-response/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-infrastructure-as-code/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-integration-test/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-integrity/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-knowledge-mapper/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-load-testing/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-ml-ops/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-mobile-patterns/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-mutation-test/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-observability/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-onboarding/SKILL.md +18 -10
- package/dist/agents/skills/codex/harness-parallel-agents/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-perf/SKILL.md +11 -0
- package/dist/agents/skills/codex/harness-perf-tdd/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-planning/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-pre-commit-review/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-product-spec/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-property-test/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-refactoring/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-release-readiness/SKILL.md +11 -0
- package/dist/agents/skills/codex/harness-resilience/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-roadmap/SKILL.md +10 -1
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/codex/harness-secrets/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-security-review/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-security-scan/SKILL.md +5 -15
- package/dist/agents/skills/codex/harness-skill-authoring/SKILL.md +29 -1
- package/dist/agents/skills/codex/harness-soundness-review/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-sql-review/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-state-management/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-supply-chain-audit/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-tdd/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-test-data/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-ux-copy/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-verification/SKILL.md +9 -0
- package/dist/agents/skills/codex/harness-verify/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-visual-regression/SKILL.md +10 -0
- package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +22 -13
- package/dist/agents/skills/codex/validate-context-engineering/SKILL.md +9 -0
- package/dist/agents/skills/cursor/add-harness-component/SKILL.md +21 -12
- package/dist/agents/skills/cursor/align-documentation/SKILL.md +9 -0
- package/dist/agents/skills/cursor/check-mechanical-constraints/SKILL.md +9 -0
- package/dist/agents/skills/cursor/cleanup-dead-code/SKILL.md +11 -0
- package/dist/agents/skills/cursor/detect-doc-drift/SKILL.md +9 -0
- package/dist/agents/skills/cursor/enforce-architecture/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-api-design/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-auth/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-caching/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-chaos/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-code-review/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-codebase-cleanup/SKILL.md +11 -0
- package/dist/agents/skills/cursor/harness-compliance/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-containerization/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-data-pipeline/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-data-validation/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-database/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-debugging/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-dependency-health/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-deployment/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-design/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-design-mobile/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-design-system/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-design-web/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-diagnostics/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-docs-pipeline/SKILL.md +11 -0
- package/dist/agents/skills/cursor/harness-dx/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-e2e/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-event-driven/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-feature-flags/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-hotspot-detector/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-i18n/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-i18n-process/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-i18n-workflow/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-impact-analysis/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-incident-response/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-infrastructure-as-code/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-integration-test/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-integrity/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-knowledge-mapper/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-load-testing/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-ml-ops/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-mobile-patterns/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-mutation-test/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-observability/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +18 -10
- package/dist/agents/skills/cursor/harness-parallel-agents/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-perf/SKILL.md +11 -0
- package/dist/agents/skills/cursor/harness-perf-tdd/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-planning/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-pre-commit-review/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-product-spec/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-property-test/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-refactoring/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-release-readiness/SKILL.md +11 -0
- package/dist/agents/skills/cursor/harness-resilience/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +10 -1
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/cursor/harness-secrets/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-security-review/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-security-scan/SKILL.md +5 -15
- package/dist/agents/skills/cursor/harness-skill-authoring/SKILL.md +29 -1
- package/dist/agents/skills/cursor/harness-soundness-review/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-sql-review/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-state-management/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-supply-chain-audit/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-tdd/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-test-data/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-ux-copy/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-verification/SKILL.md +9 -0
- package/dist/agents/skills/cursor/harness-verify/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-visual-regression/SKILL.md +10 -0
- package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +22 -13
- package/dist/agents/skills/cursor/validate-context-engineering/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/add-harness-component/SKILL.md +21 -12
- package/dist/agents/skills/gemini-cli/align-documentation/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/check-mechanical-constraints/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/cleanup-dead-code/SKILL.md +11 -0
- package/dist/agents/skills/gemini-cli/detect-doc-drift/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/enforce-architecture/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-caching/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-chaos/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +11 -0
- package/dist/agents/skills/gemini-cli/harness-compliance/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-containerization/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-data-pipeline/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-data-validation/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-debugging/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-design/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-diagnostics/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +11 -0
- package/dist/agents/skills/gemini-cli/harness-dx/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-e2e/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-event-driven/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-feature-flags/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-git-workflow/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-incident-response/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-integration-test/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-integrity/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-load-testing/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-ml-ops/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-mobile-patterns/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-mutation-test/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-onboarding/SKILL.md +18 -10
- package/dist/agents/skills/gemini-cli/harness-parallel-agents/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +11 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-pre-commit-review/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-property-test/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-refactoring/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +11 -0
- package/dist/agents/skills/gemini-cli/harness-resilience/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +10 -1
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +8 -0
- package/dist/agents/skills/gemini-cli/harness-secrets/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +5 -15
- package/dist/agents/skills/gemini-cli/harness-skill-authoring/SKILL.md +29 -1
- package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-sql-review/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-state-management/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-tdd/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-test-data/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-ux-copy/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-verify/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-visual-regression/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +22 -13
- package/dist/agents/skills/gemini-cli/validate-context-engineering/SKILL.md +9 -0
- package/dist/agents-md-HCCCO5PK.js +9 -0
- package/dist/{architecture-FVERI7BQ.js → architecture-S2H624W7.js} +5 -5
- package/dist/{assess-project-UGL5KLBV.js → assess-project-XSGK44S5.js} +1 -1
- package/dist/bin/harness-mcp.js +18 -18
- package/dist/bin/harness.js +124 -35
- package/dist/{check-phase-gate-C7JPPKMX.js → check-phase-gate-UGBJ237T.js} +5 -5
- package/dist/{chunk-RQ3AKUJB.js → chunk-2DHX6TAP.js} +4 -4
- package/dist/{chunk-7XZSHTYZ.js → chunk-2GT3HO2T.js} +3 -3
- package/dist/{chunk-ZLTFDTK7.js → chunk-2YA4XRI3.js} +5 -5
- package/dist/{chunk-GZKSBLQL.js → chunk-35EQ5UEI.js} +1 -1
- package/dist/{chunk-T5QWCVGK.js → chunk-4FHBPA3E.js} +11 -3
- package/dist/{chunk-ERS5EVUZ.js → chunk-5LMZA5LZ.js} +10 -10
- package/dist/{chunk-L57RL7MC.js → chunk-BK52Z6DR.js} +869 -419
- package/dist/{chunk-EUCASOD7.js → chunk-CLD4KL7O.js} +341 -71
- package/dist/{chunk-OD3S2NHN.js → chunk-E2GTL3YS.js} +1 -1
- package/dist/{chunk-YLN34N65.js → chunk-FP53DDB5.js} +1 -1
- package/dist/{chunk-7V5Y2L67.js → chunk-I47JLISV.js} +1 -1
- package/dist/{chunk-LAKMOIU6.js → chunk-KC5CTCEL.js} +9 -9
- package/dist/{chunk-UJHNGRS6.js → chunk-KTL3PHNQ.js} +6445 -6222
- package/dist/{chunk-DBSOCI3G.js → chunk-KV4M6Y5J.js} +1 -1
- package/dist/{chunk-FIAPHX37.js → chunk-LM5Z2WCA.js} +1 -1
- package/dist/{chunk-SD3SQOZ2.js → chunk-LOUH2LIC.js} +1 -1
- package/dist/{chunk-FNVAW5NG.js → chunk-MHOO7NLG.js} +11 -11
- package/dist/{chunk-HRUCT5YX.js → chunk-MZAHE4DK.js} +12 -12
- package/dist/{chunk-WKLLNUAT.js → chunk-NKL53UBL.js} +6 -6
- package/dist/{chunk-AQN7GFKU.js → chunk-PGF44T2D.js} +6 -6
- package/dist/{chunk-H7Y5CKTM.js → chunk-Q3XYV5UC.js} +1 -1
- package/dist/{chunk-KIR5PQX5.js → chunk-S5ZXT3TZ.js} +1 -1
- package/dist/{chunk-6KWBH4EO.js → chunk-UGD37ECK.js} +5 -5
- package/dist/{chunk-QBATHQXU.js → chunk-V27WDRYV.js} +540 -490
- package/dist/{chunk-YQ6KC6TE.js → chunk-YDRB55Q4.js} +1 -1
- package/dist/{chunk-CZEPCYVX.js → chunk-ZRYDYDB2.js} +6 -6
- package/dist/{chunk-7DMF3VT5.js → chunk-ZYJJUPNE.js} +1 -1
- package/dist/ci-workflow-I3V7FZNV.js +9 -0
- package/dist/{create-skill-U3XCFRZN.js → create-skill-AO25CJFM.js} +2 -2
- package/dist/{dist-USY2C5JL.js → dist-666AAZQ6.js} +1 -1
- package/dist/{dist-DZ63LLUD.js → dist-KQSTRP36.js} +1 -1
- package/dist/{dist-LPGVPYOZ.js → dist-MKWF5CXR.js} +7 -3
- package/dist/{dist-K56VJ4UJ.js → dist-WU3TVNNG.js} +7 -1
- package/dist/{docs-CGUBALYL.js → docs-R7UVQBMQ.js} +5 -5
- package/dist/engine-JGI3MWAC.js +9 -0
- package/dist/{entropy-H5OOCI57.js → entropy-IDHIG7HS.js} +4 -4
- package/dist/{feedback-XTDR7E3R.js → feedback-JZETY4UR.js} +1 -1
- package/dist/{generate-agent-definitions-RBI7Z4RY.js → generate-agent-definitions-D7B25YTM.js} +6 -6
- package/dist/{graph-loader-GRXDUWXO.js → graph-loader-BJULJYGG.js} +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.js +54 -54
- package/dist/loader-E4KNTOP2.js +11 -0
- package/dist/mcp-67I2DBNM.js +37 -0
- package/dist/{performance-FSXEQJYB.js → performance-744OSR6P.js} +5 -5
- package/dist/{review-pipeline-VLKL7NV2.js → review-pipeline-HIO7HBW4.js} +1 -1
- package/dist/runtime-JXQ26U4Z.js +10 -0
- package/dist/{security-B76X5RL7.js → security-GDKHVFUC.js} +1 -1
- package/dist/{validate-KN6A2GN3.js → validate-2IUR3OWX.js} +5 -5
- package/dist/validate-cross-check-AM4T6P2K.js +9 -0
- package/package.json +5 -5
- package/dist/agents-md-FJXDMZPJ.js +0 -9
- package/dist/ci-workflow-S7VY625R.js +0 -9
- package/dist/engine-PEHFAFOT.js +0 -9
- package/dist/loader-IOC5L7NL.js +0 -11
- package/dist/mcp-7RPKBGIR.js +0 -37
- package/dist/runtime-3X2MV6R4.js +0 -10
- package/dist/validate-cross-check-LITTM24O.js +0 -9
- package/dist/{chunk-CJDVBBPB.js → chunk-3ISINLYT.js} +1 -1
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
Err,
|
|
3
3
|
Ok,
|
|
4
4
|
SESSION_SECTION_NAMES
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5LMZA5LZ.js";
|
|
6
6
|
import {
|
|
7
7
|
GraphStore,
|
|
8
8
|
queryTraceability
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CLD4KL7O.js";
|
|
10
10
|
|
|
11
11
|
// ../core/dist/chunk-BQUWXBGR.mjs
|
|
12
12
|
import { z } from "zod";
|
|
@@ -139,17 +139,17 @@ function resolveFileToLayer(file, layers) {
|
|
|
139
139
|
}
|
|
140
140
|
var accessAsync = promisify(access);
|
|
141
141
|
var readFileAsync = promisify(readFile);
|
|
142
|
-
async function fileExists(
|
|
142
|
+
async function fileExists(path31) {
|
|
143
143
|
try {
|
|
144
|
-
await accessAsync(
|
|
144
|
+
await accessAsync(path31, constants.F_OK);
|
|
145
145
|
return true;
|
|
146
146
|
} catch {
|
|
147
147
|
return false;
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
-
async function readFileContent(
|
|
150
|
+
async function readFileContent(path31) {
|
|
151
151
|
try {
|
|
152
|
-
const content = await readFileAsync(
|
|
152
|
+
const content = await readFileAsync(path31, "utf-8");
|
|
153
153
|
return Ok(content);
|
|
154
154
|
} catch (error) {
|
|
155
155
|
return Err(error);
|
|
@@ -1850,49 +1850,56 @@ import * as fs12 from "fs";
|
|
|
1850
1850
|
import * as path9 from "path";
|
|
1851
1851
|
import * as fs13 from "fs";
|
|
1852
1852
|
import * as path10 from "path";
|
|
1853
|
+
import * as crypto2 from "crypto";
|
|
1853
1854
|
import * as fs14 from "fs";
|
|
1854
1855
|
import * as path11 from "path";
|
|
1855
|
-
import { execSync as execSync2 } from "child_process";
|
|
1856
1856
|
import * as fs15 from "fs";
|
|
1857
1857
|
import * as path12 from "path";
|
|
1858
1858
|
import * as fs16 from "fs";
|
|
1859
1859
|
import * as path13 from "path";
|
|
1860
1860
|
import * as fs17 from "fs";
|
|
1861
1861
|
import * as path14 from "path";
|
|
1862
|
+
import { execSync as execSync2 } from "child_process";
|
|
1862
1863
|
import * as fs18 from "fs";
|
|
1863
1864
|
import * as path15 from "path";
|
|
1864
|
-
import { z as z7 } from "zod";
|
|
1865
|
-
import * as fs20 from "fs/promises";
|
|
1866
|
-
import { minimatch as minimatch4 } from "minimatch";
|
|
1867
|
-
import { z as z8 } from "zod";
|
|
1868
1865
|
import * as fs19 from "fs";
|
|
1869
1866
|
import * as path16 from "path";
|
|
1870
|
-
import
|
|
1871
|
-
import { join as join242, dirname as dirname9 } from "path";
|
|
1867
|
+
import * as fs20 from "fs";
|
|
1872
1868
|
import * as path17 from "path";
|
|
1869
|
+
import * as fs21 from "fs";
|
|
1873
1870
|
import * as path18 from "path";
|
|
1871
|
+
import { z as z7 } from "zod";
|
|
1872
|
+
import * as fs23 from "fs/promises";
|
|
1873
|
+
import { minimatch as minimatch4 } from "minimatch";
|
|
1874
|
+
import { z as z8 } from "zod";
|
|
1875
|
+
import * as fs22 from "fs";
|
|
1874
1876
|
import * as path19 from "path";
|
|
1877
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, unlinkSync, mkdirSync as mkdirSync13, readdirSync as readdirSync3 } from "fs";
|
|
1878
|
+
import { join as join272, dirname as dirname9 } from "path";
|
|
1875
1879
|
import * as path20 from "path";
|
|
1876
|
-
import * as fs21 from "fs";
|
|
1877
1880
|
import * as path21 from "path";
|
|
1878
|
-
import * as fs22 from "fs";
|
|
1879
|
-
import { z as z9 } from "zod";
|
|
1880
|
-
import * as fs23 from "fs/promises";
|
|
1881
1881
|
import * as path22 from "path";
|
|
1882
|
-
import * as fs24 from "fs/promises";
|
|
1883
1882
|
import * as path23 from "path";
|
|
1884
|
-
import * as
|
|
1885
|
-
import * as fs25 from "fs";
|
|
1883
|
+
import * as fs24 from "fs";
|
|
1886
1884
|
import * as path24 from "path";
|
|
1887
|
-
import * as
|
|
1888
|
-
import {
|
|
1889
|
-
import Parser from "web-tree-sitter";
|
|
1885
|
+
import * as fs25 from "fs";
|
|
1886
|
+
import { z as z9 } from "zod";
|
|
1890
1887
|
import * as fs26 from "fs/promises";
|
|
1891
1888
|
import * as path25 from "path";
|
|
1892
|
-
import * as fs27 from "fs";
|
|
1889
|
+
import * as fs27 from "fs/promises";
|
|
1893
1890
|
import * as path26 from "path";
|
|
1891
|
+
import * as ejs from "ejs";
|
|
1894
1892
|
import * as fs28 from "fs";
|
|
1895
1893
|
import * as path27 from "path";
|
|
1894
|
+
import * as os from "os";
|
|
1895
|
+
import { spawn } from "child_process";
|
|
1896
|
+
import Parser from "web-tree-sitter";
|
|
1897
|
+
import * as fs29 from "fs/promises";
|
|
1898
|
+
import * as path28 from "path";
|
|
1899
|
+
import * as fs30 from "fs";
|
|
1900
|
+
import * as path29 from "path";
|
|
1901
|
+
import * as fs31 from "fs";
|
|
1902
|
+
import * as path30 from "path";
|
|
1896
1903
|
import * as os2 from "os";
|
|
1897
1904
|
async function validateFileStructure(projectPath, conventions) {
|
|
1898
1905
|
const missing = [];
|
|
@@ -1929,15 +1936,15 @@ function validateConfig(data, schema) {
|
|
|
1929
1936
|
let message = "Configuration validation failed";
|
|
1930
1937
|
const suggestions = [];
|
|
1931
1938
|
if (firstError) {
|
|
1932
|
-
const
|
|
1933
|
-
const pathDisplay =
|
|
1939
|
+
const path31 = firstError.path.join(".");
|
|
1940
|
+
const pathDisplay = path31 ? ` at "${path31}"` : "";
|
|
1934
1941
|
if (firstError.code === "invalid_type") {
|
|
1935
1942
|
const received = firstError.received;
|
|
1936
1943
|
const expected = firstError.expected;
|
|
1937
1944
|
if (received === "undefined") {
|
|
1938
1945
|
code = "MISSING_FIELD";
|
|
1939
1946
|
message = `Missing required field${pathDisplay}: ${firstError.message}`;
|
|
1940
|
-
suggestions.push(`Field "${
|
|
1947
|
+
suggestions.push(`Field "${path31}" is required and must be of type "${expected}"`);
|
|
1941
1948
|
} else {
|
|
1942
1949
|
code = "INVALID_TYPE";
|
|
1943
1950
|
message = `Invalid type${pathDisplay}: ${firstError.message}`;
|
|
@@ -2146,27 +2153,27 @@ function extractSections(content) {
|
|
|
2146
2153
|
}
|
|
2147
2154
|
return sections.map((section) => buildAgentMapSection(section, lines));
|
|
2148
2155
|
}
|
|
2149
|
-
function isExternalLink(
|
|
2150
|
-
return
|
|
2156
|
+
function isExternalLink(path31) {
|
|
2157
|
+
return path31.startsWith("http://") || path31.startsWith("https://") || path31.startsWith("#") || path31.startsWith("mailto:");
|
|
2151
2158
|
}
|
|
2152
2159
|
function resolveLinkPath(linkPath, baseDir) {
|
|
2153
2160
|
return linkPath.startsWith(".") ? join4(baseDir, linkPath) : linkPath;
|
|
2154
2161
|
}
|
|
2155
|
-
async function validateAgentsMap(
|
|
2156
|
-
const contentResult = await readFileContent(
|
|
2162
|
+
async function validateAgentsMap(path31 = "./AGENTS.md") {
|
|
2163
|
+
const contentResult = await readFileContent(path31);
|
|
2157
2164
|
if (!contentResult.ok) {
|
|
2158
2165
|
return Err(
|
|
2159
2166
|
createError(
|
|
2160
2167
|
"PARSE_ERROR",
|
|
2161
2168
|
`Failed to read AGENTS.md: ${contentResult.error.message}`,
|
|
2162
|
-
{ path:
|
|
2169
|
+
{ path: path31 },
|
|
2163
2170
|
["Ensure the file exists", "Check file permissions"]
|
|
2164
2171
|
)
|
|
2165
2172
|
);
|
|
2166
2173
|
}
|
|
2167
2174
|
const content = contentResult.value;
|
|
2168
2175
|
const sections = extractSections(content);
|
|
2169
|
-
const baseDir = dirname4(
|
|
2176
|
+
const baseDir = dirname4(path31);
|
|
2170
2177
|
const sectionTitles = sections.map((s) => s.title);
|
|
2171
2178
|
const missingSections = REQUIRED_SECTIONS.filter(
|
|
2172
2179
|
(required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
|
|
@@ -2300,8 +2307,8 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
2300
2307
|
);
|
|
2301
2308
|
}
|
|
2302
2309
|
}
|
|
2303
|
-
function suggestFix(
|
|
2304
|
-
const targetName = basename2(
|
|
2310
|
+
function suggestFix(path31, existingFiles) {
|
|
2311
|
+
const targetName = basename2(path31).toLowerCase();
|
|
2305
2312
|
const similar = existingFiles.find((file) => {
|
|
2306
2313
|
const fileName = basename2(file).toLowerCase();
|
|
2307
2314
|
return fileName.includes(targetName) || targetName.includes(fileName);
|
|
@@ -2309,7 +2316,7 @@ function suggestFix(path28, existingFiles) {
|
|
|
2309
2316
|
if (similar) {
|
|
2310
2317
|
return `Did you mean "${similar}"?`;
|
|
2311
2318
|
}
|
|
2312
|
-
return `Create the file "${
|
|
2319
|
+
return `Create the file "${path31}" or remove the link`;
|
|
2313
2320
|
}
|
|
2314
2321
|
async function validateKnowledgeMap(rootDir = process.cwd()) {
|
|
2315
2322
|
const agentsPath = join22(rootDir, "AGENTS.md");
|
|
@@ -2652,8 +2659,8 @@ function createBoundaryValidator(schema, name) {
|
|
|
2652
2659
|
return Ok(result.data);
|
|
2653
2660
|
}
|
|
2654
2661
|
const suggestions = result.error.issues.map((issue) => {
|
|
2655
|
-
const
|
|
2656
|
-
return
|
|
2662
|
+
const path31 = issue.path.join(".");
|
|
2663
|
+
return path31 ? `${path31}: ${issue.message}` : issue.message;
|
|
2657
2664
|
});
|
|
2658
2665
|
return Err(
|
|
2659
2666
|
createError(
|
|
@@ -3261,11 +3268,11 @@ function processExportListSpecifiers(exportDecl, exports) {
|
|
|
3261
3268
|
var TypeScriptParser = class {
|
|
3262
3269
|
name = "typescript";
|
|
3263
3270
|
extensions = [".ts", ".tsx", ".mts", ".cts"];
|
|
3264
|
-
async parseFile(
|
|
3265
|
-
const contentResult = await readFileContent(
|
|
3271
|
+
async parseFile(path31) {
|
|
3272
|
+
const contentResult = await readFileContent(path31);
|
|
3266
3273
|
if (!contentResult.ok) {
|
|
3267
3274
|
return Err(
|
|
3268
|
-
createParseError("NOT_FOUND", `File not found: ${
|
|
3275
|
+
createParseError("NOT_FOUND", `File not found: ${path31}`, { path: path31 }, [
|
|
3269
3276
|
"Check that the file exists",
|
|
3270
3277
|
"Verify the path is correct"
|
|
3271
3278
|
])
|
|
@@ -3275,7 +3282,7 @@ var TypeScriptParser = class {
|
|
|
3275
3282
|
const ast = parse(contentResult.value, {
|
|
3276
3283
|
loc: true,
|
|
3277
3284
|
range: true,
|
|
3278
|
-
jsx:
|
|
3285
|
+
jsx: path31.endsWith(".tsx"),
|
|
3279
3286
|
errorOnUnknownASTType: false
|
|
3280
3287
|
});
|
|
3281
3288
|
return Ok({
|
|
@@ -3286,7 +3293,7 @@ var TypeScriptParser = class {
|
|
|
3286
3293
|
} catch (e) {
|
|
3287
3294
|
const error = e;
|
|
3288
3295
|
return Err(
|
|
3289
|
-
createParseError("SYNTAX_ERROR", `Failed to parse ${
|
|
3296
|
+
createParseError("SYNTAX_ERROR", `Failed to parse ${path31}: ${error.message}`, { path: path31 }, [
|
|
3290
3297
|
"Check for syntax errors in the file",
|
|
3291
3298
|
"Ensure valid TypeScript syntax"
|
|
3292
3299
|
])
|
|
@@ -3467,22 +3474,22 @@ function extractInlineRefs(content) {
|
|
|
3467
3474
|
}
|
|
3468
3475
|
return refs;
|
|
3469
3476
|
}
|
|
3470
|
-
async function parseDocumentationFile(
|
|
3471
|
-
const contentResult = await readFileContent(
|
|
3477
|
+
async function parseDocumentationFile(path31) {
|
|
3478
|
+
const contentResult = await readFileContent(path31);
|
|
3472
3479
|
if (!contentResult.ok) {
|
|
3473
3480
|
return Err(
|
|
3474
3481
|
createEntropyError(
|
|
3475
3482
|
"PARSE_ERROR",
|
|
3476
|
-
`Failed to read documentation file: ${
|
|
3477
|
-
{ file:
|
|
3483
|
+
`Failed to read documentation file: ${path31}`,
|
|
3484
|
+
{ file: path31 },
|
|
3478
3485
|
["Check that the file exists"]
|
|
3479
3486
|
)
|
|
3480
3487
|
);
|
|
3481
3488
|
}
|
|
3482
3489
|
const content = contentResult.value;
|
|
3483
|
-
const type =
|
|
3490
|
+
const type = path31.endsWith(".md") ? "markdown" : "text";
|
|
3484
3491
|
return Ok({
|
|
3485
|
-
path:
|
|
3492
|
+
path: path31,
|
|
3486
3493
|
type,
|
|
3487
3494
|
content,
|
|
3488
3495
|
codeBlocks: extractCodeBlocks(content),
|
|
@@ -6918,8 +6925,7 @@ function parseListField(fieldMap, ...keys) {
|
|
|
6918
6925
|
if (raw === EM_DASH || raw === "none") return [];
|
|
6919
6926
|
return raw.split(",").map((s) => s.trim());
|
|
6920
6927
|
}
|
|
6921
|
-
function
|
|
6922
|
-
const fieldMap = extractFieldMap(body);
|
|
6928
|
+
function validateStatus(name, fieldMap) {
|
|
6923
6929
|
const statusRaw = fieldMap.get("Status");
|
|
6924
6930
|
if (!statusRaw || !VALID_STATUSES.has(statusRaw)) {
|
|
6925
6931
|
return Err(
|
|
@@ -6928,12 +6934,10 @@ function parseFeatureFields(name, body) {
|
|
|
6928
6934
|
)
|
|
6929
6935
|
);
|
|
6930
6936
|
}
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
const assigneeRaw = fieldMap.get("Assignee") ?? EM_DASH;
|
|
6937
|
+
return Ok(statusRaw);
|
|
6938
|
+
}
|
|
6939
|
+
function validatePriority(name, fieldMap) {
|
|
6935
6940
|
const priorityRaw = fieldMap.get("Priority") ?? EM_DASH;
|
|
6936
|
-
const externalIdRaw = fieldMap.get("External-ID") ?? EM_DASH;
|
|
6937
6941
|
if (priorityRaw !== EM_DASH && !VALID_PRIORITIES.has(priorityRaw)) {
|
|
6938
6942
|
return Err(
|
|
6939
6943
|
new Error(
|
|
@@ -6941,16 +6945,28 @@ function parseFeatureFields(name, body) {
|
|
|
6941
6945
|
)
|
|
6942
6946
|
);
|
|
6943
6947
|
}
|
|
6948
|
+
return Ok(priorityRaw === EM_DASH ? null : priorityRaw);
|
|
6949
|
+
}
|
|
6950
|
+
function optionalField(fieldMap, key) {
|
|
6951
|
+
const raw = fieldMap.get(key) ?? EM_DASH;
|
|
6952
|
+
return raw === EM_DASH ? null : raw;
|
|
6953
|
+
}
|
|
6954
|
+
function parseFeatureFields(name, body) {
|
|
6955
|
+
const fieldMap = extractFieldMap(body);
|
|
6956
|
+
const statusResult = validateStatus(name, fieldMap);
|
|
6957
|
+
if (!statusResult.ok) return statusResult;
|
|
6958
|
+
const priorityResult = validatePriority(name, fieldMap);
|
|
6959
|
+
if (!priorityResult.ok) return priorityResult;
|
|
6944
6960
|
return Ok({
|
|
6945
6961
|
name,
|
|
6946
|
-
status:
|
|
6947
|
-
spec:
|
|
6948
|
-
plans,
|
|
6949
|
-
blockedBy,
|
|
6962
|
+
status: statusResult.value,
|
|
6963
|
+
spec: optionalField(fieldMap, "Spec"),
|
|
6964
|
+
plans: parseListField(fieldMap, "Plans", "Plan"),
|
|
6965
|
+
blockedBy: parseListField(fieldMap, "Blocked by", "Blockers"),
|
|
6950
6966
|
summary: fieldMap.get("Summary") ?? "",
|
|
6951
|
-
assignee:
|
|
6952
|
-
priority:
|
|
6953
|
-
externalId:
|
|
6967
|
+
assignee: optionalField(fieldMap, "Assignee"),
|
|
6968
|
+
priority: priorityResult.value,
|
|
6969
|
+
externalId: optionalField(fieldMap, "External-ID")
|
|
6954
6970
|
});
|
|
6955
6971
|
}
|
|
6956
6972
|
function parseAssignmentHistory(body) {
|
|
@@ -7014,82 +7030,16 @@ var PredictionEngine = class {
|
|
|
7014
7030
|
const firstDate = new Date(snapshots[0].capturedAt).getTime();
|
|
7015
7031
|
const lastSnapshot = snapshots[snapshots.length - 1];
|
|
7016
7032
|
const currentT = (new Date(lastSnapshot.capturedAt).getTime() - firstDate) / (7 * 24 * 60 * 60 * 1e3);
|
|
7017
|
-
const baselines =
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
const timeSeries = this.extractTimeSeries(snapshots, category, firstDate);
|
|
7026
|
-
baselines[category] = this.forecastCategory(
|
|
7027
|
-
category,
|
|
7028
|
-
timeSeries,
|
|
7029
|
-
currentT,
|
|
7030
|
-
threshold,
|
|
7031
|
-
opts.horizon
|
|
7032
|
-
);
|
|
7033
|
-
}
|
|
7033
|
+
const baselines = this.computeBaselines(
|
|
7034
|
+
categoriesToProcess,
|
|
7035
|
+
thresholds,
|
|
7036
|
+
snapshots,
|
|
7037
|
+
firstDate,
|
|
7038
|
+
currentT,
|
|
7039
|
+
opts.horizon
|
|
7040
|
+
);
|
|
7034
7041
|
const specImpacts = this.computeSpecImpacts(opts);
|
|
7035
|
-
const categories =
|
|
7036
|
-
for (const category of ALL_CATEGORIES2) {
|
|
7037
|
-
const baseline = baselines[category];
|
|
7038
|
-
const threshold = thresholds[category];
|
|
7039
|
-
if (!specImpacts || specImpacts.length === 0) {
|
|
7040
|
-
categories[category] = {
|
|
7041
|
-
baseline,
|
|
7042
|
-
adjusted: baseline,
|
|
7043
|
-
contributingFeatures: []
|
|
7044
|
-
};
|
|
7045
|
-
continue;
|
|
7046
|
-
}
|
|
7047
|
-
let totalDelta = 0;
|
|
7048
|
-
const contributing = [];
|
|
7049
|
-
for (const impact of specImpacts) {
|
|
7050
|
-
const delta = impact.deltas?.[category] ?? 0;
|
|
7051
|
-
if (delta !== 0) {
|
|
7052
|
-
totalDelta += delta;
|
|
7053
|
-
contributing.push({
|
|
7054
|
-
name: impact.featureName,
|
|
7055
|
-
specPath: impact.specPath,
|
|
7056
|
-
delta
|
|
7057
|
-
});
|
|
7058
|
-
}
|
|
7059
|
-
}
|
|
7060
|
-
if (totalDelta === 0) {
|
|
7061
|
-
categories[category] = {
|
|
7062
|
-
baseline,
|
|
7063
|
-
adjusted: baseline,
|
|
7064
|
-
contributingFeatures: []
|
|
7065
|
-
};
|
|
7066
|
-
continue;
|
|
7067
|
-
}
|
|
7068
|
-
const adjusted = {
|
|
7069
|
-
...baseline,
|
|
7070
|
-
projectedValue4w: baseline.projectedValue4w + totalDelta,
|
|
7071
|
-
projectedValue8w: baseline.projectedValue8w + totalDelta,
|
|
7072
|
-
projectedValue12w: baseline.projectedValue12w + totalDelta
|
|
7073
|
-
};
|
|
7074
|
-
const adjustedFit = {
|
|
7075
|
-
slope: baseline.regression.slope,
|
|
7076
|
-
intercept: baseline.regression.intercept + totalDelta,
|
|
7077
|
-
rSquared: baseline.regression.rSquared,
|
|
7078
|
-
dataPoints: baseline.regression.dataPoints
|
|
7079
|
-
};
|
|
7080
|
-
adjusted.thresholdCrossingWeeks = weeksUntilThreshold(adjustedFit, currentT, threshold);
|
|
7081
|
-
adjusted.regression = {
|
|
7082
|
-
slope: adjustedFit.slope,
|
|
7083
|
-
intercept: adjustedFit.intercept,
|
|
7084
|
-
rSquared: adjustedFit.rSquared,
|
|
7085
|
-
dataPoints: adjustedFit.dataPoints
|
|
7086
|
-
};
|
|
7087
|
-
categories[category] = {
|
|
7088
|
-
baseline,
|
|
7089
|
-
adjusted,
|
|
7090
|
-
contributingFeatures: contributing
|
|
7091
|
-
};
|
|
7092
|
-
}
|
|
7042
|
+
const categories = this.computeAdjustedForecasts(baselines, thresholds, specImpacts, currentT);
|
|
7093
7043
|
const warnings = this.generateWarnings(
|
|
7094
7044
|
categories,
|
|
7095
7045
|
opts.horizon
|
|
@@ -7131,6 +7081,76 @@ var PredictionEngine = class {
|
|
|
7131
7081
|
}
|
|
7132
7082
|
return base;
|
|
7133
7083
|
}
|
|
7084
|
+
computeBaselines(categoriesToProcess, thresholds, snapshots, firstDate, currentT, horizon) {
|
|
7085
|
+
const baselines = {};
|
|
7086
|
+
for (const category of ALL_CATEGORIES2) {
|
|
7087
|
+
const threshold = thresholds[category];
|
|
7088
|
+
if (!categoriesToProcess.includes(category)) {
|
|
7089
|
+
baselines[category] = this.zeroForecast(category, threshold);
|
|
7090
|
+
continue;
|
|
7091
|
+
}
|
|
7092
|
+
const timeSeries = this.extractTimeSeries(snapshots, category, firstDate);
|
|
7093
|
+
baselines[category] = this.forecastCategory(
|
|
7094
|
+
category,
|
|
7095
|
+
timeSeries,
|
|
7096
|
+
currentT,
|
|
7097
|
+
threshold,
|
|
7098
|
+
horizon
|
|
7099
|
+
);
|
|
7100
|
+
}
|
|
7101
|
+
return baselines;
|
|
7102
|
+
}
|
|
7103
|
+
computeAdjustedForecasts(baselines, thresholds, specImpacts, currentT) {
|
|
7104
|
+
const categories = {};
|
|
7105
|
+
for (const category of ALL_CATEGORIES2) {
|
|
7106
|
+
const baseline = baselines[category];
|
|
7107
|
+
categories[category] = this.adjustForecastForCategory(
|
|
7108
|
+
category,
|
|
7109
|
+
baseline,
|
|
7110
|
+
thresholds[category],
|
|
7111
|
+
specImpacts,
|
|
7112
|
+
currentT
|
|
7113
|
+
);
|
|
7114
|
+
}
|
|
7115
|
+
return categories;
|
|
7116
|
+
}
|
|
7117
|
+
adjustForecastForCategory(category, baseline, threshold, specImpacts, currentT) {
|
|
7118
|
+
if (!specImpacts || specImpacts.length === 0) {
|
|
7119
|
+
return { baseline, adjusted: baseline, contributingFeatures: [] };
|
|
7120
|
+
}
|
|
7121
|
+
let totalDelta = 0;
|
|
7122
|
+
const contributing = [];
|
|
7123
|
+
for (const impact of specImpacts) {
|
|
7124
|
+
const delta = impact.deltas?.[category] ?? 0;
|
|
7125
|
+
if (delta !== 0) {
|
|
7126
|
+
totalDelta += delta;
|
|
7127
|
+
contributing.push({ name: impact.featureName, specPath: impact.specPath, delta });
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
if (totalDelta === 0) {
|
|
7131
|
+
return { baseline, adjusted: baseline, contributingFeatures: [] };
|
|
7132
|
+
}
|
|
7133
|
+
const adjusted = {
|
|
7134
|
+
...baseline,
|
|
7135
|
+
projectedValue4w: baseline.projectedValue4w + totalDelta,
|
|
7136
|
+
projectedValue8w: baseline.projectedValue8w + totalDelta,
|
|
7137
|
+
projectedValue12w: baseline.projectedValue12w + totalDelta
|
|
7138
|
+
};
|
|
7139
|
+
const adjustedFit = {
|
|
7140
|
+
slope: baseline.regression.slope,
|
|
7141
|
+
intercept: baseline.regression.intercept + totalDelta,
|
|
7142
|
+
rSquared: baseline.regression.rSquared,
|
|
7143
|
+
dataPoints: baseline.regression.dataPoints
|
|
7144
|
+
};
|
|
7145
|
+
adjusted.thresholdCrossingWeeks = weeksUntilThreshold(adjustedFit, currentT, threshold);
|
|
7146
|
+
adjusted.regression = {
|
|
7147
|
+
slope: adjustedFit.slope,
|
|
7148
|
+
intercept: adjustedFit.intercept,
|
|
7149
|
+
rSquared: adjustedFit.rSquared,
|
|
7150
|
+
dataPoints: adjustedFit.dataPoints
|
|
7151
|
+
};
|
|
7152
|
+
return { baseline, adjusted, contributingFeatures: contributing };
|
|
7153
|
+
}
|
|
7134
7154
|
/**
|
|
7135
7155
|
* Extract time series for a single category from snapshots.
|
|
7136
7156
|
* Returns array of { t (weeks from first), value } sorted oldest first.
|
|
@@ -7926,6 +7946,25 @@ function parseFrontmatter2(line) {
|
|
|
7926
7946
|
const tags = match[2] ? match[2].split(",").filter(Boolean) : [];
|
|
7927
7947
|
return { hash, tags };
|
|
7928
7948
|
}
|
|
7949
|
+
function parseDateFromEntry(entry) {
|
|
7950
|
+
const match = entry.match(/(\d{4}-\d{2}-\d{2})/);
|
|
7951
|
+
return match ? match[1] ?? null : null;
|
|
7952
|
+
}
|
|
7953
|
+
function extractIndexEntry(entry) {
|
|
7954
|
+
const lines = entry.split("\n");
|
|
7955
|
+
const summary = lines[0] ?? entry;
|
|
7956
|
+
const tags = [];
|
|
7957
|
+
const skillMatch = entry.match(/\[skill:([^\]]+)\]/);
|
|
7958
|
+
if (skillMatch?.[1]) tags.push(skillMatch[1]);
|
|
7959
|
+
const outcomeMatch = entry.match(/\[outcome:([^\]]+)\]/);
|
|
7960
|
+
if (outcomeMatch?.[1]) tags.push(outcomeMatch[1]);
|
|
7961
|
+
return {
|
|
7962
|
+
hash: computeEntryHash(entry),
|
|
7963
|
+
tags,
|
|
7964
|
+
summary,
|
|
7965
|
+
fullText: entry
|
|
7966
|
+
};
|
|
7967
|
+
}
|
|
7929
7968
|
function computeEntryHash(text) {
|
|
7930
7969
|
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 8);
|
|
7931
7970
|
}
|
|
@@ -7960,8 +7999,8 @@ function saveContentHashes(stateDir, index) {
|
|
|
7960
7999
|
const hashesPath = path8.join(stateDir, CONTENT_HASHES_FILE);
|
|
7961
8000
|
fs11.writeFileSync(hashesPath, JSON.stringify(index, null, 2) + "\n");
|
|
7962
8001
|
}
|
|
7963
|
-
function rebuildContentHashes(stateDir) {
|
|
7964
|
-
const learningsPath = path8.join(stateDir,
|
|
8002
|
+
function rebuildContentHashes(stateDir, learningsFile) {
|
|
8003
|
+
const learningsPath = path8.join(stateDir, learningsFile);
|
|
7965
8004
|
if (!fs11.existsSync(learningsPath)) return {};
|
|
7966
8005
|
const content = fs11.readFileSync(learningsPath, "utf-8");
|
|
7967
8006
|
const lines = content.split("\n");
|
|
@@ -7982,43 +8021,116 @@ function rebuildContentHashes(stateDir) {
|
|
|
7982
8021
|
saveContentHashes(stateDir, index);
|
|
7983
8022
|
return index;
|
|
7984
8023
|
}
|
|
7985
|
-
function
|
|
7986
|
-
const
|
|
7987
|
-
const
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
8024
|
+
function analyzeLearningPatterns(entries) {
|
|
8025
|
+
const tagGroups = /* @__PURE__ */ new Map();
|
|
8026
|
+
for (const entry of entries) {
|
|
8027
|
+
const tagMatches = entry.matchAll(/\[(skill:[^\]]+)\]|\[(outcome:[^\]]+)\]/g);
|
|
8028
|
+
for (const match of tagMatches) {
|
|
8029
|
+
const tag = match[1] ?? match[2];
|
|
8030
|
+
if (tag) {
|
|
8031
|
+
const group = tagGroups.get(tag) ?? [];
|
|
8032
|
+
group.push(entry);
|
|
8033
|
+
tagGroups.set(tag, group);
|
|
8034
|
+
}
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
const patterns = [];
|
|
8038
|
+
for (const [tag, groupEntries] of tagGroups) {
|
|
8039
|
+
if (groupEntries.length >= 3) {
|
|
8040
|
+
patterns.push({ tag, count: groupEntries.length, entries: groupEntries });
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
return patterns.sort((a, b) => b.count - a.count);
|
|
8044
|
+
}
|
|
8045
|
+
function estimateTokens(text) {
|
|
8046
|
+
return Math.ceil(text.length / 4);
|
|
8047
|
+
}
|
|
8048
|
+
function scoreRelevance(entry, intent) {
|
|
8049
|
+
if (!intent || intent.trim() === "") return 0;
|
|
8050
|
+
const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
8051
|
+
if (intentWords.length === 0) return 0;
|
|
8052
|
+
const entryLower = entry.toLowerCase();
|
|
8053
|
+
const matches = intentWords.filter((word) => entryLower.includes(word));
|
|
8054
|
+
return matches.length / intentWords.length;
|
|
7999
8055
|
}
|
|
8000
8056
|
var learningsCacheMap = /* @__PURE__ */ new Map();
|
|
8001
8057
|
function clearLearningsCache() {
|
|
8002
8058
|
learningsCacheMap.clear();
|
|
8003
8059
|
}
|
|
8060
|
+
function invalidateLearningsCacheEntry(key) {
|
|
8061
|
+
learningsCacheMap.delete(key);
|
|
8062
|
+
}
|
|
8063
|
+
async function loadRelevantLearnings(projectPath, skillName, stream, session) {
|
|
8064
|
+
try {
|
|
8065
|
+
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8066
|
+
if (!dirResult.ok) return dirResult;
|
|
8067
|
+
const stateDir = dirResult.value;
|
|
8068
|
+
const learningsPath = path9.join(stateDir, LEARNINGS_FILE);
|
|
8069
|
+
if (!fs12.existsSync(learningsPath)) {
|
|
8070
|
+
return Ok([]);
|
|
8071
|
+
}
|
|
8072
|
+
const stats = fs12.statSync(learningsPath);
|
|
8073
|
+
const cacheKey = learningsPath;
|
|
8074
|
+
const cached = learningsCacheMap.get(cacheKey);
|
|
8075
|
+
let entries;
|
|
8076
|
+
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
8077
|
+
entries = cached.entries;
|
|
8078
|
+
} else {
|
|
8079
|
+
const content = fs12.readFileSync(learningsPath, "utf-8");
|
|
8080
|
+
const lines = content.split("\n");
|
|
8081
|
+
entries = [];
|
|
8082
|
+
let currentBlock = [];
|
|
8083
|
+
for (const line of lines) {
|
|
8084
|
+
if (line.startsWith("# ")) continue;
|
|
8085
|
+
if (/^<!--\s+hash:[a-f0-9]+/.test(line)) continue;
|
|
8086
|
+
const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
|
|
8087
|
+
const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
|
|
8088
|
+
if (isDatedBullet || isHeading) {
|
|
8089
|
+
if (currentBlock.length > 0) {
|
|
8090
|
+
entries.push(currentBlock.join("\n"));
|
|
8091
|
+
}
|
|
8092
|
+
currentBlock = [line];
|
|
8093
|
+
} else if (line.trim() !== "" && currentBlock.length > 0) {
|
|
8094
|
+
currentBlock.push(line);
|
|
8095
|
+
}
|
|
8096
|
+
}
|
|
8097
|
+
if (currentBlock.length > 0) {
|
|
8098
|
+
entries.push(currentBlock.join("\n"));
|
|
8099
|
+
}
|
|
8100
|
+
learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
|
|
8101
|
+
evictIfNeeded(learningsCacheMap);
|
|
8102
|
+
}
|
|
8103
|
+
if (!skillName) {
|
|
8104
|
+
return Ok(entries);
|
|
8105
|
+
}
|
|
8106
|
+
const filtered = entries.filter((entry) => entry.includes(`[skill:${skillName}]`));
|
|
8107
|
+
return Ok(filtered);
|
|
8108
|
+
} catch (error) {
|
|
8109
|
+
return Err(
|
|
8110
|
+
new Error(
|
|
8111
|
+
`Failed to load learnings: ${error instanceof Error ? error.message : String(error)}`
|
|
8112
|
+
)
|
|
8113
|
+
);
|
|
8114
|
+
}
|
|
8115
|
+
}
|
|
8004
8116
|
async function appendLearning(projectPath, learning, skillName, outcome, stream, session) {
|
|
8005
8117
|
try {
|
|
8006
8118
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8007
8119
|
if (!dirResult.ok) return dirResult;
|
|
8008
8120
|
const stateDir = dirResult.value;
|
|
8009
|
-
const learningsPath =
|
|
8010
|
-
|
|
8121
|
+
const learningsPath = path10.join(stateDir, LEARNINGS_FILE);
|
|
8122
|
+
fs13.mkdirSync(stateDir, { recursive: true });
|
|
8011
8123
|
const normalizedContent = normalizeLearningContent(learning);
|
|
8012
8124
|
const contentHash = computeContentHash(normalizedContent);
|
|
8013
|
-
const hashesPath =
|
|
8125
|
+
const hashesPath = path10.join(stateDir, CONTENT_HASHES_FILE);
|
|
8014
8126
|
let contentHashes;
|
|
8015
|
-
if (
|
|
8127
|
+
if (fs13.existsSync(hashesPath)) {
|
|
8016
8128
|
contentHashes = loadContentHashes(stateDir);
|
|
8017
|
-
if (Object.keys(contentHashes).length === 0 &&
|
|
8018
|
-
contentHashes = rebuildContentHashes(stateDir);
|
|
8129
|
+
if (Object.keys(contentHashes).length === 0 && fs13.existsSync(learningsPath)) {
|
|
8130
|
+
contentHashes = rebuildContentHashes(stateDir, LEARNINGS_FILE);
|
|
8019
8131
|
}
|
|
8020
|
-
} else if (
|
|
8021
|
-
contentHashes = rebuildContentHashes(stateDir);
|
|
8132
|
+
} else if (fs13.existsSync(learningsPath)) {
|
|
8133
|
+
contentHashes = rebuildContentHashes(stateDir, LEARNINGS_FILE);
|
|
8022
8134
|
} else {
|
|
8023
8135
|
contentHashes = {};
|
|
8024
8136
|
}
|
|
@@ -8037,7 +8149,7 @@ async function appendLearning(projectPath, learning, skillName, outcome, stream,
|
|
|
8037
8149
|
} else {
|
|
8038
8150
|
bulletLine = `- **${timestamp}:** ${learning}`;
|
|
8039
8151
|
}
|
|
8040
|
-
const hash =
|
|
8152
|
+
const hash = crypto2.createHash("sha256").update(bulletLine).digest("hex").slice(0, 8);
|
|
8041
8153
|
const tagsStr = fmTags.length > 0 ? ` tags:${fmTags.join(",")}` : "";
|
|
8042
8154
|
const frontmatter = `<!-- hash:${hash}${tagsStr} -->`;
|
|
8043
8155
|
const entry = `
|
|
@@ -8045,19 +8157,19 @@ ${frontmatter}
|
|
|
8045
8157
|
${bulletLine}
|
|
8046
8158
|
`;
|
|
8047
8159
|
let existingLineCount;
|
|
8048
|
-
if (!
|
|
8049
|
-
|
|
8160
|
+
if (!fs13.existsSync(learningsPath)) {
|
|
8161
|
+
fs13.writeFileSync(learningsPath, `# Learnings
|
|
8050
8162
|
${entry}`);
|
|
8051
8163
|
existingLineCount = 1;
|
|
8052
8164
|
} else {
|
|
8053
|
-
const existingContent =
|
|
8165
|
+
const existingContent = fs13.readFileSync(learningsPath, "utf-8");
|
|
8054
8166
|
existingLineCount = existingContent.split("\n").length;
|
|
8055
|
-
|
|
8167
|
+
fs13.appendFileSync(learningsPath, entry);
|
|
8056
8168
|
}
|
|
8057
8169
|
const bulletLine_lineNum = existingLineCount + 2;
|
|
8058
8170
|
contentHashes[contentHash] = { date: timestamp ?? "", line: bulletLine_lineNum };
|
|
8059
8171
|
saveContentHashes(stateDir, contentHashes);
|
|
8060
|
-
|
|
8172
|
+
invalidateLearningsCacheEntry(learningsPath);
|
|
8061
8173
|
return Ok(void 0);
|
|
8062
8174
|
} catch (error) {
|
|
8063
8175
|
return Err(
|
|
@@ -8067,42 +8179,6 @@ ${entry}`);
|
|
|
8067
8179
|
);
|
|
8068
8180
|
}
|
|
8069
8181
|
}
|
|
8070
|
-
function estimateTokens(text) {
|
|
8071
|
-
return Math.ceil(text.length / 4);
|
|
8072
|
-
}
|
|
8073
|
-
function scoreRelevance(entry, intent) {
|
|
8074
|
-
if (!intent || intent.trim() === "") return 0;
|
|
8075
|
-
const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
8076
|
-
if (intentWords.length === 0) return 0;
|
|
8077
|
-
const entryLower = entry.toLowerCase();
|
|
8078
|
-
const matches = intentWords.filter((word) => entryLower.includes(word));
|
|
8079
|
-
return matches.length / intentWords.length;
|
|
8080
|
-
}
|
|
8081
|
-
function parseDateFromEntry(entry) {
|
|
8082
|
-
const match = entry.match(/(\d{4}-\d{2}-\d{2})/);
|
|
8083
|
-
return match ? match[1] ?? null : null;
|
|
8084
|
-
}
|
|
8085
|
-
function analyzeLearningPatterns(entries) {
|
|
8086
|
-
const tagGroups = /* @__PURE__ */ new Map();
|
|
8087
|
-
for (const entry of entries) {
|
|
8088
|
-
const tagMatches = entry.matchAll(/\[(skill:[^\]]+)\]|\[(outcome:[^\]]+)\]/g);
|
|
8089
|
-
for (const match of tagMatches) {
|
|
8090
|
-
const tag = match[1] ?? match[2];
|
|
8091
|
-
if (tag) {
|
|
8092
|
-
const group = tagGroups.get(tag) ?? [];
|
|
8093
|
-
group.push(entry);
|
|
8094
|
-
tagGroups.set(tag, group);
|
|
8095
|
-
}
|
|
8096
|
-
}
|
|
8097
|
-
}
|
|
8098
|
-
const patterns = [];
|
|
8099
|
-
for (const [tag, groupEntries] of tagGroups) {
|
|
8100
|
-
if (groupEntries.length >= 3) {
|
|
8101
|
-
patterns.push({ tag, count: groupEntries.length, entries: groupEntries });
|
|
8102
|
-
}
|
|
8103
|
-
}
|
|
8104
|
-
return patterns.sort((a, b) => b.count - a.count);
|
|
8105
|
-
}
|
|
8106
8182
|
async function loadBudgetedLearnings(projectPath, options) {
|
|
8107
8183
|
const { intent, tokenBudget = 1e3, skill, session, stream, depth = "summary" } = options;
|
|
8108
8184
|
if (depth === "index") {
|
|
@@ -8166,11 +8242,11 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
|
|
|
8166
8242
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8167
8243
|
if (!dirResult.ok) return dirResult;
|
|
8168
8244
|
const stateDir = dirResult.value;
|
|
8169
|
-
const learningsPath =
|
|
8170
|
-
if (!
|
|
8245
|
+
const learningsPath = path10.join(stateDir, LEARNINGS_FILE);
|
|
8246
|
+
if (!fs13.existsSync(learningsPath)) {
|
|
8171
8247
|
return Ok([]);
|
|
8172
8248
|
}
|
|
8173
|
-
const content =
|
|
8249
|
+
const content = fs13.readFileSync(learningsPath, "utf-8");
|
|
8174
8250
|
const lines = content.split("\n");
|
|
8175
8251
|
const indexEntries = [];
|
|
8176
8252
|
let pendingFrontmatter = null;
|
|
@@ -8223,74 +8299,21 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
|
|
|
8223
8299
|
);
|
|
8224
8300
|
}
|
|
8225
8301
|
}
|
|
8226
|
-
async function loadRelevantLearnings(projectPath, skillName, stream, session) {
|
|
8227
|
-
try {
|
|
8228
|
-
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8229
|
-
if (!dirResult.ok) return dirResult;
|
|
8230
|
-
const stateDir = dirResult.value;
|
|
8231
|
-
const learningsPath = path8.join(stateDir, LEARNINGS_FILE);
|
|
8232
|
-
if (!fs11.existsSync(learningsPath)) {
|
|
8233
|
-
return Ok([]);
|
|
8234
|
-
}
|
|
8235
|
-
const stats = fs11.statSync(learningsPath);
|
|
8236
|
-
const cacheKey = learningsPath;
|
|
8237
|
-
const cached = learningsCacheMap.get(cacheKey);
|
|
8238
|
-
let entries;
|
|
8239
|
-
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
8240
|
-
entries = cached.entries;
|
|
8241
|
-
} else {
|
|
8242
|
-
const content = fs11.readFileSync(learningsPath, "utf-8");
|
|
8243
|
-
const lines = content.split("\n");
|
|
8244
|
-
entries = [];
|
|
8245
|
-
let currentBlock = [];
|
|
8246
|
-
for (const line of lines) {
|
|
8247
|
-
if (line.startsWith("# ")) continue;
|
|
8248
|
-
if (/^<!--\s+hash:[a-f0-9]+/.test(line)) continue;
|
|
8249
|
-
const isDatedBullet = /^- \*\*\d{4}-\d{2}-\d{2}/.test(line);
|
|
8250
|
-
const isHeading = /^## \d{4}-\d{2}-\d{2}/.test(line);
|
|
8251
|
-
if (isDatedBullet || isHeading) {
|
|
8252
|
-
if (currentBlock.length > 0) {
|
|
8253
|
-
entries.push(currentBlock.join("\n"));
|
|
8254
|
-
}
|
|
8255
|
-
currentBlock = [line];
|
|
8256
|
-
} else if (line.trim() !== "" && currentBlock.length > 0) {
|
|
8257
|
-
currentBlock.push(line);
|
|
8258
|
-
}
|
|
8259
|
-
}
|
|
8260
|
-
if (currentBlock.length > 0) {
|
|
8261
|
-
entries.push(currentBlock.join("\n"));
|
|
8262
|
-
}
|
|
8263
|
-
learningsCacheMap.set(cacheKey, { mtimeMs: stats.mtimeMs, entries });
|
|
8264
|
-
evictIfNeeded(learningsCacheMap);
|
|
8265
|
-
}
|
|
8266
|
-
if (!skillName) {
|
|
8267
|
-
return Ok(entries);
|
|
8268
|
-
}
|
|
8269
|
-
const filtered = entries.filter((entry) => entry.includes(`[skill:${skillName}]`));
|
|
8270
|
-
return Ok(filtered);
|
|
8271
|
-
} catch (error) {
|
|
8272
|
-
return Err(
|
|
8273
|
-
new Error(
|
|
8274
|
-
`Failed to load learnings: ${error instanceof Error ? error.message : String(error)}`
|
|
8275
|
-
)
|
|
8276
|
-
);
|
|
8277
|
-
}
|
|
8278
|
-
}
|
|
8279
8302
|
async function archiveLearnings(projectPath, entries, stream) {
|
|
8280
8303
|
try {
|
|
8281
8304
|
const dirResult = await getStateDir(projectPath, stream);
|
|
8282
8305
|
if (!dirResult.ok) return dirResult;
|
|
8283
8306
|
const stateDir = dirResult.value;
|
|
8284
|
-
const archiveDir =
|
|
8285
|
-
|
|
8307
|
+
const archiveDir = path11.join(stateDir, "learnings-archive");
|
|
8308
|
+
fs14.mkdirSync(archiveDir, { recursive: true });
|
|
8286
8309
|
const now = /* @__PURE__ */ new Date();
|
|
8287
8310
|
const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
|
|
8288
|
-
const archivePath =
|
|
8311
|
+
const archivePath = path11.join(archiveDir, `${yearMonth}.md`);
|
|
8289
8312
|
const archiveContent = entries.join("\n\n") + "\n";
|
|
8290
|
-
if (
|
|
8291
|
-
|
|
8313
|
+
if (fs14.existsSync(archivePath)) {
|
|
8314
|
+
fs14.appendFileSync(archivePath, "\n" + archiveContent);
|
|
8292
8315
|
} else {
|
|
8293
|
-
|
|
8316
|
+
fs14.writeFileSync(archivePath, `# Learnings Archive
|
|
8294
8317
|
|
|
8295
8318
|
${archiveContent}`);
|
|
8296
8319
|
}
|
|
@@ -8308,8 +8331,8 @@ async function pruneLearnings(projectPath, stream) {
|
|
|
8308
8331
|
const dirResult = await getStateDir(projectPath, stream);
|
|
8309
8332
|
if (!dirResult.ok) return dirResult;
|
|
8310
8333
|
const stateDir = dirResult.value;
|
|
8311
|
-
const learningsPath =
|
|
8312
|
-
if (!
|
|
8334
|
+
const learningsPath = path11.join(stateDir, LEARNINGS_FILE);
|
|
8335
|
+
if (!fs14.existsSync(learningsPath)) {
|
|
8313
8336
|
return Ok({ kept: 0, archived: 0, patterns: [] });
|
|
8314
8337
|
}
|
|
8315
8338
|
const loadResult = await loadRelevantLearnings(projectPath, void 0, stream);
|
|
@@ -8340,8 +8363,8 @@ async function pruneLearnings(projectPath, stream) {
|
|
|
8340
8363
|
if (!archiveResult.ok) return archiveResult;
|
|
8341
8364
|
}
|
|
8342
8365
|
const newContent = "# Learnings\n\n" + toKeep.join("\n\n") + "\n";
|
|
8343
|
-
|
|
8344
|
-
|
|
8366
|
+
fs14.writeFileSync(learningsPath, newContent);
|
|
8367
|
+
invalidateLearningsCacheEntry(learningsPath);
|
|
8345
8368
|
return Ok({
|
|
8346
8369
|
kept: toKeep.length,
|
|
8347
8370
|
archived: toArchive.length,
|
|
@@ -8385,21 +8408,21 @@ async function promoteSessionLearnings(projectPath, sessionSlug, stream) {
|
|
|
8385
8408
|
const dirResult = await getStateDir(projectPath, stream);
|
|
8386
8409
|
if (!dirResult.ok) return dirResult;
|
|
8387
8410
|
const stateDir = dirResult.value;
|
|
8388
|
-
const globalPath =
|
|
8389
|
-
const existingGlobal =
|
|
8411
|
+
const globalPath = path11.join(stateDir, LEARNINGS_FILE);
|
|
8412
|
+
const existingGlobal = fs14.existsSync(globalPath) ? fs14.readFileSync(globalPath, "utf-8") : "";
|
|
8390
8413
|
const newEntries = toPromote.filter((entry) => !existingGlobal.includes(entry.trim()));
|
|
8391
8414
|
if (newEntries.length === 0) {
|
|
8392
8415
|
return Ok({ promoted: 0, skipped: skipped + toPromote.length });
|
|
8393
8416
|
}
|
|
8394
8417
|
const promotedContent = newEntries.join("\n\n") + "\n";
|
|
8395
8418
|
if (!existingGlobal) {
|
|
8396
|
-
|
|
8419
|
+
fs14.writeFileSync(globalPath, `# Learnings
|
|
8397
8420
|
|
|
8398
8421
|
${promotedContent}`);
|
|
8399
8422
|
} else {
|
|
8400
|
-
|
|
8423
|
+
fs14.appendFileSync(globalPath, "\n\n" + promotedContent);
|
|
8401
8424
|
}
|
|
8402
|
-
|
|
8425
|
+
invalidateLearningsCacheEntry(globalPath);
|
|
8403
8426
|
return Ok({
|
|
8404
8427
|
promoted: newEntries.length,
|
|
8405
8428
|
skipped: skipped + (toPromote.length - newEntries.length)
|
|
@@ -8427,17 +8450,17 @@ async function appendFailure(projectPath, description, skillName, type, stream,
|
|
|
8427
8450
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8428
8451
|
if (!dirResult.ok) return dirResult;
|
|
8429
8452
|
const stateDir = dirResult.value;
|
|
8430
|
-
const failuresPath =
|
|
8431
|
-
|
|
8453
|
+
const failuresPath = path12.join(stateDir, FAILURES_FILE);
|
|
8454
|
+
fs15.mkdirSync(stateDir, { recursive: true });
|
|
8432
8455
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8433
8456
|
const entry = `
|
|
8434
8457
|
- **${timestamp} [skill:${skillName}] [type:${type}]:** ${description}
|
|
8435
8458
|
`;
|
|
8436
|
-
if (!
|
|
8437
|
-
|
|
8459
|
+
if (!fs15.existsSync(failuresPath)) {
|
|
8460
|
+
fs15.writeFileSync(failuresPath, `# Failures
|
|
8438
8461
|
${entry}`);
|
|
8439
8462
|
} else {
|
|
8440
|
-
|
|
8463
|
+
fs15.appendFileSync(failuresPath, entry);
|
|
8441
8464
|
}
|
|
8442
8465
|
failuresCacheMap.delete(failuresPath);
|
|
8443
8466
|
return Ok(void 0);
|
|
@@ -8454,17 +8477,17 @@ async function loadFailures(projectPath, stream, session) {
|
|
|
8454
8477
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8455
8478
|
if (!dirResult.ok) return dirResult;
|
|
8456
8479
|
const stateDir = dirResult.value;
|
|
8457
|
-
const failuresPath =
|
|
8458
|
-
if (!
|
|
8480
|
+
const failuresPath = path12.join(stateDir, FAILURES_FILE);
|
|
8481
|
+
if (!fs15.existsSync(failuresPath)) {
|
|
8459
8482
|
return Ok([]);
|
|
8460
8483
|
}
|
|
8461
|
-
const stats =
|
|
8484
|
+
const stats = fs15.statSync(failuresPath);
|
|
8462
8485
|
const cacheKey = failuresPath;
|
|
8463
8486
|
const cached = failuresCacheMap.get(cacheKey);
|
|
8464
8487
|
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
8465
8488
|
return Ok(cached.entries);
|
|
8466
8489
|
}
|
|
8467
|
-
const content =
|
|
8490
|
+
const content = fs15.readFileSync(failuresPath, "utf-8");
|
|
8468
8491
|
const entries = [];
|
|
8469
8492
|
for (const line of content.split("\n")) {
|
|
8470
8493
|
const match = line.match(FAILURE_LINE_REGEX);
|
|
@@ -8493,20 +8516,20 @@ async function archiveFailures(projectPath, stream, session) {
|
|
|
8493
8516
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8494
8517
|
if (!dirResult.ok) return dirResult;
|
|
8495
8518
|
const stateDir = dirResult.value;
|
|
8496
|
-
const failuresPath =
|
|
8497
|
-
if (!
|
|
8519
|
+
const failuresPath = path12.join(stateDir, FAILURES_FILE);
|
|
8520
|
+
if (!fs15.existsSync(failuresPath)) {
|
|
8498
8521
|
return Ok(void 0);
|
|
8499
8522
|
}
|
|
8500
|
-
const archiveDir =
|
|
8501
|
-
|
|
8523
|
+
const archiveDir = path12.join(stateDir, "archive");
|
|
8524
|
+
fs15.mkdirSync(archiveDir, { recursive: true });
|
|
8502
8525
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8503
8526
|
let archiveName = `failures-${date}.md`;
|
|
8504
8527
|
let counter = 2;
|
|
8505
|
-
while (
|
|
8528
|
+
while (fs15.existsSync(path12.join(archiveDir, archiveName))) {
|
|
8506
8529
|
archiveName = `failures-${date}-${counter}.md`;
|
|
8507
8530
|
counter++;
|
|
8508
8531
|
}
|
|
8509
|
-
|
|
8532
|
+
fs15.renameSync(failuresPath, path12.join(archiveDir, archiveName));
|
|
8510
8533
|
failuresCacheMap.delete(failuresPath);
|
|
8511
8534
|
return Ok(void 0);
|
|
8512
8535
|
} catch (error) {
|
|
@@ -8522,9 +8545,9 @@ async function saveHandoff(projectPath, handoff, stream, session) {
|
|
|
8522
8545
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8523
8546
|
if (!dirResult.ok) return dirResult;
|
|
8524
8547
|
const stateDir = dirResult.value;
|
|
8525
|
-
const handoffPath =
|
|
8526
|
-
|
|
8527
|
-
|
|
8548
|
+
const handoffPath = path13.join(stateDir, HANDOFF_FILE);
|
|
8549
|
+
fs16.mkdirSync(stateDir, { recursive: true });
|
|
8550
|
+
fs16.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
|
|
8528
8551
|
return Ok(void 0);
|
|
8529
8552
|
} catch (error) {
|
|
8530
8553
|
return Err(
|
|
@@ -8537,11 +8560,11 @@ async function loadHandoff(projectPath, stream, session) {
|
|
|
8537
8560
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8538
8561
|
if (!dirResult.ok) return dirResult;
|
|
8539
8562
|
const stateDir = dirResult.value;
|
|
8540
|
-
const handoffPath =
|
|
8541
|
-
if (!
|
|
8563
|
+
const handoffPath = path13.join(stateDir, HANDOFF_FILE);
|
|
8564
|
+
if (!fs16.existsSync(handoffPath)) {
|
|
8542
8565
|
return Ok(null);
|
|
8543
8566
|
}
|
|
8544
|
-
const raw =
|
|
8567
|
+
const raw = fs16.readFileSync(handoffPath, "utf-8");
|
|
8545
8568
|
const parsed = JSON.parse(raw);
|
|
8546
8569
|
const result = HandoffSchema.safeParse(parsed);
|
|
8547
8570
|
if (!result.success) {
|
|
@@ -8556,28 +8579,28 @@ async function loadHandoff(projectPath, stream, session) {
|
|
|
8556
8579
|
}
|
|
8557
8580
|
var SAFE_GATE_COMMAND = /^(?:npm|pnpm|yarn)\s+(?:test|run\s+[\w.-]+|run-script\s+[\w.-]+)$|^go\s+(?:test|build|vet|fmt)\s+[\w./ -]+$|^(?:python|python3)\s+-m\s+[\w.-]+$|^make\s+[\w.-]+$|^cargo\s+(?:test|build|check|clippy)(?:\s+[\w./ -]+)?$|^(?:gradle|mvn)\s+[\w:.-]+$/;
|
|
8558
8581
|
function loadChecksFromConfig(gateConfigPath) {
|
|
8559
|
-
if (!
|
|
8560
|
-
const raw = JSON.parse(
|
|
8582
|
+
if (!fs17.existsSync(gateConfigPath)) return [];
|
|
8583
|
+
const raw = JSON.parse(fs17.readFileSync(gateConfigPath, "utf-8"));
|
|
8561
8584
|
const config = GateConfigSchema.safeParse(raw);
|
|
8562
8585
|
if (config.success && config.data.checks) return config.data.checks;
|
|
8563
8586
|
return [];
|
|
8564
8587
|
}
|
|
8565
8588
|
function discoverChecksFromProject(projectPath) {
|
|
8566
8589
|
const checks = [];
|
|
8567
|
-
const packageJsonPath =
|
|
8568
|
-
if (
|
|
8569
|
-
const pkg = JSON.parse(
|
|
8590
|
+
const packageJsonPath = path14.join(projectPath, "package.json");
|
|
8591
|
+
if (fs17.existsSync(packageJsonPath)) {
|
|
8592
|
+
const pkg = JSON.parse(fs17.readFileSync(packageJsonPath, "utf-8"));
|
|
8570
8593
|
const scripts = pkg.scripts || {};
|
|
8571
8594
|
if (scripts.test) checks.push({ name: "test", command: "npm test" });
|
|
8572
8595
|
if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
|
|
8573
8596
|
if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
|
|
8574
8597
|
if (scripts.build) checks.push({ name: "build", command: "npm run build" });
|
|
8575
8598
|
}
|
|
8576
|
-
if (
|
|
8599
|
+
if (fs17.existsSync(path14.join(projectPath, "go.mod"))) {
|
|
8577
8600
|
checks.push({ name: "test", command: "go test ./..." });
|
|
8578
8601
|
checks.push({ name: "build", command: "go build ./..." });
|
|
8579
8602
|
}
|
|
8580
|
-
if (
|
|
8603
|
+
if (fs17.existsSync(path14.join(projectPath, "pyproject.toml")) || fs17.existsSync(path14.join(projectPath, "setup.py"))) {
|
|
8581
8604
|
checks.push({ name: "test", command: "python -m pytest" });
|
|
8582
8605
|
}
|
|
8583
8606
|
return checks;
|
|
@@ -8617,8 +8640,8 @@ function executeCheck(check, projectPath) {
|
|
|
8617
8640
|
}
|
|
8618
8641
|
}
|
|
8619
8642
|
async function runMechanicalGate(projectPath) {
|
|
8620
|
-
const harnessDir =
|
|
8621
|
-
const gateConfigPath =
|
|
8643
|
+
const harnessDir = path14.join(projectPath, HARNESS_DIR);
|
|
8644
|
+
const gateConfigPath = path14.join(harnessDir, GATE_CONFIG_FILE);
|
|
8622
8645
|
try {
|
|
8623
8646
|
let checks = loadChecksFromConfig(gateConfigPath);
|
|
8624
8647
|
if (checks.length === 0) {
|
|
@@ -8674,9 +8697,9 @@ function writeSessionSummary(projectPath, sessionSlug, data) {
|
|
|
8674
8697
|
const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
|
|
8675
8698
|
if (!dirResult.ok) return dirResult;
|
|
8676
8699
|
const sessionDir = dirResult.value;
|
|
8677
|
-
const summaryPath =
|
|
8700
|
+
const summaryPath = path15.join(sessionDir, SUMMARY_FILE);
|
|
8678
8701
|
const content = formatSummary(data);
|
|
8679
|
-
|
|
8702
|
+
fs18.writeFileSync(summaryPath, content);
|
|
8680
8703
|
const description = deriveIndexDescription(data);
|
|
8681
8704
|
updateSessionIndex(projectPath, sessionSlug, description);
|
|
8682
8705
|
return Ok(void 0);
|
|
@@ -8693,11 +8716,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
|
|
|
8693
8716
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
8694
8717
|
if (!dirResult.ok) return dirResult;
|
|
8695
8718
|
const sessionDir = dirResult.value;
|
|
8696
|
-
const summaryPath =
|
|
8697
|
-
if (!
|
|
8719
|
+
const summaryPath = path15.join(sessionDir, SUMMARY_FILE);
|
|
8720
|
+
if (!fs18.existsSync(summaryPath)) {
|
|
8698
8721
|
return Ok(null);
|
|
8699
8722
|
}
|
|
8700
|
-
const content =
|
|
8723
|
+
const content = fs18.readFileSync(summaryPath, "utf-8");
|
|
8701
8724
|
return Ok(content);
|
|
8702
8725
|
} catch (error) {
|
|
8703
8726
|
return Err(
|
|
@@ -8709,11 +8732,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
|
|
|
8709
8732
|
}
|
|
8710
8733
|
function listActiveSessions(projectPath) {
|
|
8711
8734
|
try {
|
|
8712
|
-
const indexPath2 =
|
|
8713
|
-
if (!
|
|
8735
|
+
const indexPath2 = path15.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
|
|
8736
|
+
if (!fs18.existsSync(indexPath2)) {
|
|
8714
8737
|
return Ok(null);
|
|
8715
8738
|
}
|
|
8716
|
-
const content =
|
|
8739
|
+
const content = fs18.readFileSync(indexPath2, "utf-8");
|
|
8717
8740
|
return Ok(content);
|
|
8718
8741
|
} catch (error) {
|
|
8719
8742
|
return Err(
|
|
@@ -8734,12 +8757,12 @@ async function loadSessionState(projectPath, sessionSlug) {
|
|
|
8734
8757
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
8735
8758
|
if (!dirResult.ok) return dirResult;
|
|
8736
8759
|
const sessionDir = dirResult.value;
|
|
8737
|
-
const filePath =
|
|
8738
|
-
if (!
|
|
8760
|
+
const filePath = path16.join(sessionDir, SESSION_STATE_FILE);
|
|
8761
|
+
if (!fs19.existsSync(filePath)) {
|
|
8739
8762
|
return Ok(emptySections());
|
|
8740
8763
|
}
|
|
8741
8764
|
try {
|
|
8742
|
-
const raw =
|
|
8765
|
+
const raw = fs19.readFileSync(filePath, "utf-8");
|
|
8743
8766
|
const parsed = JSON.parse(raw);
|
|
8744
8767
|
const sections = emptySections();
|
|
8745
8768
|
for (const name of SESSION_SECTION_NAMES) {
|
|
@@ -8760,9 +8783,9 @@ async function saveSessionState(projectPath, sessionSlug, sections) {
|
|
|
8760
8783
|
const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
|
|
8761
8784
|
if (!dirResult.ok) return dirResult;
|
|
8762
8785
|
const sessionDir = dirResult.value;
|
|
8763
|
-
const filePath =
|
|
8786
|
+
const filePath = path16.join(sessionDir, SESSION_STATE_FILE);
|
|
8764
8787
|
try {
|
|
8765
|
-
|
|
8788
|
+
fs19.writeFileSync(filePath, JSON.stringify(sections, null, 2));
|
|
8766
8789
|
return Ok(void 0);
|
|
8767
8790
|
} catch (error) {
|
|
8768
8791
|
return Err(
|
|
@@ -8818,26 +8841,26 @@ async function archiveSession(projectPath, sessionSlug) {
|
|
|
8818
8841
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
8819
8842
|
if (!dirResult.ok) return dirResult;
|
|
8820
8843
|
const sessionDir = dirResult.value;
|
|
8821
|
-
if (!
|
|
8844
|
+
if (!fs20.existsSync(sessionDir)) {
|
|
8822
8845
|
return Err(new Error(`Session '${sessionSlug}' not found at ${sessionDir}`));
|
|
8823
8846
|
}
|
|
8824
|
-
const archiveBase =
|
|
8847
|
+
const archiveBase = path17.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
|
|
8825
8848
|
try {
|
|
8826
|
-
|
|
8849
|
+
fs20.mkdirSync(archiveBase, { recursive: true });
|
|
8827
8850
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8828
8851
|
let archiveName = `${sessionSlug}-${date}`;
|
|
8829
8852
|
let counter = 1;
|
|
8830
|
-
while (
|
|
8853
|
+
while (fs20.existsSync(path17.join(archiveBase, archiveName))) {
|
|
8831
8854
|
archiveName = `${sessionSlug}-${date}-${counter}`;
|
|
8832
8855
|
counter++;
|
|
8833
8856
|
}
|
|
8834
|
-
const dest =
|
|
8857
|
+
const dest = path17.join(archiveBase, archiveName);
|
|
8835
8858
|
try {
|
|
8836
|
-
|
|
8859
|
+
fs20.renameSync(sessionDir, dest);
|
|
8837
8860
|
} catch (renameErr) {
|
|
8838
8861
|
if (renameErr instanceof Error && "code" in renameErr && renameErr.code === "EXDEV") {
|
|
8839
|
-
|
|
8840
|
-
|
|
8862
|
+
fs20.cpSync(sessionDir, dest, { recursive: true });
|
|
8863
|
+
fs20.rmSync(sessionDir, { recursive: true });
|
|
8841
8864
|
} else {
|
|
8842
8865
|
throw renameErr;
|
|
8843
8866
|
}
|
|
@@ -8870,8 +8893,8 @@ function loadKnownHashes(eventsPath) {
|
|
|
8870
8893
|
const cached = knownHashesCache.get(eventsPath);
|
|
8871
8894
|
if (cached) return cached;
|
|
8872
8895
|
const hashes = /* @__PURE__ */ new Set();
|
|
8873
|
-
if (
|
|
8874
|
-
const content =
|
|
8896
|
+
if (fs21.existsSync(eventsPath)) {
|
|
8897
|
+
const content = fs21.readFileSync(eventsPath, "utf-8");
|
|
8875
8898
|
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
8876
8899
|
for (const line of lines) {
|
|
8877
8900
|
try {
|
|
@@ -8894,8 +8917,8 @@ async function emitEvent(projectPath, event, options) {
|
|
|
8894
8917
|
const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
|
|
8895
8918
|
if (!dirResult.ok) return dirResult;
|
|
8896
8919
|
const stateDir = dirResult.value;
|
|
8897
|
-
const eventsPath =
|
|
8898
|
-
|
|
8920
|
+
const eventsPath = path18.join(stateDir, EVENTS_FILE);
|
|
8921
|
+
fs21.mkdirSync(stateDir, { recursive: true });
|
|
8899
8922
|
const contentHash = computeEventHash(event, options?.session);
|
|
8900
8923
|
const knownHashes = loadKnownHashes(eventsPath);
|
|
8901
8924
|
if (knownHashes.has(contentHash)) {
|
|
@@ -8909,7 +8932,7 @@ async function emitEvent(projectPath, event, options) {
|
|
|
8909
8932
|
if (options?.session) {
|
|
8910
8933
|
fullEvent.session = options.session;
|
|
8911
8934
|
}
|
|
8912
|
-
|
|
8935
|
+
fs21.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
|
|
8913
8936
|
knownHashes.add(contentHash);
|
|
8914
8937
|
return Ok({ written: true });
|
|
8915
8938
|
} catch (error) {
|
|
@@ -8923,11 +8946,11 @@ async function loadEvents(projectPath, options) {
|
|
|
8923
8946
|
const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
|
|
8924
8947
|
if (!dirResult.ok) return dirResult;
|
|
8925
8948
|
const stateDir = dirResult.value;
|
|
8926
|
-
const eventsPath =
|
|
8927
|
-
if (!
|
|
8949
|
+
const eventsPath = path18.join(stateDir, EVENTS_FILE);
|
|
8950
|
+
if (!fs21.existsSync(eventsPath)) {
|
|
8928
8951
|
return Ok([]);
|
|
8929
8952
|
}
|
|
8930
|
-
const content =
|
|
8953
|
+
const content = fs21.readFileSync(eventsPath, "utf-8");
|
|
8931
8954
|
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
8932
8955
|
const events = [];
|
|
8933
8956
|
for (const line of lines) {
|
|
@@ -9212,11 +9235,11 @@ function resolveRuleSeverity(ruleId, defaultSeverity, overrides, strict) {
|
|
|
9212
9235
|
}
|
|
9213
9236
|
function detectStack(projectRoot) {
|
|
9214
9237
|
const stacks = [];
|
|
9215
|
-
const pkgJsonPath =
|
|
9216
|
-
if (
|
|
9238
|
+
const pkgJsonPath = path19.join(projectRoot, "package.json");
|
|
9239
|
+
if (fs22.existsSync(pkgJsonPath)) {
|
|
9217
9240
|
stacks.push("node");
|
|
9218
9241
|
try {
|
|
9219
|
-
const pkgJson = JSON.parse(
|
|
9242
|
+
const pkgJson = JSON.parse(fs22.readFileSync(pkgJsonPath, "utf-8"));
|
|
9220
9243
|
const allDeps = {
|
|
9221
9244
|
...pkgJson.dependencies,
|
|
9222
9245
|
...pkgJson.devDependencies
|
|
@@ -9231,13 +9254,13 @@ function detectStack(projectRoot) {
|
|
|
9231
9254
|
} catch {
|
|
9232
9255
|
}
|
|
9233
9256
|
}
|
|
9234
|
-
const goModPath =
|
|
9235
|
-
if (
|
|
9257
|
+
const goModPath = path19.join(projectRoot, "go.mod");
|
|
9258
|
+
if (fs22.existsSync(goModPath)) {
|
|
9236
9259
|
stacks.push("go");
|
|
9237
9260
|
}
|
|
9238
|
-
const requirementsPath =
|
|
9239
|
-
const pyprojectPath =
|
|
9240
|
-
if (
|
|
9261
|
+
const requirementsPath = path19.join(projectRoot, "requirements.txt");
|
|
9262
|
+
const pyprojectPath = path19.join(projectRoot, "pyproject.toml");
|
|
9263
|
+
if (fs22.existsSync(requirementsPath) || fs22.existsSync(pyprojectPath)) {
|
|
9241
9264
|
stacks.push("python");
|
|
9242
9265
|
}
|
|
9243
9266
|
return stacks;
|
|
@@ -10036,7 +10059,7 @@ var SecurityScanner = class {
|
|
|
10036
10059
|
}
|
|
10037
10060
|
async scanFile(filePath) {
|
|
10038
10061
|
if (!this.config.enabled) return [];
|
|
10039
|
-
const content = await
|
|
10062
|
+
const content = await fs23.readFile(filePath, "utf-8");
|
|
10040
10063
|
return this.scanContentForFile(content, filePath, 1);
|
|
10041
10064
|
}
|
|
10042
10065
|
scanContentForFile(content, filePath, startLine = 1) {
|
|
@@ -10363,13 +10386,13 @@ var TAINT_DURATION_MS = 30 * 60 * 1e3;
|
|
|
10363
10386
|
var DEFAULT_SESSION_ID = "default";
|
|
10364
10387
|
function getTaintFilePath(projectRoot, sessionId) {
|
|
10365
10388
|
const id = sessionId || DEFAULT_SESSION_ID;
|
|
10366
|
-
return
|
|
10389
|
+
return join272(projectRoot, ".harness", `session-taint-${id}.json`);
|
|
10367
10390
|
}
|
|
10368
10391
|
function readTaint(projectRoot, sessionId) {
|
|
10369
10392
|
const filePath = getTaintFilePath(projectRoot, sessionId);
|
|
10370
10393
|
let content;
|
|
10371
10394
|
try {
|
|
10372
|
-
content =
|
|
10395
|
+
content = readFileSync20(filePath, "utf8");
|
|
10373
10396
|
} catch {
|
|
10374
10397
|
return null;
|
|
10375
10398
|
}
|
|
@@ -10414,7 +10437,7 @@ function writeTaint(projectRoot, sessionId, reason, findings, source) {
|
|
|
10414
10437
|
const filePath = getTaintFilePath(projectRoot, id);
|
|
10415
10438
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10416
10439
|
const dir = dirname9(filePath);
|
|
10417
|
-
|
|
10440
|
+
mkdirSync13(dir, { recursive: true });
|
|
10418
10441
|
const existing = readTaint(projectRoot, id);
|
|
10419
10442
|
const maxSeverity = findings.some((f) => f.severity === "high") ? "high" : "medium";
|
|
10420
10443
|
const taintFindings = findings.map((f) => ({
|
|
@@ -10432,7 +10455,7 @@ function writeTaint(projectRoot, sessionId, reason, findings, source) {
|
|
|
10432
10455
|
severity: existing?.severity === "high" || maxSeverity === "high" ? "high" : "medium",
|
|
10433
10456
|
findings: [...existing?.findings || [], ...taintFindings]
|
|
10434
10457
|
};
|
|
10435
|
-
|
|
10458
|
+
writeFileSync14(filePath, JSON.stringify(state, null, 2) + "\n");
|
|
10436
10459
|
return state;
|
|
10437
10460
|
}
|
|
10438
10461
|
function clearTaint(projectRoot, sessionId) {
|
|
@@ -10445,14 +10468,14 @@ function clearTaint(projectRoot, sessionId) {
|
|
|
10445
10468
|
return 0;
|
|
10446
10469
|
}
|
|
10447
10470
|
}
|
|
10448
|
-
const harnessDir =
|
|
10471
|
+
const harnessDir = join272(projectRoot, ".harness");
|
|
10449
10472
|
let count = 0;
|
|
10450
10473
|
try {
|
|
10451
10474
|
const files = readdirSync3(harnessDir);
|
|
10452
10475
|
for (const file of files) {
|
|
10453
10476
|
if (file.startsWith("session-taint-") && file.endsWith(".json")) {
|
|
10454
10477
|
try {
|
|
10455
|
-
unlinkSync(
|
|
10478
|
+
unlinkSync(join272(harnessDir, file));
|
|
10456
10479
|
count++;
|
|
10457
10480
|
} catch {
|
|
10458
10481
|
}
|
|
@@ -10463,7 +10486,7 @@ function clearTaint(projectRoot, sessionId) {
|
|
|
10463
10486
|
return count;
|
|
10464
10487
|
}
|
|
10465
10488
|
function listTaintedSessions(projectRoot) {
|
|
10466
|
-
const harnessDir =
|
|
10489
|
+
const harnessDir = join272(projectRoot, ".harness");
|
|
10467
10490
|
const sessions = [];
|
|
10468
10491
|
try {
|
|
10469
10492
|
const files = readdirSync3(harnessDir);
|
|
@@ -10542,7 +10565,7 @@ var ALL_CHECKS = [
|
|
|
10542
10565
|
];
|
|
10543
10566
|
async function runValidateCheck(projectRoot, config) {
|
|
10544
10567
|
const issues = [];
|
|
10545
|
-
const agentsPath =
|
|
10568
|
+
const agentsPath = path20.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
|
|
10546
10569
|
const result = await validateAgentsMap(agentsPath);
|
|
10547
10570
|
if (!result.ok) {
|
|
10548
10571
|
issues.push({ severity: "error", message: result.error.message });
|
|
@@ -10599,7 +10622,7 @@ async function runDepsCheck(projectRoot, config) {
|
|
|
10599
10622
|
}
|
|
10600
10623
|
async function runDocsCheck(projectRoot, config) {
|
|
10601
10624
|
const issues = [];
|
|
10602
|
-
const docsDir =
|
|
10625
|
+
const docsDir = path20.join(projectRoot, config.docsDir ?? "docs");
|
|
10603
10626
|
const entropyConfig = config.entropy || {};
|
|
10604
10627
|
const result = await checkDocCoverage("project", {
|
|
10605
10628
|
docsDir,
|
|
@@ -10784,7 +10807,7 @@ async function runTraceabilityCheck(projectRoot, config) {
|
|
|
10784
10807
|
const issues = [];
|
|
10785
10808
|
const traceConfig = config.traceability || {};
|
|
10786
10809
|
if (traceConfig.enabled === false) return issues;
|
|
10787
|
-
const graphDir =
|
|
10810
|
+
const graphDir = path20.join(projectRoot, ".harness", "graph");
|
|
10788
10811
|
const store = new GraphStore();
|
|
10789
10812
|
const loaded = await store.load(graphDir);
|
|
10790
10813
|
if (!loaded) {
|
|
@@ -10922,7 +10945,7 @@ async function runMechanicalChecks(options) {
|
|
|
10922
10945
|
};
|
|
10923
10946
|
if (!skip.includes("validate")) {
|
|
10924
10947
|
try {
|
|
10925
|
-
const agentsPath =
|
|
10948
|
+
const agentsPath = path21.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
|
|
10926
10949
|
const result = await validateAgentsMap(agentsPath);
|
|
10927
10950
|
if (!result.ok) {
|
|
10928
10951
|
statuses.validate = "fail";
|
|
@@ -10959,7 +10982,7 @@ async function runMechanicalChecks(options) {
|
|
|
10959
10982
|
statuses.validate = "fail";
|
|
10960
10983
|
findings.push({
|
|
10961
10984
|
tool: "validate",
|
|
10962
|
-
file:
|
|
10985
|
+
file: path21.join(projectRoot, "AGENTS.md"),
|
|
10963
10986
|
message: err instanceof Error ? err.message : String(err),
|
|
10964
10987
|
severity: "error"
|
|
10965
10988
|
});
|
|
@@ -11023,7 +11046,7 @@ async function runMechanicalChecks(options) {
|
|
|
11023
11046
|
(async () => {
|
|
11024
11047
|
const localFindings = [];
|
|
11025
11048
|
try {
|
|
11026
|
-
const docsDir =
|
|
11049
|
+
const docsDir = path21.join(projectRoot, config.docsDir ?? "docs");
|
|
11027
11050
|
const result = await checkDocCoverage("project", { docsDir });
|
|
11028
11051
|
if (!result.ok) {
|
|
11029
11052
|
statuses["check-docs"] = "warn";
|
|
@@ -11050,7 +11073,7 @@ async function runMechanicalChecks(options) {
|
|
|
11050
11073
|
statuses["check-docs"] = "warn";
|
|
11051
11074
|
localFindings.push({
|
|
11052
11075
|
tool: "check-docs",
|
|
11053
|
-
file:
|
|
11076
|
+
file: path21.join(projectRoot, "docs"),
|
|
11054
11077
|
message: err instanceof Error ? err.message : String(err),
|
|
11055
11078
|
severity: "warning"
|
|
11056
11079
|
});
|
|
@@ -11199,18 +11222,18 @@ function computeContextBudget(diffLines) {
|
|
|
11199
11222
|
return diffLines;
|
|
11200
11223
|
}
|
|
11201
11224
|
function isWithinProject(absPath, projectRoot) {
|
|
11202
|
-
const resolvedRoot =
|
|
11203
|
-
const resolvedPath =
|
|
11204
|
-
return resolvedPath.startsWith(resolvedRoot) || resolvedPath ===
|
|
11225
|
+
const resolvedRoot = path22.resolve(projectRoot) + path22.sep;
|
|
11226
|
+
const resolvedPath = path22.resolve(absPath);
|
|
11227
|
+
return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path22.resolve(projectRoot);
|
|
11205
11228
|
}
|
|
11206
11229
|
async function readContextFile(projectRoot, filePath, reason) {
|
|
11207
|
-
const absPath =
|
|
11230
|
+
const absPath = path22.isAbsolute(filePath) ? filePath : path22.join(projectRoot, filePath);
|
|
11208
11231
|
if (!isWithinProject(absPath, projectRoot)) return null;
|
|
11209
11232
|
const result = await readFileContent(absPath);
|
|
11210
11233
|
if (!result.ok) return null;
|
|
11211
11234
|
const content = result.value;
|
|
11212
11235
|
const lines = content.split("\n").length;
|
|
11213
|
-
const relPath =
|
|
11236
|
+
const relPath = path22.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
|
|
11214
11237
|
return { path: relPath, content, reason, lines };
|
|
11215
11238
|
}
|
|
11216
11239
|
function extractImportSources2(content) {
|
|
@@ -11225,18 +11248,18 @@ function extractImportSources2(content) {
|
|
|
11225
11248
|
}
|
|
11226
11249
|
async function resolveImportPath2(projectRoot, fromFile, importSource) {
|
|
11227
11250
|
if (!importSource.startsWith(".")) return null;
|
|
11228
|
-
const fromDir =
|
|
11229
|
-
const basePath =
|
|
11251
|
+
const fromDir = path22.dirname(path22.join(projectRoot, fromFile));
|
|
11252
|
+
const basePath = path22.resolve(fromDir, importSource);
|
|
11230
11253
|
if (!isWithinProject(basePath, projectRoot)) return null;
|
|
11231
11254
|
const relBase = relativePosix(projectRoot, basePath);
|
|
11232
11255
|
const candidates = [
|
|
11233
11256
|
relBase + ".ts",
|
|
11234
11257
|
relBase + ".tsx",
|
|
11235
11258
|
relBase + ".mts",
|
|
11236
|
-
|
|
11259
|
+
path22.join(relBase, "index.ts")
|
|
11237
11260
|
];
|
|
11238
11261
|
for (const candidate of candidates) {
|
|
11239
|
-
const absCandidate =
|
|
11262
|
+
const absCandidate = path22.join(projectRoot, candidate);
|
|
11240
11263
|
if (await fileExists(absCandidate)) {
|
|
11241
11264
|
return candidate;
|
|
11242
11265
|
}
|
|
@@ -11244,7 +11267,7 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
|
|
|
11244
11267
|
return null;
|
|
11245
11268
|
}
|
|
11246
11269
|
async function findTestFiles(projectRoot, sourceFile) {
|
|
11247
|
-
const baseName =
|
|
11270
|
+
const baseName = path22.basename(sourceFile, path22.extname(sourceFile));
|
|
11248
11271
|
const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
|
|
11249
11272
|
const results = await findFiles(pattern, projectRoot);
|
|
11250
11273
|
return results.map((f) => relativePosix(projectRoot, f));
|
|
@@ -12057,7 +12080,7 @@ function normalizePath(filePath, projectRoot) {
|
|
|
12057
12080
|
let normalized = filePath;
|
|
12058
12081
|
normalized = normalized.replace(/\\/g, "/");
|
|
12059
12082
|
const normalizedRoot = projectRoot.replace(/\\/g, "/");
|
|
12060
|
-
if (
|
|
12083
|
+
if (path23.isAbsolute(normalized)) {
|
|
12061
12084
|
const root = normalizedRoot.endsWith("/") ? normalizedRoot : normalizedRoot + "/";
|
|
12062
12085
|
if (normalized.startsWith(root)) {
|
|
12063
12086
|
normalized = normalized.slice(root.length);
|
|
@@ -12082,12 +12105,12 @@ function followImportChain(fromFile, fileContents, maxDepth = 2) {
|
|
|
12082
12105
|
while ((match = importRegex.exec(content)) !== null) {
|
|
12083
12106
|
const importPath = match[1];
|
|
12084
12107
|
if (!importPath.startsWith(".")) continue;
|
|
12085
|
-
const dir =
|
|
12086
|
-
let resolved =
|
|
12108
|
+
const dir = path23.dirname(current.file);
|
|
12109
|
+
let resolved = path23.join(dir, importPath).replace(/\\/g, "/");
|
|
12087
12110
|
if (!resolved.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
12088
12111
|
resolved += ".ts";
|
|
12089
12112
|
}
|
|
12090
|
-
resolved =
|
|
12113
|
+
resolved = path23.normalize(resolved).replace(/\\/g, "/");
|
|
12091
12114
|
if (!visited.has(resolved) && current.depth + 1 <= maxDepth) {
|
|
12092
12115
|
queue.push({ file: resolved, depth: current.depth + 1 });
|
|
12093
12116
|
}
|
|
@@ -12104,7 +12127,7 @@ async function validateFindings(options) {
|
|
|
12104
12127
|
if (exclusionSet.isExcluded(normalizedFile, finding.lineRange) || exclusionSet.isExcluded(finding.file, finding.lineRange)) {
|
|
12105
12128
|
continue;
|
|
12106
12129
|
}
|
|
12107
|
-
const absoluteFile =
|
|
12130
|
+
const absoluteFile = path23.isAbsolute(finding.file) ? finding.file : path23.join(projectRoot, finding.file).replace(/\\/g, "/");
|
|
12108
12131
|
if (exclusionSet.isExcluded(absoluteFile, finding.lineRange)) {
|
|
12109
12132
|
continue;
|
|
12110
12133
|
}
|
|
@@ -12791,10 +12814,10 @@ function inferStatus(feature, projectPath, allFeatures) {
|
|
|
12791
12814
|
const featuresWithPlans = allFeatures.filter((f) => f.plans.length > 0);
|
|
12792
12815
|
const useRootState = featuresWithPlans.length <= 1;
|
|
12793
12816
|
if (useRootState) {
|
|
12794
|
-
const rootStatePath =
|
|
12795
|
-
if (
|
|
12817
|
+
const rootStatePath = path24.join(projectPath, ".harness", "state.json");
|
|
12818
|
+
if (fs24.existsSync(rootStatePath)) {
|
|
12796
12819
|
try {
|
|
12797
|
-
const raw =
|
|
12820
|
+
const raw = fs24.readFileSync(rootStatePath, "utf-8");
|
|
12798
12821
|
const state = JSON.parse(raw);
|
|
12799
12822
|
if (state.progress) {
|
|
12800
12823
|
for (const status of Object.values(state.progress)) {
|
|
@@ -12805,16 +12828,16 @@ function inferStatus(feature, projectPath, allFeatures) {
|
|
|
12805
12828
|
}
|
|
12806
12829
|
}
|
|
12807
12830
|
}
|
|
12808
|
-
const sessionsDir =
|
|
12809
|
-
if (
|
|
12831
|
+
const sessionsDir = path24.join(projectPath, ".harness", "sessions");
|
|
12832
|
+
if (fs24.existsSync(sessionsDir)) {
|
|
12810
12833
|
try {
|
|
12811
|
-
const sessionDirs =
|
|
12834
|
+
const sessionDirs = fs24.readdirSync(sessionsDir, { withFileTypes: true });
|
|
12812
12835
|
for (const entry of sessionDirs) {
|
|
12813
12836
|
if (!entry.isDirectory()) continue;
|
|
12814
|
-
const autopilotPath =
|
|
12815
|
-
if (!
|
|
12837
|
+
const autopilotPath = path24.join(sessionsDir, entry.name, "autopilot-state.json");
|
|
12838
|
+
if (!fs24.existsSync(autopilotPath)) continue;
|
|
12816
12839
|
try {
|
|
12817
|
-
const raw =
|
|
12840
|
+
const raw = fs24.readFileSync(autopilotPath, "utf-8");
|
|
12818
12841
|
const autopilot = JSON.parse(raw);
|
|
12819
12842
|
if (!autopilot.phases) continue;
|
|
12820
12843
|
const linkedPhases = autopilot.phases.filter(
|
|
@@ -13306,6 +13329,9 @@ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTic
|
|
|
13306
13329
|
if (!forceSync && isRegression(feature.status, newStatus)) {
|
|
13307
13330
|
continue;
|
|
13308
13331
|
}
|
|
13332
|
+
if (!forceSync && feature.status === "blocked" && newStatus === "planned") {
|
|
13333
|
+
continue;
|
|
13334
|
+
}
|
|
13309
13335
|
feature.status = newStatus;
|
|
13310
13336
|
}
|
|
13311
13337
|
}
|
|
@@ -13320,7 +13346,7 @@ async function fullSync(roadmapPath, adapter, config, options) {
|
|
|
13320
13346
|
});
|
|
13321
13347
|
await previousSync;
|
|
13322
13348
|
try {
|
|
13323
|
-
const raw =
|
|
13349
|
+
const raw = fs25.readFileSync(roadmapPath, "utf-8");
|
|
13324
13350
|
const parseResult = parseRoadmap(raw);
|
|
13325
13351
|
if (!parseResult.ok) {
|
|
13326
13352
|
return {
|
|
@@ -13333,7 +13359,7 @@ async function fullSync(roadmapPath, adapter, config, options) {
|
|
|
13333
13359
|
const tickets = fetchResult.ok ? fetchResult.value : void 0;
|
|
13334
13360
|
const pushResult = await syncToExternal(roadmap, adapter, config, tickets);
|
|
13335
13361
|
const pullResult = await syncFromExternal(roadmap, adapter, config, options, tickets);
|
|
13336
|
-
|
|
13362
|
+
fs25.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
|
|
13337
13363
|
return {
|
|
13338
13364
|
created: pushResult.created,
|
|
13339
13365
|
updated: pushResult.updated,
|
|
@@ -13491,10 +13517,10 @@ var ProjectScanner = class {
|
|
|
13491
13517
|
}
|
|
13492
13518
|
rootDir;
|
|
13493
13519
|
async scan() {
|
|
13494
|
-
let projectName =
|
|
13520
|
+
let projectName = path25.basename(this.rootDir);
|
|
13495
13521
|
try {
|
|
13496
|
-
const pkgPath =
|
|
13497
|
-
const pkgRaw = await
|
|
13522
|
+
const pkgPath = path25.join(this.rootDir, "package.json");
|
|
13523
|
+
const pkgRaw = await fs26.readFile(pkgPath, "utf-8");
|
|
13498
13524
|
const pkg = JSON.parse(pkgRaw);
|
|
13499
13525
|
if (pkg.name) projectName = pkg.name;
|
|
13500
13526
|
} catch {
|
|
@@ -13607,13 +13633,13 @@ var BlueprintGenerator = class {
|
|
|
13607
13633
|
styles: STYLES,
|
|
13608
13634
|
scripts: SCRIPTS
|
|
13609
13635
|
});
|
|
13610
|
-
await
|
|
13611
|
-
await
|
|
13636
|
+
await fs27.mkdir(options.outputDir, { recursive: true });
|
|
13637
|
+
await fs27.writeFile(path26.join(options.outputDir, "index.html"), html);
|
|
13612
13638
|
}
|
|
13613
13639
|
};
|
|
13614
13640
|
function getStatePath() {
|
|
13615
13641
|
const home = process.env["HOME"] || os.homedir();
|
|
13616
|
-
return
|
|
13642
|
+
return path27.join(home, ".harness", "update-check.json");
|
|
13617
13643
|
}
|
|
13618
13644
|
function isUpdateCheckEnabled(configInterval) {
|
|
13619
13645
|
if (process.env["HARNESS_NO_UPDATE_CHECK"] === "1") return false;
|
|
@@ -13626,7 +13652,7 @@ function shouldRunCheck(state, intervalMs) {
|
|
|
13626
13652
|
}
|
|
13627
13653
|
function readCheckState() {
|
|
13628
13654
|
try {
|
|
13629
|
-
const raw =
|
|
13655
|
+
const raw = fs28.readFileSync(getStatePath(), "utf-8");
|
|
13630
13656
|
const parsed = JSON.parse(raw);
|
|
13631
13657
|
if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
|
|
13632
13658
|
const state = parsed;
|
|
@@ -13643,7 +13669,7 @@ function readCheckState() {
|
|
|
13643
13669
|
}
|
|
13644
13670
|
function spawnBackgroundCheck(currentVersion) {
|
|
13645
13671
|
const statePath = getStatePath();
|
|
13646
|
-
const stateDir =
|
|
13672
|
+
const stateDir = path27.dirname(statePath);
|
|
13647
13673
|
const script = `
|
|
13648
13674
|
const { execSync } = require('child_process');
|
|
13649
13675
|
const fs = require('fs');
|
|
@@ -13727,9 +13753,9 @@ async function resolveWasmPath(grammarName) {
|
|
|
13727
13753
|
const { createRequire } = await import("module");
|
|
13728
13754
|
const require2 = createRequire(import.meta.url ?? __filename);
|
|
13729
13755
|
const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
|
|
13730
|
-
const
|
|
13731
|
-
const pkgDir =
|
|
13732
|
-
return
|
|
13756
|
+
const path31 = await import("path");
|
|
13757
|
+
const pkgDir = path31.dirname(pkgPath);
|
|
13758
|
+
return path31.join(pkgDir, "out", `${grammarName}.wasm`);
|
|
13733
13759
|
}
|
|
13734
13760
|
async function loadLanguage(lang) {
|
|
13735
13761
|
const grammarName = GRAMMAR_MAP[lang];
|
|
@@ -14171,14 +14197,14 @@ var LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/mai
|
|
|
14171
14197
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
14172
14198
|
var STALENESS_WARNING_DAYS = 7;
|
|
14173
14199
|
function getCachePath(projectRoot) {
|
|
14174
|
-
return
|
|
14200
|
+
return path28.join(projectRoot, ".harness", "cache", "pricing.json");
|
|
14175
14201
|
}
|
|
14176
14202
|
function getStalenessMarkerPath(projectRoot) {
|
|
14177
|
-
return
|
|
14203
|
+
return path28.join(projectRoot, ".harness", "cache", "staleness-marker.json");
|
|
14178
14204
|
}
|
|
14179
14205
|
async function readDiskCache(projectRoot) {
|
|
14180
14206
|
try {
|
|
14181
|
-
const raw = await
|
|
14207
|
+
const raw = await fs29.readFile(getCachePath(projectRoot), "utf-8");
|
|
14182
14208
|
return JSON.parse(raw);
|
|
14183
14209
|
} catch {
|
|
14184
14210
|
return null;
|
|
@@ -14186,8 +14212,8 @@ async function readDiskCache(projectRoot) {
|
|
|
14186
14212
|
}
|
|
14187
14213
|
async function writeDiskCache(projectRoot, data) {
|
|
14188
14214
|
const cachePath = getCachePath(projectRoot);
|
|
14189
|
-
await
|
|
14190
|
-
await
|
|
14215
|
+
await fs29.mkdir(path28.dirname(cachePath), { recursive: true });
|
|
14216
|
+
await fs29.writeFile(cachePath, JSON.stringify(data, null, 2));
|
|
14191
14217
|
}
|
|
14192
14218
|
async function fetchFromNetwork() {
|
|
14193
14219
|
try {
|
|
@@ -14214,7 +14240,7 @@ function loadFallbackDataset() {
|
|
|
14214
14240
|
async function checkAndWarnStaleness(projectRoot) {
|
|
14215
14241
|
const markerPath = getStalenessMarkerPath(projectRoot);
|
|
14216
14242
|
try {
|
|
14217
|
-
const raw = await
|
|
14243
|
+
const raw = await fs29.readFile(markerPath, "utf-8");
|
|
14218
14244
|
const marker = JSON.parse(raw);
|
|
14219
14245
|
const firstUse = new Date(marker.firstFallbackUse).getTime();
|
|
14220
14246
|
const now = Date.now();
|
|
@@ -14226,8 +14252,8 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
14226
14252
|
}
|
|
14227
14253
|
} catch {
|
|
14228
14254
|
try {
|
|
14229
|
-
await
|
|
14230
|
-
await
|
|
14255
|
+
await fs29.mkdir(path28.dirname(markerPath), { recursive: true });
|
|
14256
|
+
await fs29.writeFile(
|
|
14231
14257
|
markerPath,
|
|
14232
14258
|
JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
|
|
14233
14259
|
);
|
|
@@ -14237,7 +14263,7 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
14237
14263
|
}
|
|
14238
14264
|
async function clearStalenessMarker(projectRoot) {
|
|
14239
14265
|
try {
|
|
14240
|
-
await
|
|
14266
|
+
await fs29.unlink(getStalenessMarkerPath(projectRoot));
|
|
14241
14267
|
} catch {
|
|
14242
14268
|
}
|
|
14243
14269
|
}
|
|
@@ -14279,8 +14305,7 @@ function calculateCost(record, dataset) {
|
|
|
14279
14305
|
}
|
|
14280
14306
|
return Math.round(costUSD * MICRODOLLARS_PER_DOLLAR);
|
|
14281
14307
|
}
|
|
14282
|
-
function
|
|
14283
|
-
if (records.length === 0) return [];
|
|
14308
|
+
function bucketRecordsBySession(records) {
|
|
14284
14309
|
const sessionMap = /* @__PURE__ */ new Map();
|
|
14285
14310
|
for (const record of records) {
|
|
14286
14311
|
const tagged = record;
|
|
@@ -14296,58 +14321,104 @@ function aggregateBySession(records) {
|
|
|
14296
14321
|
}
|
|
14297
14322
|
bucket.allRecords.push(tagged);
|
|
14298
14323
|
}
|
|
14324
|
+
return sessionMap;
|
|
14325
|
+
}
|
|
14326
|
+
function accumulateCost(running, recordCost) {
|
|
14327
|
+
if (recordCost != null && running != null) {
|
|
14328
|
+
return running + recordCost;
|
|
14329
|
+
}
|
|
14330
|
+
if (recordCost == null) {
|
|
14331
|
+
return null;
|
|
14332
|
+
}
|
|
14333
|
+
return running;
|
|
14334
|
+
}
|
|
14335
|
+
function sumRecordTokens(tokenSource) {
|
|
14336
|
+
const tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
14337
|
+
let cacheCreation;
|
|
14338
|
+
let cacheRead;
|
|
14339
|
+
let costMicroUSD = 0;
|
|
14340
|
+
let model;
|
|
14341
|
+
for (const r of tokenSource) {
|
|
14342
|
+
tokens.inputTokens += r.tokens.inputTokens;
|
|
14343
|
+
tokens.outputTokens += r.tokens.outputTokens;
|
|
14344
|
+
tokens.totalTokens += r.tokens.totalTokens;
|
|
14345
|
+
if (r.cacheCreationTokens != null) {
|
|
14346
|
+
cacheCreation = (cacheCreation ?? 0) + r.cacheCreationTokens;
|
|
14347
|
+
}
|
|
14348
|
+
if (r.cacheReadTokens != null) {
|
|
14349
|
+
cacheRead = (cacheRead ?? 0) + r.cacheReadTokens;
|
|
14350
|
+
}
|
|
14351
|
+
costMicroUSD = accumulateCost(costMicroUSD, r.costMicroUSD);
|
|
14352
|
+
if (!model && r.model) {
|
|
14353
|
+
model = r.model;
|
|
14354
|
+
}
|
|
14355
|
+
}
|
|
14356
|
+
return { tokens, cacheCreation, cacheRead, costMicroUSD, model };
|
|
14357
|
+
}
|
|
14358
|
+
function findModel(records) {
|
|
14359
|
+
for (const r of records) {
|
|
14360
|
+
if (r.model) return r.model;
|
|
14361
|
+
}
|
|
14362
|
+
return void 0;
|
|
14363
|
+
}
|
|
14364
|
+
function determineSource(hasHarness, hasCC) {
|
|
14365
|
+
if (hasHarness && hasCC) return "merged";
|
|
14366
|
+
if (hasCC) return "claude-code";
|
|
14367
|
+
return "harness";
|
|
14368
|
+
}
|
|
14369
|
+
function applyOptionalFields(session, totals, model) {
|
|
14370
|
+
if (model) session.model = model;
|
|
14371
|
+
if (totals.cacheCreation != null) session.cacheCreationTokens = totals.cacheCreation;
|
|
14372
|
+
if (totals.cacheRead != null) session.cacheReadTokens = totals.cacheRead;
|
|
14373
|
+
}
|
|
14374
|
+
function buildSessionUsage(sessionId, bucket) {
|
|
14375
|
+
const hasHarness = bucket.harnessRecords.length > 0;
|
|
14376
|
+
const hasCC = bucket.ccRecords.length > 0;
|
|
14377
|
+
const tokenSource = hasHarness ? bucket.harnessRecords : bucket.ccRecords;
|
|
14378
|
+
const totals = sumRecordTokens(tokenSource);
|
|
14379
|
+
const model = totals.model ?? (hasCC ? findModel(bucket.ccRecords) : void 0);
|
|
14380
|
+
const timestamps = bucket.allRecords.map((r) => r.timestamp).sort();
|
|
14381
|
+
const session = {
|
|
14382
|
+
sessionId,
|
|
14383
|
+
firstTimestamp: timestamps[0] ?? "",
|
|
14384
|
+
lastTimestamp: timestamps[timestamps.length - 1] ?? "",
|
|
14385
|
+
tokens: totals.tokens,
|
|
14386
|
+
costMicroUSD: totals.costMicroUSD,
|
|
14387
|
+
source: determineSource(hasHarness, hasCC)
|
|
14388
|
+
};
|
|
14389
|
+
applyOptionalFields(session, totals, model);
|
|
14390
|
+
return session;
|
|
14391
|
+
}
|
|
14392
|
+
function accumulateIntoDayBucket(day, record) {
|
|
14393
|
+
day.sessions.add(record.sessionId);
|
|
14394
|
+
day.tokens.inputTokens += record.tokens.inputTokens;
|
|
14395
|
+
day.tokens.outputTokens += record.tokens.outputTokens;
|
|
14396
|
+
day.tokens.totalTokens += record.tokens.totalTokens;
|
|
14397
|
+
if (record.cacheCreationTokens != null) {
|
|
14398
|
+
day.cacheCreation = (day.cacheCreation ?? 0) + record.cacheCreationTokens;
|
|
14399
|
+
}
|
|
14400
|
+
if (record.cacheReadTokens != null) {
|
|
14401
|
+
day.cacheRead = (day.cacheRead ?? 0) + record.cacheReadTokens;
|
|
14402
|
+
}
|
|
14403
|
+
day.costMicroUSD = accumulateCost(day.costMicroUSD, record.costMicroUSD);
|
|
14404
|
+
if (record.model) {
|
|
14405
|
+
day.models.add(record.model);
|
|
14406
|
+
}
|
|
14407
|
+
}
|
|
14408
|
+
function createDayBucket() {
|
|
14409
|
+
return {
|
|
14410
|
+
sessions: /* @__PURE__ */ new Set(),
|
|
14411
|
+
tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
|
|
14412
|
+
costMicroUSD: 0,
|
|
14413
|
+
models: /* @__PURE__ */ new Set()
|
|
14414
|
+
};
|
|
14415
|
+
}
|
|
14416
|
+
function aggregateBySession(records) {
|
|
14417
|
+
if (records.length === 0) return [];
|
|
14418
|
+
const sessionMap = bucketRecordsBySession(records);
|
|
14299
14419
|
const results = [];
|
|
14300
14420
|
for (const [sessionId, bucket] of sessionMap) {
|
|
14301
|
-
|
|
14302
|
-
const hasCC = bucket.ccRecords.length > 0;
|
|
14303
|
-
const isMerged = hasHarness && hasCC;
|
|
14304
|
-
const tokenSource = hasHarness ? bucket.harnessRecords : bucket.ccRecords;
|
|
14305
|
-
const tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
14306
|
-
let cacheCreation;
|
|
14307
|
-
let cacheRead;
|
|
14308
|
-
let costMicroUSD = 0;
|
|
14309
|
-
let model;
|
|
14310
|
-
for (const r of tokenSource) {
|
|
14311
|
-
tokens.inputTokens += r.tokens.inputTokens;
|
|
14312
|
-
tokens.outputTokens += r.tokens.outputTokens;
|
|
14313
|
-
tokens.totalTokens += r.tokens.totalTokens;
|
|
14314
|
-
if (r.cacheCreationTokens != null) {
|
|
14315
|
-
cacheCreation = (cacheCreation ?? 0) + r.cacheCreationTokens;
|
|
14316
|
-
}
|
|
14317
|
-
if (r.cacheReadTokens != null) {
|
|
14318
|
-
cacheRead = (cacheRead ?? 0) + r.cacheReadTokens;
|
|
14319
|
-
}
|
|
14320
|
-
if (r.costMicroUSD != null && costMicroUSD != null) {
|
|
14321
|
-
costMicroUSD += r.costMicroUSD;
|
|
14322
|
-
} else if (r.costMicroUSD == null) {
|
|
14323
|
-
costMicroUSD = null;
|
|
14324
|
-
}
|
|
14325
|
-
if (!model && r.model) {
|
|
14326
|
-
model = r.model;
|
|
14327
|
-
}
|
|
14328
|
-
}
|
|
14329
|
-
if (!model && hasCC) {
|
|
14330
|
-
for (const r of bucket.ccRecords) {
|
|
14331
|
-
if (r.model) {
|
|
14332
|
-
model = r.model;
|
|
14333
|
-
break;
|
|
14334
|
-
}
|
|
14335
|
-
}
|
|
14336
|
-
}
|
|
14337
|
-
const timestamps = bucket.allRecords.map((r) => r.timestamp).sort();
|
|
14338
|
-
const source = isMerged ? "merged" : hasCC ? "claude-code" : "harness";
|
|
14339
|
-
const session = {
|
|
14340
|
-
sessionId,
|
|
14341
|
-
firstTimestamp: timestamps[0] ?? "",
|
|
14342
|
-
lastTimestamp: timestamps[timestamps.length - 1] ?? "",
|
|
14343
|
-
tokens,
|
|
14344
|
-
costMicroUSD,
|
|
14345
|
-
source
|
|
14346
|
-
};
|
|
14347
|
-
if (model) session.model = model;
|
|
14348
|
-
if (cacheCreation != null) session.cacheCreationTokens = cacheCreation;
|
|
14349
|
-
if (cacheRead != null) session.cacheReadTokens = cacheRead;
|
|
14350
|
-
results.push(session);
|
|
14421
|
+
results.push(buildSessionUsage(sessionId, bucket));
|
|
14351
14422
|
}
|
|
14352
14423
|
results.sort((a, b) => b.firstTimestamp.localeCompare(a.firstTimestamp));
|
|
14353
14424
|
return results;
|
|
@@ -14358,32 +14429,9 @@ function aggregateByDay(records) {
|
|
|
14358
14429
|
for (const record of records) {
|
|
14359
14430
|
const date = record.timestamp.slice(0, 10);
|
|
14360
14431
|
if (!dayMap.has(date)) {
|
|
14361
|
-
dayMap.set(date,
|
|
14362
|
-
sessions: /* @__PURE__ */ new Set(),
|
|
14363
|
-
tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
|
|
14364
|
-
costMicroUSD: 0,
|
|
14365
|
-
models: /* @__PURE__ */ new Set()
|
|
14366
|
-
});
|
|
14367
|
-
}
|
|
14368
|
-
const day = dayMap.get(date);
|
|
14369
|
-
day.sessions.add(record.sessionId);
|
|
14370
|
-
day.tokens.inputTokens += record.tokens.inputTokens;
|
|
14371
|
-
day.tokens.outputTokens += record.tokens.outputTokens;
|
|
14372
|
-
day.tokens.totalTokens += record.tokens.totalTokens;
|
|
14373
|
-
if (record.cacheCreationTokens != null) {
|
|
14374
|
-
day.cacheCreation = (day.cacheCreation ?? 0) + record.cacheCreationTokens;
|
|
14375
|
-
}
|
|
14376
|
-
if (record.cacheReadTokens != null) {
|
|
14377
|
-
day.cacheRead = (day.cacheRead ?? 0) + record.cacheReadTokens;
|
|
14378
|
-
}
|
|
14379
|
-
if (record.costMicroUSD != null && day.costMicroUSD != null) {
|
|
14380
|
-
day.costMicroUSD += record.costMicroUSD;
|
|
14381
|
-
} else if (record.costMicroUSD == null) {
|
|
14382
|
-
day.costMicroUSD = null;
|
|
14383
|
-
}
|
|
14384
|
-
if (record.model) {
|
|
14385
|
-
day.models.add(record.model);
|
|
14432
|
+
dayMap.set(date, createDayBucket());
|
|
14386
14433
|
}
|
|
14434
|
+
accumulateIntoDayBucket(dayMap.get(date), record);
|
|
14387
14435
|
}
|
|
14388
14436
|
const results = [];
|
|
14389
14437
|
for (const [date, day] of dayMap) {
|
|
@@ -14439,10 +14487,10 @@ function parseLine(line, lineNumber) {
|
|
|
14439
14487
|
return record;
|
|
14440
14488
|
}
|
|
14441
14489
|
function readCostRecords(projectRoot) {
|
|
14442
|
-
const costsFile =
|
|
14490
|
+
const costsFile = path29.join(projectRoot, ".harness", "metrics", "costs.jsonl");
|
|
14443
14491
|
let raw;
|
|
14444
14492
|
try {
|
|
14445
|
-
raw =
|
|
14493
|
+
raw = fs30.readFileSync(costsFile, "utf-8");
|
|
14446
14494
|
} catch {
|
|
14447
14495
|
return [];
|
|
14448
14496
|
}
|
|
@@ -14489,7 +14537,7 @@ function parseCCLine(line, filePath, lineNumber) {
|
|
|
14489
14537
|
entry = JSON.parse(line);
|
|
14490
14538
|
} catch {
|
|
14491
14539
|
console.warn(
|
|
14492
|
-
`[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${
|
|
14540
|
+
`[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path30.basename(filePath)}`
|
|
14493
14541
|
);
|
|
14494
14542
|
return null;
|
|
14495
14543
|
}
|
|
@@ -14503,7 +14551,7 @@ function parseCCLine(line, filePath, lineNumber) {
|
|
|
14503
14551
|
function readCCFile(filePath) {
|
|
14504
14552
|
let raw;
|
|
14505
14553
|
try {
|
|
14506
|
-
raw =
|
|
14554
|
+
raw = fs31.readFileSync(filePath, "utf-8");
|
|
14507
14555
|
} catch {
|
|
14508
14556
|
return [];
|
|
14509
14557
|
}
|
|
@@ -14525,10 +14573,10 @@ function readCCFile(filePath) {
|
|
|
14525
14573
|
}
|
|
14526
14574
|
function parseCCRecords() {
|
|
14527
14575
|
const homeDir = process.env.HOME ?? os2.homedir();
|
|
14528
|
-
const projectsDir =
|
|
14576
|
+
const projectsDir = path30.join(homeDir, ".claude", "projects");
|
|
14529
14577
|
let projectDirs;
|
|
14530
14578
|
try {
|
|
14531
|
-
projectDirs =
|
|
14579
|
+
projectDirs = fs31.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path30.join(projectsDir, d.name));
|
|
14532
14580
|
} catch {
|
|
14533
14581
|
return [];
|
|
14534
14582
|
}
|
|
@@ -14536,7 +14584,7 @@ function parseCCRecords() {
|
|
|
14536
14584
|
for (const dir of projectDirs) {
|
|
14537
14585
|
let files;
|
|
14538
14586
|
try {
|
|
14539
|
-
files =
|
|
14587
|
+
files = fs31.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path30.join(dir, f));
|
|
14540
14588
|
} catch {
|
|
14541
14589
|
continue;
|
|
14542
14590
|
}
|
|
@@ -14716,14 +14764,16 @@ export {
|
|
|
14716
14764
|
loadState,
|
|
14717
14765
|
saveState,
|
|
14718
14766
|
parseFrontmatter2,
|
|
14767
|
+
parseDateFromEntry,
|
|
14719
14768
|
extractIndexEntry,
|
|
14769
|
+
normalizeLearningContent,
|
|
14770
|
+
computeContentHash,
|
|
14771
|
+
analyzeLearningPatterns,
|
|
14720
14772
|
clearLearningsCache,
|
|
14773
|
+
loadRelevantLearnings,
|
|
14721
14774
|
appendLearning,
|
|
14722
|
-
parseDateFromEntry,
|
|
14723
|
-
analyzeLearningPatterns,
|
|
14724
14775
|
loadBudgetedLearnings,
|
|
14725
14776
|
loadIndexEntries,
|
|
14726
|
-
loadRelevantLearnings,
|
|
14727
14777
|
archiveLearnings,
|
|
14728
14778
|
pruneLearnings,
|
|
14729
14779
|
promoteSessionLearnings,
|