@harness-engineering/cli 1.12.0 → 1.13.1
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/skills/claude-code/add-harness-component/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/align-documentation/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/check-mechanical-constraints/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/detect-doc-drift/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-accessibility/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-api-design/SKILL.md +304 -0
- package/dist/agents/skills/claude-code/harness-api-design/skill.yaml +74 -0
- package/dist/agents/skills/claude-code/harness-architecture-advisor/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-auth/SKILL.md +279 -0
- package/dist/agents/skills/claude-code/harness-auth/skill.yaml +81 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +57 -9
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +1 -1
- package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-caching/SKILL.md +309 -0
- package/dist/agents/skills/claude-code/harness-caching/skill.yaml +73 -0
- package/dist/agents/skills/claude-code/harness-chaos/SKILL.md +295 -0
- package/dist/agents/skills/claude-code/harness-chaos/skill.yaml +72 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +19 -2
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-compliance/SKILL.md +303 -0
- package/dist/agents/skills/claude-code/harness-compliance/skill.yaml +78 -0
- package/dist/agents/skills/claude-code/harness-containerization/SKILL.md +284 -0
- package/dist/agents/skills/claude-code/harness-containerization/skill.yaml +80 -0
- package/dist/agents/skills/claude-code/harness-data-pipeline/SKILL.md +274 -0
- package/dist/agents/skills/claude-code/harness-data-pipeline/skill.yaml +81 -0
- package/dist/agents/skills/claude-code/harness-data-validation/SKILL.md +343 -0
- package/dist/agents/skills/claude-code/harness-data-validation/skill.yaml +75 -0
- package/dist/agents/skills/claude-code/harness-database/SKILL.md +258 -0
- package/dist/agents/skills/claude-code/harness-database/skill.yaml +80 -0
- package/dist/agents/skills/claude-code/harness-debugging/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-deployment/SKILL.md +255 -0
- package/dist/agents/skills/claude-code/harness-deployment/skill.yaml +77 -0
- package/dist/agents/skills/claude-code/harness-design/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-design-system/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-design-web/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-diagnostics/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-dx/SKILL.md +276 -0
- package/dist/agents/skills/claude-code/harness-dx/skill.yaml +76 -0
- package/dist/agents/skills/claude-code/harness-e2e/SKILL.md +245 -0
- package/dist/agents/skills/claude-code/harness-e2e/skill.yaml +78 -0
- package/dist/agents/skills/claude-code/harness-event-driven/SKILL.md +280 -0
- package/dist/agents/skills/claude-code/harness-event-driven/skill.yaml +77 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +39 -12
- package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-feature-flags/SKILL.md +287 -0
- package/dist/agents/skills/claude-code/harness-feature-flags/skill.yaml +74 -0
- package/dist/agents/skills/claude-code/harness-git-workflow/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-incident-response/SKILL.md +223 -0
- package/dist/agents/skills/claude-code/harness-incident-response/skill.yaml +78 -0
- package/dist/agents/skills/claude-code/harness-infrastructure-as-code/SKILL.md +279 -0
- package/dist/agents/skills/claude-code/harness-infrastructure-as-code/skill.yaml +80 -0
- package/dist/agents/skills/claude-code/harness-integration-test/SKILL.md +271 -0
- package/dist/agents/skills/claude-code/harness-integration-test/skill.yaml +73 -0
- package/dist/agents/skills/claude-code/harness-integrity/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-load-testing/SKILL.md +274 -0
- package/dist/agents/skills/claude-code/harness-load-testing/skill.yaml +79 -0
- package/dist/agents/skills/claude-code/harness-ml-ops/SKILL.md +341 -0
- package/dist/agents/skills/claude-code/harness-ml-ops/skill.yaml +79 -0
- package/dist/agents/skills/claude-code/harness-mobile-patterns/SKILL.md +326 -0
- package/dist/agents/skills/claude-code/harness-mobile-patterns/skill.yaml +82 -0
- package/dist/agents/skills/claude-code/harness-mutation-test/SKILL.md +251 -0
- package/dist/agents/skills/claude-code/harness-mutation-test/skill.yaml +70 -0
- package/dist/agents/skills/claude-code/harness-observability/SKILL.md +283 -0
- package/dist/agents/skills/claude-code/harness-observability/skill.yaml +78 -0
- package/dist/agents/skills/claude-code/harness-onboarding/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-parallel-agents/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +28 -11
- package/dist/agents/skills/claude-code/harness-planning/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-pre-commit-review/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +285 -0
- package/dist/agents/skills/claude-code/harness-product-spec/skill.yaml +72 -0
- package/dist/agents/skills/claude-code/harness-property-test/SKILL.md +281 -0
- package/dist/agents/skills/claude-code/harness-property-test/skill.yaml +71 -0
- package/dist/agents/skills/claude-code/harness-refactoring/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-resilience/SKILL.md +255 -0
- package/dist/agents/skills/claude-code/harness-resilience/skill.yaml +76 -0
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +34 -0
- package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-secrets/SKILL.md +293 -0
- package/dist/agents/skills/claude-code/harness-secrets/skill.yaml +76 -0
- package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-skill-authoring/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-sql-review/SKILL.md +315 -0
- package/dist/agents/skills/claude-code/harness-sql-review/skill.yaml +74 -0
- package/dist/agents/skills/claude-code/harness-state-management/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-tdd/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-test-data/SKILL.md +268 -0
- package/dist/agents/skills/claude-code/harness-test-data/skill.yaml +74 -0
- package/dist/agents/skills/claude-code/harness-ux-copy/SKILL.md +271 -0
- package/dist/agents/skills/claude-code/harness-ux-copy/skill.yaml +77 -0
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +42 -0
- package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-verify/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-visual-regression/SKILL.md +257 -0
- package/dist/agents/skills/claude-code/harness-visual-regression/skill.yaml +74 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/validate-context-engineering/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/add-harness-component/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/align-documentation/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/check-mechanical-constraints/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/cleanup-dead-code/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/detect-doc-drift/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/enforce-architecture/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-api-design/SKILL.md +304 -0
- package/dist/agents/skills/gemini-cli/harness-api-design/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/harness-architecture-advisor/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-auth/SKILL.md +279 -0
- package/dist/agents/skills/gemini-cli/harness-auth/skill.yaml +81 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +57 -9
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +1 -1
- package/dist/agents/skills/gemini-cli/harness-brainstorming/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-caching/SKILL.md +309 -0
- package/dist/agents/skills/gemini-cli/harness-caching/skill.yaml +73 -0
- package/dist/agents/skills/gemini-cli/harness-chaos/SKILL.md +295 -0
- package/dist/agents/skills/gemini-cli/harness-chaos/skill.yaml +72 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +19 -2
- package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-compliance/SKILL.md +303 -0
- package/dist/agents/skills/gemini-cli/harness-compliance/skill.yaml +78 -0
- package/dist/agents/skills/gemini-cli/harness-containerization/SKILL.md +284 -0
- package/dist/agents/skills/gemini-cli/harness-containerization/skill.yaml +80 -0
- package/dist/agents/skills/gemini-cli/harness-data-pipeline/SKILL.md +274 -0
- package/dist/agents/skills/gemini-cli/harness-data-pipeline/skill.yaml +81 -0
- package/dist/agents/skills/gemini-cli/harness-data-validation/SKILL.md +343 -0
- package/dist/agents/skills/gemini-cli/harness-data-validation/skill.yaml +75 -0
- package/dist/agents/skills/gemini-cli/harness-database/SKILL.md +258 -0
- package/dist/agents/skills/gemini-cli/harness-database/skill.yaml +80 -0
- package/dist/agents/skills/gemini-cli/harness-debugging/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-deployment/SKILL.md +255 -0
- package/dist/agents/skills/gemini-cli/harness-deployment/skill.yaml +77 -0
- package/dist/agents/skills/gemini-cli/harness-design/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-diagnostics/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-dx/SKILL.md +276 -0
- package/dist/agents/skills/gemini-cli/harness-dx/skill.yaml +76 -0
- package/dist/agents/skills/gemini-cli/harness-e2e/SKILL.md +245 -0
- package/dist/agents/skills/gemini-cli/harness-e2e/skill.yaml +78 -0
- package/dist/agents/skills/gemini-cli/harness-event-driven/SKILL.md +280 -0
- package/dist/agents/skills/gemini-cli/harness-event-driven/skill.yaml +77 -0
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +39 -12
- package/dist/agents/skills/gemini-cli/harness-execution/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-feature-flags/SKILL.md +287 -0
- package/dist/agents/skills/gemini-cli/harness-feature-flags/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/harness-git-workflow/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-incident-response/SKILL.md +223 -0
- package/dist/agents/skills/gemini-cli/harness-incident-response/skill.yaml +78 -0
- package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/SKILL.md +279 -0
- package/dist/agents/skills/gemini-cli/harness-infrastructure-as-code/skill.yaml +80 -0
- package/dist/agents/skills/gemini-cli/harness-integration-test/SKILL.md +271 -0
- package/dist/agents/skills/gemini-cli/harness-integration-test/skill.yaml +73 -0
- package/dist/agents/skills/gemini-cli/harness-integrity/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-load-testing/SKILL.md +274 -0
- package/dist/agents/skills/gemini-cli/harness-load-testing/skill.yaml +79 -0
- package/dist/agents/skills/gemini-cli/harness-ml-ops/SKILL.md +341 -0
- package/dist/agents/skills/gemini-cli/harness-ml-ops/skill.yaml +79 -0
- package/dist/agents/skills/gemini-cli/harness-mobile-patterns/SKILL.md +326 -0
- package/dist/agents/skills/gemini-cli/harness-mobile-patterns/skill.yaml +82 -0
- package/dist/agents/skills/gemini-cli/harness-mutation-test/SKILL.md +251 -0
- package/dist/agents/skills/gemini-cli/harness-mutation-test/skill.yaml +70 -0
- package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +283 -0
- package/dist/agents/skills/gemini-cli/harness-observability/skill.yaml +78 -0
- package/dist/agents/skills/gemini-cli/harness-onboarding/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-parallel-agents/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +28 -11
- package/dist/agents/skills/gemini-cli/harness-planning/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-pre-commit-review/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +285 -0
- package/dist/agents/skills/gemini-cli/harness-product-spec/skill.yaml +72 -0
- package/dist/agents/skills/gemini-cli/harness-property-test/SKILL.md +281 -0
- package/dist/agents/skills/gemini-cli/harness-property-test/skill.yaml +71 -0
- package/dist/agents/skills/gemini-cli/harness-refactoring/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-release-readiness/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-resilience/SKILL.md +255 -0
- package/dist/agents/skills/gemini-cli/harness-resilience/skill.yaml +76 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +34 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-secrets/SKILL.md +293 -0
- package/dist/agents/skills/gemini-cli/harness-secrets/skill.yaml +76 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/SKILL.md +240 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-skill-authoring/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-sql-review/SKILL.md +315 -0
- package/dist/agents/skills/gemini-cli/harness-sql-review/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/harness-state-management/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-tdd/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-test-data/SKILL.md +268 -0
- package/dist/agents/skills/gemini-cli/harness-test-data/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/harness-ux-copy/SKILL.md +271 -0
- package/dist/agents/skills/gemini-cli/harness-ux-copy/skill.yaml +77 -0
- package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +42 -0
- package/dist/agents/skills/gemini-cli/harness-verification/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-verify/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/harness-visual-regression/SKILL.md +257 -0
- package/dist/agents/skills/gemini-cli/harness-visual-regression/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/validate-context-engineering/skill.yaml +1 -0
- package/dist/{agents-md-KIS2RSMG.js → agents-md-XU3BHE22.js} +1 -1
- package/dist/{architecture-AJAUDRQQ.js → architecture-2R5Z4ZAF.js} +2 -2
- package/dist/bin/harness-mcp.js +14 -13
- package/dist/bin/harness.js +22 -21
- package/dist/{check-phase-gate-K7QCSYRJ.js → check-phase-gate-2OFZ7OWW.js} +3 -2
- package/dist/{chunk-TJVVU3HB.js → chunk-4ZMOCPYO.js} +1 -1
- package/dist/{chunk-EAURF4LH.js → chunk-65FRIL4D.js} +2 -2
- package/dist/{chunk-L2KLU56K.js → chunk-AOZRDOIP.js} +2 -2
- package/dist/{chunk-JLXOEO5C.js → chunk-DZS7CJKL.js} +4 -4
- package/dist/{chunk-FLOEMHDF.js → chunk-IM32EEDM.js} +9 -9
- package/dist/{chunk-2YPZKGAG.js → chunk-IMFVFNJE.js} +1 -1
- package/dist/{chunk-HD4IBGLA.js → chunk-N5G5QMS3.js} +24 -1
- package/dist/{chunk-CTTFXXKJ.js → chunk-ND6PNADU.js} +23 -9
- package/dist/{chunk-747VBPA4.js → chunk-NERR4TAO.js} +783 -444
- package/dist/{chunk-YXOG2277.js → chunk-NOPU4RZ4.js} +2 -2
- package/dist/{chunk-AE2OWWDH.js → chunk-PQ5YK4AY.js} +870 -504
- package/dist/{chunk-OIGVQF5V.js → chunk-QY4T6YAZ.js} +3 -3
- package/dist/{chunk-B5SBNH4S.js → chunk-SSKDAOX5.js} +93 -30
- package/dist/{chunk-2SWJ4VO7.js → chunk-TKJZKICB.js} +6 -6
- package/dist/{chunk-GNGELAXY.js → chunk-TS3XWPW5.js} +1 -1
- package/dist/chunk-UAX4I5ZE.js +217 -0
- package/dist/{chunk-VRFZWGMS.js → chunk-XYLGHKG6.js} +5 -1
- package/dist/{chunk-6N4R6FVX.js → chunk-YBJ262QL.js} +1 -1
- package/dist/{chunk-ZU2UBYBY.js → chunk-Z77YQRQT.js} +11 -207
- package/dist/{ci-workflow-NBL4OT4A.js → ci-workflow-EHV65NQB.js} +1 -1
- package/dist/{create-skill-WPXHSLX2.js → create-skill-XSWHMSM5.js} +2 -2
- package/dist/{dist-IJ4J4C5G.js → dist-2B363XUH.js} +25 -1
- package/dist/{dist-M6BQODWC.js → dist-HXHWB7SV.js} +2 -2
- package/dist/{docs-CPTMH3VY.js → docs-FZOPM4GK.js} +4 -2
- package/dist/{engine-BUWPAAGD.js → engine-OL4T6NZS.js} +1 -1
- package/dist/{entropy-Z4FYVQ7L.js → entropy-LVHJMFGH.js} +2 -2
- package/dist/{feedback-TT6WF5YX.js → feedback-IHLVLMRD.js} +1 -1
- package/dist/{generate-agent-definitions-J5HANRNR.js → generate-agent-definitions-64S3CLEZ.js} +3 -3
- package/dist/{glob-helper-5OHBUQAI.js → glob-helper-R5FXNUPS.js} +1 -1
- package/dist/{graph-loader-KO4GJ5N2.js → graph-loader-GJZ4FN4Y.js} +1 -1
- package/dist/index.d.ts +60 -33
- package/dist/index.js +23 -21
- package/dist/{loader-PCU5YWRH.js → loader-DPYFB6R6.js} +1 -1
- package/dist/{mcp-YM6QLHLZ.js → mcp-JQUI7BVZ.js} +14 -13
- package/dist/{performance-YJVXOKIB.js → performance-ZTVSUANN.js} +2 -2
- package/dist/{review-pipeline-KGMIMLIE.js → review-pipeline-76JHKGSV.js} +1 -1
- package/dist/{runtime-F6R27LD6.js → runtime-X7U6SC7K.js} +1 -1
- package/dist/{security-MX5VVXBC.js → security-FWQZF2IZ.js} +1 -1
- package/dist/skill-executor-XZLYZYAK.js +8 -0
- package/dist/{validate-EFNMSFKD.js → validate-GCHZJIL7.js} +2 -2
- package/dist/{validate-cross-check-LJX65SBS.js → validate-cross-check-STFHYMAZ.js} +1 -1
- package/package.json +4 -4
- package/dist/skill-executor-RG45LUO5.js +0 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectEntropyDefinition,
|
|
3
3
|
handleDetectEntropy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DZS7CJKL.js";
|
|
5
5
|
import {
|
|
6
6
|
checkPerformanceDefinition,
|
|
7
7
|
getCriticalPathsDefinition,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
handleGetPerfBaselines,
|
|
12
12
|
handleUpdatePerfBaselines,
|
|
13
13
|
updatePerfBaselinesDefinition
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TKJZKICB.js";
|
|
15
15
|
import {
|
|
16
16
|
analyzeDiffDefinition,
|
|
17
17
|
createSelfReviewDefinition,
|
|
@@ -19,15 +19,15 @@ import {
|
|
|
19
19
|
handleCreateSelfReview,
|
|
20
20
|
handleRequestPeerReview,
|
|
21
21
|
requestPeerReviewDefinition
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IM32EEDM.js";
|
|
23
23
|
import {
|
|
24
24
|
handleRunSecurityScan,
|
|
25
25
|
runSecurityScanDefinition
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-65FRIL4D.js";
|
|
27
27
|
import {
|
|
28
28
|
handleRunCodeReview,
|
|
29
29
|
runCodeReviewDefinition
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-4ZMOCPYO.js";
|
|
31
31
|
import {
|
|
32
32
|
GENERATED_HEADER_CLAUDE,
|
|
33
33
|
GENERATED_HEADER_GEMINI,
|
|
@@ -38,21 +38,24 @@ import {
|
|
|
38
38
|
import {
|
|
39
39
|
handleValidateProject,
|
|
40
40
|
validateToolDefinition
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-NOPU4RZ4.js";
|
|
42
42
|
import {
|
|
43
43
|
loadGraphStore
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-IMFVFNJE.js";
|
|
45
45
|
import {
|
|
46
46
|
checkDependenciesDefinition,
|
|
47
47
|
handleCheckDependencies
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-QY4T6YAZ.js";
|
|
49
49
|
import {
|
|
50
50
|
resolveProjectConfig
|
|
51
51
|
} from "./chunk-K6XAPGML.js";
|
|
52
52
|
import {
|
|
53
53
|
checkDocsDefinition,
|
|
54
54
|
handleCheckDocs
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-ND6PNADU.js";
|
|
56
|
+
import {
|
|
57
|
+
resolveConfig
|
|
58
|
+
} from "./chunk-Z77YQRQT.js";
|
|
56
59
|
import {
|
|
57
60
|
resultToMcpResponse
|
|
58
61
|
} from "./chunk-IDZNPTYD.js";
|
|
@@ -60,13 +63,14 @@ import {
|
|
|
60
63
|
sanitizePath
|
|
61
64
|
} from "./chunk-W6Y7ZW3Y.js";
|
|
62
65
|
import {
|
|
66
|
+
resolveAllSkillsDirs,
|
|
63
67
|
resolveCommunitySkillsDir,
|
|
64
68
|
resolveGlobalSkillsDir,
|
|
65
69
|
resolvePersonasDir,
|
|
66
70
|
resolveProjectSkillsDir,
|
|
67
71
|
resolveSkillsDir,
|
|
68
72
|
resolveTemplatesDir
|
|
69
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-N5G5QMS3.js";
|
|
70
74
|
import {
|
|
71
75
|
CLIError,
|
|
72
76
|
ExitCode,
|
|
@@ -74,7 +78,7 @@ import {
|
|
|
74
78
|
} from "./chunk-3WGJMBKH.js";
|
|
75
79
|
import {
|
|
76
80
|
SkillMetadataSchema
|
|
77
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-XYLGHKG6.js";
|
|
78
82
|
import {
|
|
79
83
|
Err,
|
|
80
84
|
Ok
|
|
@@ -180,7 +184,7 @@ var initProjectDefinition = {
|
|
|
180
184
|
};
|
|
181
185
|
async function handleInitProject(input) {
|
|
182
186
|
try {
|
|
183
|
-
const { TemplateEngine } = await import("./engine-
|
|
187
|
+
const { TemplateEngine } = await import("./engine-OL4T6NZS.js");
|
|
184
188
|
const templatesDir = resolveTemplatesDir();
|
|
185
189
|
const engine = new TemplateEngine(templatesDir);
|
|
186
190
|
const level = input.level ?? "basic";
|
|
@@ -218,7 +222,7 @@ var listPersonasDefinition = {
|
|
|
218
222
|
inputSchema: { type: "object", properties: {} }
|
|
219
223
|
};
|
|
220
224
|
async function handleListPersonas() {
|
|
221
|
-
const { listPersonas } = await import("./loader-
|
|
225
|
+
const { listPersonas } = await import("./loader-DPYFB6R6.js");
|
|
222
226
|
const result = listPersonas(resolvePersonasDir());
|
|
223
227
|
return resultToMcpResponse(result);
|
|
224
228
|
}
|
|
@@ -242,10 +246,10 @@ async function handleGeneratePersonaArtifacts(input) {
|
|
|
242
246
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
|
|
243
247
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
|
|
244
248
|
}
|
|
245
|
-
const { loadPersona } = await import("./loader-
|
|
246
|
-
const { generateRuntime } = await import("./runtime-
|
|
247
|
-
const { generateAgentsMd } = await import("./agents-md-
|
|
248
|
-
const { generateCIWorkflow } = await import("./ci-workflow-
|
|
249
|
+
const { loadPersona } = await import("./loader-DPYFB6R6.js");
|
|
250
|
+
const { generateRuntime } = await import("./runtime-X7U6SC7K.js");
|
|
251
|
+
const { generateAgentsMd } = await import("./agents-md-XU3BHE22.js");
|
|
252
|
+
const { generateCIWorkflow } = await import("./ci-workflow-EHV65NQB.js");
|
|
249
253
|
const personasDir = resolvePersonasDir();
|
|
250
254
|
const filePath = path2.join(personasDir, `${input.name}.yaml`);
|
|
251
255
|
if (!filePath.startsWith(personasDir)) {
|
|
@@ -300,9 +304,9 @@ async function handleRunPersona(input) {
|
|
|
300
304
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
|
|
301
305
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
|
|
302
306
|
}
|
|
303
|
-
const { loadPersona } = await import("./loader-
|
|
307
|
+
const { loadPersona } = await import("./loader-DPYFB6R6.js");
|
|
304
308
|
const { runPersona } = await import("./runner-VMYLHWOC.js");
|
|
305
|
-
const { executeSkill } = await import("./skill-executor-
|
|
309
|
+
const { executeSkill } = await import("./skill-executor-XZLYZYAK.js");
|
|
306
310
|
const personasDir = resolvePersonasDir();
|
|
307
311
|
const filePath = path2.join(personasDir, `${input.persona}.yaml`);
|
|
308
312
|
if (!filePath.startsWith(personasDir)) {
|
|
@@ -466,8 +470,243 @@ async function handleRunAgentTask(input) {
|
|
|
466
470
|
}
|
|
467
471
|
|
|
468
472
|
// src/mcp/tools/skill.ts
|
|
469
|
-
import * as
|
|
470
|
-
import * as
|
|
473
|
+
import * as fs3 from "fs";
|
|
474
|
+
import * as path5 from "path";
|
|
475
|
+
|
|
476
|
+
// src/skill/dispatcher.ts
|
|
477
|
+
var TIER_1_SKILLS = /* @__PURE__ */ new Set([
|
|
478
|
+
"harness-brainstorming",
|
|
479
|
+
"harness-planning",
|
|
480
|
+
"harness-execution",
|
|
481
|
+
"harness-autopilot",
|
|
482
|
+
"harness-tdd",
|
|
483
|
+
"harness-debugging",
|
|
484
|
+
"harness-refactoring"
|
|
485
|
+
]);
|
|
486
|
+
function isTier1Skill(skillName) {
|
|
487
|
+
return TIER_1_SKILLS.has(skillName);
|
|
488
|
+
}
|
|
489
|
+
function scoreSkill(entry, queryTerms, profile, recentFiles) {
|
|
490
|
+
const matchedKeywords = entry.keywords.filter(
|
|
491
|
+
(kw) => queryTerms.some(
|
|
492
|
+
(term) => kw.toLowerCase().includes(term.toLowerCase()) || term.toLowerCase().includes(kw.toLowerCase())
|
|
493
|
+
)
|
|
494
|
+
);
|
|
495
|
+
const keywordScore = queryTerms.length > 0 ? matchedKeywords.length / queryTerms.length : 0;
|
|
496
|
+
let stackScore = 0;
|
|
497
|
+
if (profile && entry.stackSignals.length > 0) {
|
|
498
|
+
const matchedSignals = entry.stackSignals.filter((signal) => {
|
|
499
|
+
if (profile.signals[signal]) return true;
|
|
500
|
+
return profile.detectedDomains.some(
|
|
501
|
+
(domain) => entry.keywords.some((kw) => kw.toLowerCase() === domain.toLowerCase())
|
|
502
|
+
);
|
|
503
|
+
});
|
|
504
|
+
stackScore = matchedSignals.length / entry.stackSignals.length;
|
|
505
|
+
}
|
|
506
|
+
let recencyBoost = 0;
|
|
507
|
+
if (recentFiles.length > 0) {
|
|
508
|
+
const hasRecentMatch = entry.stackSignals.some((signal) => {
|
|
509
|
+
const cleanSignal = signal.replace(/\*/g, "").replace(/\*\*/g, "");
|
|
510
|
+
return recentFiles.some((f) => f.includes(cleanSignal));
|
|
511
|
+
});
|
|
512
|
+
recencyBoost = hasRecentMatch ? 1 : 0;
|
|
513
|
+
}
|
|
514
|
+
return 0.5 * keywordScore + 0.3 * stackScore + 0.2 * recencyBoost;
|
|
515
|
+
}
|
|
516
|
+
function suggest(index, taskDescription, profile, recentFiles, config) {
|
|
517
|
+
const queryTerms = taskDescription.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
518
|
+
const scored = [];
|
|
519
|
+
for (const [name, entry] of Object.entries(index.skills)) {
|
|
520
|
+
if (config?.neverSuggest?.includes(name)) continue;
|
|
521
|
+
const score = scoreSkill(entry, queryTerms, profile, recentFiles);
|
|
522
|
+
const isForced = config?.alwaysSuggest?.includes(name);
|
|
523
|
+
if (score >= 0.4 || isForced) {
|
|
524
|
+
scored.push({
|
|
525
|
+
name,
|
|
526
|
+
description: entry.description,
|
|
527
|
+
score: isForced ? Math.max(score, 1) : score
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return scored.sort((a, b) => b.score - a.score).slice(0, 3);
|
|
532
|
+
}
|
|
533
|
+
function formatSuggestions(suggestions) {
|
|
534
|
+
if (suggestions.length === 0) return "";
|
|
535
|
+
const lines = suggestions.map((s) => `- **${s.name}** \u2014 ${s.description}`);
|
|
536
|
+
return [
|
|
537
|
+
"",
|
|
538
|
+
"---",
|
|
539
|
+
"## Suggested Domain Skills",
|
|
540
|
+
"Based on your task and project stack, these catalog skills may be relevant:",
|
|
541
|
+
...lines,
|
|
542
|
+
"",
|
|
543
|
+
'To load a skill: call search_skills("<skill-name>") for full details.',
|
|
544
|
+
"---"
|
|
545
|
+
].join("\n");
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/skill/index-builder.ts
|
|
549
|
+
import fs from "fs";
|
|
550
|
+
import path3 from "path";
|
|
551
|
+
import crypto from "crypto";
|
|
552
|
+
import { parse } from "yaml";
|
|
553
|
+
function computeSkillsDirHash(skillsDirs) {
|
|
554
|
+
const hash = crypto.createHash("sha256");
|
|
555
|
+
for (const dir of skillsDirs) {
|
|
556
|
+
if (!fs.existsSync(dir)) continue;
|
|
557
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
558
|
+
if (!entry.isDirectory()) continue;
|
|
559
|
+
const yamlPath = path3.join(dir, entry.name, "skill.yaml");
|
|
560
|
+
if (!fs.existsSync(yamlPath)) continue;
|
|
561
|
+
const stat = fs.statSync(yamlPath);
|
|
562
|
+
hash.update(`${yamlPath}:${stat.mtimeMs}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return hash.digest("hex");
|
|
566
|
+
}
|
|
567
|
+
function parseSkillEntry(yamlPath, source, tierOverrides) {
|
|
568
|
+
const raw = fs.readFileSync(yamlPath, "utf-8");
|
|
569
|
+
const parsed = parse(raw);
|
|
570
|
+
const result = SkillMetadataSchema.safeParse(parsed);
|
|
571
|
+
if (!result.success) return null;
|
|
572
|
+
const meta = result.data;
|
|
573
|
+
const effectiveTier = tierOverrides?.[meta.name] ?? meta.tier;
|
|
574
|
+
if (meta.internal) return null;
|
|
575
|
+
if (effectiveTier !== 3 && source !== "community") return null;
|
|
576
|
+
return {
|
|
577
|
+
tier: effectiveTier ?? 3,
|
|
578
|
+
description: meta.description,
|
|
579
|
+
keywords: meta.keywords ?? [],
|
|
580
|
+
stackSignals: meta.stack_signals ?? [],
|
|
581
|
+
cognitiveMode: meta.cognitive_mode,
|
|
582
|
+
phases: (meta.phases ?? []).map((p) => p.name),
|
|
583
|
+
source
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function scanDirectory(dir, source, index, tierOverrides) {
|
|
587
|
+
if (!fs.existsSync(dir)) return;
|
|
588
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
589
|
+
if (!entry.isDirectory()) continue;
|
|
590
|
+
if (index.skills[entry.name]) continue;
|
|
591
|
+
const yamlPath = path3.join(dir, entry.name, "skill.yaml");
|
|
592
|
+
if (!fs.existsSync(yamlPath)) continue;
|
|
593
|
+
try {
|
|
594
|
+
const parsed = parseSkillEntry(yamlPath, source, tierOverrides);
|
|
595
|
+
if (parsed) index.skills[entry.name] = parsed;
|
|
596
|
+
} catch {
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function buildIndex(platform, _projectRoot, tierOverrides) {
|
|
602
|
+
const skillsDirs = resolveAllSkillsDirs(platform);
|
|
603
|
+
const sourceMap = ["project", "community", "bundled"];
|
|
604
|
+
const index = {
|
|
605
|
+
version: 1,
|
|
606
|
+
hash: computeSkillsDirHash(skillsDirs),
|
|
607
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
608
|
+
skills: {}
|
|
609
|
+
};
|
|
610
|
+
for (let i = 0; i < skillsDirs.length; i++) {
|
|
611
|
+
scanDirectory(skillsDirs[i], sourceMap[i] ?? "bundled", index, tierOverrides);
|
|
612
|
+
}
|
|
613
|
+
return index;
|
|
614
|
+
}
|
|
615
|
+
function loadOrRebuildIndex(platform, projectRoot, tierOverrides) {
|
|
616
|
+
const indexPath = path3.join(projectRoot, ".harness", "skills-index.json");
|
|
617
|
+
const skillsDirs = resolveAllSkillsDirs(platform);
|
|
618
|
+
const currentHash = computeSkillsDirHash(skillsDirs);
|
|
619
|
+
if (fs.existsSync(indexPath)) {
|
|
620
|
+
try {
|
|
621
|
+
const existing = JSON.parse(fs.readFileSync(indexPath, "utf-8"));
|
|
622
|
+
if (existing.hash === currentHash) return existing;
|
|
623
|
+
} catch {
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const index = buildIndex(platform, projectRoot, tierOverrides);
|
|
627
|
+
fs.mkdirSync(path3.dirname(indexPath), { recursive: true });
|
|
628
|
+
fs.writeFileSync(indexPath, JSON.stringify(index, null, 2));
|
|
629
|
+
return index;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// src/skill/stack-profile.ts
|
|
633
|
+
import fs2 from "fs";
|
|
634
|
+
import path4 from "path";
|
|
635
|
+
var SIGNAL_DOMAIN_MAP = {
|
|
636
|
+
"prisma/schema.prisma": ["database"],
|
|
637
|
+
"drizzle.config.ts": ["database"],
|
|
638
|
+
"knexfile.js": ["database"],
|
|
639
|
+
"knexfile.ts": ["database"],
|
|
640
|
+
migrations: ["database"],
|
|
641
|
+
Dockerfile: ["containerization"],
|
|
642
|
+
"docker-compose.yml": ["containerization"],
|
|
643
|
+
"docker-compose.yaml": ["containerization"],
|
|
644
|
+
k8s: ["containerization"],
|
|
645
|
+
kubernetes: ["containerization"],
|
|
646
|
+
helm: ["containerization"],
|
|
647
|
+
".github/workflows": ["deployment"],
|
|
648
|
+
".gitlab-ci.yml": ["deployment"],
|
|
649
|
+
Jenkinsfile: ["deployment"],
|
|
650
|
+
terraform: ["infrastructure-as-code"],
|
|
651
|
+
"Pulumi.yaml": ["infrastructure-as-code"],
|
|
652
|
+
"cdk.json": ["infrastructure-as-code"],
|
|
653
|
+
"openapi.yaml": ["api-design"],
|
|
654
|
+
"openapi.json": ["api-design"],
|
|
655
|
+
"swagger.yaml": ["api-design"],
|
|
656
|
+
"swagger.json": ["api-design"],
|
|
657
|
+
"schema.graphql": ["api-design"],
|
|
658
|
+
".env": ["secrets"],
|
|
659
|
+
".env.example": ["secrets"],
|
|
660
|
+
"vault.hcl": ["secrets"],
|
|
661
|
+
e2e: ["e2e"],
|
|
662
|
+
cypress: ["e2e"],
|
|
663
|
+
"playwright.config.ts": ["e2e"],
|
|
664
|
+
"playwright.config.js": ["e2e"],
|
|
665
|
+
"stryker.conf.js": ["mutation-test"],
|
|
666
|
+
"stryker.conf.mjs": ["mutation-test"],
|
|
667
|
+
k6: ["load-testing"],
|
|
668
|
+
"artillery.yml": ["load-testing"],
|
|
669
|
+
"dbt_project.yml": ["data-pipeline"],
|
|
670
|
+
airflow: ["data-pipeline"],
|
|
671
|
+
ios: ["mobile-patterns"],
|
|
672
|
+
android: ["mobile-patterns"],
|
|
673
|
+
"pubspec.yaml": ["mobile-patterns"],
|
|
674
|
+
"App.tsx": ["mobile-patterns"],
|
|
675
|
+
runbooks: ["incident-response"],
|
|
676
|
+
"docs/runbooks": ["incident-response"]
|
|
677
|
+
};
|
|
678
|
+
function generateStackProfile(projectRoot) {
|
|
679
|
+
const signals = {};
|
|
680
|
+
const domainSet = /* @__PURE__ */ new Set();
|
|
681
|
+
for (const [pattern, domains] of Object.entries(SIGNAL_DOMAIN_MAP)) {
|
|
682
|
+
const fullPath = path4.join(projectRoot, pattern);
|
|
683
|
+
const exists = fs2.existsSync(fullPath);
|
|
684
|
+
signals[pattern] = exists;
|
|
685
|
+
if (exists) {
|
|
686
|
+
for (const domain of domains) domainSet.add(domain);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
691
|
+
signals,
|
|
692
|
+
detectedDomains: [...domainSet].sort()
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function loadOrGenerateProfile(projectRoot) {
|
|
696
|
+
const profilePath = path4.join(projectRoot, ".harness", "stack-profile.json");
|
|
697
|
+
if (fs2.existsSync(profilePath)) {
|
|
698
|
+
try {
|
|
699
|
+
return JSON.parse(fs2.readFileSync(profilePath, "utf-8"));
|
|
700
|
+
} catch {
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const profile = generateStackProfile(projectRoot);
|
|
704
|
+
fs2.mkdirSync(path4.dirname(profilePath), { recursive: true });
|
|
705
|
+
fs2.writeFileSync(profilePath, JSON.stringify(profile, null, 2));
|
|
706
|
+
return profile;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/mcp/tools/skill.ts
|
|
471
710
|
var runSkillDefinition = {
|
|
472
711
|
name: "run_skill",
|
|
473
712
|
description: "Load and return the content of a skill (SKILL.md), optionally with project state context",
|
|
@@ -492,23 +731,23 @@ async function handleRunSkill(input) {
|
|
|
492
731
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.skill)) {
|
|
493
732
|
return resultToMcpResponse(Err(new Error(`Invalid skill name: ${input.skill}`)));
|
|
494
733
|
}
|
|
495
|
-
const skillDir =
|
|
734
|
+
const skillDir = path5.join(skillsDir, input.skill);
|
|
496
735
|
if (!skillDir.startsWith(skillsDir)) {
|
|
497
736
|
return resultToMcpResponse(Err(new Error(`Invalid skill path: ${input.skill}`)));
|
|
498
737
|
}
|
|
499
|
-
if (!
|
|
738
|
+
if (!fs3.existsSync(skillDir)) {
|
|
500
739
|
return resultToMcpResponse(Err(new Error(`Skill not found: ${input.skill}`)));
|
|
501
740
|
}
|
|
502
|
-
const skillMdPath =
|
|
503
|
-
if (!
|
|
741
|
+
const skillMdPath = path5.join(skillDir, "SKILL.md");
|
|
742
|
+
if (!fs3.existsSync(skillMdPath)) {
|
|
504
743
|
return resultToMcpResponse(Err(new Error(`SKILL.md not found for skill: ${input.skill}`)));
|
|
505
744
|
}
|
|
506
|
-
let content =
|
|
745
|
+
let content = fs3.readFileSync(skillMdPath, "utf-8");
|
|
507
746
|
if (input.path) {
|
|
508
747
|
const projectPath = sanitizePath(input.path);
|
|
509
|
-
const stateFile =
|
|
510
|
-
if (
|
|
511
|
-
const stateContent =
|
|
748
|
+
const stateFile = path5.join(projectPath, ".harness", "state.json");
|
|
749
|
+
if (fs3.existsSync(stateFile)) {
|
|
750
|
+
const stateContent = fs3.readFileSync(stateFile, "utf-8");
|
|
512
751
|
content += `
|
|
513
752
|
|
|
514
753
|
---
|
|
@@ -519,6 +758,23 @@ ${stateContent}
|
|
|
519
758
|
`;
|
|
520
759
|
}
|
|
521
760
|
}
|
|
761
|
+
if (isTier1Skill(input.skill)) {
|
|
762
|
+
try {
|
|
763
|
+
const projectRoot = input.path ? sanitizePath(input.path) : process.cwd();
|
|
764
|
+
const platform = "claude-code";
|
|
765
|
+
const configResult = resolveConfig();
|
|
766
|
+
const skillsConfig = configResult.ok ? configResult.value.skills : void 0;
|
|
767
|
+
const index = loadOrRebuildIndex(platform, projectRoot, skillsConfig?.tierOverrides);
|
|
768
|
+
const profile = loadOrGenerateProfile(projectRoot);
|
|
769
|
+
const taskDesc = [input.skill, input.phase].filter(Boolean).join(" ");
|
|
770
|
+
const suggestions = suggest(index, taskDesc, profile, [], skillsConfig);
|
|
771
|
+
const suggestionText = formatSuggestions(suggestions);
|
|
772
|
+
if (suggestionText) {
|
|
773
|
+
content += suggestionText;
|
|
774
|
+
}
|
|
775
|
+
} catch {
|
|
776
|
+
}
|
|
777
|
+
}
|
|
522
778
|
return resultToMcpResponse(Ok(content));
|
|
523
779
|
}
|
|
524
780
|
var createSkillDefinition = {
|
|
@@ -548,7 +804,7 @@ var createSkillDefinition = {
|
|
|
548
804
|
};
|
|
549
805
|
async function handleCreateSkill(input) {
|
|
550
806
|
try {
|
|
551
|
-
const { generateSkillFiles } = await import("./create-skill-
|
|
807
|
+
const { generateSkillFiles } = await import("./create-skill-XSWHMSM5.js");
|
|
552
808
|
const result = generateSkillFiles({
|
|
553
809
|
name: input.name,
|
|
554
810
|
description: input.description,
|
|
@@ -570,22 +826,22 @@ async function handleCreateSkill(input) {
|
|
|
570
826
|
}
|
|
571
827
|
|
|
572
828
|
// src/mcp/resources/skills.ts
|
|
573
|
-
import * as
|
|
574
|
-
import * as
|
|
829
|
+
import * as fs4 from "fs";
|
|
830
|
+
import * as path6 from "path";
|
|
575
831
|
import * as yaml from "yaml";
|
|
576
832
|
async function getSkillsResource(projectRoot) {
|
|
577
|
-
const skillsDir =
|
|
833
|
+
const skillsDir = path6.join(projectRoot, "agents", "skills", "claude-code");
|
|
578
834
|
const skills = [];
|
|
579
|
-
if (!
|
|
835
|
+
if (!fs4.existsSync(skillsDir)) {
|
|
580
836
|
return JSON.stringify(skills, null, 2);
|
|
581
837
|
}
|
|
582
|
-
const entries =
|
|
838
|
+
const entries = fs4.readdirSync(skillsDir, { withFileTypes: true });
|
|
583
839
|
for (const entry of entries) {
|
|
584
840
|
if (!entry.isDirectory()) continue;
|
|
585
|
-
const skillYamlPath =
|
|
586
|
-
if (!
|
|
841
|
+
const skillYamlPath = path6.join(skillsDir, entry.name, "skill.yaml");
|
|
842
|
+
if (!fs4.existsSync(skillYamlPath)) continue;
|
|
587
843
|
try {
|
|
588
|
-
const content =
|
|
844
|
+
const content = fs4.readFileSync(skillYamlPath, "utf-8");
|
|
589
845
|
const parsed = yaml.parse(content);
|
|
590
846
|
skills.push({
|
|
591
847
|
name: parsed.name,
|
|
@@ -601,14 +857,14 @@ async function getSkillsResource(projectRoot) {
|
|
|
601
857
|
}
|
|
602
858
|
|
|
603
859
|
// src/mcp/resources/rules.ts
|
|
604
|
-
import * as
|
|
605
|
-
import * as
|
|
860
|
+
import * as fs5 from "fs";
|
|
861
|
+
import * as path7 from "path";
|
|
606
862
|
async function getRulesResource(projectRoot) {
|
|
607
863
|
const rules = [];
|
|
608
|
-
const configPath =
|
|
609
|
-
if (
|
|
864
|
+
const configPath = path7.join(projectRoot, "harness.config.json");
|
|
865
|
+
if (fs5.existsSync(configPath)) {
|
|
610
866
|
try {
|
|
611
|
-
const config = JSON.parse(
|
|
867
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
612
868
|
if (config.layers) {
|
|
613
869
|
rules.push({ type: "layer-enforcement", config: config.layers });
|
|
614
870
|
}
|
|
@@ -621,10 +877,10 @@ async function getRulesResource(projectRoot) {
|
|
|
621
877
|
} catch {
|
|
622
878
|
}
|
|
623
879
|
}
|
|
624
|
-
const linterPath =
|
|
625
|
-
if (
|
|
880
|
+
const linterPath = path7.join(projectRoot, ".harness", "linter.json");
|
|
881
|
+
if (fs5.existsSync(linterPath)) {
|
|
626
882
|
try {
|
|
627
|
-
const linterConfig = JSON.parse(
|
|
883
|
+
const linterConfig = JSON.parse(fs5.readFileSync(linterPath, "utf-8"));
|
|
628
884
|
rules.push({ type: "linter", config: linterConfig });
|
|
629
885
|
} catch {
|
|
630
886
|
}
|
|
@@ -633,28 +889,28 @@ async function getRulesResource(projectRoot) {
|
|
|
633
889
|
}
|
|
634
890
|
|
|
635
891
|
// src/mcp/resources/project.ts
|
|
636
|
-
import * as
|
|
637
|
-
import * as
|
|
892
|
+
import * as fs6 from "fs";
|
|
893
|
+
import * as path8 from "path";
|
|
638
894
|
async function getProjectResource(projectRoot) {
|
|
639
|
-
const agentsPath =
|
|
640
|
-
if (
|
|
641
|
-
return
|
|
895
|
+
const agentsPath = path8.join(projectRoot, "AGENTS.md");
|
|
896
|
+
if (fs6.existsSync(agentsPath)) {
|
|
897
|
+
return fs6.readFileSync(agentsPath, "utf-8");
|
|
642
898
|
}
|
|
643
899
|
return "# No AGENTS.md found";
|
|
644
900
|
}
|
|
645
901
|
|
|
646
902
|
// src/mcp/resources/learnings.ts
|
|
647
|
-
import * as
|
|
648
|
-
import * as
|
|
903
|
+
import * as fs7 from "fs";
|
|
904
|
+
import * as path9 from "path";
|
|
649
905
|
async function getLearningsResource(projectRoot) {
|
|
650
906
|
const sections = [];
|
|
651
|
-
const reviewPath =
|
|
652
|
-
if (
|
|
653
|
-
sections.push("## Review Learnings\n\n" +
|
|
907
|
+
const reviewPath = path9.join(projectRoot, ".harness", "review-learnings.md");
|
|
908
|
+
if (fs7.existsSync(reviewPath)) {
|
|
909
|
+
sections.push("## Review Learnings\n\n" + fs7.readFileSync(reviewPath, "utf-8"));
|
|
654
910
|
}
|
|
655
|
-
const antiPath =
|
|
656
|
-
if (
|
|
657
|
-
sections.push("## Anti-Pattern Log\n\n" +
|
|
911
|
+
const antiPath = path9.join(projectRoot, ".harness", "anti-patterns.md");
|
|
912
|
+
if (fs7.existsSync(antiPath)) {
|
|
913
|
+
sections.push("## Anti-Pattern Log\n\n" + fs7.readFileSync(antiPath, "utf-8"));
|
|
658
914
|
}
|
|
659
915
|
return sections.length > 0 ? sections.join("\n\n---\n\n") : "No learnings files found.";
|
|
660
916
|
}
|
|
@@ -690,6 +946,10 @@ var manageStateDefinition = {
|
|
|
690
946
|
stream: {
|
|
691
947
|
type: "string",
|
|
692
948
|
description: "Stream name to target (auto-resolves from branch if omitted)"
|
|
949
|
+
},
|
|
950
|
+
session: {
|
|
951
|
+
type: "string",
|
|
952
|
+
description: "Session slug for session-scoped state (takes priority over stream when provided)"
|
|
693
953
|
}
|
|
694
954
|
},
|
|
695
955
|
required: ["path", "action"]
|
|
@@ -705,11 +965,11 @@ async function handleManageState(input) {
|
|
|
705
965
|
archiveFailures,
|
|
706
966
|
runMechanicalGate,
|
|
707
967
|
DEFAULT_STATE
|
|
708
|
-
} = await import("./dist-
|
|
968
|
+
} = await import("./dist-2B363XUH.js");
|
|
709
969
|
const projectPath = sanitizePath(input.path);
|
|
710
970
|
switch (input.action) {
|
|
711
971
|
case "show": {
|
|
712
|
-
const result = await loadState(projectPath, input.stream);
|
|
972
|
+
const result = await loadState(projectPath, input.stream, input.session);
|
|
713
973
|
return resultToMcpResponse(result);
|
|
714
974
|
}
|
|
715
975
|
case "learn": {
|
|
@@ -726,7 +986,8 @@ async function handleManageState(input) {
|
|
|
726
986
|
input.learning,
|
|
727
987
|
input.skillName,
|
|
728
988
|
input.outcome,
|
|
729
|
-
input.stream
|
|
989
|
+
input.stream,
|
|
990
|
+
input.session
|
|
730
991
|
);
|
|
731
992
|
if (!result.ok) return resultToMcpResponse(result);
|
|
732
993
|
return resultToMcpResponse(Ok({ recorded: true }));
|
|
@@ -756,18 +1017,24 @@ async function handleManageState(input) {
|
|
|
756
1017
|
input.description,
|
|
757
1018
|
input.skillName ?? "unknown",
|
|
758
1019
|
input.failureType,
|
|
759
|
-
input.stream
|
|
1020
|
+
input.stream,
|
|
1021
|
+
input.session
|
|
760
1022
|
);
|
|
761
1023
|
if (!result.ok) return resultToMcpResponse(result);
|
|
762
1024
|
return resultToMcpResponse(Ok({ recorded: true }));
|
|
763
1025
|
}
|
|
764
1026
|
case "archive": {
|
|
765
|
-
const result = await archiveFailures(projectPath, input.stream);
|
|
1027
|
+
const result = await archiveFailures(projectPath, input.stream, input.session);
|
|
766
1028
|
if (!result.ok) return resultToMcpResponse(result);
|
|
767
1029
|
return resultToMcpResponse(Ok({ archived: true }));
|
|
768
1030
|
}
|
|
769
1031
|
case "reset": {
|
|
770
|
-
const result = await saveState(
|
|
1032
|
+
const result = await saveState(
|
|
1033
|
+
projectPath,
|
|
1034
|
+
{ ...DEFAULT_STATE },
|
|
1035
|
+
input.stream,
|
|
1036
|
+
input.session
|
|
1037
|
+
);
|
|
771
1038
|
if (!result.ok) return resultToMcpResponse(result);
|
|
772
1039
|
return resultToMcpResponse(Ok({ reset: true }));
|
|
773
1040
|
}
|
|
@@ -784,17 +1051,18 @@ async function handleManageState(input) {
|
|
|
784
1051
|
isError: true
|
|
785
1052
|
};
|
|
786
1053
|
}
|
|
787
|
-
const { saveHandoff } = await import("./dist-
|
|
1054
|
+
const { saveHandoff } = await import("./dist-2B363XUH.js");
|
|
788
1055
|
const result = await saveHandoff(
|
|
789
1056
|
projectPath,
|
|
790
1057
|
input.handoff,
|
|
791
|
-
input.stream
|
|
1058
|
+
input.stream,
|
|
1059
|
+
input.session
|
|
792
1060
|
);
|
|
793
1061
|
return resultToMcpResponse(result.ok ? Ok({ saved: true }) : result);
|
|
794
1062
|
}
|
|
795
1063
|
case "load-handoff": {
|
|
796
|
-
const { loadHandoff } = await import("./dist-
|
|
797
|
-
const result = await loadHandoff(projectPath, input.stream);
|
|
1064
|
+
const { loadHandoff } = await import("./dist-2B363XUH.js");
|
|
1065
|
+
const result = await loadHandoff(projectPath, input.stream, input.session);
|
|
798
1066
|
return resultToMcpResponse(result);
|
|
799
1067
|
}
|
|
800
1068
|
default: {
|
|
@@ -829,7 +1097,7 @@ var listStreamsDefinition = {
|
|
|
829
1097
|
};
|
|
830
1098
|
async function handleListStreams(input) {
|
|
831
1099
|
try {
|
|
832
|
-
const { listStreams, loadStreamIndex } = await import("./dist-
|
|
1100
|
+
const { listStreams, loadStreamIndex } = await import("./dist-2B363XUH.js");
|
|
833
1101
|
const projectPath = sanitizePath(input.path);
|
|
834
1102
|
const indexResult = await loadStreamIndex(projectPath);
|
|
835
1103
|
const streamsResult = await listStreams(projectPath);
|
|
@@ -867,7 +1135,7 @@ var checkPhaseGateDefinition = {
|
|
|
867
1135
|
};
|
|
868
1136
|
async function handleCheckPhaseGate(input) {
|
|
869
1137
|
try {
|
|
870
|
-
const { runCheckPhaseGate } = await import("./check-phase-gate-
|
|
1138
|
+
const { runCheckPhaseGate } = await import("./check-phase-gate-2OFZ7OWW.js");
|
|
871
1139
|
const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
|
|
872
1140
|
if (result.ok) {
|
|
873
1141
|
return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
|
|
@@ -887,7 +1155,7 @@ async function handleCheckPhaseGate(input) {
|
|
|
887
1155
|
}
|
|
888
1156
|
|
|
889
1157
|
// src/mcp/tools/cross-check.ts
|
|
890
|
-
import * as
|
|
1158
|
+
import * as path10 from "path";
|
|
891
1159
|
var validateCrossCheckDefinition = {
|
|
892
1160
|
name: "validate_cross_check",
|
|
893
1161
|
description: "Validate plan-to-implementation coverage: checks that specs have plans and plans have implementations, detects staleness",
|
|
@@ -923,15 +1191,15 @@ async function handleValidateCrossCheck(input) {
|
|
|
923
1191
|
};
|
|
924
1192
|
}
|
|
925
1193
|
try {
|
|
926
|
-
const { runCrossCheck } = await import("./validate-cross-check-
|
|
927
|
-
const specsDir =
|
|
1194
|
+
const { runCrossCheck } = await import("./validate-cross-check-STFHYMAZ.js");
|
|
1195
|
+
const specsDir = path10.resolve(projectPath, input.specsDir ?? "docs/specs");
|
|
928
1196
|
if (!specsDir.startsWith(projectPath)) {
|
|
929
1197
|
return {
|
|
930
1198
|
content: [{ type: "text", text: "Error: specsDir escapes project root" }],
|
|
931
1199
|
isError: true
|
|
932
1200
|
};
|
|
933
1201
|
}
|
|
934
|
-
const plansDir =
|
|
1202
|
+
const plansDir = path10.resolve(projectPath, input.plansDir ?? "docs/plans");
|
|
935
1203
|
if (!plansDir.startsWith(projectPath)) {
|
|
936
1204
|
return {
|
|
937
1205
|
content: [{ type: "text", text: "Error: plansDir escapes project root" }],
|
|
@@ -962,15 +1230,15 @@ async function handleValidateCrossCheck(input) {
|
|
|
962
1230
|
|
|
963
1231
|
// src/commands/generate-slash-commands.ts
|
|
964
1232
|
import { Command } from "commander";
|
|
965
|
-
import
|
|
966
|
-
import
|
|
1233
|
+
import fs9 from "fs";
|
|
1234
|
+
import path12 from "path";
|
|
967
1235
|
import os from "os";
|
|
968
1236
|
import readline from "readline";
|
|
969
1237
|
|
|
970
1238
|
// src/slash-commands/normalize.ts
|
|
971
|
-
import
|
|
972
|
-
import
|
|
973
|
-
import { parse as
|
|
1239
|
+
import fs8 from "fs";
|
|
1240
|
+
import path11 from "path";
|
|
1241
|
+
import { parse as parse3 } from "yaml";
|
|
974
1242
|
|
|
975
1243
|
// src/slash-commands/normalize-name.ts
|
|
976
1244
|
function normalizeName(skillName) {
|
|
@@ -990,18 +1258,18 @@ function normalizeSkills(skillSources, platforms) {
|
|
|
990
1258
|
const specs = [];
|
|
991
1259
|
const nameMap = /* @__PURE__ */ new Map();
|
|
992
1260
|
for (const { dir: skillsDir, source } of skillSources) {
|
|
993
|
-
if (!
|
|
994
|
-
const entries =
|
|
1261
|
+
if (!fs8.existsSync(skillsDir)) continue;
|
|
1262
|
+
const entries = fs8.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
995
1263
|
for (const entry of entries) {
|
|
996
|
-
const yamlPath =
|
|
997
|
-
if (!
|
|
1264
|
+
const yamlPath = path11.join(skillsDir, entry.name, "skill.yaml");
|
|
1265
|
+
if (!fs8.existsSync(yamlPath)) continue;
|
|
998
1266
|
let raw;
|
|
999
1267
|
try {
|
|
1000
|
-
raw =
|
|
1268
|
+
raw = fs8.readFileSync(yamlPath, "utf-8");
|
|
1001
1269
|
} catch {
|
|
1002
1270
|
continue;
|
|
1003
1271
|
}
|
|
1004
|
-
const parsed =
|
|
1272
|
+
const parsed = parse3(raw);
|
|
1005
1273
|
const result = SkillMetadataSchema.safeParse(parsed);
|
|
1006
1274
|
if (!result.success) {
|
|
1007
1275
|
console.warn(`Skipping ${entry.name}: invalid skill.yaml`);
|
|
@@ -1010,6 +1278,9 @@ function normalizeSkills(skillSources, platforms) {
|
|
|
1010
1278
|
const meta = result.data;
|
|
1011
1279
|
const matchesPlatform = platforms.some((p) => meta.platforms.includes(p));
|
|
1012
1280
|
if (!matchesPlatform) continue;
|
|
1281
|
+
const tier = meta.tier;
|
|
1282
|
+
const isInternal = meta.internal;
|
|
1283
|
+
if (tier === 3 || isInternal) continue;
|
|
1013
1284
|
const normalized = normalizeName(meta.name);
|
|
1014
1285
|
const existing = nameMap.get(normalized);
|
|
1015
1286
|
if (existing) {
|
|
@@ -1021,16 +1292,10 @@ function normalizeSkills(skillSources, platforms) {
|
|
|
1021
1292
|
continue;
|
|
1022
1293
|
}
|
|
1023
1294
|
nameMap.set(normalized, { skillName: meta.name, source });
|
|
1024
|
-
const skillMdPath =
|
|
1025
|
-
const skillMdContent =
|
|
1026
|
-
const skillMdRelative =
|
|
1027
|
-
|
|
1028
|
-
path9.join(skillsDir, entry.name, "SKILL.md")
|
|
1029
|
-
);
|
|
1030
|
-
const skillYamlRelative = path9.relative(
|
|
1031
|
-
process.cwd(),
|
|
1032
|
-
path9.join(skillsDir, entry.name, "skill.yaml")
|
|
1033
|
-
);
|
|
1295
|
+
const skillMdPath = path11.join(skillsDir, entry.name, "SKILL.md");
|
|
1296
|
+
const skillMdContent = fs8.existsSync(skillMdPath) ? fs8.readFileSync(skillMdPath, "utf-8") : "";
|
|
1297
|
+
const skillMdRelative = path11.relative(process.cwd(), path11.join(skillsDir, entry.name, "SKILL.md")).replaceAll("\\", "/");
|
|
1298
|
+
const skillYamlRelative = path11.relative(process.cwd(), path11.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
|
|
1034
1299
|
const args = (meta.cli?.args ?? []).map((a) => ({
|
|
1035
1300
|
name: a.name,
|
|
1036
1301
|
description: a.description ?? "",
|
|
@@ -1195,13 +1460,13 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
|
|
|
1195
1460
|
// src/commands/generate-slash-commands.ts
|
|
1196
1461
|
function resolveOutputDir(platform, opts) {
|
|
1197
1462
|
if (opts.output) {
|
|
1198
|
-
return
|
|
1463
|
+
return path12.join(opts.output, "harness");
|
|
1199
1464
|
}
|
|
1200
1465
|
if (opts.global) {
|
|
1201
1466
|
const home = os.homedir();
|
|
1202
|
-
return platform === "claude-code" ?
|
|
1467
|
+
return platform === "claude-code" ? path12.join(home, ".claude", "commands", "harness") : path12.join(home, ".gemini", "commands", "harness");
|
|
1203
1468
|
}
|
|
1204
|
-
return platform === "claude-code" ?
|
|
1469
|
+
return platform === "claude-code" ? path12.join("agents", "commands", "claude-code", "harness") : path12.join("agents", "commands", "gemini-cli", "harness");
|
|
1205
1470
|
}
|
|
1206
1471
|
function fileExtension(platform) {
|
|
1207
1472
|
return platform === "claude-code" ? ".md" : ".toml";
|
|
@@ -1226,12 +1491,12 @@ function generateSlashCommands(opts) {
|
|
|
1226
1491
|
skillSources.push({ dir: projectDir, source: "project" });
|
|
1227
1492
|
}
|
|
1228
1493
|
const communityDir = resolveCommunitySkillsDir();
|
|
1229
|
-
if (
|
|
1494
|
+
if (fs9.existsSync(communityDir)) {
|
|
1230
1495
|
skillSources.push({ dir: communityDir, source: "community" });
|
|
1231
1496
|
}
|
|
1232
1497
|
if (opts.includeGlobal || skillSources.length === 0) {
|
|
1233
1498
|
const globalDir = resolveGlobalSkillsDir();
|
|
1234
|
-
if (!projectDir ||
|
|
1499
|
+
if (!projectDir || path12.resolve(globalDir) !== path12.resolve(projectDir)) {
|
|
1235
1500
|
skillSources.push({ dir: globalDir, source: "global" });
|
|
1236
1501
|
}
|
|
1237
1502
|
}
|
|
@@ -1253,7 +1518,7 @@ function generateSlashCommands(opts) {
|
|
|
1253
1518
|
executionContext: spec.prompt.executionContext.split("\n").map((line) => {
|
|
1254
1519
|
if (line.startsWith("@")) {
|
|
1255
1520
|
const relPath = line.slice(1);
|
|
1256
|
-
return `@${
|
|
1521
|
+
return `@${path12.resolve(relPath)}`;
|
|
1257
1522
|
}
|
|
1258
1523
|
return line;
|
|
1259
1524
|
}).join("\n")
|
|
@@ -1261,10 +1526,10 @@ function generateSlashCommands(opts) {
|
|
|
1261
1526
|
} : spec;
|
|
1262
1527
|
rendered.set(filename, renderClaudeCode(renderSpec));
|
|
1263
1528
|
} else {
|
|
1264
|
-
const mdPath =
|
|
1265
|
-
const yamlPath =
|
|
1266
|
-
const mdContent =
|
|
1267
|
-
const yamlContent =
|
|
1529
|
+
const mdPath = path12.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
|
|
1530
|
+
const yamlPath = path12.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
|
|
1531
|
+
const mdContent = fs9.existsSync(mdPath) ? fs9.readFileSync(mdPath, "utf-8") : "";
|
|
1532
|
+
const yamlContent = fs9.existsSync(yamlPath) ? fs9.readFileSync(yamlPath, "utf-8") : "";
|
|
1268
1533
|
rendered.set(filename, renderGemini(spec, mdContent, yamlContent));
|
|
1269
1534
|
}
|
|
1270
1535
|
}
|
|
@@ -1290,9 +1555,9 @@ async function handleOrphanDeletion(results, opts) {
|
|
|
1290
1555
|
const shouldDelete = opts.yes || await confirmDeletion(result.removed);
|
|
1291
1556
|
if (shouldDelete) {
|
|
1292
1557
|
for (const filename of result.removed) {
|
|
1293
|
-
const filePath =
|
|
1294
|
-
if (
|
|
1295
|
-
|
|
1558
|
+
const filePath = path12.join(result.outputDir, filename);
|
|
1559
|
+
if (fs9.existsSync(filePath)) {
|
|
1560
|
+
fs9.unlinkSync(filePath);
|
|
1296
1561
|
}
|
|
1297
1562
|
}
|
|
1298
1563
|
}
|
|
@@ -1418,7 +1683,7 @@ async function handleGenerateSlashCommands(input) {
|
|
|
1418
1683
|
// src/mcp/resources/state.ts
|
|
1419
1684
|
async function getStateResource(projectRoot) {
|
|
1420
1685
|
try {
|
|
1421
|
-
const { loadState, migrateToStreams } = await import("./dist-
|
|
1686
|
+
const { loadState, migrateToStreams } = await import("./dist-2B363XUH.js");
|
|
1422
1687
|
await migrateToStreams(projectRoot);
|
|
1423
1688
|
const result = await loadState(projectRoot);
|
|
1424
1689
|
if (result.ok) {
|
|
@@ -1442,8 +1707,7 @@ async function getStateResource(projectRoot) {
|
|
|
1442
1707
|
}
|
|
1443
1708
|
}
|
|
1444
1709
|
|
|
1445
|
-
// src/mcp/tools/graph.ts
|
|
1446
|
-
import * as path11 from "path";
|
|
1710
|
+
// src/mcp/tools/graph/shared.ts
|
|
1447
1711
|
function graphNotFoundError() {
|
|
1448
1712
|
return {
|
|
1449
1713
|
content: [
|
|
@@ -1455,6 +1719,8 @@ function graphNotFoundError() {
|
|
|
1455
1719
|
isError: true
|
|
1456
1720
|
};
|
|
1457
1721
|
}
|
|
1722
|
+
|
|
1723
|
+
// src/mcp/tools/graph/query-graph.ts
|
|
1458
1724
|
var queryGraphDefinition = {
|
|
1459
1725
|
name: "query_graph",
|
|
1460
1726
|
description: "Query the project knowledge graph using ContextQL. Traverses from root nodes outward, filtering by node/edge types.",
|
|
@@ -1505,7 +1771,7 @@ async function handleQueryGraph(input) {
|
|
|
1505
1771
|
const projectPath = sanitizePath(input.path);
|
|
1506
1772
|
const store = await loadGraphStore(projectPath);
|
|
1507
1773
|
if (!store) return graphNotFoundError();
|
|
1508
|
-
const { ContextQL } = await import("./dist-
|
|
1774
|
+
const { ContextQL } = await import("./dist-HXHWB7SV.js");
|
|
1509
1775
|
const cql = new ContextQL(store);
|
|
1510
1776
|
const result = cql.execute({
|
|
1511
1777
|
rootNodeIds: input.rootNodeIds,
|
|
@@ -1571,6 +1837,8 @@ async function handleQueryGraph(input) {
|
|
|
1571
1837
|
};
|
|
1572
1838
|
}
|
|
1573
1839
|
}
|
|
1840
|
+
|
|
1841
|
+
// src/mcp/tools/graph/search-similar.ts
|
|
1574
1842
|
var searchSimilarDefinition = {
|
|
1575
1843
|
name: "search_similar",
|
|
1576
1844
|
description: "Search the knowledge graph for nodes similar to a query string using keyword and semantic fusion.",
|
|
@@ -1594,7 +1862,7 @@ async function handleSearchSimilar(input) {
|
|
|
1594
1862
|
const projectPath = sanitizePath(input.path);
|
|
1595
1863
|
const store = await loadGraphStore(projectPath);
|
|
1596
1864
|
if (!store) return graphNotFoundError();
|
|
1597
|
-
const { FusionLayer } = await import("./dist-
|
|
1865
|
+
const { FusionLayer } = await import("./dist-HXHWB7SV.js");
|
|
1598
1866
|
const fusion = new FusionLayer(store);
|
|
1599
1867
|
const results = fusion.search(input.query, input.topK ?? 10);
|
|
1600
1868
|
if (input.mode === "summary") {
|
|
@@ -1626,6 +1894,8 @@ async function handleSearchSimilar(input) {
|
|
|
1626
1894
|
};
|
|
1627
1895
|
}
|
|
1628
1896
|
}
|
|
1897
|
+
|
|
1898
|
+
// src/mcp/tools/graph/find-context-for.ts
|
|
1629
1899
|
var findContextForDefinition = {
|
|
1630
1900
|
name: "find_context_for",
|
|
1631
1901
|
description: "Find relevant context for a given intent by searching the graph and expanding around top results. Returns assembled context within a token budget.",
|
|
@@ -1647,7 +1917,7 @@ async function handleFindContextFor(input) {
|
|
|
1647
1917
|
const projectPath = sanitizePath(input.path);
|
|
1648
1918
|
const store = await loadGraphStore(projectPath);
|
|
1649
1919
|
if (!store) return graphNotFoundError();
|
|
1650
|
-
const { FusionLayer, ContextQL } = await import("./dist-
|
|
1920
|
+
const { FusionLayer, ContextQL } = await import("./dist-HXHWB7SV.js");
|
|
1651
1921
|
const fusion = new FusionLayer(store);
|
|
1652
1922
|
const cql = new ContextQL(store);
|
|
1653
1923
|
const tokenBudget = input.tokenBudget ?? 4e3;
|
|
@@ -1713,6 +1983,8 @@ async function handleFindContextFor(input) {
|
|
|
1713
1983
|
};
|
|
1714
1984
|
}
|
|
1715
1985
|
}
|
|
1986
|
+
|
|
1987
|
+
// src/mcp/tools/graph/get-relationships.ts
|
|
1716
1988
|
var getRelationshipsDefinition = {
|
|
1717
1989
|
name: "get_relationships",
|
|
1718
1990
|
description: "Get relationships for a specific node in the knowledge graph, with configurable direction and depth.",
|
|
@@ -1741,7 +2013,7 @@ async function handleGetRelationships(input) {
|
|
|
1741
2013
|
const projectPath = sanitizePath(input.path);
|
|
1742
2014
|
const store = await loadGraphStore(projectPath);
|
|
1743
2015
|
if (!store) return graphNotFoundError();
|
|
1744
|
-
const { ContextQL } = await import("./dist-
|
|
2016
|
+
const { ContextQL } = await import("./dist-HXHWB7SV.js");
|
|
1745
2017
|
const cql = new ContextQL(store);
|
|
1746
2018
|
const direction = input.direction ?? "both";
|
|
1747
2019
|
const bidirectional = direction === "both" || direction === "inbound";
|
|
@@ -1808,6 +2080,8 @@ async function handleGetRelationships(input) {
|
|
|
1808
2080
|
};
|
|
1809
2081
|
}
|
|
1810
2082
|
}
|
|
2083
|
+
|
|
2084
|
+
// src/mcp/tools/graph/get-impact.ts
|
|
1811
2085
|
var getImpactDefinition = {
|
|
1812
2086
|
name: "get_impact",
|
|
1813
2087
|
description: "Analyze the impact of changing a node or file. Returns affected tests, docs, code, and other nodes grouped by type.",
|
|
@@ -1845,7 +2119,7 @@ async function handleGetImpact(input) {
|
|
|
1845
2119
|
const projectPath = sanitizePath(input.path);
|
|
1846
2120
|
const store = await loadGraphStore(projectPath);
|
|
1847
2121
|
if (!store) return graphNotFoundError();
|
|
1848
|
-
const { ContextQL } = await import("./dist-
|
|
2122
|
+
const { ContextQL } = await import("./dist-HXHWB7SV.js");
|
|
1849
2123
|
let targetNodeId = input.nodeId;
|
|
1850
2124
|
if (!targetNodeId && input.filePath) {
|
|
1851
2125
|
const fileNodes = store.findNodes({ type: "file" });
|
|
@@ -1954,6 +2228,9 @@ async function handleGetImpact(input) {
|
|
|
1954
2228
|
};
|
|
1955
2229
|
}
|
|
1956
2230
|
}
|
|
2231
|
+
|
|
2232
|
+
// src/mcp/tools/graph/ingest-source.ts
|
|
2233
|
+
import * as path13 from "path";
|
|
1957
2234
|
var ingestSourceDefinition = {
|
|
1958
2235
|
name: "ingest_source",
|
|
1959
2236
|
description: "Ingest sources into the project knowledge graph. Supports code analysis, knowledge documents, git history, or all at once.",
|
|
@@ -1973,10 +2250,10 @@ var ingestSourceDefinition = {
|
|
|
1973
2250
|
async function handleIngestSource(input) {
|
|
1974
2251
|
try {
|
|
1975
2252
|
const projectPath = sanitizePath(input.path);
|
|
1976
|
-
const graphDir =
|
|
1977
|
-
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-
|
|
1978
|
-
const
|
|
1979
|
-
await
|
|
2253
|
+
const graphDir = path13.join(projectPath, ".harness", "graph");
|
|
2254
|
+
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-HXHWB7SV.js");
|
|
2255
|
+
const fs12 = await import("fs/promises");
|
|
2256
|
+
await fs12.mkdir(graphDir, { recursive: true });
|
|
1980
2257
|
const store = new GraphStore();
|
|
1981
2258
|
await store.load(graphDir);
|
|
1982
2259
|
const results = [];
|
|
@@ -2025,6 +2302,8 @@ async function handleIngestSource(input) {
|
|
|
2025
2302
|
};
|
|
2026
2303
|
}
|
|
2027
2304
|
}
|
|
2305
|
+
|
|
2306
|
+
// src/mcp/tools/graph/detect-anomalies.ts
|
|
2028
2307
|
var detectAnomaliesDefinition = {
|
|
2029
2308
|
name: "detect_anomalies",
|
|
2030
2309
|
description: "Detect structural anomalies \u2014 statistical outliers across code metrics and topological single points of failure in the import graph",
|
|
@@ -2047,7 +2326,7 @@ async function handleDetectAnomalies(input) {
|
|
|
2047
2326
|
const projectPath = sanitizePath(input.path);
|
|
2048
2327
|
const store = await loadGraphStore(projectPath);
|
|
2049
2328
|
if (!store) return graphNotFoundError();
|
|
2050
|
-
const { GraphAnomalyAdapter } = await import("./dist-
|
|
2329
|
+
const { GraphAnomalyAdapter } = await import("./dist-HXHWB7SV.js");
|
|
2051
2330
|
const adapter = new GraphAnomalyAdapter(store);
|
|
2052
2331
|
const report = adapter.detect({
|
|
2053
2332
|
...input.threshold !== void 0 && { threshold: input.threshold },
|
|
@@ -2068,6 +2347,8 @@ async function handleDetectAnomalies(input) {
|
|
|
2068
2347
|
};
|
|
2069
2348
|
}
|
|
2070
2349
|
}
|
|
2350
|
+
|
|
2351
|
+
// src/mcp/tools/graph/ask-graph.ts
|
|
2071
2352
|
var askGraphDefinition = {
|
|
2072
2353
|
name: "ask_graph",
|
|
2073
2354
|
description: 'Ask a natural language question about the codebase knowledge graph. Supports questions about impact ("what breaks if I change X?"), finding entities ("where is the auth middleware?"), relationships ("what calls UserService?"), explanations ("what is GraphStore?"), and anomalies ("what looks wrong?"). Returns a human-readable summary and raw graph data.',
|
|
@@ -2085,7 +2366,7 @@ async function handleAskGraph(input) {
|
|
|
2085
2366
|
const projectPath = sanitizePath(input.path);
|
|
2086
2367
|
const store = await loadGraphStore(projectPath);
|
|
2087
2368
|
if (!store) return graphNotFoundError();
|
|
2088
|
-
const { askGraph } = await import("./dist-
|
|
2369
|
+
const { askGraph } = await import("./dist-HXHWB7SV.js");
|
|
2089
2370
|
const result = await askGraph(store, input.question);
|
|
2090
2371
|
return {
|
|
2091
2372
|
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
@@ -2104,8 +2385,8 @@ async function handleAskGraph(input) {
|
|
|
2104
2385
|
}
|
|
2105
2386
|
|
|
2106
2387
|
// src/mcp/resources/graph.ts
|
|
2107
|
-
import * as
|
|
2108
|
-
import * as
|
|
2388
|
+
import * as fs10 from "fs/promises";
|
|
2389
|
+
import * as path14 from "path";
|
|
2109
2390
|
var MAX_ITEMS = 5e3;
|
|
2110
2391
|
function formatStaleness(isoTimestamp) {
|
|
2111
2392
|
const then = new Date(isoTimestamp).getTime();
|
|
@@ -2128,11 +2409,11 @@ async function getGraphResource(projectRoot) {
|
|
|
2128
2409
|
message: "No knowledge graph found. Run harness scan to build one."
|
|
2129
2410
|
});
|
|
2130
2411
|
}
|
|
2131
|
-
const graphDir =
|
|
2132
|
-
const metadataPath =
|
|
2412
|
+
const graphDir = path14.join(projectRoot, ".harness", "graph");
|
|
2413
|
+
const metadataPath = path14.join(graphDir, "metadata.json");
|
|
2133
2414
|
let lastScanTimestamp = null;
|
|
2134
2415
|
try {
|
|
2135
|
-
const raw = JSON.parse(await
|
|
2416
|
+
const raw = JSON.parse(await fs10.readFile(metadataPath, "utf-8"));
|
|
2136
2417
|
lastScanTimestamp = raw.lastScanTimestamp ?? null;
|
|
2137
2418
|
} catch {
|
|
2138
2419
|
}
|
|
@@ -2221,7 +2502,7 @@ var generateAgentDefinitionsDefinition = {
|
|
|
2221
2502
|
}
|
|
2222
2503
|
};
|
|
2223
2504
|
async function handleGenerateAgentDefinitions(input) {
|
|
2224
|
-
const { generateAgentDefinitions } = await import("./generate-agent-definitions-
|
|
2505
|
+
const { generateAgentDefinitions } = await import("./generate-agent-definitions-64S3CLEZ.js");
|
|
2225
2506
|
const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
|
|
2226
2507
|
const results = generateAgentDefinitions({
|
|
2227
2508
|
platforms: [...platforms],
|
|
@@ -2232,8 +2513,8 @@ async function handleGenerateAgentDefinitions(input) {
|
|
|
2232
2513
|
}
|
|
2233
2514
|
|
|
2234
2515
|
// src/mcp/tools/roadmap.ts
|
|
2235
|
-
import * as
|
|
2236
|
-
import * as
|
|
2516
|
+
import * as fs11 from "fs";
|
|
2517
|
+
import * as path15 from "path";
|
|
2237
2518
|
var manageRoadmapDefinition = {
|
|
2238
2519
|
name: "manage_roadmap",
|
|
2239
2520
|
description: "Manage the project roadmap: show, add, update, remove, sync features, or query by filter. Reads and writes docs/roadmap.md.",
|
|
@@ -2288,309 +2569,261 @@ var manageRoadmapDefinition = {
|
|
|
2288
2569
|
}
|
|
2289
2570
|
};
|
|
2290
2571
|
function roadmapPath(projectRoot) {
|
|
2291
|
-
return
|
|
2572
|
+
return path15.join(projectRoot, "docs", "roadmap.md");
|
|
2292
2573
|
}
|
|
2293
2574
|
function readRoadmapFile(projectRoot) {
|
|
2294
2575
|
const filePath = roadmapPath(projectRoot);
|
|
2295
2576
|
try {
|
|
2296
|
-
return
|
|
2577
|
+
return fs11.readFileSync(filePath, "utf-8");
|
|
2297
2578
|
} catch {
|
|
2298
2579
|
return null;
|
|
2299
2580
|
}
|
|
2300
2581
|
}
|
|
2301
2582
|
function writeRoadmapFile(projectRoot, content) {
|
|
2302
2583
|
const filePath = roadmapPath(projectRoot);
|
|
2303
|
-
const dir =
|
|
2304
|
-
|
|
2305
|
-
|
|
2584
|
+
const dir = path15.dirname(filePath);
|
|
2585
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
2586
|
+
fs11.writeFileSync(filePath, content, "utf-8");
|
|
2587
|
+
}
|
|
2588
|
+
function roadmapNotFoundError() {
|
|
2589
|
+
return {
|
|
2590
|
+
content: [
|
|
2591
|
+
{
|
|
2592
|
+
type: "text",
|
|
2593
|
+
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2594
|
+
}
|
|
2595
|
+
],
|
|
2596
|
+
isError: true
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
function handleShow(projectPath, input, deps) {
|
|
2600
|
+
const { parseRoadmap, Ok: Ok2 } = deps;
|
|
2601
|
+
const raw = readRoadmapFile(projectPath);
|
|
2602
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2603
|
+
const result = parseRoadmap(raw);
|
|
2604
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2605
|
+
let roadmap = result.value;
|
|
2606
|
+
if (input.milestone) {
|
|
2607
|
+
const milestoneFilter = input.milestone;
|
|
2608
|
+
roadmap = {
|
|
2609
|
+
...roadmap,
|
|
2610
|
+
milestones: roadmap.milestones.filter(
|
|
2611
|
+
(m) => m.name.toLowerCase() === milestoneFilter.toLowerCase()
|
|
2612
|
+
)
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
if (input.status) {
|
|
2616
|
+
const statusFilter = input.status;
|
|
2617
|
+
roadmap = {
|
|
2618
|
+
...roadmap,
|
|
2619
|
+
milestones: roadmap.milestones.map((m) => ({
|
|
2620
|
+
...m,
|
|
2621
|
+
features: m.features.filter((f) => f.status === statusFilter)
|
|
2622
|
+
})).filter((m) => m.features.length > 0)
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2625
|
+
return resultToMcpResponse(Ok2(roadmap));
|
|
2626
|
+
}
|
|
2627
|
+
function handleAdd(projectPath, input, deps) {
|
|
2628
|
+
const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
|
|
2629
|
+
if (!input.feature) {
|
|
2630
|
+
return {
|
|
2631
|
+
content: [{ type: "text", text: "Error: feature is required for add action" }],
|
|
2632
|
+
isError: true
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
if (!input.milestone) {
|
|
2636
|
+
return {
|
|
2637
|
+
content: [{ type: "text", text: "Error: milestone is required for add action" }],
|
|
2638
|
+
isError: true
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
if (!input.status) {
|
|
2642
|
+
return {
|
|
2643
|
+
content: [{ type: "text", text: "Error: status is required for add action" }],
|
|
2644
|
+
isError: true
|
|
2645
|
+
};
|
|
2646
|
+
}
|
|
2647
|
+
if (!input.summary) {
|
|
2648
|
+
return {
|
|
2649
|
+
content: [{ type: "text", text: "Error: summary is required for add action" }],
|
|
2650
|
+
isError: true
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
const raw = readRoadmapFile(projectPath);
|
|
2654
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2655
|
+
const result = parseRoadmap(raw);
|
|
2656
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2657
|
+
const roadmap = result.value;
|
|
2658
|
+
const milestone = roadmap.milestones.find(
|
|
2659
|
+
(m) => m.name.toLowerCase() === input.milestone.toLowerCase()
|
|
2660
|
+
);
|
|
2661
|
+
if (!milestone) {
|
|
2662
|
+
return {
|
|
2663
|
+
content: [{ type: "text", text: `Error: milestone "${input.milestone}" not found` }],
|
|
2664
|
+
isError: true
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
milestone.features.push({
|
|
2668
|
+
name: input.feature,
|
|
2669
|
+
status: input.status,
|
|
2670
|
+
spec: input.spec ?? null,
|
|
2671
|
+
plans: input.plans ?? [],
|
|
2672
|
+
blockedBy: input.blocked_by ?? [],
|
|
2673
|
+
summary: input.summary
|
|
2674
|
+
});
|
|
2675
|
+
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2676
|
+
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2677
|
+
return resultToMcpResponse(Ok2(roadmap));
|
|
2678
|
+
}
|
|
2679
|
+
function handleUpdate(projectPath, input, deps) {
|
|
2680
|
+
const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
|
|
2681
|
+
if (!input.feature) {
|
|
2682
|
+
return {
|
|
2683
|
+
content: [{ type: "text", text: "Error: feature is required for update action" }],
|
|
2684
|
+
isError: true
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
const raw = readRoadmapFile(projectPath);
|
|
2688
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2689
|
+
const result = parseRoadmap(raw);
|
|
2690
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2691
|
+
const roadmap = result.value;
|
|
2692
|
+
let found = false;
|
|
2693
|
+
for (const m of roadmap.milestones) {
|
|
2694
|
+
const feature = m.features.find((f) => f.name.toLowerCase() === input.feature.toLowerCase());
|
|
2695
|
+
if (feature) {
|
|
2696
|
+
if (input.status) feature.status = input.status;
|
|
2697
|
+
if (input.summary !== void 0) feature.summary = input.summary;
|
|
2698
|
+
if (input.spec !== void 0) feature.spec = input.spec || null;
|
|
2699
|
+
if (input.plans !== void 0) feature.plans = input.plans;
|
|
2700
|
+
if (input.blocked_by !== void 0) feature.blockedBy = input.blocked_by;
|
|
2701
|
+
found = true;
|
|
2702
|
+
break;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
if (!found) {
|
|
2706
|
+
return {
|
|
2707
|
+
content: [{ type: "text", text: `Error: feature "${input.feature}" not found` }],
|
|
2708
|
+
isError: true
|
|
2709
|
+
};
|
|
2710
|
+
}
|
|
2711
|
+
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2712
|
+
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2713
|
+
return resultToMcpResponse(Ok2(roadmap));
|
|
2714
|
+
}
|
|
2715
|
+
function handleRemove(projectPath, input, deps) {
|
|
2716
|
+
const { parseRoadmap, serializeRoadmap, Ok: Ok2 } = deps;
|
|
2717
|
+
if (!input.feature) {
|
|
2718
|
+
return {
|
|
2719
|
+
content: [{ type: "text", text: "Error: feature is required for remove action" }],
|
|
2720
|
+
isError: true
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
const raw = readRoadmapFile(projectPath);
|
|
2724
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2725
|
+
const result = parseRoadmap(raw);
|
|
2726
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2727
|
+
const roadmap = result.value;
|
|
2728
|
+
let found = false;
|
|
2729
|
+
for (const m of roadmap.milestones) {
|
|
2730
|
+
const idx = m.features.findIndex((f) => f.name.toLowerCase() === input.feature.toLowerCase());
|
|
2731
|
+
if (idx !== -1) {
|
|
2732
|
+
m.features.splice(idx, 1);
|
|
2733
|
+
found = true;
|
|
2734
|
+
break;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
if (!found) {
|
|
2738
|
+
return {
|
|
2739
|
+
content: [{ type: "text", text: `Error: feature "${input.feature}" not found` }],
|
|
2740
|
+
isError: true
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2744
|
+
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2745
|
+
return resultToMcpResponse(Ok2(roadmap));
|
|
2746
|
+
}
|
|
2747
|
+
function handleQuery(projectPath, input, deps) {
|
|
2748
|
+
const { parseRoadmap, Ok: Ok2 } = deps;
|
|
2749
|
+
if (!input.filter) {
|
|
2750
|
+
return {
|
|
2751
|
+
content: [{ type: "text", text: "Error: filter is required for query action" }],
|
|
2752
|
+
isError: true
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
const raw = readRoadmapFile(projectPath);
|
|
2756
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2757
|
+
const result = parseRoadmap(raw);
|
|
2758
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2759
|
+
const roadmap = result.value;
|
|
2760
|
+
const allFeatures = roadmap.milestones.flatMap(
|
|
2761
|
+
(m) => m.features.map((f) => ({ ...f, milestone: m.name }))
|
|
2762
|
+
);
|
|
2763
|
+
const filter = input.filter.toLowerCase();
|
|
2764
|
+
let filtered;
|
|
2765
|
+
if (filter.startsWith("milestone:")) {
|
|
2766
|
+
const milestoneName = filter.slice("milestone:".length).trim();
|
|
2767
|
+
filtered = allFeatures.filter((f) => f.milestone.toLowerCase().includes(milestoneName));
|
|
2768
|
+
} else {
|
|
2769
|
+
filtered = allFeatures.filter((f) => f.status === filter);
|
|
2770
|
+
}
|
|
2771
|
+
return resultToMcpResponse(Ok2(filtered));
|
|
2772
|
+
}
|
|
2773
|
+
function handleSync(projectPath, input, deps) {
|
|
2774
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 } = deps;
|
|
2775
|
+
const raw = readRoadmapFile(projectPath);
|
|
2776
|
+
if (raw === null) return roadmapNotFoundError();
|
|
2777
|
+
const result = parseRoadmap(raw);
|
|
2778
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
2779
|
+
const roadmap = result.value;
|
|
2780
|
+
const syncResult = syncRoadmap({
|
|
2781
|
+
projectPath,
|
|
2782
|
+
roadmap,
|
|
2783
|
+
forceSync: input.force_sync ?? false
|
|
2784
|
+
});
|
|
2785
|
+
if (!syncResult.ok) return resultToMcpResponse(syncResult);
|
|
2786
|
+
const changes = syncResult.value;
|
|
2787
|
+
if (changes.length === 0) {
|
|
2788
|
+
return resultToMcpResponse(Ok2({ changes: [], message: "Roadmap is up to date." }));
|
|
2789
|
+
}
|
|
2790
|
+
if (input.apply) {
|
|
2791
|
+
for (const change of changes) {
|
|
2792
|
+
for (const m of roadmap.milestones) {
|
|
2793
|
+
const feature = m.features.find(
|
|
2794
|
+
(f) => f.name.toLowerCase() === change.feature.toLowerCase()
|
|
2795
|
+
);
|
|
2796
|
+
if (feature) {
|
|
2797
|
+
feature.status = change.to;
|
|
2798
|
+
break;
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
|
|
2803
|
+
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2804
|
+
return resultToMcpResponse(Ok2({ changes, applied: true, roadmap }));
|
|
2805
|
+
}
|
|
2806
|
+
return resultToMcpResponse(Ok2({ changes, applied: false }));
|
|
2306
2807
|
}
|
|
2307
2808
|
async function handleManageRoadmap(input) {
|
|
2308
2809
|
try {
|
|
2309
|
-
const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-
|
|
2810
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-2B363XUH.js");
|
|
2310
2811
|
const { Ok: Ok2 } = await import("./dist-D4RYGUZE.js");
|
|
2311
2812
|
const projectPath = sanitizePath(input.path);
|
|
2813
|
+
const deps = { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 };
|
|
2312
2814
|
switch (input.action) {
|
|
2313
|
-
case "show":
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
}
|
|
2326
|
-
const result = parseRoadmap(raw);
|
|
2327
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2328
|
-
let roadmap = result.value;
|
|
2329
|
-
if (input.milestone) {
|
|
2330
|
-
const milestoneFilter = input.milestone;
|
|
2331
|
-
roadmap = {
|
|
2332
|
-
...roadmap,
|
|
2333
|
-
milestones: roadmap.milestones.filter(
|
|
2334
|
-
(m) => m.name.toLowerCase() === milestoneFilter.toLowerCase()
|
|
2335
|
-
)
|
|
2336
|
-
};
|
|
2337
|
-
}
|
|
2338
|
-
if (input.status) {
|
|
2339
|
-
const statusFilter = input.status;
|
|
2340
|
-
roadmap = {
|
|
2341
|
-
...roadmap,
|
|
2342
|
-
milestones: roadmap.milestones.map((m) => ({
|
|
2343
|
-
...m,
|
|
2344
|
-
features: m.features.filter((f) => f.status === statusFilter)
|
|
2345
|
-
})).filter((m) => m.features.length > 0)
|
|
2346
|
-
};
|
|
2347
|
-
}
|
|
2348
|
-
return resultToMcpResponse(Ok2(roadmap));
|
|
2349
|
-
}
|
|
2350
|
-
case "add": {
|
|
2351
|
-
if (!input.feature) {
|
|
2352
|
-
return {
|
|
2353
|
-
content: [{ type: "text", text: "Error: feature is required for add action" }],
|
|
2354
|
-
isError: true
|
|
2355
|
-
};
|
|
2356
|
-
}
|
|
2357
|
-
if (!input.milestone) {
|
|
2358
|
-
return {
|
|
2359
|
-
content: [
|
|
2360
|
-
{ type: "text", text: "Error: milestone is required for add action" }
|
|
2361
|
-
],
|
|
2362
|
-
isError: true
|
|
2363
|
-
};
|
|
2364
|
-
}
|
|
2365
|
-
if (!input.status) {
|
|
2366
|
-
return {
|
|
2367
|
-
content: [{ type: "text", text: "Error: status is required for add action" }],
|
|
2368
|
-
isError: true
|
|
2369
|
-
};
|
|
2370
|
-
}
|
|
2371
|
-
if (!input.summary) {
|
|
2372
|
-
return {
|
|
2373
|
-
content: [{ type: "text", text: "Error: summary is required for add action" }],
|
|
2374
|
-
isError: true
|
|
2375
|
-
};
|
|
2376
|
-
}
|
|
2377
|
-
const raw = readRoadmapFile(projectPath);
|
|
2378
|
-
if (raw === null) {
|
|
2379
|
-
return {
|
|
2380
|
-
content: [
|
|
2381
|
-
{
|
|
2382
|
-
type: "text",
|
|
2383
|
-
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2384
|
-
}
|
|
2385
|
-
],
|
|
2386
|
-
isError: true
|
|
2387
|
-
};
|
|
2388
|
-
}
|
|
2389
|
-
const result = parseRoadmap(raw);
|
|
2390
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2391
|
-
const roadmap = result.value;
|
|
2392
|
-
const milestone = roadmap.milestones.find(
|
|
2393
|
-
(m) => m.name.toLowerCase() === input.milestone.toLowerCase()
|
|
2394
|
-
);
|
|
2395
|
-
if (!milestone) {
|
|
2396
|
-
return {
|
|
2397
|
-
content: [
|
|
2398
|
-
{ type: "text", text: `Error: milestone "${input.milestone}" not found` }
|
|
2399
|
-
],
|
|
2400
|
-
isError: true
|
|
2401
|
-
};
|
|
2402
|
-
}
|
|
2403
|
-
milestone.features.push({
|
|
2404
|
-
name: input.feature,
|
|
2405
|
-
status: input.status,
|
|
2406
|
-
spec: input.spec ?? null,
|
|
2407
|
-
plans: input.plans ?? [],
|
|
2408
|
-
blockedBy: input.blocked_by ?? [],
|
|
2409
|
-
summary: input.summary
|
|
2410
|
-
});
|
|
2411
|
-
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2412
|
-
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2413
|
-
return resultToMcpResponse(Ok2(roadmap));
|
|
2414
|
-
}
|
|
2415
|
-
case "update": {
|
|
2416
|
-
if (!input.feature) {
|
|
2417
|
-
return {
|
|
2418
|
-
content: [
|
|
2419
|
-
{ type: "text", text: "Error: feature is required for update action" }
|
|
2420
|
-
],
|
|
2421
|
-
isError: true
|
|
2422
|
-
};
|
|
2423
|
-
}
|
|
2424
|
-
const raw = readRoadmapFile(projectPath);
|
|
2425
|
-
if (raw === null) {
|
|
2426
|
-
return {
|
|
2427
|
-
content: [
|
|
2428
|
-
{
|
|
2429
|
-
type: "text",
|
|
2430
|
-
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2431
|
-
}
|
|
2432
|
-
],
|
|
2433
|
-
isError: true
|
|
2434
|
-
};
|
|
2435
|
-
}
|
|
2436
|
-
const result = parseRoadmap(raw);
|
|
2437
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2438
|
-
const roadmap = result.value;
|
|
2439
|
-
let found = false;
|
|
2440
|
-
for (const m of roadmap.milestones) {
|
|
2441
|
-
const feature = m.features.find(
|
|
2442
|
-
(f) => f.name.toLowerCase() === input.feature.toLowerCase()
|
|
2443
|
-
);
|
|
2444
|
-
if (feature) {
|
|
2445
|
-
if (input.status) feature.status = input.status;
|
|
2446
|
-
if (input.summary !== void 0) feature.summary = input.summary;
|
|
2447
|
-
if (input.spec !== void 0) feature.spec = input.spec || null;
|
|
2448
|
-
if (input.plans !== void 0) feature.plans = input.plans;
|
|
2449
|
-
if (input.blocked_by !== void 0) feature.blockedBy = input.blocked_by;
|
|
2450
|
-
found = true;
|
|
2451
|
-
break;
|
|
2452
|
-
}
|
|
2453
|
-
}
|
|
2454
|
-
if (!found) {
|
|
2455
|
-
return {
|
|
2456
|
-
content: [
|
|
2457
|
-
{ type: "text", text: `Error: feature "${input.feature}" not found` }
|
|
2458
|
-
],
|
|
2459
|
-
isError: true
|
|
2460
|
-
};
|
|
2461
|
-
}
|
|
2462
|
-
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2463
|
-
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2464
|
-
return resultToMcpResponse(Ok2(roadmap));
|
|
2465
|
-
}
|
|
2466
|
-
case "remove": {
|
|
2467
|
-
if (!input.feature) {
|
|
2468
|
-
return {
|
|
2469
|
-
content: [
|
|
2470
|
-
{ type: "text", text: "Error: feature is required for remove action" }
|
|
2471
|
-
],
|
|
2472
|
-
isError: true
|
|
2473
|
-
};
|
|
2474
|
-
}
|
|
2475
|
-
const raw = readRoadmapFile(projectPath);
|
|
2476
|
-
if (raw === null) {
|
|
2477
|
-
return {
|
|
2478
|
-
content: [
|
|
2479
|
-
{
|
|
2480
|
-
type: "text",
|
|
2481
|
-
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2482
|
-
}
|
|
2483
|
-
],
|
|
2484
|
-
isError: true
|
|
2485
|
-
};
|
|
2486
|
-
}
|
|
2487
|
-
const result = parseRoadmap(raw);
|
|
2488
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2489
|
-
const roadmap = result.value;
|
|
2490
|
-
let found = false;
|
|
2491
|
-
for (const m of roadmap.milestones) {
|
|
2492
|
-
const idx = m.features.findIndex(
|
|
2493
|
-
(f) => f.name.toLowerCase() === input.feature.toLowerCase()
|
|
2494
|
-
);
|
|
2495
|
-
if (idx !== -1) {
|
|
2496
|
-
m.features.splice(idx, 1);
|
|
2497
|
-
found = true;
|
|
2498
|
-
break;
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
if (!found) {
|
|
2502
|
-
return {
|
|
2503
|
-
content: [
|
|
2504
|
-
{ type: "text", text: `Error: feature "${input.feature}" not found` }
|
|
2505
|
-
],
|
|
2506
|
-
isError: true
|
|
2507
|
-
};
|
|
2508
|
-
}
|
|
2509
|
-
roadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
2510
|
-
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2511
|
-
return resultToMcpResponse(Ok2(roadmap));
|
|
2512
|
-
}
|
|
2513
|
-
case "query": {
|
|
2514
|
-
if (!input.filter) {
|
|
2515
|
-
return {
|
|
2516
|
-
content: [
|
|
2517
|
-
{ type: "text", text: "Error: filter is required for query action" }
|
|
2518
|
-
],
|
|
2519
|
-
isError: true
|
|
2520
|
-
};
|
|
2521
|
-
}
|
|
2522
|
-
const raw = readRoadmapFile(projectPath);
|
|
2523
|
-
if (raw === null) {
|
|
2524
|
-
return {
|
|
2525
|
-
content: [
|
|
2526
|
-
{
|
|
2527
|
-
type: "text",
|
|
2528
|
-
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2529
|
-
}
|
|
2530
|
-
],
|
|
2531
|
-
isError: true
|
|
2532
|
-
};
|
|
2533
|
-
}
|
|
2534
|
-
const result = parseRoadmap(raw);
|
|
2535
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2536
|
-
const roadmap = result.value;
|
|
2537
|
-
const allFeatures = roadmap.milestones.flatMap(
|
|
2538
|
-
(m) => m.features.map((f) => ({ ...f, milestone: m.name }))
|
|
2539
|
-
);
|
|
2540
|
-
const filter = input.filter.toLowerCase();
|
|
2541
|
-
let filtered;
|
|
2542
|
-
if (filter.startsWith("milestone:")) {
|
|
2543
|
-
const milestoneName = filter.slice("milestone:".length).trim();
|
|
2544
|
-
filtered = allFeatures.filter((f) => f.milestone.toLowerCase().includes(milestoneName));
|
|
2545
|
-
} else {
|
|
2546
|
-
filtered = allFeatures.filter((f) => f.status === filter);
|
|
2547
|
-
}
|
|
2548
|
-
return resultToMcpResponse(Ok2(filtered));
|
|
2549
|
-
}
|
|
2550
|
-
case "sync": {
|
|
2551
|
-
const raw = readRoadmapFile(projectPath);
|
|
2552
|
-
if (raw === null) {
|
|
2553
|
-
return {
|
|
2554
|
-
content: [
|
|
2555
|
-
{
|
|
2556
|
-
type: "text",
|
|
2557
|
-
text: "Error: docs/roadmap.md not found. Create a roadmap first."
|
|
2558
|
-
}
|
|
2559
|
-
],
|
|
2560
|
-
isError: true
|
|
2561
|
-
};
|
|
2562
|
-
}
|
|
2563
|
-
const result = parseRoadmap(raw);
|
|
2564
|
-
if (!result.ok) return resultToMcpResponse(result);
|
|
2565
|
-
const roadmap = result.value;
|
|
2566
|
-
const syncResult = syncRoadmap({
|
|
2567
|
-
projectPath,
|
|
2568
|
-
roadmap,
|
|
2569
|
-
forceSync: input.force_sync ?? false
|
|
2570
|
-
});
|
|
2571
|
-
if (!syncResult.ok) return resultToMcpResponse(syncResult);
|
|
2572
|
-
const changes = syncResult.value;
|
|
2573
|
-
if (changes.length === 0) {
|
|
2574
|
-
return resultToMcpResponse(Ok2({ changes: [], message: "Roadmap is up to date." }));
|
|
2575
|
-
}
|
|
2576
|
-
if (input.apply) {
|
|
2577
|
-
for (const change of changes) {
|
|
2578
|
-
for (const m of roadmap.milestones) {
|
|
2579
|
-
const feature = m.features.find(
|
|
2580
|
-
(f) => f.name.toLowerCase() === change.feature.toLowerCase()
|
|
2581
|
-
);
|
|
2582
|
-
if (feature) {
|
|
2583
|
-
feature.status = change.to;
|
|
2584
|
-
break;
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
|
|
2589
|
-
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
2590
|
-
return resultToMcpResponse(Ok2({ changes, applied: true, roadmap }));
|
|
2591
|
-
}
|
|
2592
|
-
return resultToMcpResponse(Ok2({ changes, applied: false }));
|
|
2593
|
-
}
|
|
2815
|
+
case "show":
|
|
2816
|
+
return handleShow(projectPath, input, deps);
|
|
2817
|
+
case "add":
|
|
2818
|
+
return handleAdd(projectPath, input, deps);
|
|
2819
|
+
case "update":
|
|
2820
|
+
return handleUpdate(projectPath, input, deps);
|
|
2821
|
+
case "remove":
|
|
2822
|
+
return handleRemove(projectPath, input, deps);
|
|
2823
|
+
case "query":
|
|
2824
|
+
return handleQuery(projectPath, input, deps);
|
|
2825
|
+
case "sync":
|
|
2826
|
+
return handleSync(projectPath, input, deps);
|
|
2594
2827
|
default: {
|
|
2595
2828
|
return {
|
|
2596
2829
|
content: [{ type: "text", text: `Error: unknown action` }],
|
|
@@ -2699,6 +2932,7 @@ var EmitInteractionInputSchema = z.object({
|
|
|
2699
2932
|
path: z.string().min(1),
|
|
2700
2933
|
type: InteractionTypeSchema,
|
|
2701
2934
|
stream: z.string().optional(),
|
|
2935
|
+
session: z.string().optional(),
|
|
2702
2936
|
// Uses base schema here; refined validation (recommendation required with options)
|
|
2703
2937
|
// is applied in the handler's question branch via InteractionQuestionWithOptionsSchema.
|
|
2704
2938
|
// Refined schemas with .refine() cannot be nested inside z.object().optional() reliably.
|
|
@@ -2823,6 +3057,10 @@ var emitInteractionDefinition = {
|
|
|
2823
3057
|
type: "string",
|
|
2824
3058
|
description: "State stream for recording (auto-resolves from branch if omitted)"
|
|
2825
3059
|
},
|
|
3060
|
+
session: {
|
|
3061
|
+
type: "string",
|
|
3062
|
+
description: "Session slug for session-scoped handoff (takes priority over stream when provided)"
|
|
3063
|
+
},
|
|
2826
3064
|
question: {
|
|
2827
3065
|
type: "object",
|
|
2828
3066
|
description: "Question payload (required when type is question)",
|
|
@@ -3072,7 +3310,7 @@ async function handleEmitInteraction(input) {
|
|
|
3072
3310
|
const transition = transitionResult.data;
|
|
3073
3311
|
const prompt = renderTransition(transition);
|
|
3074
3312
|
try {
|
|
3075
|
-
const { saveHandoff } = await import("./dist-
|
|
3313
|
+
const { saveHandoff } = await import("./dist-2B363XUH.js");
|
|
3076
3314
|
await saveHandoff(
|
|
3077
3315
|
projectPath,
|
|
3078
3316
|
{
|
|
@@ -3087,7 +3325,8 @@ async function handleEmitInteraction(input) {
|
|
|
3087
3325
|
blockers: [],
|
|
3088
3326
|
contextKeywords: []
|
|
3089
3327
|
},
|
|
3090
|
-
validInput.stream
|
|
3328
|
+
validInput.stream,
|
|
3329
|
+
validInput.session
|
|
3091
3330
|
);
|
|
3092
3331
|
} catch {
|
|
3093
3332
|
}
|
|
@@ -3173,7 +3412,7 @@ async function handleEmitInteraction(input) {
|
|
|
3173
3412
|
}
|
|
3174
3413
|
async function recordInteraction(projectPath, id, type, decision, stream) {
|
|
3175
3414
|
try {
|
|
3176
|
-
const { loadState, saveState } = await import("./dist-
|
|
3415
|
+
const { loadState, saveState } = await import("./dist-2B363XUH.js");
|
|
3177
3416
|
const stateResult = await loadState(projectPath, stream);
|
|
3178
3417
|
if (stateResult.ok) {
|
|
3179
3418
|
const state = stateResult.value;
|
|
@@ -3220,6 +3459,14 @@ var gatherContextDefinition = {
|
|
|
3220
3459
|
type: "string",
|
|
3221
3460
|
enum: ["summary", "detailed"],
|
|
3222
3461
|
description: "Response density. Default: summary"
|
|
3462
|
+
},
|
|
3463
|
+
learningsBudget: {
|
|
3464
|
+
type: "number",
|
|
3465
|
+
description: "Token budget for learnings slice (default 1000). Separate from graph tokenBudget."
|
|
3466
|
+
},
|
|
3467
|
+
session: {
|
|
3468
|
+
type: "string",
|
|
3469
|
+
description: "Session slug for session-scoped state. When provided, state/learnings/handoff/failures are read from .harness/sessions/<session>/ instead of .harness/. Omit for global fallback."
|
|
3223
3470
|
}
|
|
3224
3471
|
},
|
|
3225
3472
|
required: ["path", "intent"]
|
|
@@ -3245,16 +3492,25 @@ async function handleGatherContext(input) {
|
|
|
3245
3492
|
input.include ?? ["state", "learnings", "handoff", "graph", "validation"]
|
|
3246
3493
|
);
|
|
3247
3494
|
const errors = [];
|
|
3248
|
-
const statePromise = includeSet.has("state") ? import("./dist-
|
|
3249
|
-
|
|
3250
|
-
|
|
3495
|
+
const statePromise = includeSet.has("state") ? import("./dist-2B363XUH.js").then(
|
|
3496
|
+
(core) => core.loadState(projectPath, void 0, input.session)
|
|
3497
|
+
) : Promise.resolve(null);
|
|
3498
|
+
const learningsPromise = includeSet.has("learnings") ? import("./dist-2B363XUH.js").then(
|
|
3499
|
+
(core) => core.loadBudgetedLearnings(projectPath, {
|
|
3500
|
+
intent: input.intent,
|
|
3501
|
+
tokenBudget: input.learningsBudget ?? 1e3,
|
|
3502
|
+
...input.skill !== void 0 && { skill: input.skill },
|
|
3503
|
+
...input.session !== void 0 && { session: input.session }
|
|
3504
|
+
})
|
|
3505
|
+
) : Promise.resolve(null);
|
|
3506
|
+
const handoffPromise = includeSet.has("handoff") ? import("./dist-2B363XUH.js").then(
|
|
3507
|
+
(core) => core.loadHandoff(projectPath, void 0, input.session)
|
|
3251
3508
|
) : Promise.resolve(null);
|
|
3252
|
-
const handoffPromise = includeSet.has("handoff") ? import("./dist-IJ4J4C5G.js").then((core) => core.loadHandoff(projectPath)) : Promise.resolve(null);
|
|
3253
3509
|
const graphPromise = includeSet.has("graph") ? (async () => {
|
|
3254
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
3510
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-GJZ4FN4Y.js");
|
|
3255
3511
|
const store = await loadGraphStore2(projectPath);
|
|
3256
3512
|
if (!store) return null;
|
|
3257
|
-
const { FusionLayer, ContextQL } = await import("./dist-
|
|
3513
|
+
const { FusionLayer, ContextQL } = await import("./dist-HXHWB7SV.js");
|
|
3258
3514
|
const fusion = new FusionLayer(store);
|
|
3259
3515
|
const cql = new ContextQL(store);
|
|
3260
3516
|
const tokenBudget = input.tokenBudget ?? 4e3;
|
|
@@ -3292,7 +3548,7 @@ async function handleGatherContext(input) {
|
|
|
3292
3548
|
};
|
|
3293
3549
|
})() : Promise.resolve(null);
|
|
3294
3550
|
const validationPromise = includeSet.has("validation") ? (async () => {
|
|
3295
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
3551
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-GCHZJIL7.js");
|
|
3296
3552
|
const result = await handleValidateProject2({ path: projectPath });
|
|
3297
3553
|
const first = result.content[0];
|
|
3298
3554
|
return first ? JSON.parse(first.text) : null;
|
|
@@ -3364,6 +3620,17 @@ async function handleGatherContext(input) {
|
|
|
3364
3620
|
errors
|
|
3365
3621
|
}
|
|
3366
3622
|
};
|
|
3623
|
+
if (input.session) {
|
|
3624
|
+
try {
|
|
3625
|
+
const core = await import("./dist-2B363XUH.js");
|
|
3626
|
+
core.updateSessionIndex(
|
|
3627
|
+
projectPath,
|
|
3628
|
+
input.session,
|
|
3629
|
+
`${input.skill ?? "unknown"} \u2014 ${input.intent}`
|
|
3630
|
+
);
|
|
3631
|
+
} catch {
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3367
3634
|
const outputText = JSON.stringify(output);
|
|
3368
3635
|
const tokenEstimate = Math.ceil(outputText.length / 4);
|
|
3369
3636
|
output.meta.tokenEstimate = tokenEstimate;
|
|
@@ -3425,7 +3692,7 @@ async function handleAssessProject(input) {
|
|
|
3425
3692
|
let validateResult = null;
|
|
3426
3693
|
if (checksToRun.has("validate")) {
|
|
3427
3694
|
try {
|
|
3428
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
3695
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-GCHZJIL7.js");
|
|
3429
3696
|
const result = await handleValidateProject2({ path: projectPath });
|
|
3430
3697
|
const first = result.content[0];
|
|
3431
3698
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3450,7 +3717,7 @@ async function handleAssessProject(input) {
|
|
|
3450
3717
|
parallelChecks.push(
|
|
3451
3718
|
(async () => {
|
|
3452
3719
|
try {
|
|
3453
|
-
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-
|
|
3720
|
+
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-2R5Z4ZAF.js");
|
|
3454
3721
|
const result = await handleCheckDependencies2({ path: projectPath });
|
|
3455
3722
|
const first = result.content[0];
|
|
3456
3723
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3477,7 +3744,7 @@ async function handleAssessProject(input) {
|
|
|
3477
3744
|
parallelChecks.push(
|
|
3478
3745
|
(async () => {
|
|
3479
3746
|
try {
|
|
3480
|
-
const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-
|
|
3747
|
+
const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-FZOPM4GK.js");
|
|
3481
3748
|
const result = await handleCheckDocs2({ path: projectPath, scope: "coverage" });
|
|
3482
3749
|
const first = result.content[0];
|
|
3483
3750
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3504,7 +3771,7 @@ async function handleAssessProject(input) {
|
|
|
3504
3771
|
parallelChecks.push(
|
|
3505
3772
|
(async () => {
|
|
3506
3773
|
try {
|
|
3507
|
-
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-
|
|
3774
|
+
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-LVHJMFGH.js");
|
|
3508
3775
|
const result = await handleDetectEntropy2({ path: projectPath, type: "all" });
|
|
3509
3776
|
const first = result.content[0];
|
|
3510
3777
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3531,7 +3798,7 @@ async function handleAssessProject(input) {
|
|
|
3531
3798
|
parallelChecks.push(
|
|
3532
3799
|
(async () => {
|
|
3533
3800
|
try {
|
|
3534
|
-
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-
|
|
3801
|
+
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-FWQZF2IZ.js");
|
|
3535
3802
|
const result = await handleRunSecurityScan2({ path: projectPath });
|
|
3536
3803
|
const first = result.content[0];
|
|
3537
3804
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3563,7 +3830,7 @@ async function handleAssessProject(input) {
|
|
|
3563
3830
|
parallelChecks.push(
|
|
3564
3831
|
(async () => {
|
|
3565
3832
|
try {
|
|
3566
|
-
const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-
|
|
3833
|
+
const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-ZTVSUANN.js");
|
|
3567
3834
|
const result = await handleCheckPerformance2({ path: projectPath });
|
|
3568
3835
|
const first = result.content[0];
|
|
3569
3836
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3738,7 +4005,7 @@ async function handleReviewChanges(input) {
|
|
|
3738
4005
|
}
|
|
3739
4006
|
try {
|
|
3740
4007
|
if (effectiveDepth === "quick") {
|
|
3741
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-
|
|
4008
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-IHLVLMRD.js");
|
|
3742
4009
|
const result2 = await handleAnalyzeDiff2({ diff, path: projectPath });
|
|
3743
4010
|
const firstContent = result2.content[0];
|
|
3744
4011
|
if (!firstContent) throw new Error("Empty analyze_diff response");
|
|
@@ -3760,7 +4027,7 @@ async function handleReviewChanges(input) {
|
|
|
3760
4027
|
};
|
|
3761
4028
|
}
|
|
3762
4029
|
if (effectiveDepth === "standard") {
|
|
3763
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-
|
|
4030
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-IHLVLMRD.js");
|
|
3764
4031
|
const [diffResult, reviewResult] = await Promise.all([
|
|
3765
4032
|
handleAnalyzeDiff2({ diff, path: projectPath }),
|
|
3766
4033
|
handleCreateSelfReview2({ path: projectPath, diff })
|
|
@@ -3791,7 +4058,7 @@ async function handleReviewChanges(input) {
|
|
|
3791
4058
|
]
|
|
3792
4059
|
};
|
|
3793
4060
|
}
|
|
3794
|
-
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-
|
|
4061
|
+
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-76JHKGSV.js");
|
|
3795
4062
|
const result = await handleRunCodeReview2({ path: projectPath, diff });
|
|
3796
4063
|
const deepContent = result.content[0];
|
|
3797
4064
|
if (!deepContent) throw new Error("Empty code review response");
|
|
@@ -3868,7 +4135,7 @@ async function handleCheckTaskIndependence(input) {
|
|
|
3868
4135
|
try {
|
|
3869
4136
|
const projectPath = sanitizePath(input.path);
|
|
3870
4137
|
const store = await loadGraphStore(projectPath);
|
|
3871
|
-
const { TaskIndependenceAnalyzer } = await import("./dist-
|
|
4138
|
+
const { TaskIndependenceAnalyzer } = await import("./dist-HXHWB7SV.js");
|
|
3872
4139
|
const analyzer = new TaskIndependenceAnalyzer(store ?? void 0);
|
|
3873
4140
|
const result = analyzer.analyze({
|
|
3874
4141
|
tasks: input.tasks,
|
|
@@ -3956,7 +4223,7 @@ async function handlePredictConflicts(input) {
|
|
|
3956
4223
|
try {
|
|
3957
4224
|
const projectPath = sanitizePath(input.path);
|
|
3958
4225
|
const store = await loadGraphStore(projectPath);
|
|
3959
|
-
const { ConflictPredictor } = await import("./dist-
|
|
4226
|
+
const { ConflictPredictor } = await import("./dist-HXHWB7SV.js");
|
|
3960
4227
|
const predictor = new ConflictPredictor(store ?? void 0);
|
|
3961
4228
|
const result = predictor.predict({
|
|
3962
4229
|
tasks: input.tasks,
|
|
@@ -4062,7 +4329,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
4062
4329
|
isError: true
|
|
4063
4330
|
};
|
|
4064
4331
|
}
|
|
4065
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
4332
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-GJZ4FN4Y.js");
|
|
4066
4333
|
const store = await loadGraphStore2(projectPath);
|
|
4067
4334
|
if (!store) {
|
|
4068
4335
|
return {
|
|
@@ -4083,7 +4350,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
4083
4350
|
]
|
|
4084
4351
|
};
|
|
4085
4352
|
}
|
|
4086
|
-
const { detectStaleConstraints } = await import("./dist-
|
|
4353
|
+
const { detectStaleConstraints } = await import("./dist-2B363XUH.js");
|
|
4087
4354
|
const result = detectStaleConstraints(
|
|
4088
4355
|
store,
|
|
4089
4356
|
windowDays,
|
|
@@ -4110,6 +4377,76 @@ async function handleDetectStaleConstraints(input) {
|
|
|
4110
4377
|
}
|
|
4111
4378
|
}
|
|
4112
4379
|
|
|
4380
|
+
// src/mcp/tools/search-skills.ts
|
|
4381
|
+
var searchSkillsDefinition = {
|
|
4382
|
+
name: "search_skills",
|
|
4383
|
+
description: "Search the skill catalog for domain-specific skills. Returns ranked results based on keyword and stack-signal matching. Use this to discover catalog skills that are not loaded as slash commands.",
|
|
4384
|
+
inputSchema: {
|
|
4385
|
+
type: "object",
|
|
4386
|
+
properties: {
|
|
4387
|
+
query: {
|
|
4388
|
+
type: "string",
|
|
4389
|
+
description: "Natural language or keyword query to search for skills"
|
|
4390
|
+
},
|
|
4391
|
+
path: {
|
|
4392
|
+
type: "string",
|
|
4393
|
+
description: "Project root path (defaults to cwd)"
|
|
4394
|
+
},
|
|
4395
|
+
platform: {
|
|
4396
|
+
type: "string",
|
|
4397
|
+
enum: ["claude-code", "gemini-cli"],
|
|
4398
|
+
description: "Target platform (defaults to claude-code)"
|
|
4399
|
+
}
|
|
4400
|
+
},
|
|
4401
|
+
required: ["query"]
|
|
4402
|
+
}
|
|
4403
|
+
};
|
|
4404
|
+
async function handleSearchSkills(input) {
|
|
4405
|
+
const query = input.query;
|
|
4406
|
+
const projectRoot = input.path || process.cwd();
|
|
4407
|
+
const platform = input.platform || "claude-code";
|
|
4408
|
+
const configResult = resolveConfig();
|
|
4409
|
+
const tierOverrides = configResult.ok ? configResult.value.skills?.tierOverrides : void 0;
|
|
4410
|
+
const index = loadOrRebuildIndex(platform, projectRoot, tierOverrides);
|
|
4411
|
+
const profile = loadOrGenerateProfile(projectRoot);
|
|
4412
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
4413
|
+
const results = [];
|
|
4414
|
+
for (const [name, entry] of Object.entries(index.skills)) {
|
|
4415
|
+
const matchedKeywords = entry.keywords.filter(
|
|
4416
|
+
(kw) => queryTerms.some(
|
|
4417
|
+
(term) => kw.toLowerCase().includes(term.toLowerCase()) || term.toLowerCase().includes(kw.toLowerCase())
|
|
4418
|
+
)
|
|
4419
|
+
);
|
|
4420
|
+
const keywordScore = queryTerms.length > 0 ? matchedKeywords.length / queryTerms.length : 0;
|
|
4421
|
+
let stackScore = 0;
|
|
4422
|
+
if (entry.stackSignals.length > 0) {
|
|
4423
|
+
const matchedSignals = entry.stackSignals.filter((signal) => profile.signals[signal]);
|
|
4424
|
+
stackScore = matchedSignals.length / entry.stackSignals.length;
|
|
4425
|
+
}
|
|
4426
|
+
const score = 0.6 * keywordScore + 0.4 * stackScore;
|
|
4427
|
+
if (score > 0 || queryTerms.length === 0) {
|
|
4428
|
+
results.push({
|
|
4429
|
+
name,
|
|
4430
|
+
description: entry.description,
|
|
4431
|
+
keywords: entry.keywords,
|
|
4432
|
+
phases: entry.phases,
|
|
4433
|
+
score: Math.round(score * 100) / 100,
|
|
4434
|
+
source: entry.source
|
|
4435
|
+
});
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
results.sort((a, b) => b.score - a.score);
|
|
4439
|
+
const top5 = results.slice(0, 5);
|
|
4440
|
+
return {
|
|
4441
|
+
content: [
|
|
4442
|
+
{
|
|
4443
|
+
type: "text",
|
|
4444
|
+
text: JSON.stringify({ results: top5 }, null, 2)
|
|
4445
|
+
}
|
|
4446
|
+
]
|
|
4447
|
+
};
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4113
4450
|
// src/mcp/server.ts
|
|
4114
4451
|
var TOOL_DEFINITIONS = [
|
|
4115
4452
|
validateToolDefinition,
|
|
@@ -4156,7 +4493,8 @@ var TOOL_DEFINITIONS = [
|
|
|
4156
4493
|
askGraphDefinition,
|
|
4157
4494
|
checkTaskIndependenceDefinition,
|
|
4158
4495
|
predictConflictsDefinition,
|
|
4159
|
-
detectStaleConstraintsDefinition
|
|
4496
|
+
detectStaleConstraintsDefinition,
|
|
4497
|
+
searchSkillsDefinition
|
|
4160
4498
|
];
|
|
4161
4499
|
var TOOL_HANDLERS = {
|
|
4162
4500
|
validate_project: handleValidateProject,
|
|
@@ -4203,7 +4541,8 @@ var TOOL_HANDLERS = {
|
|
|
4203
4541
|
ask_graph: handleAskGraph,
|
|
4204
4542
|
check_task_independence: handleCheckTaskIndependence,
|
|
4205
4543
|
predict_conflicts: handlePredictConflicts,
|
|
4206
|
-
detect_stale_constraints: handleDetectStaleConstraints
|
|
4544
|
+
detect_stale_constraints: handleDetectStaleConstraints,
|
|
4545
|
+
search_skills: handleSearchSkills
|
|
4207
4546
|
};
|
|
4208
4547
|
var RESOURCE_DEFINITIONS = [
|
|
4209
4548
|
{
|
|
@@ -4294,7 +4633,7 @@ function createHarnessServer(projectRoot) {
|
|
|
4294
4633
|
shouldRunCheck,
|
|
4295
4634
|
readCheckState,
|
|
4296
4635
|
spawnBackgroundCheck
|
|
4297
|
-
} = await import("./dist-
|
|
4636
|
+
} = await import("./dist-2B363XUH.js");
|
|
4298
4637
|
const { CLI_VERSION: version } = await import("./version-KFFPOQAX.js");
|
|
4299
4638
|
let CLI_VERSION = version;
|
|
4300
4639
|
let configInterval;
|