@harness-engineering/cli 1.26.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/README.md +1 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +3 -1
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +3 -1
- package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +55 -24
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +49 -10
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +21 -6
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-debugging/SKILL.md +13 -1
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +22 -6
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-integration/SKILL.md +560 -0
- package/dist/agents/skills/claude-code/harness-integration/skill.yaml +65 -0
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +9 -7
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +102 -11
- package/dist/agents/skills/claude-code/harness-refactoring/SKILL.md +13 -4
- package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +3 -1
- package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/harness-tdd/SKILL.md +5 -2
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +22 -6
- package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +2 -1
- package/dist/agents/skills/claude-code/initialize-test-suite-project/SKILL.md +415 -0
- package/dist/agents/skills/claude-code/initialize-test-suite-project/skill.yaml +35 -0
- package/dist/agents/skills/codex/cleanup-dead-code/SKILL.md +3 -1
- package/dist/agents/skills/codex/detect-doc-drift/SKILL.md +3 -1
- package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +4 -0
- package/dist/agents/skills/codex/harness-autopilot/SKILL.md +55 -24
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +49 -10
- package/dist/agents/skills/codex/harness-code-review/SKILL.md +21 -6
- package/dist/agents/skills/codex/harness-codebase-cleanup/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-debugging/SKILL.md +13 -1
- package/dist/agents/skills/codex/harness-dependency-health/SKILL.md +4 -0
- package/dist/agents/skills/codex/harness-execution/SKILL.md +22 -6
- package/dist/agents/skills/codex/harness-impact-analysis/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-integration/SKILL.md +560 -0
- package/dist/agents/skills/codex/harness-integration/skill.yaml +65 -0
- package/dist/agents/skills/codex/harness-integrity/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-onboarding/SKILL.md +4 -0
- package/dist/agents/skills/codex/harness-perf/SKILL.md +9 -7
- package/dist/agents/skills/codex/harness-planning/SKILL.md +102 -11
- package/dist/agents/skills/codex/harness-refactoring/SKILL.md +13 -4
- package/dist/agents/skills/codex/harness-security-scan/SKILL.md +3 -1
- package/dist/agents/skills/codex/harness-soundness-review/SKILL.md +4 -0
- package/dist/agents/skills/codex/harness-tdd/SKILL.md +5 -2
- package/dist/agents/skills/codex/harness-verification/SKILL.md +4 -0
- package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +22 -6
- package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +2 -1
- package/dist/agents/skills/codex/initialize-test-suite-project/SKILL.md +415 -0
- package/dist/agents/skills/codex/initialize-test-suite-project/skill.yaml +35 -0
- package/dist/agents/skills/cursor/cleanup-dead-code/SKILL.md +3 -1
- package/dist/agents/skills/cursor/detect-doc-drift/SKILL.md +3 -1
- package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +4 -0
- package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +55 -24
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +49 -10
- package/dist/agents/skills/cursor/harness-code-review/SKILL.md +21 -6
- package/dist/agents/skills/cursor/harness-codebase-cleanup/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-debugging/SKILL.md +13 -1
- package/dist/agents/skills/cursor/harness-dependency-health/SKILL.md +4 -0
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +22 -6
- package/dist/agents/skills/cursor/harness-impact-analysis/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-integration/SKILL.md +560 -0
- package/dist/agents/skills/cursor/harness-integration/skill.yaml +65 -0
- package/dist/agents/skills/cursor/harness-integrity/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-onboarding/SKILL.md +4 -0
- package/dist/agents/skills/cursor/harness-perf/SKILL.md +9 -7
- package/dist/agents/skills/cursor/harness-planning/SKILL.md +102 -11
- package/dist/agents/skills/cursor/harness-refactoring/SKILL.md +13 -4
- package/dist/agents/skills/cursor/harness-security-scan/SKILL.md +3 -1
- package/dist/agents/skills/cursor/harness-soundness-review/SKILL.md +4 -0
- package/dist/agents/skills/cursor/harness-tdd/SKILL.md +5 -2
- package/dist/agents/skills/cursor/harness-verification/SKILL.md +4 -0
- package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +22 -6
- package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +2 -1
- package/dist/agents/skills/cursor/initialize-test-suite-project/SKILL.md +415 -0
- package/dist/agents/skills/cursor/initialize-test-suite-project/skill.yaml +35 -0
- package/dist/agents/skills/gemini-cli/cleanup-dead-code/SKILL.md +3 -1
- package/dist/agents/skills/gemini-cli/detect-doc-drift/SKILL.md +3 -1
- package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +55 -24
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +49 -10
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +21 -6
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-debugging/SKILL.md +13 -1
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +22 -6
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-integration/SKILL.md +560 -0
- package/dist/agents/skills/gemini-cli/harness-integration/skill.yaml +65 -0
- package/dist/agents/skills/gemini-cli/harness-integrity/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-onboarding/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +9 -7
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +102 -11
- package/dist/agents/skills/gemini-cli/harness-refactoring/SKILL.md +13 -4
- package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +3 -1
- package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/harness-tdd/SKILL.md +5 -2
- package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +22 -6
- package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +2 -1
- package/dist/agents/skills/gemini-cli/initialize-test-suite-project/SKILL.md +415 -0
- package/dist/agents/skills/gemini-cli/initialize-test-suite-project/skill.yaml +35 -0
- package/dist/agents/skills/tests/initialize-test-suite-project.test.ts +152 -0
- package/dist/{agents-md-OPOZA5L7.js → agents-md-2RN666DE.js} +3 -3
- package/dist/{architecture-PMVMO6SF.js → architecture-ZR33YKJB.js} +4 -4
- package/dist/{assess-project-ZW7EKNIT.js → assess-project-LLWWEQEV.js} +1 -1
- package/dist/bin/harness-mcp.js +18 -16
- package/dist/bin/harness.js +29 -28
- package/dist/{business-knowledge-6RHYJOB3.js → business-knowledge-EISPR7FU.js} +1 -1
- package/dist/{check-phase-gate-NTLAU3LO.js → check-phase-gate-ZVG56NT2.js} +4 -4
- package/dist/chunk-27AJKSQY.js +107 -0
- package/dist/{chunk-G6SYTGOH.js → chunk-2FOLD76X.js} +2 -2
- package/dist/{chunk-IFHAUFJX.js → chunk-3AJW7VQ3.js} +2 -2
- package/dist/{chunk-KXIAHHHP.js → chunk-3XMOWLK3.js} +2 -2
- package/dist/{chunk-Z2JORLRT.js → chunk-776JFSPK.js} +1 -1
- package/dist/{chunk-4KSKV5MK.js → chunk-A4ETL34H.js} +7 -2
- package/dist/{chunk-JWSVLC4I.js → chunk-BO4AJZRE.js} +1 -1
- package/dist/{chunk-UBRD5FH4.js → chunk-BZZNYHRY.js} +9 -9
- package/dist/{chunk-6SCA4NEZ.js → chunk-C7RPQWBG.js} +1 -1
- package/dist/{chunk-NVGQO4VM.js → chunk-CJYNZMOP.js} +8 -8
- package/dist/{chunk-7JNZXJKY.js → chunk-EGRQHLDM.js} +5 -5
- package/dist/{chunk-EXTWTJRF.js → chunk-EICASBYP.js} +1 -1
- package/dist/{chunk-RNAGPTKF.js → chunk-F3Y64VNF.js} +6 -6
- package/dist/{chunk-HAOBHL3W.js → chunk-FUS4OOGC.js} +1 -1
- package/dist/{chunk-VV2PJT4K.js → chunk-GAIOIINV.js} +1353 -707
- package/dist/{chunk-77EZGPSR.js → chunk-IBTHD2UA.js} +139 -78
- package/dist/{chunk-RC5ZY3EV.js → chunk-IOW3MW2K.js} +2 -2
- package/dist/{chunk-JZ6GORAK.js → chunk-L3Y7L4EG.js} +1 -1
- package/dist/{chunk-KFE2X7LG.js → chunk-MGPVA2EM.js} +27 -4
- package/dist/{chunk-JBJ4AVE4.js → chunk-Q5DKIL46.js} +3 -3
- package/dist/{chunk-NIOB6FTG.js → chunk-QTXW5TIS.js} +1 -1
- package/dist/{chunk-ZBQ3ZY75.js → chunk-SA57FVGX.js} +100 -60
- package/dist/{chunk-KSFUJT5B.js → chunk-SDDQPMZK.js} +1 -1
- package/dist/{chunk-QYSWNPXZ.js → chunk-SDPHFDQS.js} +1 -1
- package/dist/{chunk-FI3D6D7U.js → chunk-T7UZOJF4.js} +9 -9
- package/dist/{chunk-CAS3TS4Y.js → chunk-TCMVZ3B7.js} +1142 -348
- package/dist/{chunk-J3O64D2A.js → chunk-YZH4I4JO.js} +1 -1
- package/dist/{ci-workflow-H52EMCL6.js → ci-workflow-JFOL4YWW.js} +3 -3
- package/dist/{create-skill-6QWJHQYS.js → create-skill-4T5CBSJ2.js} +2 -2
- package/dist/{dist-PGQ32ZI7.js → dist-BZS2XRLG.js} +5 -1
- package/dist/{dist-TG63OKA5.js → dist-CPKL5Y2R.js} +2 -2
- package/dist/{docs-GP4VUSIB.js → docs-FUTRJQHA.js} +4 -4
- package/dist/{engine-KQG5RVXX.js → engine-FB3HCNVT.js} +3 -3
- package/dist/{entropy-RXESIYKC.js → entropy-FIEE4YDA.js} +3 -3
- package/dist/{feedback-HS7ZYXOU.js → feedback-7EC4T6XG.js} +1 -1
- package/dist/{generate-agent-definitions-I4B7CVOB.js → generate-agent-definitions-FOSFADNR.js} +4 -4
- package/dist/{graph-loader-TIVI6NQ7.js → graph-loader-QEI7SYOQ.js} +1 -1
- package/dist/hooks/adoption-tracker.js +36 -8
- package/dist/hooks/sentinel-pre.js +3 -2
- package/dist/hooks/telemetry-reporter.js +34 -15
- package/dist/index-builder-3AOQ3ZII.js +13 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +31 -30
- package/dist/{loader-CWAH6B4H.js → loader-HXUOBTYA.js} +3 -3
- package/dist/mcp-ICXMTAD3.js +41 -0
- package/dist/{performance-WDW5WS3J.js → performance-TYXBCTR7.js} +4 -4
- package/dist/{review-pipeline-QOZGWCTY.js → review-pipeline-B4WPU6BQ.js} +3 -3
- package/dist/{runtime-SFEFRPLX.js → runtime-HQQNOARD.js} +3 -3
- package/dist/{scan-IJ7EYTF7.js → scan-TX55R6QS.js} +1 -1
- package/dist/{security-2K7UUK6T.js → security-25VFLIAO.js} +1 -1
- package/dist/templates/orchestrator/harness.orchestrator.md +18 -8
- package/dist/{validate-HXM6DXRZ.js → validate-EAVGKZQB.js} +4 -4
- package/dist/{validate-cross-check-ULQLEOME.js → validate-cross-check-SPL3H4O5.js} +3 -3
- package/package.json +14 -6
- package/dist/agents/commands/claude-code/harness/harness.md +0 -36
- package/dist/agents/commands/codex/AGENTS.md +0 -39
- package/dist/agents/commands/codex/harness/add-harness-component/SKILL.md +0 -204
- package/dist/agents/commands/codex/harness/add-harness-component/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/cleanup-dead-code/SKILL.md +0 -257
- package/dist/agents/commands/codex/harness/cleanup-dead-code/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/detect-doc-drift/SKILL.md +0 -191
- package/dist/agents/commands/codex/harness/detect-doc-drift/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/enforce-architecture/SKILL.md +0 -289
- package/dist/agents/commands/codex/harness/enforce-architecture/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-architecture-advisor/SKILL.md +0 -442
- package/dist/agents/commands/codex/harness/harness-architecture-advisor/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-autopilot/SKILL.md +0 -929
- package/dist/agents/commands/codex/harness/harness-autopilot/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-brainstorming/SKILL.md +0 -418
- package/dist/agents/commands/codex/harness/harness-brainstorming/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-code-review/SKILL.md +0 -850
- package/dist/agents/commands/codex/harness/harness-code-review/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-codebase-cleanup/SKILL.md +0 -236
- package/dist/agents/commands/codex/harness/harness-codebase-cleanup/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-debugging/SKILL.md +0 -378
- package/dist/agents/commands/codex/harness/harness-debugging/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-dependency-health/SKILL.md +0 -190
- package/dist/agents/commands/codex/harness/harness-dependency-health/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-docs-pipeline/SKILL.md +0 -472
- package/dist/agents/commands/codex/harness/harness-docs-pipeline/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-execution/SKILL.md +0 -522
- package/dist/agents/commands/codex/harness/harness-execution/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-hotspot-detector/SKILL.md +0 -172
- package/dist/agents/commands/codex/harness/harness-hotspot-detector/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-impact-analysis/SKILL.md +0 -195
- package/dist/agents/commands/codex/harness/harness-impact-analysis/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-integrity/SKILL.md +0 -178
- package/dist/agents/commands/codex/harness/harness-integrity/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-onboarding/SKILL.md +0 -299
- package/dist/agents/commands/codex/harness/harness-onboarding/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-perf/SKILL.md +0 -272
- package/dist/agents/commands/codex/harness/harness-perf/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-planning/SKILL.md +0 -592
- package/dist/agents/commands/codex/harness/harness-planning/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-refactoring/SKILL.md +0 -181
- package/dist/agents/commands/codex/harness/harness-refactoring/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-release-readiness/SKILL.md +0 -701
- package/dist/agents/commands/codex/harness/harness-release-readiness/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-roadmap/SKILL.md +0 -607
- package/dist/agents/commands/codex/harness/harness-roadmap/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-security-scan/SKILL.md +0 -147
- package/dist/agents/commands/codex/harness/harness-security-scan/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-skill-authoring/SKILL.md +0 -314
- package/dist/agents/commands/codex/harness/harness-skill-authoring/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-soundness-review/SKILL.md +0 -1280
- package/dist/agents/commands/codex/harness/harness-soundness-review/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-supply-chain-audit/SKILL.md +0 -255
- package/dist/agents/commands/codex/harness/harness-supply-chain-audit/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-tdd/SKILL.md +0 -189
- package/dist/agents/commands/codex/harness/harness-tdd/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-test-advisor/SKILL.md +0 -171
- package/dist/agents/commands/codex/harness/harness-test-advisor/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-verification/SKILL.md +0 -433
- package/dist/agents/commands/codex/harness/harness-verification/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/harness-verify/SKILL.md +0 -170
- package/dist/agents/commands/codex/harness/harness-verify/agents/openai.yaml +0 -3
- package/dist/agents/commands/codex/harness/initialize-harness-project/SKILL.md +0 -244
- package/dist/agents/commands/codex/harness/initialize-harness-project/agents/openai.yaml +0 -3
- package/dist/agents/commands/cursor/harness/add-harness-component.mdc +0 -200
- package/dist/agents/commands/cursor/harness/cleanup-dead-code.mdc +0 -253
- package/dist/agents/commands/cursor/harness/detect-doc-drift.mdc +0 -187
- package/dist/agents/commands/cursor/harness/enforce-architecture.mdc +0 -304
- package/dist/agents/commands/cursor/harness/harness-architecture-advisor.mdc +0 -457
- package/dist/agents/commands/cursor/harness/harness-autopilot.mdc +0 -924
- package/dist/agents/commands/cursor/harness/harness-brainstorming.mdc +0 -414
- package/dist/agents/commands/cursor/harness/harness-code-review.mdc +0 -865
- package/dist/agents/commands/cursor/harness/harness-codebase-cleanup.mdc +0 -232
- package/dist/agents/commands/cursor/harness/harness-debugging.mdc +0 -374
- package/dist/agents/commands/cursor/harness/harness-dependency-health.mdc +0 -187
- package/dist/agents/commands/cursor/harness/harness-docs-pipeline.mdc +0 -468
- package/dist/agents/commands/cursor/harness/harness-execution.mdc +0 -518
- package/dist/agents/commands/cursor/harness/harness-hotspot-detector.mdc +0 -169
- package/dist/agents/commands/cursor/harness/harness-impact-analysis.mdc +0 -192
- package/dist/agents/commands/cursor/harness/harness-integrity.mdc +0 -175
- package/dist/agents/commands/cursor/harness/harness-onboarding.mdc +0 -296
- package/dist/agents/commands/cursor/harness/harness-perf.mdc +0 -268
- package/dist/agents/commands/cursor/harness/harness-planning.mdc +0 -587
- package/dist/agents/commands/cursor/harness/harness-refactoring.mdc +0 -177
- package/dist/agents/commands/cursor/harness/harness-release-readiness.mdc +0 -697
- package/dist/agents/commands/cursor/harness/harness-roadmap.mdc +0 -603
- package/dist/agents/commands/cursor/harness/harness-security-scan.mdc +0 -162
- package/dist/agents/commands/cursor/harness/harness-skill-authoring.mdc +0 -300
- package/dist/agents/commands/cursor/harness/harness-soundness-review.mdc +0 -1275
- package/dist/agents/commands/cursor/harness/harness-supply-chain-audit.mdc +0 -252
- package/dist/agents/commands/cursor/harness/harness-tdd.mdc +0 -185
- package/dist/agents/commands/cursor/harness/harness-test-advisor.mdc +0 -168
- package/dist/agents/commands/cursor/harness/harness-verification.mdc +0 -429
- package/dist/agents/commands/cursor/harness/harness-verify.mdc +0 -167
- package/dist/agents/commands/cursor/harness/initialize-harness-project.mdc +0 -240
- package/dist/agents/commands/gemini-cli/harness/harness.toml +0 -277
- package/dist/hooks/profiles.ts +0 -48
- package/dist/mcp-KHK5KYER.js +0 -39
- package/dist/{chunk-RRHUCDRD.js → chunk-ZP5E7YET.js} +3 -3
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleRunCodeReview,
|
|
3
|
+
runCodeReviewDefinition,
|
|
4
|
+
sortFindingsBySeverity
|
|
5
|
+
} from "./chunk-2FOLD76X.js";
|
|
1
6
|
import {
|
|
2
7
|
assessProjectDefinition,
|
|
3
8
|
handleAssessProject
|
|
4
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-F3Y64VNF.js";
|
|
5
10
|
import {
|
|
6
11
|
getBusinessKnowledgeResource
|
|
7
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IOW3MW2K.js";
|
|
8
13
|
import {
|
|
9
14
|
analyzeDiffDefinition,
|
|
10
15
|
createSelfReviewDefinition,
|
|
@@ -12,37 +17,35 @@ import {
|
|
|
12
17
|
handleCreateSelfReview,
|
|
13
18
|
handleRequestPeerReview,
|
|
14
19
|
requestPeerReviewDefinition
|
|
15
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-BZZNYHRY.js";
|
|
16
21
|
import {
|
|
17
22
|
getSecurityTrendsDefinition,
|
|
18
23
|
handleGetSecurityTrends,
|
|
19
24
|
handleRunSecurityScan,
|
|
20
25
|
runSecurityScanDefinition
|
|
21
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-3AJW7VQ3.js";
|
|
22
27
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
sortFindingsBySeverity
|
|
26
|
-
} from "./chunk-G6SYTGOH.js";
|
|
28
|
+
loadGraphStore
|
|
29
|
+
} from "./chunk-776JFSPK.js";
|
|
27
30
|
import {
|
|
28
31
|
handleValidateProject,
|
|
29
32
|
validateToolDefinition
|
|
30
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-Q5DKIL46.js";
|
|
31
34
|
import {
|
|
32
35
|
checkDependenciesDefinition,
|
|
33
36
|
handleCheckDependencies
|
|
34
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-MGPVA2EM.js";
|
|
35
38
|
import {
|
|
36
39
|
resolveProjectConfig
|
|
37
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-YZH4I4JO.js";
|
|
38
41
|
import {
|
|
39
42
|
checkDocsDefinition,
|
|
40
43
|
handleCheckDocs
|
|
41
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-T7UZOJF4.js";
|
|
42
45
|
import {
|
|
43
46
|
detectEntropyDefinition,
|
|
44
47
|
handleDetectEntropy
|
|
45
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-EGRQHLDM.js";
|
|
46
49
|
import {
|
|
47
50
|
checkPerformanceDefinition,
|
|
48
51
|
getCriticalPathsDefinition,
|
|
@@ -52,16 +55,19 @@ import {
|
|
|
52
55
|
handleGetPerfBaselines,
|
|
53
56
|
handleUpdatePerfBaselines,
|
|
54
57
|
updatePerfBaselinesDefinition
|
|
55
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-CJYNZMOP.js";
|
|
56
59
|
import {
|
|
57
60
|
resultToMcpResponse
|
|
58
61
|
} from "./chunk-EPUKTTJZ.js";
|
|
59
62
|
import {
|
|
60
63
|
sanitizePath
|
|
61
64
|
} from "./chunk-W6Y7ZW3Y.js";
|
|
65
|
+
import {
|
|
66
|
+
loadOrRebuildIndex
|
|
67
|
+
} from "./chunk-27AJKSQY.js";
|
|
62
68
|
import {
|
|
63
69
|
resolveConfig
|
|
64
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-A4ETL34H.js";
|
|
65
71
|
import {
|
|
66
72
|
GENERATED_HEADER_CLAUDE,
|
|
67
73
|
GENERATED_HEADER_CODEX,
|
|
@@ -72,7 +78,6 @@ import {
|
|
|
72
78
|
computeSyncPlan
|
|
73
79
|
} from "./chunk-3ISINLYT.js";
|
|
74
80
|
import {
|
|
75
|
-
resolveAllSkillsDirs,
|
|
76
81
|
resolveCommunitySkillsDir,
|
|
77
82
|
resolveGlobalCommunitySkillsDir,
|
|
78
83
|
resolveGlobalSkillsDir,
|
|
@@ -81,9 +86,6 @@ import {
|
|
|
81
86
|
resolveSkillsDir,
|
|
82
87
|
resolveTemplatesDir
|
|
83
88
|
} from "./chunk-6B6UN6SG.js";
|
|
84
|
-
import {
|
|
85
|
-
loadGraphStore
|
|
86
|
-
} from "./chunk-Z2JORLRT.js";
|
|
87
89
|
import {
|
|
88
90
|
CompactionPipeline,
|
|
89
91
|
DEFAULT_TOKEN_BUDGET,
|
|
@@ -101,7 +103,7 @@ import {
|
|
|
101
103
|
scanForInjection,
|
|
102
104
|
serializeEnvelope,
|
|
103
105
|
writeTaint
|
|
104
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-IBTHD2UA.js";
|
|
105
107
|
import {
|
|
106
108
|
Err,
|
|
107
109
|
Ok
|
|
@@ -109,6 +111,9 @@ import {
|
|
|
109
111
|
import {
|
|
110
112
|
SkillMetadataSchema
|
|
111
113
|
} from "./chunk-HIK6OEUF.js";
|
|
114
|
+
import {
|
|
115
|
+
logger
|
|
116
|
+
} from "./chunk-EBJQ6N4M.js";
|
|
112
117
|
import {
|
|
113
118
|
CLIError,
|
|
114
119
|
ExitCode,
|
|
@@ -701,7 +706,7 @@ ${skippedMsg}`
|
|
|
701
706
|
async function handleInitProject(input) {
|
|
702
707
|
const i = input;
|
|
703
708
|
try {
|
|
704
|
-
const { TemplateEngine } = await import("./engine-
|
|
709
|
+
const { TemplateEngine } = await import("./engine-FB3HCNVT.js");
|
|
705
710
|
const engine = new TemplateEngine(resolveTemplatesDir());
|
|
706
711
|
const safePath = sanitizePath(i.path);
|
|
707
712
|
const detected = tryDetectFramework(engine, safePath, i);
|
|
@@ -723,7 +728,7 @@ var listPersonasDefinition = {
|
|
|
723
728
|
inputSchema: { type: "object", properties: {} }
|
|
724
729
|
};
|
|
725
730
|
async function handleListPersonas() {
|
|
726
|
-
const { listPersonas } = await import("./loader-
|
|
731
|
+
const { listPersonas } = await import("./loader-HXUOBTYA.js");
|
|
727
732
|
const result = listPersonas(resolvePersonasDir());
|
|
728
733
|
return resultToMcpResponse(result);
|
|
729
734
|
}
|
|
@@ -747,10 +752,10 @@ async function handleGeneratePersonaArtifacts(input) {
|
|
|
747
752
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
|
|
748
753
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
|
|
749
754
|
}
|
|
750
|
-
const { loadPersona } = await import("./loader-
|
|
751
|
-
const { generateRuntime } = await import("./runtime-
|
|
752
|
-
const { generateAgentsMd } = await import("./agents-md-
|
|
753
|
-
const { generateCIWorkflow } = await import("./ci-workflow-
|
|
755
|
+
const { loadPersona } = await import("./loader-HXUOBTYA.js");
|
|
756
|
+
const { generateRuntime } = await import("./runtime-HQQNOARD.js");
|
|
757
|
+
const { generateAgentsMd } = await import("./agents-md-2RN666DE.js");
|
|
758
|
+
const { generateCIWorkflow } = await import("./ci-workflow-JFOL4YWW.js");
|
|
754
759
|
const personasDir = resolvePersonasDir();
|
|
755
760
|
const filePath = path3.join(personasDir, `${input.name}.yaml`);
|
|
756
761
|
if (!filePath.startsWith(personasDir)) {
|
|
@@ -805,7 +810,7 @@ async function handleRunPersona(input) {
|
|
|
805
810
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
|
|
806
811
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
|
|
807
812
|
}
|
|
808
|
-
const { loadPersona } = await import("./loader-
|
|
813
|
+
const { loadPersona } = await import("./loader-HXUOBTYA.js");
|
|
809
814
|
const { runPersona } = await import("./runner-AAEF2TXY.js");
|
|
810
815
|
const { executeSkill } = await import("./skill-executor-MOCUIAYS.js");
|
|
811
816
|
const personasDir = resolvePersonasDir();
|
|
@@ -972,8 +977,8 @@ async function handleRunAgentTask(input) {
|
|
|
972
977
|
|
|
973
978
|
// src/mcp/tools/skill.ts
|
|
974
979
|
init_dist();
|
|
975
|
-
import * as
|
|
976
|
-
import * as
|
|
980
|
+
import * as fs4 from "fs";
|
|
981
|
+
import * as path5 from "path";
|
|
977
982
|
import { parse as parseYaml } from "yaml";
|
|
978
983
|
|
|
979
984
|
// src/skill/dispatcher.ts
|
|
@@ -1159,103 +1164,9 @@ function formatSuggestions(suggestions) {
|
|
|
1159
1164
|
].join("\n");
|
|
1160
1165
|
}
|
|
1161
1166
|
|
|
1162
|
-
// src/skill/
|
|
1167
|
+
// src/skill/stack-profile.ts
|
|
1163
1168
|
import fs3 from "fs";
|
|
1164
1169
|
import path4 from "path";
|
|
1165
|
-
import crypto from "crypto";
|
|
1166
|
-
import { parse } from "yaml";
|
|
1167
|
-
function computeSkillsDirHash(skillsDirs) {
|
|
1168
|
-
const hash = crypto.createHash("sha256");
|
|
1169
|
-
for (const dir of skillsDirs) {
|
|
1170
|
-
if (!fs3.existsSync(dir)) continue;
|
|
1171
|
-
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
1172
|
-
if (!entry.isDirectory()) continue;
|
|
1173
|
-
const yamlPath = path4.join(dir, entry.name, "skill.yaml");
|
|
1174
|
-
if (!fs3.existsSync(yamlPath)) continue;
|
|
1175
|
-
const stat = fs3.statSync(yamlPath);
|
|
1176
|
-
hash.update(`${yamlPath}:${stat.mtimeMs}`);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
return hash.digest("hex");
|
|
1180
|
-
}
|
|
1181
|
-
function parseSkillEntry(yamlPath, source, tierOverrides) {
|
|
1182
|
-
const raw = fs3.readFileSync(yamlPath, "utf-8");
|
|
1183
|
-
const parsed = parse(raw);
|
|
1184
|
-
const result = SkillMetadataSchema.safeParse(parsed);
|
|
1185
|
-
if (!result.success) return null;
|
|
1186
|
-
const meta = result.data;
|
|
1187
|
-
const effectiveTier = tierOverrides?.[meta.name] ?? meta.tier;
|
|
1188
|
-
if (meta.internal) return null;
|
|
1189
|
-
return {
|
|
1190
|
-
tier: effectiveTier ?? 3,
|
|
1191
|
-
type: meta.type,
|
|
1192
|
-
description: meta.description,
|
|
1193
|
-
keywords: meta.keywords ?? [],
|
|
1194
|
-
stackSignals: meta.stack_signals ?? [],
|
|
1195
|
-
cognitiveMode: meta.cognitive_mode,
|
|
1196
|
-
phases: (meta.phases ?? []).map((p) => p.name),
|
|
1197
|
-
paths: meta.paths ?? [],
|
|
1198
|
-
relatedSkills: meta.related_skills ?? [],
|
|
1199
|
-
source,
|
|
1200
|
-
addresses: meta.addresses ?? [],
|
|
1201
|
-
dependsOn: meta.depends_on ?? [],
|
|
1202
|
-
...meta.context_budget && {
|
|
1203
|
-
contextBudget: {
|
|
1204
|
-
maxTokens: meta.context_budget.max_tokens,
|
|
1205
|
-
priority: meta.context_budget.priority
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
};
|
|
1209
|
-
}
|
|
1210
|
-
function scanDirectory(dir, source, index, tierOverrides) {
|
|
1211
|
-
if (!fs3.existsSync(dir)) return;
|
|
1212
|
-
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
1213
|
-
if (!entry.isDirectory()) continue;
|
|
1214
|
-
if (index.skills[entry.name]) continue;
|
|
1215
|
-
const yamlPath = path4.join(dir, entry.name, "skill.yaml");
|
|
1216
|
-
if (!fs3.existsSync(yamlPath)) continue;
|
|
1217
|
-
try {
|
|
1218
|
-
const parsed = parseSkillEntry(yamlPath, source, tierOverrides);
|
|
1219
|
-
if (parsed) index.skills[entry.name] = parsed;
|
|
1220
|
-
} catch {
|
|
1221
|
-
continue;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
function buildIndex(platform, _projectRoot, tierOverrides) {
|
|
1226
|
-
const skillsDirs = resolveAllSkillsDirs(platform);
|
|
1227
|
-
const sourceMap = ["project", "community", "bundled"];
|
|
1228
|
-
const index = {
|
|
1229
|
-
version: 1,
|
|
1230
|
-
hash: computeSkillsDirHash(skillsDirs),
|
|
1231
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1232
|
-
skills: {}
|
|
1233
|
-
};
|
|
1234
|
-
for (let i = 0; i < skillsDirs.length; i++) {
|
|
1235
|
-
scanDirectory(skillsDirs[i], sourceMap[i] ?? "bundled", index, tierOverrides);
|
|
1236
|
-
}
|
|
1237
|
-
return index;
|
|
1238
|
-
}
|
|
1239
|
-
function loadOrRebuildIndex(platform, projectRoot, tierOverrides) {
|
|
1240
|
-
const indexPath = path4.join(projectRoot, ".harness", "skills-index.json");
|
|
1241
|
-
const skillsDirs = resolveAllSkillsDirs(platform);
|
|
1242
|
-
const currentHash = computeSkillsDirHash(skillsDirs);
|
|
1243
|
-
if (fs3.existsSync(indexPath)) {
|
|
1244
|
-
try {
|
|
1245
|
-
const existing = JSON.parse(fs3.readFileSync(indexPath, "utf-8"));
|
|
1246
|
-
if (existing.hash === currentHash) return existing;
|
|
1247
|
-
} catch {
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
const index = buildIndex(platform, projectRoot, tierOverrides);
|
|
1251
|
-
fs3.mkdirSync(path4.dirname(indexPath), { recursive: true });
|
|
1252
|
-
fs3.writeFileSync(indexPath, JSON.stringify(index, null, 2));
|
|
1253
|
-
return index;
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
// src/skill/stack-profile.ts
|
|
1257
|
-
import fs4 from "fs";
|
|
1258
|
-
import path5 from "path";
|
|
1259
1170
|
var SIGNAL_DOMAIN_MAP = {
|
|
1260
1171
|
"prisma/schema.prisma": ["database"],
|
|
1261
1172
|
"drizzle.config.ts": ["database"],
|
|
@@ -1314,8 +1225,8 @@ function generateStackProfile(projectRoot) {
|
|
|
1314
1225
|
const signals = {};
|
|
1315
1226
|
const domainSet = /* @__PURE__ */ new Set();
|
|
1316
1227
|
for (const [pattern, domains] of Object.entries(SIGNAL_DOMAIN_MAP)) {
|
|
1317
|
-
const fullPath =
|
|
1318
|
-
const exists =
|
|
1228
|
+
const fullPath = path4.join(projectRoot, pattern);
|
|
1229
|
+
const exists = fs3.existsSync(fullPath);
|
|
1319
1230
|
signals[pattern] = exists;
|
|
1320
1231
|
if (exists) {
|
|
1321
1232
|
for (const domain of domains) domainSet.add(domain);
|
|
@@ -1328,23 +1239,23 @@ function generateStackProfile(projectRoot) {
|
|
|
1328
1239
|
};
|
|
1329
1240
|
}
|
|
1330
1241
|
function loadOrGenerateProfile(projectRoot) {
|
|
1331
|
-
const profilePath =
|
|
1332
|
-
if (
|
|
1242
|
+
const profilePath = path4.join(projectRoot, ".harness", "stack-profile.json");
|
|
1243
|
+
if (fs3.existsSync(profilePath)) {
|
|
1333
1244
|
try {
|
|
1334
|
-
return JSON.parse(
|
|
1245
|
+
return JSON.parse(fs3.readFileSync(profilePath, "utf-8"));
|
|
1335
1246
|
} catch {
|
|
1336
1247
|
}
|
|
1337
1248
|
}
|
|
1338
1249
|
const profile = generateStackProfile(projectRoot);
|
|
1339
|
-
|
|
1340
|
-
|
|
1250
|
+
fs3.mkdirSync(path4.dirname(profilePath), { recursive: true });
|
|
1251
|
+
fs3.writeFileSync(profilePath, JSON.stringify(profile, null, 2));
|
|
1341
1252
|
return profile;
|
|
1342
1253
|
}
|
|
1343
1254
|
|
|
1344
1255
|
// src/mcp/tools/event-emitter.ts
|
|
1345
1256
|
async function emitSkillEvent(projectPath, event) {
|
|
1346
1257
|
try {
|
|
1347
|
-
const { emitEvent } = await import("./dist-
|
|
1258
|
+
const { emitEvent } = await import("./dist-CPKL5Y2R.js");
|
|
1348
1259
|
await emitEvent(projectPath, event);
|
|
1349
1260
|
} catch {
|
|
1350
1261
|
}
|
|
@@ -1379,18 +1290,18 @@ async function handleRunSkill(input) {
|
|
|
1379
1290
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.skill)) {
|
|
1380
1291
|
return resultToMcpResponse(Err(new Error(`Invalid skill name: ${input.skill}`)));
|
|
1381
1292
|
}
|
|
1382
|
-
const skillDir =
|
|
1293
|
+
const skillDir = path5.join(skillsDir, input.skill);
|
|
1383
1294
|
if (!skillDir.startsWith(skillsDir)) {
|
|
1384
1295
|
return resultToMcpResponse(Err(new Error(`Invalid skill path: ${input.skill}`)));
|
|
1385
1296
|
}
|
|
1386
|
-
if (!
|
|
1297
|
+
if (!fs4.existsSync(skillDir)) {
|
|
1387
1298
|
return resultToMcpResponse(Err(new Error(`Skill not found: ${input.skill}`)));
|
|
1388
1299
|
}
|
|
1389
|
-
const skillMdPath =
|
|
1390
|
-
if (!
|
|
1300
|
+
const skillMdPath = path5.join(skillDir, "SKILL.md");
|
|
1301
|
+
if (!fs4.existsSync(skillMdPath)) {
|
|
1391
1302
|
return resultToMcpResponse(Err(new Error(`SKILL.md not found for skill: ${input.skill}`)));
|
|
1392
1303
|
}
|
|
1393
|
-
let content =
|
|
1304
|
+
let content = fs4.readFileSync(skillMdPath, "utf-8");
|
|
1394
1305
|
const projectRoot = input.path ? sanitizePath(input.path) : process.cwd();
|
|
1395
1306
|
const configResult = resolveConfig();
|
|
1396
1307
|
const skillsConfig = configResult.ok ? configResult.value.skills : void 0;
|
|
@@ -1417,9 +1328,9 @@ async function handleRunSkill(input) {
|
|
|
1417
1328
|
}
|
|
1418
1329
|
if (input.path) {
|
|
1419
1330
|
const projectPath = sanitizePath(input.path);
|
|
1420
|
-
const stateFile =
|
|
1421
|
-
if (
|
|
1422
|
-
const stateContent =
|
|
1331
|
+
const stateFile = path5.join(projectPath, ".harness", "state.json");
|
|
1332
|
+
if (fs4.existsSync(stateFile)) {
|
|
1333
|
+
const stateContent = fs4.readFileSync(stateFile, "utf-8");
|
|
1423
1334
|
content += `
|
|
1424
1335
|
|
|
1425
1336
|
---
|
|
@@ -1430,10 +1341,10 @@ ${stateContent}
|
|
|
1430
1341
|
`;
|
|
1431
1342
|
}
|
|
1432
1343
|
}
|
|
1433
|
-
const skillYamlPath =
|
|
1434
|
-
if (
|
|
1344
|
+
const skillYamlPath = path5.join(skillDir, "skill.yaml");
|
|
1345
|
+
if (fs4.existsSync(skillYamlPath)) {
|
|
1435
1346
|
try {
|
|
1436
|
-
const rawYaml =
|
|
1347
|
+
const rawYaml = fs4.readFileSync(skillYamlPath, "utf-8");
|
|
1437
1348
|
const skillMeta = parseYaml(rawYaml);
|
|
1438
1349
|
if (skillMeta.type === "knowledge") {
|
|
1439
1350
|
const boundary = content.indexOf("\n## Details");
|
|
@@ -1494,7 +1405,7 @@ var createSkillDefinition = {
|
|
|
1494
1405
|
};
|
|
1495
1406
|
async function handleCreateSkill(input) {
|
|
1496
1407
|
try {
|
|
1497
|
-
const { generateSkillFiles } = await import("./create-skill-
|
|
1408
|
+
const { generateSkillFiles } = await import("./create-skill-4T5CBSJ2.js");
|
|
1498
1409
|
const result = generateSkillFiles({
|
|
1499
1410
|
name: input.name,
|
|
1500
1411
|
description: input.description,
|
|
@@ -1516,22 +1427,22 @@ async function handleCreateSkill(input) {
|
|
|
1516
1427
|
}
|
|
1517
1428
|
|
|
1518
1429
|
// src/mcp/resources/skills.ts
|
|
1519
|
-
import * as
|
|
1520
|
-
import * as
|
|
1430
|
+
import * as fs5 from "fs";
|
|
1431
|
+
import * as path6 from "path";
|
|
1521
1432
|
import * as yaml from "yaml";
|
|
1522
1433
|
async function getSkillsResource(projectRoot) {
|
|
1523
|
-
const skillsDir =
|
|
1434
|
+
const skillsDir = path6.join(projectRoot, "agents", "skills", "claude-code");
|
|
1524
1435
|
const skills = [];
|
|
1525
|
-
if (!
|
|
1436
|
+
if (!fs5.existsSync(skillsDir)) {
|
|
1526
1437
|
return JSON.stringify(skills, null, 2);
|
|
1527
1438
|
}
|
|
1528
|
-
const entries =
|
|
1439
|
+
const entries = fs5.readdirSync(skillsDir, { withFileTypes: true });
|
|
1529
1440
|
for (const entry of entries) {
|
|
1530
1441
|
if (!entry.isDirectory()) continue;
|
|
1531
|
-
const skillYamlPath =
|
|
1532
|
-
if (!
|
|
1442
|
+
const skillYamlPath = path6.join(skillsDir, entry.name, "skill.yaml");
|
|
1443
|
+
if (!fs5.existsSync(skillYamlPath)) continue;
|
|
1533
1444
|
try {
|
|
1534
|
-
const content =
|
|
1445
|
+
const content = fs5.readFileSync(skillYamlPath, "utf-8");
|
|
1535
1446
|
const parsed = yaml.parse(content);
|
|
1536
1447
|
skills.push({
|
|
1537
1448
|
name: parsed.name,
|
|
@@ -1547,14 +1458,14 @@ async function getSkillsResource(projectRoot) {
|
|
|
1547
1458
|
}
|
|
1548
1459
|
|
|
1549
1460
|
// src/mcp/resources/rules.ts
|
|
1550
|
-
import * as
|
|
1551
|
-
import * as
|
|
1461
|
+
import * as fs6 from "fs";
|
|
1462
|
+
import * as path7 from "path";
|
|
1552
1463
|
async function getRulesResource(projectRoot) {
|
|
1553
1464
|
const rules = [];
|
|
1554
|
-
const configPath =
|
|
1555
|
-
if (
|
|
1465
|
+
const configPath = path7.join(projectRoot, "harness.config.json");
|
|
1466
|
+
if (fs6.existsSync(configPath)) {
|
|
1556
1467
|
try {
|
|
1557
|
-
const config = JSON.parse(
|
|
1468
|
+
const config = JSON.parse(fs6.readFileSync(configPath, "utf-8"));
|
|
1558
1469
|
if (config.layers) {
|
|
1559
1470
|
rules.push({ type: "layer-enforcement", config: config.layers });
|
|
1560
1471
|
}
|
|
@@ -1567,10 +1478,10 @@ async function getRulesResource(projectRoot) {
|
|
|
1567
1478
|
} catch {
|
|
1568
1479
|
}
|
|
1569
1480
|
}
|
|
1570
|
-
const linterPath =
|
|
1571
|
-
if (
|
|
1481
|
+
const linterPath = path7.join(projectRoot, ".harness", "linter.json");
|
|
1482
|
+
if (fs6.existsSync(linterPath)) {
|
|
1572
1483
|
try {
|
|
1573
|
-
const linterConfig = JSON.parse(
|
|
1484
|
+
const linterConfig = JSON.parse(fs6.readFileSync(linterPath, "utf-8"));
|
|
1574
1485
|
rules.push({ type: "linter", config: linterConfig });
|
|
1575
1486
|
} catch {
|
|
1576
1487
|
}
|
|
@@ -1579,28 +1490,28 @@ async function getRulesResource(projectRoot) {
|
|
|
1579
1490
|
}
|
|
1580
1491
|
|
|
1581
1492
|
// src/mcp/resources/project.ts
|
|
1582
|
-
import * as
|
|
1583
|
-
import * as
|
|
1493
|
+
import * as fs7 from "fs";
|
|
1494
|
+
import * as path8 from "path";
|
|
1584
1495
|
async function getProjectResource(projectRoot) {
|
|
1585
|
-
const agentsPath =
|
|
1586
|
-
if (
|
|
1587
|
-
return
|
|
1496
|
+
const agentsPath = path8.join(projectRoot, "AGENTS.md");
|
|
1497
|
+
if (fs7.existsSync(agentsPath)) {
|
|
1498
|
+
return fs7.readFileSync(agentsPath, "utf-8");
|
|
1588
1499
|
}
|
|
1589
1500
|
return "# No AGENTS.md found";
|
|
1590
1501
|
}
|
|
1591
1502
|
|
|
1592
1503
|
// src/mcp/resources/learnings.ts
|
|
1593
|
-
import * as
|
|
1594
|
-
import * as
|
|
1504
|
+
import * as fs8 from "fs";
|
|
1505
|
+
import * as path9 from "path";
|
|
1595
1506
|
async function getLearningsResource(projectRoot) {
|
|
1596
1507
|
const sections = [];
|
|
1597
|
-
const reviewPath =
|
|
1598
|
-
if (
|
|
1599
|
-
sections.push("## Review Learnings\n\n" +
|
|
1508
|
+
const reviewPath = path9.join(projectRoot, ".harness", "review-learnings.md");
|
|
1509
|
+
if (fs8.existsSync(reviewPath)) {
|
|
1510
|
+
sections.push("## Review Learnings\n\n" + fs8.readFileSync(reviewPath, "utf-8"));
|
|
1600
1511
|
}
|
|
1601
|
-
const antiPath =
|
|
1602
|
-
if (
|
|
1603
|
-
sections.push("## Anti-Pattern Log\n\n" +
|
|
1512
|
+
const antiPath = path9.join(projectRoot, ".harness", "anti-patterns.md");
|
|
1513
|
+
if (fs8.existsSync(antiPath)) {
|
|
1514
|
+
sections.push("## Anti-Pattern Log\n\n" + fs8.readFileSync(antiPath, "utf-8"));
|
|
1604
1515
|
}
|
|
1605
1516
|
return sections.length > 0 ? sections.join("\n\n---\n\n") : "No learnings files found.";
|
|
1606
1517
|
}
|
|
@@ -1610,14 +1521,14 @@ init_dist();
|
|
|
1610
1521
|
|
|
1611
1522
|
// src/mcp/tools/roadmap-auto-sync.ts
|
|
1612
1523
|
init_dist();
|
|
1613
|
-
import * as
|
|
1614
|
-
import * as
|
|
1524
|
+
import * as fs9 from "fs";
|
|
1525
|
+
import * as path10 from "path";
|
|
1615
1526
|
async function autoSyncRoadmap(projectPath) {
|
|
1616
1527
|
try {
|
|
1617
|
-
const roadmapFile =
|
|
1618
|
-
if (!
|
|
1619
|
-
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-
|
|
1620
|
-
const raw =
|
|
1528
|
+
const roadmapFile = path10.join(projectPath, "docs", "roadmap.md");
|
|
1529
|
+
if (!fs9.existsSync(roadmapFile)) return;
|
|
1530
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-CPKL5Y2R.js");
|
|
1531
|
+
const raw = fs9.readFileSync(roadmapFile, "utf-8");
|
|
1621
1532
|
const parseResult = parseRoadmap(raw);
|
|
1622
1533
|
if (!parseResult.ok) return;
|
|
1623
1534
|
const roadmap = parseResult.value;
|
|
@@ -1627,7 +1538,7 @@ async function autoSyncRoadmap(projectPath) {
|
|
|
1627
1538
|
return;
|
|
1628
1539
|
}
|
|
1629
1540
|
applySyncChanges(roadmap, syncResult.value);
|
|
1630
|
-
|
|
1541
|
+
fs9.writeFileSync(roadmapFile, serializeRoadmap(roadmap), "utf-8");
|
|
1631
1542
|
await triggerExternalSync(projectPath, roadmapFile);
|
|
1632
1543
|
} catch {
|
|
1633
1544
|
}
|
|
@@ -1636,8 +1547,8 @@ async function triggerExternalSync(projectPath, roadmapFile) {
|
|
|
1636
1547
|
try {
|
|
1637
1548
|
const trackerConfig = loadTrackerSyncConfig(projectPath);
|
|
1638
1549
|
if (!trackerConfig) return;
|
|
1639
|
-
const projectEnvPath =
|
|
1640
|
-
if (
|
|
1550
|
+
const projectEnvPath = path10.join(projectPath, ".env");
|
|
1551
|
+
if (fs9.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
|
|
1641
1552
|
const { config: loadDotenv } = await import("dotenv");
|
|
1642
1553
|
loadDotenv({ path: projectEnvPath });
|
|
1643
1554
|
}
|
|
@@ -1646,7 +1557,7 @@ async function triggerExternalSync(projectPath, roadmapFile) {
|
|
|
1646
1557
|
console.warn("[roadmap-sync] GITHUB_TOKEN not found \u2014 external sync skipped");
|
|
1647
1558
|
return;
|
|
1648
1559
|
}
|
|
1649
|
-
const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-
|
|
1560
|
+
const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-CPKL5Y2R.js");
|
|
1650
1561
|
const adapter = new GitHubIssuesSyncAdapter({
|
|
1651
1562
|
token,
|
|
1652
1563
|
config: trackerConfig
|
|
@@ -1743,12 +1654,12 @@ var manageStateDefinition = {
|
|
|
1743
1654
|
}
|
|
1744
1655
|
};
|
|
1745
1656
|
async function handleShow(projectPath, input) {
|
|
1746
|
-
const { loadState } = await import("./dist-
|
|
1657
|
+
const { loadState } = await import("./dist-CPKL5Y2R.js");
|
|
1747
1658
|
return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
|
|
1748
1659
|
}
|
|
1749
1660
|
async function handleLearn(projectPath, input) {
|
|
1750
1661
|
if (!input.learning) return mcpError("Error: learning is required for learn action");
|
|
1751
|
-
const { appendLearning } = await import("./dist-
|
|
1662
|
+
const { appendLearning } = await import("./dist-CPKL5Y2R.js");
|
|
1752
1663
|
const result = await appendLearning(
|
|
1753
1664
|
projectPath,
|
|
1754
1665
|
input.learning,
|
|
@@ -1763,7 +1674,7 @@ async function handleLearn(projectPath, input) {
|
|
|
1763
1674
|
async function handleFailure(projectPath, input) {
|
|
1764
1675
|
if (!input.description) return mcpError("Error: description is required for failure action");
|
|
1765
1676
|
if (!input.failureType) return mcpError("Error: failureType is required for failure action");
|
|
1766
|
-
const { appendFailure } = await import("./dist-
|
|
1677
|
+
const { appendFailure } = await import("./dist-CPKL5Y2R.js");
|
|
1767
1678
|
const result = await appendFailure(
|
|
1768
1679
|
projectPath,
|
|
1769
1680
|
input.description,
|
|
@@ -1782,19 +1693,19 @@ async function handleFailure(projectPath, input) {
|
|
|
1782
1693
|
return resultToMcpResponse(Ok({ recorded: true }));
|
|
1783
1694
|
}
|
|
1784
1695
|
async function handleArchive(projectPath, input) {
|
|
1785
|
-
const { archiveFailures } = await import("./dist-
|
|
1696
|
+
const { archiveFailures } = await import("./dist-CPKL5Y2R.js");
|
|
1786
1697
|
const result = await archiveFailures(projectPath, input.stream, input.session);
|
|
1787
1698
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1788
1699
|
return resultToMcpResponse(Ok({ archived: true }));
|
|
1789
1700
|
}
|
|
1790
1701
|
async function handleReset(projectPath, input) {
|
|
1791
|
-
const { saveState, DEFAULT_STATE } = await import("./dist-
|
|
1702
|
+
const { saveState, DEFAULT_STATE } = await import("./dist-CPKL5Y2R.js");
|
|
1792
1703
|
const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
|
|
1793
1704
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1794
1705
|
return resultToMcpResponse(Ok({ reset: true }));
|
|
1795
1706
|
}
|
|
1796
1707
|
async function handleGate(projectPath, input) {
|
|
1797
|
-
const { runMechanicalGate } = await import("./dist-
|
|
1708
|
+
const { runMechanicalGate } = await import("./dist-CPKL5Y2R.js");
|
|
1798
1709
|
const result = await runMechanicalGate(projectPath);
|
|
1799
1710
|
if (result.ok) {
|
|
1800
1711
|
await emitSkillEvent(projectPath, {
|
|
@@ -1814,7 +1725,7 @@ async function handleGate(projectPath, input) {
|
|
|
1814
1725
|
}
|
|
1815
1726
|
async function handleSaveHandoff(projectPath, input) {
|
|
1816
1727
|
if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
|
|
1817
|
-
const { saveHandoff } = await import("./dist-
|
|
1728
|
+
const { saveHandoff } = await import("./dist-CPKL5Y2R.js");
|
|
1818
1729
|
const result = await saveHandoff(
|
|
1819
1730
|
projectPath,
|
|
1820
1731
|
input.handoff,
|
|
@@ -1836,7 +1747,7 @@ async function handleSaveHandoff(projectPath, input) {
|
|
|
1836
1747
|
return resultToMcpResponse(Ok({ saved: true }));
|
|
1837
1748
|
}
|
|
1838
1749
|
async function handleLoadHandoff(projectPath, input) {
|
|
1839
|
-
const { loadHandoff } = await import("./dist-
|
|
1750
|
+
const { loadHandoff } = await import("./dist-CPKL5Y2R.js");
|
|
1840
1751
|
return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
|
|
1841
1752
|
}
|
|
1842
1753
|
async function handleAppendEntry(projectPath, input) {
|
|
@@ -1844,7 +1755,7 @@ async function handleAppendEntry(projectPath, input) {
|
|
|
1844
1755
|
if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
|
|
1845
1756
|
if (!input.content) return mcpError("Error: content is required for append_entry action");
|
|
1846
1757
|
if (input.session) {
|
|
1847
|
-
const { appendSessionEntry } = await import("./dist-
|
|
1758
|
+
const { appendSessionEntry } = await import("./dist-CPKL5Y2R.js");
|
|
1848
1759
|
const result = await appendSessionEntry(
|
|
1849
1760
|
projectPath,
|
|
1850
1761
|
input.session,
|
|
@@ -1857,7 +1768,7 @@ async function handleAppendEntry(projectPath, input) {
|
|
|
1857
1768
|
if (input.section !== "decisions") {
|
|
1858
1769
|
return mcpError("Error: session is required for non-decisions sections");
|
|
1859
1770
|
}
|
|
1860
|
-
const { loadState, saveState } = await import("./dist-
|
|
1771
|
+
const { loadState, saveState } = await import("./dist-CPKL5Y2R.js");
|
|
1861
1772
|
const lr = await loadState(projectPath, input.stream);
|
|
1862
1773
|
if (!lr.ok) return resultToMcpResponse(lr);
|
|
1863
1774
|
lr.value.decisions.push({
|
|
@@ -1875,7 +1786,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
1875
1786
|
if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
|
|
1876
1787
|
if (!input.newStatus)
|
|
1877
1788
|
return mcpError("Error: newStatus is required for update_entry_status action");
|
|
1878
|
-
const { updateSessionEntryStatus } = await import("./dist-
|
|
1789
|
+
const { updateSessionEntryStatus } = await import("./dist-CPKL5Y2R.js");
|
|
1879
1790
|
const result = await updateSessionEntryStatus(
|
|
1880
1791
|
projectPath,
|
|
1881
1792
|
input.session,
|
|
@@ -1888,7 +1799,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
1888
1799
|
async function handleReadSection(projectPath, input) {
|
|
1889
1800
|
if (!input.session) return mcpError("Error: session is required for read_section action");
|
|
1890
1801
|
if (!input.section) return mcpError("Error: section is required for read_section action");
|
|
1891
|
-
const { readSessionSection } = await import("./dist-
|
|
1802
|
+
const { readSessionSection } = await import("./dist-CPKL5Y2R.js");
|
|
1892
1803
|
const result = await readSessionSection(
|
|
1893
1804
|
projectPath,
|
|
1894
1805
|
input.session,
|
|
@@ -1898,13 +1809,13 @@ async function handleReadSection(projectPath, input) {
|
|
|
1898
1809
|
}
|
|
1899
1810
|
async function handleReadSections(projectPath, input) {
|
|
1900
1811
|
if (!input.session) return mcpError("Error: session is required for read_sections action");
|
|
1901
|
-
const { readSessionSections } = await import("./dist-
|
|
1812
|
+
const { readSessionSections } = await import("./dist-CPKL5Y2R.js");
|
|
1902
1813
|
const result = await readSessionSections(projectPath, input.session);
|
|
1903
1814
|
return resultToMcpResponse(result);
|
|
1904
1815
|
}
|
|
1905
1816
|
async function handleArchiveSession(projectPath, input) {
|
|
1906
1817
|
if (!input.session) return mcpError("Error: session is required for archive_session action");
|
|
1907
|
-
const { archiveSession } = await import("./dist-
|
|
1818
|
+
const { archiveSession } = await import("./dist-CPKL5Y2R.js");
|
|
1908
1819
|
const result = await archiveSession(projectPath, input.session);
|
|
1909
1820
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1910
1821
|
await autoSyncRoadmap(projectPath);
|
|
@@ -1984,7 +1895,7 @@ var listStreamsDefinition = {
|
|
|
1984
1895
|
};
|
|
1985
1896
|
async function handleListStreams(input) {
|
|
1986
1897
|
try {
|
|
1987
|
-
const { listStreams, loadStreamIndex } = await import("./dist-
|
|
1898
|
+
const { listStreams, loadStreamIndex } = await import("./dist-CPKL5Y2R.js");
|
|
1988
1899
|
const projectPath = sanitizePath(input.path);
|
|
1989
1900
|
const indexResult = await loadStreamIndex(projectPath);
|
|
1990
1901
|
const streamsResult = await listStreams(projectPath);
|
|
@@ -2022,7 +1933,7 @@ var checkPhaseGateDefinition = {
|
|
|
2022
1933
|
};
|
|
2023
1934
|
async function handleCheckPhaseGate(input) {
|
|
2024
1935
|
try {
|
|
2025
|
-
const { runCheckPhaseGate } = await import("./check-phase-gate-
|
|
1936
|
+
const { runCheckPhaseGate } = await import("./check-phase-gate-ZVG56NT2.js");
|
|
2026
1937
|
const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
|
|
2027
1938
|
if (result.ok) {
|
|
2028
1939
|
return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
|
|
@@ -2042,7 +1953,7 @@ async function handleCheckPhaseGate(input) {
|
|
|
2042
1953
|
}
|
|
2043
1954
|
|
|
2044
1955
|
// src/mcp/tools/cross-check.ts
|
|
2045
|
-
import * as
|
|
1956
|
+
import * as path11 from "path";
|
|
2046
1957
|
var validateCrossCheckDefinition = {
|
|
2047
1958
|
name: "validate_cross_check",
|
|
2048
1959
|
description: "Validate plan-to-implementation coverage: checks that specs have plans and plans have implementations, detects staleness",
|
|
@@ -2078,15 +1989,15 @@ async function handleValidateCrossCheck(input) {
|
|
|
2078
1989
|
};
|
|
2079
1990
|
}
|
|
2080
1991
|
try {
|
|
2081
|
-
const { runCrossCheck } = await import("./validate-cross-check-
|
|
2082
|
-
const specsDir =
|
|
1992
|
+
const { runCrossCheck } = await import("./validate-cross-check-SPL3H4O5.js");
|
|
1993
|
+
const specsDir = path11.resolve(projectPath, input.specsDir ?? "docs/specs");
|
|
2083
1994
|
if (!specsDir.startsWith(projectPath)) {
|
|
2084
1995
|
return {
|
|
2085
1996
|
content: [{ type: "text", text: "Error: specsDir escapes project root" }],
|
|
2086
1997
|
isError: true
|
|
2087
1998
|
};
|
|
2088
1999
|
}
|
|
2089
|
-
const plansDir =
|
|
2000
|
+
const plansDir = path11.resolve(projectPath, input.plansDir ?? "docs/plans");
|
|
2090
2001
|
if (!plansDir.startsWith(projectPath)) {
|
|
2091
2002
|
return {
|
|
2092
2003
|
content: [{ type: "text", text: "Error: plansDir escapes project root" }],
|
|
@@ -2120,15 +2031,15 @@ init_dist();
|
|
|
2120
2031
|
|
|
2121
2032
|
// src/commands/generate-slash-commands.ts
|
|
2122
2033
|
import { Command } from "commander";
|
|
2123
|
-
import
|
|
2124
|
-
import
|
|
2034
|
+
import fs12 from "fs";
|
|
2035
|
+
import path14 from "path";
|
|
2125
2036
|
import os from "os";
|
|
2126
2037
|
import readline from "readline";
|
|
2127
2038
|
|
|
2128
2039
|
// src/slash-commands/normalize.ts
|
|
2129
|
-
import
|
|
2130
|
-
import
|
|
2131
|
-
import { parse as
|
|
2040
|
+
import fs10 from "fs";
|
|
2041
|
+
import path12 from "path";
|
|
2042
|
+
import { parse as parse2 } from "yaml";
|
|
2132
2043
|
|
|
2133
2044
|
// src/slash-commands/normalize-name.ts
|
|
2134
2045
|
function normalizeName(skillName) {
|
|
@@ -2147,11 +2058,11 @@ function normalizeName(skillName) {
|
|
|
2147
2058
|
function readSkillYaml(yamlPath) {
|
|
2148
2059
|
let raw;
|
|
2149
2060
|
try {
|
|
2150
|
-
raw =
|
|
2061
|
+
raw = fs10.readFileSync(yamlPath, "utf-8");
|
|
2151
2062
|
} catch {
|
|
2152
2063
|
return null;
|
|
2153
2064
|
}
|
|
2154
|
-
return SkillMetadataSchema.safeParse(
|
|
2065
|
+
return SkillMetadataSchema.safeParse(parse2(raw));
|
|
2155
2066
|
}
|
|
2156
2067
|
var DERIVED_FROM_CLAUDE_CODE = ["cursor", "codex"];
|
|
2157
2068
|
function shouldSkipSkill(meta, platforms) {
|
|
@@ -2211,10 +2122,10 @@ function buildProcessLines(meta) {
|
|
|
2211
2122
|
];
|
|
2212
2123
|
}
|
|
2213
2124
|
function buildSpec(meta, normalized, entry, skillsDir, source) {
|
|
2214
|
-
const skillMdPath =
|
|
2215
|
-
const skillMdContent =
|
|
2216
|
-
const skillMdRelative =
|
|
2217
|
-
const skillYamlRelative =
|
|
2125
|
+
const skillMdPath = path12.join(skillsDir, entry.name, "SKILL.md");
|
|
2126
|
+
const skillMdContent = fs10.existsSync(skillMdPath) ? fs10.readFileSync(skillMdPath, "utf-8") : "";
|
|
2127
|
+
const skillMdRelative = path12.relative(process.cwd(), skillMdPath).replaceAll("\\", "/");
|
|
2128
|
+
const skillYamlRelative = path12.relative(process.cwd(), path12.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
|
|
2218
2129
|
const args = (meta.cli?.args ?? []).map((a) => ({
|
|
2219
2130
|
name: a.name,
|
|
2220
2131
|
description: a.description ?? "",
|
|
@@ -2269,11 +2180,11 @@ function normalizeSkills(skillSources, platforms) {
|
|
|
2269
2180
|
const specs = [];
|
|
2270
2181
|
const nameMap = /* @__PURE__ */ new Map();
|
|
2271
2182
|
for (const { dir: skillsDir, source } of skillSources) {
|
|
2272
|
-
if (!
|
|
2273
|
-
const entries =
|
|
2183
|
+
if (!fs10.existsSync(skillsDir)) continue;
|
|
2184
|
+
const entries = fs10.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
2274
2185
|
for (const entry of entries) {
|
|
2275
|
-
const yamlPath =
|
|
2276
|
-
if (!
|
|
2186
|
+
const yamlPath = path12.join(skillsDir, entry.name, "skill.yaml");
|
|
2187
|
+
if (!fs10.existsSync(yamlPath)) continue;
|
|
2277
2188
|
const result = readSkillYaml(yamlPath);
|
|
2278
2189
|
if (!result) continue;
|
|
2279
2190
|
if (!result.success) {
|
|
@@ -2443,27 +2354,27 @@ function renderCodexAgentsMd(specs) {
|
|
|
2443
2354
|
}
|
|
2444
2355
|
|
|
2445
2356
|
// src/slash-commands/sync-codex.ts
|
|
2446
|
-
import
|
|
2447
|
-
import
|
|
2357
|
+
import fs11 from "fs";
|
|
2358
|
+
import path13 from "path";
|
|
2448
2359
|
function computeCodexSync(outputDir, specs, dryRun) {
|
|
2449
2360
|
const added = [];
|
|
2450
2361
|
const updated = [];
|
|
2451
2362
|
const unchanged = [];
|
|
2452
2363
|
const specSkillNames = /* @__PURE__ */ new Set();
|
|
2453
2364
|
for (const spec of specs) {
|
|
2454
|
-
const mdPath =
|
|
2455
|
-
const skillMd =
|
|
2456
|
-
const skillDir =
|
|
2365
|
+
const mdPath = path13.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
|
|
2366
|
+
const skillMd = fs11.existsSync(mdPath) ? fs11.readFileSync(mdPath, "utf-8") : "";
|
|
2367
|
+
const skillDir = path13.join(outputDir, spec.skillYamlName);
|
|
2457
2368
|
specSkillNames.add(spec.skillYamlName);
|
|
2458
2369
|
const renderedSkillMd = renderCodexSkill(skillMd);
|
|
2459
2370
|
const renderedOpenaiYaml = renderCodexOpenaiYaml(spec);
|
|
2460
|
-
const existingSkillMdPath =
|
|
2461
|
-
const existingOpenaiYamlPath =
|
|
2462
|
-
if (!
|
|
2371
|
+
const existingSkillMdPath = path13.join(skillDir, "SKILL.md");
|
|
2372
|
+
const existingOpenaiYamlPath = path13.join(skillDir, "agents", "openai.yaml");
|
|
2373
|
+
if (!fs11.existsSync(skillDir)) {
|
|
2463
2374
|
added.push(spec.skillYamlName);
|
|
2464
2375
|
} else {
|
|
2465
|
-
const existingSkillMd =
|
|
2466
|
-
const existingOpenaiYaml =
|
|
2376
|
+
const existingSkillMd = fs11.existsSync(existingSkillMdPath) ? fs11.readFileSync(existingSkillMdPath, "utf-8") : "";
|
|
2377
|
+
const existingOpenaiYaml = fs11.existsSync(existingOpenaiYamlPath) ? fs11.readFileSync(existingOpenaiYamlPath, "utf-8") : "";
|
|
2467
2378
|
if (existingSkillMd === renderedSkillMd && existingOpenaiYaml === renderedOpenaiYaml) {
|
|
2468
2379
|
unchanged.push(spec.skillYamlName);
|
|
2469
2380
|
} else {
|
|
@@ -2471,10 +2382,10 @@ function computeCodexSync(outputDir, specs, dryRun) {
|
|
|
2471
2382
|
}
|
|
2472
2383
|
}
|
|
2473
2384
|
if (!dryRun && !unchanged.includes(spec.skillYamlName)) {
|
|
2474
|
-
const agentsSubDir =
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2385
|
+
const agentsSubDir = path13.join(skillDir, "agents");
|
|
2386
|
+
fs11.mkdirSync(agentsSubDir, { recursive: true });
|
|
2387
|
+
fs11.writeFileSync(existingSkillMdPath, renderedSkillMd, "utf-8");
|
|
2388
|
+
fs11.writeFileSync(existingOpenaiYamlPath, renderedOpenaiYaml, "utf-8");
|
|
2478
2389
|
}
|
|
2479
2390
|
}
|
|
2480
2391
|
const removed = detectCodexOrphans(outputDir, specSkillNames);
|
|
@@ -2482,13 +2393,13 @@ function computeCodexSync(outputDir, specs, dryRun) {
|
|
|
2482
2393
|
}
|
|
2483
2394
|
function detectCodexOrphans(outputDir, specSkillNames) {
|
|
2484
2395
|
const removed = [];
|
|
2485
|
-
if (!
|
|
2486
|
-
const existingDirs =
|
|
2396
|
+
if (!fs11.existsSync(outputDir)) return removed;
|
|
2397
|
+
const existingDirs = fs11.readdirSync(outputDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
2487
2398
|
for (const dirName of existingDirs) {
|
|
2488
2399
|
if (specSkillNames.has(dirName)) continue;
|
|
2489
|
-
const skillMdPath =
|
|
2490
|
-
if (
|
|
2491
|
-
const content =
|
|
2400
|
+
const skillMdPath = path13.join(outputDir, dirName, "SKILL.md");
|
|
2401
|
+
if (fs11.existsSync(skillMdPath)) {
|
|
2402
|
+
const content = fs11.readFileSync(skillMdPath, "utf-8");
|
|
2492
2403
|
if (content.includes(GENERATED_HEADER_CODEX)) {
|
|
2493
2404
|
removed.push(dirName);
|
|
2494
2405
|
}
|
|
@@ -2500,19 +2411,19 @@ function detectCodexOrphans(outputDir, specSkillNames) {
|
|
|
2500
2411
|
// src/commands/generate-slash-commands.ts
|
|
2501
2412
|
function resolveOutputDir(platform, opts) {
|
|
2502
2413
|
if (opts.output) {
|
|
2503
|
-
return
|
|
2414
|
+
return path14.join(opts.output, "harness");
|
|
2504
2415
|
}
|
|
2505
2416
|
if (opts.global) {
|
|
2506
2417
|
const home = os.homedir();
|
|
2507
|
-
if (platform === "claude-code") return
|
|
2508
|
-
if (platform === "gemini-cli") return
|
|
2509
|
-
if (platform === "cursor") return
|
|
2510
|
-
return
|
|
2418
|
+
if (platform === "claude-code") return path14.join(home, ".claude", "commands", "harness");
|
|
2419
|
+
if (platform === "gemini-cli") return path14.join(home, ".gemini", "commands", "harness");
|
|
2420
|
+
if (platform === "cursor") return path14.join(home, ".cursor", "rules", "harness");
|
|
2421
|
+
return path14.join(home, ".codex", "harness");
|
|
2511
2422
|
}
|
|
2512
|
-
if (platform === "claude-code") return
|
|
2513
|
-
if (platform === "gemini-cli") return
|
|
2514
|
-
if (platform === "cursor") return
|
|
2515
|
-
return
|
|
2423
|
+
if (platform === "claude-code") return path14.join("agents", "commands", "claude-code", "harness");
|
|
2424
|
+
if (platform === "gemini-cli") return path14.join("agents", "commands", "gemini-cli", "harness");
|
|
2425
|
+
if (platform === "cursor") return path14.join("agents", "commands", "cursor", "harness");
|
|
2426
|
+
return path14.join("agents", "commands", "codex", "harness");
|
|
2516
2427
|
}
|
|
2517
2428
|
async function confirmDeletion(files) {
|
|
2518
2429
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -2528,8 +2439,8 @@ function resolveSkillSources(opts) {
|
|
|
2528
2439
|
const sources = [];
|
|
2529
2440
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
2530
2441
|
function addSource(dir, source) {
|
|
2531
|
-
const resolved =
|
|
2532
|
-
if (!seenPaths.has(resolved) &&
|
|
2442
|
+
const resolved = path14.resolve(dir);
|
|
2443
|
+
if (!seenPaths.has(resolved) && fs12.existsSync(dir)) {
|
|
2533
2444
|
seenPaths.add(resolved);
|
|
2534
2445
|
sources.push({ dir, source });
|
|
2535
2446
|
}
|
|
@@ -2556,32 +2467,32 @@ function resolveAbsoluteExecutionContext(spec) {
|
|
|
2556
2467
|
...spec,
|
|
2557
2468
|
prompt: {
|
|
2558
2469
|
...spec.prompt,
|
|
2559
|
-
executionContext: spec.prompt.executionContext.split("\n").map((line) => line.startsWith("@") ? `@${
|
|
2470
|
+
executionContext: spec.prompt.executionContext.split("\n").map((line) => line.startsWith("@") ? `@${path14.resolve(line.slice(1))}` : line).join("\n")
|
|
2560
2471
|
}
|
|
2561
2472
|
};
|
|
2562
2473
|
}
|
|
2563
2474
|
function renderSpec(platform, spec, useAbsolutePaths) {
|
|
2564
2475
|
if (platform === "cursor") {
|
|
2565
|
-
const mdPath2 =
|
|
2566
|
-
const skillMd =
|
|
2476
|
+
const mdPath2 = path14.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
|
|
2477
|
+
const skillMd = fs12.existsSync(mdPath2) ? fs12.readFileSync(mdPath2, "utf-8") : "";
|
|
2567
2478
|
return [`${spec.skillYamlName}.mdc`, renderCursor(spec, skillMd, spec.cursor)];
|
|
2568
2479
|
}
|
|
2569
2480
|
if (platform === "claude-code") {
|
|
2570
2481
|
const renderSpecValue = useAbsolutePaths ? resolveAbsoluteExecutionContext(spec) : spec;
|
|
2571
2482
|
return [`${spec.name}.md`, renderClaudeCode(renderSpecValue)];
|
|
2572
2483
|
}
|
|
2573
|
-
const mdPath =
|
|
2574
|
-
const yamlPath =
|
|
2575
|
-
const mdContent =
|
|
2576
|
-
const yamlContent =
|
|
2484
|
+
const mdPath = path14.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
|
|
2485
|
+
const yamlPath = path14.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
|
|
2486
|
+
const mdContent = fs12.existsSync(mdPath) ? fs12.readFileSync(mdPath, "utf-8") : "";
|
|
2487
|
+
const yamlContent = fs12.existsSync(yamlPath) ? fs12.readFileSync(yamlPath, "utf-8") : "";
|
|
2577
2488
|
return [`${spec.name}.toml`, renderGemini(spec, mdContent, yamlContent)];
|
|
2578
2489
|
}
|
|
2579
2490
|
function generateForCodex(platform, outputDir, specs, dryRun) {
|
|
2580
2491
|
const codexSync = computeCodexSync(outputDir, specs, dryRun);
|
|
2581
|
-
const codexRoot =
|
|
2492
|
+
const codexRoot = path14.dirname(outputDir);
|
|
2582
2493
|
if (!dryRun) {
|
|
2583
|
-
|
|
2584
|
-
|
|
2494
|
+
fs12.mkdirSync(codexRoot, { recursive: true });
|
|
2495
|
+
fs12.writeFileSync(path14.join(codexRoot, "AGENTS.md"), renderCodexAgentsMd(specs), "utf-8");
|
|
2585
2496
|
}
|
|
2586
2497
|
return { platform, ...codexSync, outputDir };
|
|
2587
2498
|
}
|
|
@@ -2612,9 +2523,9 @@ function generateForPlatform(platform, outputDir, specs, opts) {
|
|
|
2612
2523
|
const allUpdated = [...plan.updated];
|
|
2613
2524
|
const allRemoved = [...plan.removed];
|
|
2614
2525
|
const allUnchanged = [...plan.unchanged];
|
|
2615
|
-
const parentDir =
|
|
2526
|
+
const parentDir = path14.dirname(outputDir);
|
|
2616
2527
|
for (const [ns, nsRendered] of customNamespaceRendered) {
|
|
2617
|
-
const nsDir =
|
|
2528
|
+
const nsDir = path14.join(parentDir, ns);
|
|
2618
2529
|
const nsPlan = computeSyncPlan(nsDir, nsRendered);
|
|
2619
2530
|
if (!opts.dryRun) {
|
|
2620
2531
|
applySyncPlan(nsDir, nsRendered, nsPlan, false);
|
|
@@ -2664,13 +2575,13 @@ async function handleOrphanDeletion(results, opts) {
|
|
|
2664
2575
|
const shouldDelete = opts.yes || await confirmDeletion(result.removed);
|
|
2665
2576
|
if (!shouldDelete) continue;
|
|
2666
2577
|
for (const filename of result.removed) {
|
|
2667
|
-
const filePath =
|
|
2668
|
-
if (!
|
|
2669
|
-
const stat =
|
|
2578
|
+
const filePath = path14.join(result.outputDir, filename);
|
|
2579
|
+
if (!fs12.existsSync(filePath)) continue;
|
|
2580
|
+
const stat = fs12.statSync(filePath);
|
|
2670
2581
|
if (stat.isDirectory()) {
|
|
2671
|
-
|
|
2582
|
+
fs12.rmSync(filePath, { recursive: true, force: true });
|
|
2672
2583
|
} else {
|
|
2673
|
-
|
|
2584
|
+
fs12.unlinkSync(filePath);
|
|
2674
2585
|
}
|
|
2675
2586
|
}
|
|
2676
2587
|
}
|
|
@@ -2801,7 +2712,7 @@ async function handleGenerateSlashCommands(input) {
|
|
|
2801
2712
|
// src/mcp/resources/state.ts
|
|
2802
2713
|
async function getStateResource(projectRoot) {
|
|
2803
2714
|
try {
|
|
2804
|
-
const { loadState, migrateToStreams } = await import("./dist-
|
|
2715
|
+
const { loadState, migrateToStreams } = await import("./dist-CPKL5Y2R.js");
|
|
2805
2716
|
await migrateToStreams(projectRoot);
|
|
2806
2717
|
const result = await loadState(projectRoot);
|
|
2807
2718
|
if (result.ok) {
|
|
@@ -2919,7 +2830,7 @@ async function handleQueryGraph(input) {
|
|
|
2919
2830
|
const projectPath = sanitizePath(input.path);
|
|
2920
2831
|
const store = await loadGraphStore(projectPath);
|
|
2921
2832
|
if (!store) return graphNotFoundError();
|
|
2922
|
-
const { ContextQL } = await import("./dist-
|
|
2833
|
+
const { ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
2923
2834
|
const cql = new ContextQL(store);
|
|
2924
2835
|
const result = cql.execute({
|
|
2925
2836
|
rootNodeIds: input.rootNodeIds,
|
|
@@ -3001,7 +2912,7 @@ async function handleSearchSimilar(input) {
|
|
|
3001
2912
|
const projectPath = sanitizePath(input.path);
|
|
3002
2913
|
const store = await loadGraphStore(projectPath);
|
|
3003
2914
|
if (!store) return graphNotFoundError();
|
|
3004
|
-
const { FusionLayer } = await import("./dist-
|
|
2915
|
+
const { FusionLayer } = await import("./dist-BZS2XRLG.js");
|
|
3005
2916
|
const fusion = new FusionLayer(store);
|
|
3006
2917
|
const results = fusion.search(input.query, input.topK ?? 10);
|
|
3007
2918
|
if (input.mode === "summary") {
|
|
@@ -3056,7 +2967,7 @@ async function handleFindContextFor(input) {
|
|
|
3056
2967
|
const projectPath = sanitizePath(input.path);
|
|
3057
2968
|
const store = await loadGraphStore(projectPath);
|
|
3058
2969
|
if (!store) return graphNotFoundError();
|
|
3059
|
-
const { FusionLayer, ContextQL } = await import("./dist-
|
|
2970
|
+
const { FusionLayer, ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
3060
2971
|
const fusion = new FusionLayer(store);
|
|
3061
2972
|
const cql = new ContextQL(store);
|
|
3062
2973
|
const tokenBudget = input.tokenBudget ?? 4e3;
|
|
@@ -3161,7 +3072,7 @@ async function handleGetRelationships(input) {
|
|
|
3161
3072
|
const projectPath = sanitizePath(input.path);
|
|
3162
3073
|
const store = await loadGraphStore(projectPath);
|
|
3163
3074
|
if (!store) return graphNotFoundError();
|
|
3164
|
-
const { ContextQL } = await import("./dist-
|
|
3075
|
+
const { ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
3165
3076
|
const cql = new ContextQL(store);
|
|
3166
3077
|
const direction = input.direction ?? "both";
|
|
3167
3078
|
const bidirectional = direction === "both" || direction === "inbound";
|
|
@@ -3279,7 +3190,7 @@ async function handleGetImpact(input) {
|
|
|
3279
3190
|
const projectPath = sanitizePath(input.path);
|
|
3280
3191
|
const store = await loadGraphStore(projectPath);
|
|
3281
3192
|
if (!store) return graphNotFoundError();
|
|
3282
|
-
const { ContextQL } = await import("./dist-
|
|
3193
|
+
const { ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
3283
3194
|
let targetNodeId = input.nodeId;
|
|
3284
3195
|
if (!targetNodeId && input.filePath) {
|
|
3285
3196
|
const fileNodes = store.findNodes({ type: "file" });
|
|
@@ -3390,7 +3301,7 @@ async function handleGetImpact(input) {
|
|
|
3390
3301
|
}
|
|
3391
3302
|
|
|
3392
3303
|
// src/mcp/tools/graph/ingest-source.ts
|
|
3393
|
-
import * as
|
|
3304
|
+
import * as path15 from "path";
|
|
3394
3305
|
var ingestSourceDefinition = {
|
|
3395
3306
|
name: "ingest_source",
|
|
3396
3307
|
description: "Ingest sources into the project knowledge graph. Supports code analysis, knowledge documents, git history, or all at once.",
|
|
@@ -3410,8 +3321,8 @@ var ingestSourceDefinition = {
|
|
|
3410
3321
|
async function handleIngestSource(input) {
|
|
3411
3322
|
try {
|
|
3412
3323
|
const projectPath = sanitizePath(input.path);
|
|
3413
|
-
const graphDir =
|
|
3414
|
-
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-
|
|
3324
|
+
const graphDir = path15.join(projectPath, ".harness", "graph");
|
|
3325
|
+
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-BZS2XRLG.js");
|
|
3415
3326
|
const fs17 = await import("fs/promises");
|
|
3416
3327
|
await fs17.mkdir(graphDir, { recursive: true });
|
|
3417
3328
|
const store = new GraphStore();
|
|
@@ -3435,13 +3346,13 @@ async function handleIngestSource(input) {
|
|
|
3435
3346
|
results.push(gitResult);
|
|
3436
3347
|
}
|
|
3437
3348
|
if (input.source === "business-signals" || input.source === "all") {
|
|
3438
|
-
const { createExtractionRunner } = await import("./dist-
|
|
3439
|
-
const extractedDir =
|
|
3349
|
+
const { createExtractionRunner } = await import("./dist-BZS2XRLG.js");
|
|
3350
|
+
const extractedDir = path15.join(projectPath, ".harness", "knowledge", "extracted");
|
|
3440
3351
|
const signalsResult = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
3441
3352
|
results.push(signalsResult);
|
|
3442
3353
|
}
|
|
3443
3354
|
if (input.source === "diagrams" || input.source === "all") {
|
|
3444
|
-
const { DiagramParser } = await import("./dist-
|
|
3355
|
+
const { DiagramParser } = await import("./dist-BZS2XRLG.js");
|
|
3445
3356
|
const diagramParser = new DiagramParser(store);
|
|
3446
3357
|
const diagramResult = await diagramParser.ingest(projectPath);
|
|
3447
3358
|
results.push(diagramResult);
|
|
@@ -3507,7 +3418,7 @@ async function handleDetectAnomalies(input) {
|
|
|
3507
3418
|
const projectPath = sanitizePath(input.path);
|
|
3508
3419
|
const store = await loadGraphStore(projectPath);
|
|
3509
3420
|
if (!store) return graphNotFoundError();
|
|
3510
|
-
const { GraphAnomalyAdapter } = await import("./dist-
|
|
3421
|
+
const { GraphAnomalyAdapter } = await import("./dist-BZS2XRLG.js");
|
|
3511
3422
|
const adapter = new GraphAnomalyAdapter(store);
|
|
3512
3423
|
const report = adapter.detect({
|
|
3513
3424
|
...input.threshold !== void 0 && { threshold: input.threshold },
|
|
@@ -3556,7 +3467,7 @@ async function handleAskGraph(input) {
|
|
|
3556
3467
|
const projectPath = sanitizePath(input.path);
|
|
3557
3468
|
const store = await loadGraphStore(projectPath);
|
|
3558
3469
|
if (!store) return graphNotFoundError();
|
|
3559
|
-
const { askGraph } = await import("./dist-
|
|
3470
|
+
const { askGraph } = await import("./dist-BZS2XRLG.js");
|
|
3560
3471
|
const result = await askGraph(store, input.question);
|
|
3561
3472
|
return {
|
|
3562
3473
|
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
@@ -3620,7 +3531,7 @@ async function handleComputeBlastRadius(input) {
|
|
|
3620
3531
|
const projectPath = sanitizePath(input.path);
|
|
3621
3532
|
const store = await loadGraphStore(projectPath);
|
|
3622
3533
|
if (!store) return graphNotFoundError();
|
|
3623
|
-
const { CascadeSimulator } = await import("./dist-
|
|
3534
|
+
const { CascadeSimulator } = await import("./dist-BZS2XRLG.js");
|
|
3624
3535
|
let targetNodeId = input.nodeId;
|
|
3625
3536
|
if (!targetNodeId && input.file) {
|
|
3626
3537
|
const fileNodes = store.findNodes({ type: "file" });
|
|
@@ -3707,8 +3618,8 @@ async function handleComputeBlastRadius(input) {
|
|
|
3707
3618
|
}
|
|
3708
3619
|
|
|
3709
3620
|
// src/mcp/resources/graph.ts
|
|
3710
|
-
import * as
|
|
3711
|
-
import * as
|
|
3621
|
+
import * as fs13 from "fs/promises";
|
|
3622
|
+
import * as path16 from "path";
|
|
3712
3623
|
var MAX_ITEMS = 5e3;
|
|
3713
3624
|
function formatStaleness(isoTimestamp) {
|
|
3714
3625
|
const then = new Date(isoTimestamp).getTime();
|
|
@@ -3731,9 +3642,9 @@ function countByType(items) {
|
|
|
3731
3642
|
return counts;
|
|
3732
3643
|
}
|
|
3733
3644
|
async function readLastScanTimestamp(projectRoot) {
|
|
3734
|
-
const metadataPath =
|
|
3645
|
+
const metadataPath = path16.join(projectRoot, ".harness", "graph", "metadata.json");
|
|
3735
3646
|
try {
|
|
3736
|
-
const raw = JSON.parse(await
|
|
3647
|
+
const raw = JSON.parse(await fs13.readFile(metadataPath, "utf-8"));
|
|
3737
3648
|
return raw.lastScanTimestamp ?? null;
|
|
3738
3649
|
} catch {
|
|
3739
3650
|
return null;
|
|
@@ -3821,7 +3732,7 @@ var generateAgentDefinitionsDefinition = {
|
|
|
3821
3732
|
}
|
|
3822
3733
|
};
|
|
3823
3734
|
async function handleGenerateAgentDefinitions(input) {
|
|
3824
|
-
const { generateAgentDefinitions } = await import("./generate-agent-definitions-
|
|
3735
|
+
const { generateAgentDefinitions } = await import("./generate-agent-definitions-FOSFADNR.js");
|
|
3825
3736
|
const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
|
|
3826
3737
|
const results = generateAgentDefinitions({
|
|
3827
3738
|
platforms: [...platforms],
|
|
@@ -3832,8 +3743,8 @@ async function handleGenerateAgentDefinitions(input) {
|
|
|
3832
3743
|
}
|
|
3833
3744
|
|
|
3834
3745
|
// src/mcp/tools/roadmap.ts
|
|
3835
|
-
import * as
|
|
3836
|
-
import * as
|
|
3746
|
+
import * as fs14 from "fs";
|
|
3747
|
+
import * as path17 from "path";
|
|
3837
3748
|
var manageRoadmapDefinition = {
|
|
3838
3749
|
name: "manage_roadmap",
|
|
3839
3750
|
description: "Manage the project roadmap: show, add, update, remove, sync features, or query by filter. Reads and writes docs/roadmap.md.",
|
|
@@ -3892,21 +3803,21 @@ var manageRoadmapDefinition = {
|
|
|
3892
3803
|
}
|
|
3893
3804
|
};
|
|
3894
3805
|
function roadmapPath(projectRoot) {
|
|
3895
|
-
return
|
|
3806
|
+
return path17.join(projectRoot, "docs", "roadmap.md");
|
|
3896
3807
|
}
|
|
3897
3808
|
function readRoadmapFile(projectRoot) {
|
|
3898
3809
|
const filePath = roadmapPath(projectRoot);
|
|
3899
3810
|
try {
|
|
3900
|
-
return
|
|
3811
|
+
return fs14.readFileSync(filePath, "utf-8");
|
|
3901
3812
|
} catch {
|
|
3902
3813
|
return null;
|
|
3903
3814
|
}
|
|
3904
3815
|
}
|
|
3905
3816
|
function writeRoadmapFile(projectRoot, content) {
|
|
3906
3817
|
const filePath = roadmapPath(projectRoot);
|
|
3907
|
-
const dir =
|
|
3908
|
-
|
|
3909
|
-
|
|
3818
|
+
const dir = path17.dirname(filePath);
|
|
3819
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
3820
|
+
fs14.writeFileSync(filePath, content, "utf-8");
|
|
3910
3821
|
}
|
|
3911
3822
|
function roadmapNotFoundError() {
|
|
3912
3823
|
return {
|
|
@@ -4149,7 +4060,7 @@ function shouldTriggerExternalSync(input, response) {
|
|
|
4149
4060
|
}
|
|
4150
4061
|
async function handleManageRoadmap(input) {
|
|
4151
4062
|
try {
|
|
4152
|
-
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges, assignFeature } = await import("./dist-
|
|
4063
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges, assignFeature } = await import("./dist-CPKL5Y2R.js");
|
|
4153
4064
|
const { Ok: Ok2 } = await import("./dist-3EWNRFFQ.js");
|
|
4154
4065
|
const projectPath = sanitizePath(input.path);
|
|
4155
4066
|
const deps = {
|
|
@@ -4588,7 +4499,7 @@ async function handleTransition(validInput, projectPath, id) {
|
|
|
4588
4499
|
const transition = transitionResult.data;
|
|
4589
4500
|
const prompt = renderTransition(transition);
|
|
4590
4501
|
try {
|
|
4591
|
-
const { saveHandoff } = await import("./dist-
|
|
4502
|
+
const { saveHandoff } = await import("./dist-CPKL5Y2R.js");
|
|
4592
4503
|
await saveHandoff(
|
|
4593
4504
|
projectPath,
|
|
4594
4505
|
{
|
|
@@ -4669,7 +4580,7 @@ async function handleEmitInteraction(input) {
|
|
|
4669
4580
|
}
|
|
4670
4581
|
async function recordInteraction(projectPath, id, type, decision, stream) {
|
|
4671
4582
|
try {
|
|
4672
|
-
const { loadState, saveState } = await import("./dist-
|
|
4583
|
+
const { loadState, saveState } = await import("./dist-CPKL5Y2R.js");
|
|
4673
4584
|
const stateResult = await loadState(projectPath, stream);
|
|
4674
4585
|
if (stateResult.ok) {
|
|
4675
4586
|
const state = stateResult.value;
|
|
@@ -4827,13 +4738,13 @@ async function handleGatherContext(input) {
|
|
|
4827
4738
|
};
|
|
4828
4739
|
}
|
|
4829
4740
|
const includeSet = new Set(
|
|
4830
|
-
input.include ?? ["state", "learnings", "handoff", "graph", "validation"]
|
|
4741
|
+
input.include ?? ["state", "learnings", "handoff", "graph", "validation", "businessKnowledge"]
|
|
4831
4742
|
);
|
|
4832
4743
|
const errors = [];
|
|
4833
|
-
const statePromise = includeSet.has("state") ? import("./dist-
|
|
4744
|
+
const statePromise = includeSet.has("state") ? import("./dist-CPKL5Y2R.js").then(
|
|
4834
4745
|
(core) => core.loadState(projectPath, void 0, input.session)
|
|
4835
4746
|
) : Promise.resolve(null);
|
|
4836
|
-
const learningsPromise = includeSet.has("learnings") ? import("./dist-
|
|
4747
|
+
const learningsPromise = includeSet.has("learnings") ? import("./dist-CPKL5Y2R.js").then(
|
|
4837
4748
|
(core) => core.loadBudgetedLearnings(projectPath, {
|
|
4838
4749
|
intent: input.intent,
|
|
4839
4750
|
tokenBudget: input.learningsBudget ?? 1e3,
|
|
@@ -4842,14 +4753,14 @@ async function handleGatherContext(input) {
|
|
|
4842
4753
|
...input.depth !== void 0 && { depth: input.depth }
|
|
4843
4754
|
})
|
|
4844
4755
|
) : Promise.resolve(null);
|
|
4845
|
-
const handoffPromise = includeSet.has("handoff") ? import("./dist-
|
|
4756
|
+
const handoffPromise = includeSet.has("handoff") ? import("./dist-CPKL5Y2R.js").then(
|
|
4846
4757
|
(core) => core.loadHandoff(projectPath, void 0, input.session)
|
|
4847
4758
|
) : Promise.resolve(null);
|
|
4848
4759
|
const graphPromise = includeSet.has("graph") ? (async () => {
|
|
4849
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
4760
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-QEI7SYOQ.js");
|
|
4850
4761
|
const store = await loadGraphStore2(projectPath);
|
|
4851
4762
|
if (!store) return null;
|
|
4852
|
-
const { FusionLayer, ContextQL } = await import("./dist-
|
|
4763
|
+
const { FusionLayer, ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
4853
4764
|
const fusion = new FusionLayer(store);
|
|
4854
4765
|
const cql = new ContextQL(store);
|
|
4855
4766
|
const tokenBudget = input.tokenBudget ?? 4e3;
|
|
@@ -4886,11 +4797,11 @@ async function handleGatherContext(input) {
|
|
|
4886
4797
|
context: contextBlocks
|
|
4887
4798
|
};
|
|
4888
4799
|
})() : Promise.resolve(null);
|
|
4889
|
-
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-
|
|
4800
|
+
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-CPKL5Y2R.js").then(
|
|
4890
4801
|
(core) => core.readSessionSections(projectPath, input.session)
|
|
4891
4802
|
) : Promise.resolve(null);
|
|
4892
4803
|
const shouldIncludeEvents = input.includeEvents !== void 0 ? input.includeEvents : includeSet.has("events") || !!input.session && !input.include;
|
|
4893
|
-
const eventsPromise = shouldIncludeEvents ? import("./dist-
|
|
4804
|
+
const eventsPromise = shouldIncludeEvents ? import("./dist-CPKL5Y2R.js").then(async (core) => {
|
|
4894
4805
|
const result = await core.loadEvents(projectPath, {
|
|
4895
4806
|
session: input.session
|
|
4896
4807
|
});
|
|
@@ -4898,13 +4809,13 @@ async function handleGatherContext(input) {
|
|
|
4898
4809
|
return core.formatEventTimeline(result.value);
|
|
4899
4810
|
}) : Promise.resolve(null);
|
|
4900
4811
|
const validationPromise = includeSet.has("validation") ? (async () => {
|
|
4901
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
4812
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-EAVGKZQB.js");
|
|
4902
4813
|
const result = await handleValidateProject2({ path: projectPath });
|
|
4903
4814
|
const first = result.content[0];
|
|
4904
4815
|
return first ? JSON.parse(first.text) : null;
|
|
4905
4816
|
})() : Promise.resolve(null);
|
|
4906
4817
|
const businessKnowledgePromise = includeSet.has("businessKnowledge") ? (async () => {
|
|
4907
|
-
const { getBusinessKnowledgeResource: getBusinessKnowledgeResource2 } = await import("./business-knowledge-
|
|
4818
|
+
const { getBusinessKnowledgeResource: getBusinessKnowledgeResource2 } = await import("./business-knowledge-EISPR7FU.js");
|
|
4908
4819
|
const raw = await getBusinessKnowledgeResource2(projectPath);
|
|
4909
4820
|
return JSON.parse(raw);
|
|
4910
4821
|
})() : Promise.resolve(null);
|
|
@@ -5001,7 +4912,7 @@ async function handleGatherContext(input) {
|
|
|
5001
4912
|
};
|
|
5002
4913
|
if (input.session) {
|
|
5003
4914
|
try {
|
|
5004
|
-
const core = await import("./dist-
|
|
4915
|
+
const core = await import("./dist-CPKL5Y2R.js");
|
|
5005
4916
|
core.updateSessionIndex(
|
|
5006
4917
|
projectPath,
|
|
5007
4918
|
input.session,
|
|
@@ -5153,7 +5064,7 @@ async function handleReviewChanges(input) {
|
|
|
5153
5064
|
}
|
|
5154
5065
|
}
|
|
5155
5066
|
async function runQuickReview(projectPath, diff, diffLines, downgraded, offset, limit) {
|
|
5156
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-
|
|
5067
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-7EC4T6XG.js");
|
|
5157
5068
|
const result = await handleAnalyzeDiff2({ diff, path: projectPath });
|
|
5158
5069
|
const firstContent = result.content[0];
|
|
5159
5070
|
if (!firstContent) throw new Error("Empty analyze_diff response");
|
|
@@ -5188,7 +5099,7 @@ function extractFileCount(diffParsed) {
|
|
|
5188
5099
|
return files?.length ?? 0;
|
|
5189
5100
|
}
|
|
5190
5101
|
async function runStandardReview(projectPath, diff, diffLines, downgraded, offset, limit) {
|
|
5191
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-
|
|
5102
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-7EC4T6XG.js");
|
|
5192
5103
|
const [diffResult, reviewResult] = await Promise.all([
|
|
5193
5104
|
handleAnalyzeDiff2({ diff, path: projectPath }),
|
|
5194
5105
|
handleCreateSelfReview2({ path: projectPath, diff })
|
|
@@ -5223,7 +5134,7 @@ async function runStandardReview(projectPath, diff, diffLines, downgraded, offse
|
|
|
5223
5134
|
};
|
|
5224
5135
|
}
|
|
5225
5136
|
async function runDeepReview(projectPath, diff, diffLines, _downgraded, offset, limit) {
|
|
5226
|
-
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-
|
|
5137
|
+
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-B4WPU6BQ.js");
|
|
5227
5138
|
const result = await handleRunCodeReview2({
|
|
5228
5139
|
path: projectPath,
|
|
5229
5140
|
diff,
|
|
@@ -5302,7 +5213,7 @@ async function handleCheckTaskIndependence(input) {
|
|
|
5302
5213
|
try {
|
|
5303
5214
|
const projectPath = sanitizePath(input.path);
|
|
5304
5215
|
const store = await loadGraphStore(projectPath);
|
|
5305
|
-
const { TaskIndependenceAnalyzer } = await import("./dist-
|
|
5216
|
+
const { TaskIndependenceAnalyzer } = await import("./dist-BZS2XRLG.js");
|
|
5306
5217
|
const analyzer = new TaskIndependenceAnalyzer(store ?? void 0);
|
|
5307
5218
|
const result = analyzer.analyze({
|
|
5308
5219
|
tasks: input.tasks,
|
|
@@ -5390,7 +5301,7 @@ async function handlePredictConflicts(input) {
|
|
|
5390
5301
|
try {
|
|
5391
5302
|
const projectPath = sanitizePath(input.path);
|
|
5392
5303
|
const store = await loadGraphStore(projectPath);
|
|
5393
|
-
const { ConflictPredictor } = await import("./dist-
|
|
5304
|
+
const { ConflictPredictor } = await import("./dist-BZS2XRLG.js");
|
|
5394
5305
|
const predictor = new ConflictPredictor(store ?? void 0);
|
|
5395
5306
|
const result = predictor.predict({
|
|
5396
5307
|
tasks: input.tasks,
|
|
@@ -5496,7 +5407,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
5496
5407
|
isError: true
|
|
5497
5408
|
};
|
|
5498
5409
|
}
|
|
5499
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
5410
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-QEI7SYOQ.js");
|
|
5500
5411
|
const store = await loadGraphStore2(projectPath);
|
|
5501
5412
|
if (!store) {
|
|
5502
5413
|
return {
|
|
@@ -5517,7 +5428,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
5517
5428
|
]
|
|
5518
5429
|
};
|
|
5519
5430
|
}
|
|
5520
|
-
const { detectStaleConstraints } = await import("./dist-
|
|
5431
|
+
const { detectStaleConstraints } = await import("./dist-CPKL5Y2R.js");
|
|
5521
5432
|
const result = detectStaleConstraints(
|
|
5522
5433
|
store,
|
|
5523
5434
|
windowDays,
|
|
@@ -5549,8 +5460,8 @@ init_dist();
|
|
|
5549
5460
|
|
|
5550
5461
|
// src/skill/health-snapshot.ts
|
|
5551
5462
|
import { execSync } from "child_process";
|
|
5552
|
-
import * as
|
|
5553
|
-
import * as
|
|
5463
|
+
import * as fs15 from "fs";
|
|
5464
|
+
import * as path18 from "path";
|
|
5554
5465
|
var CACHE_FILE = "health-snapshot.json";
|
|
5555
5466
|
var STALENESS_MS = 36e5;
|
|
5556
5467
|
function isSnapshotFresh(snapshot, projectPath) {
|
|
@@ -5567,19 +5478,19 @@ function isSnapshotFresh(snapshot, projectPath) {
|
|
|
5567
5478
|
return age < STALENESS_MS;
|
|
5568
5479
|
}
|
|
5569
5480
|
function loadCachedSnapshot(projectPath) {
|
|
5570
|
-
const filePath =
|
|
5481
|
+
const filePath = path18.join(projectPath, ".harness", CACHE_FILE);
|
|
5571
5482
|
try {
|
|
5572
|
-
const raw =
|
|
5483
|
+
const raw = fs15.readFileSync(filePath, "utf-8");
|
|
5573
5484
|
return JSON.parse(raw);
|
|
5574
5485
|
} catch {
|
|
5575
5486
|
return null;
|
|
5576
5487
|
}
|
|
5577
5488
|
}
|
|
5578
5489
|
function saveCachedSnapshot(snapshot, projectPath) {
|
|
5579
|
-
const dir =
|
|
5580
|
-
|
|
5581
|
-
const filePath =
|
|
5582
|
-
|
|
5490
|
+
const dir = path18.join(projectPath, ".harness");
|
|
5491
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
5492
|
+
const filePath = path18.join(dir, CACHE_FILE);
|
|
5493
|
+
fs15.writeFileSync(filePath, JSON.stringify(snapshot, null, 2));
|
|
5583
5494
|
}
|
|
5584
5495
|
var SIGNAL_RULES = [
|
|
5585
5496
|
["circular-deps", (c) => c.deps.circularDeps > 0],
|
|
@@ -5637,10 +5548,10 @@ function countCriticalFindings(securityData) {
|
|
|
5637
5548
|
return findings.filter((f) => f.severity === "error").length;
|
|
5638
5549
|
}
|
|
5639
5550
|
async function runHealthChecks(projectPath) {
|
|
5640
|
-
const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-
|
|
5641
|
-
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-
|
|
5642
|
-
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-
|
|
5643
|
-
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-
|
|
5551
|
+
const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-LLWWEQEV.js");
|
|
5552
|
+
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-ZR33YKJB.js");
|
|
5553
|
+
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-FIEE4YDA.js");
|
|
5554
|
+
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-25VFLIAO.js");
|
|
5644
5555
|
const [assessResult, depsResult, entropyResult, securityResult] = await Promise.all([
|
|
5645
5556
|
handleAssessProject2({
|
|
5646
5557
|
path: projectPath,
|
|
@@ -5695,10 +5606,10 @@ function avg(values) {
|
|
|
5695
5606
|
}
|
|
5696
5607
|
async function runGraphMetrics(projectPath) {
|
|
5697
5608
|
try {
|
|
5698
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
5609
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-QEI7SYOQ.js");
|
|
5699
5610
|
const store = await loadGraphStore2(projectPath);
|
|
5700
5611
|
if (!store) return ZERO_METRICS;
|
|
5701
|
-
const { GraphCouplingAdapter, GraphComplexityAdapter, GraphAnomalyAdapter } = await import("./dist-
|
|
5612
|
+
const { GraphCouplingAdapter, GraphComplexityAdapter, GraphAnomalyAdapter } = await import("./dist-BZS2XRLG.js");
|
|
5702
5613
|
const couplingAdapter = new GraphCouplingAdapter(store);
|
|
5703
5614
|
const couplingData = couplingAdapter.computeCouplingData();
|
|
5704
5615
|
const files = couplingData.files;
|
|
@@ -5927,7 +5838,8 @@ function resolveMetricValue(metrics, metricName) {
|
|
|
5927
5838
|
function buildSkillAddressIndex(skills) {
|
|
5928
5839
|
const index = /* @__PURE__ */ new Map();
|
|
5929
5840
|
for (const [name, entry] of Object.entries(skills)) {
|
|
5930
|
-
const
|
|
5841
|
+
const canonicalName = name.replace(/^harness-/, "");
|
|
5842
|
+
const addresses = entry.addresses.length > 0 ? entry.addresses : FALLBACK_RULES[name] ?? FALLBACK_RULES[canonicalName] ?? [];
|
|
5931
5843
|
index.set(name, { addresses, dependsOn: entry.dependsOn });
|
|
5932
5844
|
}
|
|
5933
5845
|
for (const [name, addresses] of Object.entries(FALLBACK_RULES)) {
|
|
@@ -6087,7 +5999,14 @@ function recommend(snapshot, skills, options = {}) {
|
|
|
6087
5999
|
const hardRecs = matchHardRules(snapshot, addressIndex);
|
|
6088
6000
|
const softRecs = scoreByHealth(snapshot, addressIndex);
|
|
6089
6001
|
const hardSkills = new Set(hardRecs.map((r) => r.skillName));
|
|
6090
|
-
|
|
6002
|
+
let merged = [...hardRecs, ...softRecs.filter((r) => !hardSkills.has(r.skillName))];
|
|
6003
|
+
const { trigger, skillTriggers } = options;
|
|
6004
|
+
if (trigger && skillTriggers) {
|
|
6005
|
+
merged = merged.filter((r) => {
|
|
6006
|
+
const triggers = skillTriggers.get(r.skillName);
|
|
6007
|
+
return triggers ? triggers.includes(trigger) : true;
|
|
6008
|
+
});
|
|
6009
|
+
}
|
|
6091
6010
|
merged.sort((a, b) => b.score - a.score);
|
|
6092
6011
|
const limited = merged.slice(0, top);
|
|
6093
6012
|
const depMap = /* @__PURE__ */ new Map();
|
|
@@ -6252,7 +6171,12 @@ function dispatchSkills(context, options = {}) {
|
|
|
6252
6171
|
const { snapshot, changeType, domains, allSignals } = context;
|
|
6253
6172
|
const limit = options.limit ?? 5;
|
|
6254
6173
|
const enrichedSnapshot = { ...snapshot, signals: allSignals };
|
|
6255
|
-
const
|
|
6174
|
+
const recOpts = {
|
|
6175
|
+
top: limit
|
|
6176
|
+
};
|
|
6177
|
+
if (options.trigger) recOpts.trigger = options.trigger;
|
|
6178
|
+
if (options.skillTriggers) recOpts.skillTriggers = options.skillTriggers;
|
|
6179
|
+
const recResult = recommend(enrichedSnapshot, {}, recOpts);
|
|
6256
6180
|
const addressIndex = buildSkillAddressIndex({});
|
|
6257
6181
|
const skills = recResult.recommendations.map((rec, i) => {
|
|
6258
6182
|
const prevRec = i > 0 ? recResult.recommendations[i - 1] : null;
|
|
@@ -6303,6 +6227,8 @@ async function dispatchSkillsFromGit(projectPath, options = {}) {
|
|
|
6303
6227
|
const ctx = await enrichSnapshotForDispatch(projectPath, enrichOpts);
|
|
6304
6228
|
const dispatchOpts = {};
|
|
6305
6229
|
if (options.limit !== void 0) dispatchOpts.limit = options.limit;
|
|
6230
|
+
if (options.trigger) dispatchOpts.trigger = options.trigger;
|
|
6231
|
+
if (options.skillTriggers) dispatchOpts.skillTriggers = options.skillTriggers;
|
|
6306
6232
|
return dispatchSkills(ctx, dispatchOpts);
|
|
6307
6233
|
}
|
|
6308
6234
|
|
|
@@ -6333,6 +6259,10 @@ var dispatchSkillsDefinition = {
|
|
|
6333
6259
|
limit: {
|
|
6334
6260
|
type: "number",
|
|
6335
6261
|
description: "Maximum number of skills to return (default: 5)"
|
|
6262
|
+
},
|
|
6263
|
+
trigger: {
|
|
6264
|
+
type: "string",
|
|
6265
|
+
description: "Filter to skills declaring this trigger (e.g. on_pr, on_commit, on_milestone, on_task_complete, on_refactor, on_review). Only skills whose triggers array includes this value are returned."
|
|
6336
6266
|
}
|
|
6337
6267
|
},
|
|
6338
6268
|
required: []
|
|
@@ -6345,19 +6275,23 @@ function buildEnrichOpts(files, commitMessage, fresh) {
|
|
|
6345
6275
|
if (fresh) opts.fresh = fresh;
|
|
6346
6276
|
return opts;
|
|
6347
6277
|
}
|
|
6348
|
-
async function dispatchWithExplicitInput(projectRoot, files, commitMessage, fresh, limit) {
|
|
6278
|
+
async function dispatchWithExplicitInput(projectRoot, files, commitMessage, fresh, limit, trigger, skillTriggers) {
|
|
6349
6279
|
const ctx = await enrichSnapshotForDispatch(
|
|
6350
6280
|
projectRoot,
|
|
6351
6281
|
buildEnrichOpts(files, commitMessage, fresh)
|
|
6352
6282
|
);
|
|
6353
6283
|
const dispatchOpts = {};
|
|
6354
6284
|
if (limit !== 5) dispatchOpts.limit = limit;
|
|
6285
|
+
if (trigger) dispatchOpts.trigger = trigger;
|
|
6286
|
+
if (skillTriggers) dispatchOpts.skillTriggers = skillTriggers;
|
|
6355
6287
|
return dispatchSkills(ctx, dispatchOpts);
|
|
6356
6288
|
}
|
|
6357
|
-
async function dispatchFromGit(projectRoot, fresh, limit) {
|
|
6289
|
+
async function dispatchFromGit(projectRoot, fresh, limit, trigger, skillTriggers) {
|
|
6358
6290
|
const opts = {};
|
|
6359
6291
|
if (fresh) opts.fresh = fresh;
|
|
6360
6292
|
if (limit !== 5) opts.limit = limit;
|
|
6293
|
+
if (trigger) opts.trigger = trigger;
|
|
6294
|
+
if (skillTriggers) opts.skillTriggers = skillTriggers;
|
|
6361
6295
|
return dispatchSkillsFromGit(projectRoot, opts);
|
|
6362
6296
|
}
|
|
6363
6297
|
async function handleDispatchSkills(input) {
|
|
@@ -6366,9 +6300,30 @@ async function handleDispatchSkills(input) {
|
|
|
6366
6300
|
const commitMessage = input.commitMessage;
|
|
6367
6301
|
const fresh = input.fresh ?? false;
|
|
6368
6302
|
const limit = input.limit ?? 5;
|
|
6303
|
+
const trigger = input.trigger;
|
|
6369
6304
|
try {
|
|
6305
|
+
let skillTriggers;
|
|
6306
|
+
if (trigger) {
|
|
6307
|
+
try {
|
|
6308
|
+
const { loadOrRebuildIndex: loadOrRebuildIndex2 } = await import("./index-builder-3AOQ3ZII.js");
|
|
6309
|
+
const index = loadOrRebuildIndex2("claude-code", projectRoot);
|
|
6310
|
+
skillTriggers = /* @__PURE__ */ new Map();
|
|
6311
|
+
for (const [name, entry] of Object.entries(index.skills)) {
|
|
6312
|
+
skillTriggers.set(name, entry.triggers ?? ["manual"]);
|
|
6313
|
+
}
|
|
6314
|
+
} catch {
|
|
6315
|
+
}
|
|
6316
|
+
}
|
|
6370
6317
|
const hasExplicitInput = files !== void 0 || commitMessage !== void 0;
|
|
6371
|
-
const result = hasExplicitInput ? await dispatchWithExplicitInput(
|
|
6318
|
+
const result = hasExplicitInput ? await dispatchWithExplicitInput(
|
|
6319
|
+
projectRoot,
|
|
6320
|
+
files,
|
|
6321
|
+
commitMessage,
|
|
6322
|
+
fresh,
|
|
6323
|
+
limit,
|
|
6324
|
+
trigger,
|
|
6325
|
+
skillTriggers
|
|
6326
|
+
) : await dispatchFromGit(projectRoot, fresh, limit, trigger, skillTriggers);
|
|
6372
6327
|
if (result.skills.length > limit) {
|
|
6373
6328
|
result.skills = result.skills.slice(0, limit);
|
|
6374
6329
|
}
|
|
@@ -6437,7 +6392,7 @@ async function handleGetDecayTrends(input) {
|
|
|
6437
6392
|
};
|
|
6438
6393
|
}
|
|
6439
6394
|
try {
|
|
6440
|
-
const core = await import("./dist-
|
|
6395
|
+
const core = await import("./dist-CPKL5Y2R.js");
|
|
6441
6396
|
const { TimelineManager } = core;
|
|
6442
6397
|
const manager = new TimelineManager(projectPath);
|
|
6443
6398
|
const timeline = manager.load();
|
|
@@ -6572,7 +6527,7 @@ async function handleCodeOutline(input) {
|
|
|
6572
6527
|
};
|
|
6573
6528
|
}
|
|
6574
6529
|
try {
|
|
6575
|
-
const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-
|
|
6530
|
+
const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-CPKL5Y2R.js");
|
|
6576
6531
|
const { stat } = await import("fs/promises");
|
|
6577
6532
|
const stats = await stat(targetPath).catch(() => null);
|
|
6578
6533
|
if (stats?.isFile()) {
|
|
@@ -6591,7 +6546,7 @@ async function handleCodeOutline(input) {
|
|
|
6591
6546
|
})
|
|
6592
6547
|
);
|
|
6593
6548
|
fileStats.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
6594
|
-
const { paginate: paginate2 } = await import("./dist-
|
|
6549
|
+
const { paginate: paginate2 } = await import("./dist-CPKL5Y2R.js");
|
|
6595
6550
|
const paged = paginate2(fileStats, input.offset ?? 0, input.limit ?? 30);
|
|
6596
6551
|
const results = [];
|
|
6597
6552
|
for (const entry of paged.items) {
|
|
@@ -6664,7 +6619,7 @@ async function handleCodeSearch(input) {
|
|
|
6664
6619
|
};
|
|
6665
6620
|
}
|
|
6666
6621
|
try {
|
|
6667
|
-
const { searchSymbols } = await import("./dist-
|
|
6622
|
+
const { searchSymbols } = await import("./dist-CPKL5Y2R.js");
|
|
6668
6623
|
const result = await searchSymbols(input.query, directory, input.glob);
|
|
6669
6624
|
const lines = [`Search: "${result.query}" \u2014 ${result.matches.length} matches`];
|
|
6670
6625
|
for (const match of result.matches) {
|
|
@@ -6733,7 +6688,7 @@ async function handleCodeUnfold(input) {
|
|
|
6733
6688
|
}
|
|
6734
6689
|
try {
|
|
6735
6690
|
if (input.symbol) {
|
|
6736
|
-
const { unfoldSymbol } = await import("./dist-
|
|
6691
|
+
const { unfoldSymbol } = await import("./dist-CPKL5Y2R.js");
|
|
6737
6692
|
const result = await unfoldSymbol(filePath, input.symbol);
|
|
6738
6693
|
const header = result.warning ? `${result.file}:${result.startLine}-${result.endLine} ${result.warning}
|
|
6739
6694
|
` : `${result.file}:${result.startLine}-${result.endLine}
|
|
@@ -6741,7 +6696,7 @@ async function handleCodeUnfold(input) {
|
|
|
6741
6696
|
return { content: [{ type: "text", text: header + result.content }] };
|
|
6742
6697
|
}
|
|
6743
6698
|
if (input.startLine != null && input.endLine != null) {
|
|
6744
|
-
const { unfoldRange } = await import("./dist-
|
|
6699
|
+
const { unfoldRange } = await import("./dist-CPKL5Y2R.js");
|
|
6745
6700
|
const result = await unfoldRange(filePath, input.startLine, input.endLine);
|
|
6746
6701
|
const header = `${result.file}:${result.startLine}-${result.endLine}
|
|
6747
6702
|
`;
|
|
@@ -6803,7 +6758,7 @@ async function handleCheckTraceability(input) {
|
|
|
6803
6758
|
isError: true
|
|
6804
6759
|
};
|
|
6805
6760
|
}
|
|
6806
|
-
const { queryTraceability } = await import("./dist-
|
|
6761
|
+
const { queryTraceability } = await import("./dist-BZS2XRLG.js");
|
|
6807
6762
|
const options = {};
|
|
6808
6763
|
if (input.spec) options.specPath = input.spec;
|
|
6809
6764
|
if (input.feature) options.featureName = input.feature;
|
|
@@ -6926,7 +6881,7 @@ async function handlePredictFailures(input) {
|
|
|
6926
6881
|
};
|
|
6927
6882
|
}
|
|
6928
6883
|
try {
|
|
6929
|
-
const core = await import("./dist-
|
|
6884
|
+
const core = await import("./dist-CPKL5Y2R.js");
|
|
6930
6885
|
const { TimelineManager, PredictionEngine, SpecImpactEstimator } = core;
|
|
6931
6886
|
const manager = new TimelineManager(projectPath);
|
|
6932
6887
|
const includeRoadmap = input.includeRoadmap !== false;
|
|
@@ -7028,6 +6983,699 @@ async function handleRecommendSkills(input) {
|
|
|
7028
6983
|
};
|
|
7029
6984
|
}
|
|
7030
6985
|
|
|
6986
|
+
// src/mcp/tools/advise-skills.ts
|
|
6987
|
+
import path20 from "path";
|
|
6988
|
+
|
|
6989
|
+
// src/commands/advise-skills.ts
|
|
6990
|
+
import { Command as Command2 } from "commander";
|
|
6991
|
+
import fs16 from "fs";
|
|
6992
|
+
import path19 from "path";
|
|
6993
|
+
import chalk from "chalk";
|
|
6994
|
+
|
|
6995
|
+
// src/skill/content-matcher-types.ts
|
|
6996
|
+
var TIER_THRESHOLDS = {
|
|
6997
|
+
apply: 0.6,
|
|
6998
|
+
reference: 0.35,
|
|
6999
|
+
consider: 0.15
|
|
7000
|
+
};
|
|
7001
|
+
var SCORING_WEIGHTS = {
|
|
7002
|
+
keyword: 0.35,
|
|
7003
|
+
stack: 0.25,
|
|
7004
|
+
termOverlap: 0.25,
|
|
7005
|
+
domain: 0.15
|
|
7006
|
+
};
|
|
7007
|
+
var DOMAIN_KEYWORD_MAP = {
|
|
7008
|
+
design: [
|
|
7009
|
+
"layout",
|
|
7010
|
+
"responsive",
|
|
7011
|
+
"typography",
|
|
7012
|
+
"color",
|
|
7013
|
+
"theme",
|
|
7014
|
+
"dark mode",
|
|
7015
|
+
"ui",
|
|
7016
|
+
"ux",
|
|
7017
|
+
"component",
|
|
7018
|
+
"palette",
|
|
7019
|
+
"breakpoint",
|
|
7020
|
+
"grid",
|
|
7021
|
+
"elevation",
|
|
7022
|
+
"shadow",
|
|
7023
|
+
"motion",
|
|
7024
|
+
"animation",
|
|
7025
|
+
"css"
|
|
7026
|
+
],
|
|
7027
|
+
auth: [
|
|
7028
|
+
"authentication",
|
|
7029
|
+
"authorization",
|
|
7030
|
+
"oauth",
|
|
7031
|
+
"session",
|
|
7032
|
+
"token",
|
|
7033
|
+
"jwt",
|
|
7034
|
+
"login",
|
|
7035
|
+
"signup",
|
|
7036
|
+
"password",
|
|
7037
|
+
"credential",
|
|
7038
|
+
"rbac",
|
|
7039
|
+
"permission",
|
|
7040
|
+
"identity"
|
|
7041
|
+
],
|
|
7042
|
+
data: [
|
|
7043
|
+
"database",
|
|
7044
|
+
"schema",
|
|
7045
|
+
"migration",
|
|
7046
|
+
"query",
|
|
7047
|
+
"sql",
|
|
7048
|
+
"nosql",
|
|
7049
|
+
"orm",
|
|
7050
|
+
"model",
|
|
7051
|
+
"table",
|
|
7052
|
+
"transaction",
|
|
7053
|
+
"prisma",
|
|
7054
|
+
"drizzle"
|
|
7055
|
+
],
|
|
7056
|
+
security: [
|
|
7057
|
+
"security",
|
|
7058
|
+
"vulnerability",
|
|
7059
|
+
"xss",
|
|
7060
|
+
"csrf",
|
|
7061
|
+
"injection",
|
|
7062
|
+
"sanitiz",
|
|
7063
|
+
"encrypt",
|
|
7064
|
+
"hash",
|
|
7065
|
+
"owasp",
|
|
7066
|
+
"cve",
|
|
7067
|
+
"audit"
|
|
7068
|
+
],
|
|
7069
|
+
a11y: [
|
|
7070
|
+
"accessibility",
|
|
7071
|
+
"a11y",
|
|
7072
|
+
"aria",
|
|
7073
|
+
"screen reader",
|
|
7074
|
+
"screen-reader",
|
|
7075
|
+
"wcag",
|
|
7076
|
+
"contrast",
|
|
7077
|
+
"keyboard navigation",
|
|
7078
|
+
"focus management"
|
|
7079
|
+
],
|
|
7080
|
+
perf: [
|
|
7081
|
+
"performance",
|
|
7082
|
+
"latency",
|
|
7083
|
+
"throughput",
|
|
7084
|
+
"cache",
|
|
7085
|
+
"lazy load",
|
|
7086
|
+
"bundle size",
|
|
7087
|
+
"tree shaking",
|
|
7088
|
+
"code splitting",
|
|
7089
|
+
"lighthouse",
|
|
7090
|
+
"optimization",
|
|
7091
|
+
"bundle"
|
|
7092
|
+
],
|
|
7093
|
+
testing: [
|
|
7094
|
+
"test",
|
|
7095
|
+
"coverage",
|
|
7096
|
+
"mock",
|
|
7097
|
+
"stub",
|
|
7098
|
+
"fixture",
|
|
7099
|
+
"assertion",
|
|
7100
|
+
"snapshot",
|
|
7101
|
+
"e2e",
|
|
7102
|
+
"integration test",
|
|
7103
|
+
"unit test",
|
|
7104
|
+
"tdd"
|
|
7105
|
+
],
|
|
7106
|
+
api: [
|
|
7107
|
+
"api",
|
|
7108
|
+
"endpoint",
|
|
7109
|
+
"rest",
|
|
7110
|
+
"graphql",
|
|
7111
|
+
"openapi",
|
|
7112
|
+
"swagger",
|
|
7113
|
+
"route",
|
|
7114
|
+
"middleware",
|
|
7115
|
+
"webhook",
|
|
7116
|
+
"grpc"
|
|
7117
|
+
],
|
|
7118
|
+
infra: [
|
|
7119
|
+
"docker",
|
|
7120
|
+
"kubernetes",
|
|
7121
|
+
"ci/cd",
|
|
7122
|
+
"ci",
|
|
7123
|
+
"cd",
|
|
7124
|
+
"deploy",
|
|
7125
|
+
"terraform",
|
|
7126
|
+
"aws",
|
|
7127
|
+
"gcp",
|
|
7128
|
+
"azure",
|
|
7129
|
+
"cloud",
|
|
7130
|
+
"container",
|
|
7131
|
+
"helm"
|
|
7132
|
+
],
|
|
7133
|
+
mobile: [
|
|
7134
|
+
"mobile",
|
|
7135
|
+
"ios",
|
|
7136
|
+
"android",
|
|
7137
|
+
"react native",
|
|
7138
|
+
"react-native",
|
|
7139
|
+
"flutter",
|
|
7140
|
+
"app store",
|
|
7141
|
+
"push notification"
|
|
7142
|
+
]
|
|
7143
|
+
};
|
|
7144
|
+
|
|
7145
|
+
// src/skill/signal-extractor.ts
|
|
7146
|
+
var STEM_SUFFIXES = [
|
|
7147
|
+
"ation",
|
|
7148
|
+
"tion",
|
|
7149
|
+
"sion",
|
|
7150
|
+
"ment",
|
|
7151
|
+
"ness",
|
|
7152
|
+
"ible",
|
|
7153
|
+
"able",
|
|
7154
|
+
"ive",
|
|
7155
|
+
"ous",
|
|
7156
|
+
"ful",
|
|
7157
|
+
"ing",
|
|
7158
|
+
"ity",
|
|
7159
|
+
"ly",
|
|
7160
|
+
"ed",
|
|
7161
|
+
"er",
|
|
7162
|
+
"es",
|
|
7163
|
+
"s"
|
|
7164
|
+
];
|
|
7165
|
+
function simpleStem(word) {
|
|
7166
|
+
const w = word.toLowerCase();
|
|
7167
|
+
if (w.length <= 4) return w;
|
|
7168
|
+
for (const suffix of STEM_SUFFIXES) {
|
|
7169
|
+
if (w.endsWith(suffix) && w.length - suffix.length >= 3) {
|
|
7170
|
+
return w.slice(0, -suffix.length);
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7173
|
+
return w;
|
|
7174
|
+
}
|
|
7175
|
+
function extractSpecKeywords(specText) {
|
|
7176
|
+
const match = specText.match(/\*\*Keywords?:\*\*\s*(.+)/i);
|
|
7177
|
+
if (!match?.[1]) return [];
|
|
7178
|
+
return match[1].split(",").map((k) => k.trim()).filter((k) => k.length > 0);
|
|
7179
|
+
}
|
|
7180
|
+
var STACK_SIGNAL_MAP = {
|
|
7181
|
+
react: "react",
|
|
7182
|
+
"react-dom": "react",
|
|
7183
|
+
"react-native": "react-native",
|
|
7184
|
+
next: "next",
|
|
7185
|
+
vue: "vue",
|
|
7186
|
+
nuxt: "nuxt",
|
|
7187
|
+
angular: "angular",
|
|
7188
|
+
svelte: "svelte",
|
|
7189
|
+
express: "express",
|
|
7190
|
+
fastify: "fastify",
|
|
7191
|
+
nestjs: "nest",
|
|
7192
|
+
"@nestjs/core": "nest",
|
|
7193
|
+
typescript: "typescript",
|
|
7194
|
+
tailwindcss: "tailwind",
|
|
7195
|
+
prisma: "prisma",
|
|
7196
|
+
"@prisma/client": "prisma",
|
|
7197
|
+
"drizzle-orm": "drizzle",
|
|
7198
|
+
graphql: "graphql",
|
|
7199
|
+
"@trpc/server": "trpc",
|
|
7200
|
+
trpc: "trpc",
|
|
7201
|
+
vitest: "vitest",
|
|
7202
|
+
jest: "jest",
|
|
7203
|
+
playwright: "playwright",
|
|
7204
|
+
cypress: "cypress",
|
|
7205
|
+
vite: "vite",
|
|
7206
|
+
webpack: "webpack",
|
|
7207
|
+
zod: "zod",
|
|
7208
|
+
mongoose: "mongoose",
|
|
7209
|
+
redis: "redis",
|
|
7210
|
+
ioredis: "redis",
|
|
7211
|
+
"socket.io": "websocket",
|
|
7212
|
+
ws: "websocket"
|
|
7213
|
+
};
|
|
7214
|
+
function detectStackFromDeps(dependencies, devDependencies) {
|
|
7215
|
+
const signals = /* @__PURE__ */ new Set();
|
|
7216
|
+
const allDeps = { ...dependencies, ...devDependencies };
|
|
7217
|
+
for (const pkgName of Object.keys(allDeps)) {
|
|
7218
|
+
const signal = STACK_SIGNAL_MAP[pkgName];
|
|
7219
|
+
if (signal) {
|
|
7220
|
+
signals.add(signal);
|
|
7221
|
+
}
|
|
7222
|
+
}
|
|
7223
|
+
return [...signals].sort();
|
|
7224
|
+
}
|
|
7225
|
+
function inferDomain(specText) {
|
|
7226
|
+
const lower = specText.toLowerCase();
|
|
7227
|
+
const domains = [];
|
|
7228
|
+
for (const [domain, markers] of Object.entries(DOMAIN_KEYWORD_MAP)) {
|
|
7229
|
+
const hits = markers.filter((m) => lower.includes(m)).length;
|
|
7230
|
+
if (hits >= 2) {
|
|
7231
|
+
domains.push(domain);
|
|
7232
|
+
}
|
|
7233
|
+
}
|
|
7234
|
+
return domains.sort();
|
|
7235
|
+
}
|
|
7236
|
+
function extractSignals(specText, dependencies, devDependencies, contextKeywords, taskText) {
|
|
7237
|
+
const specKeywords = extractSpecKeywords(specText);
|
|
7238
|
+
if (contextKeywords) {
|
|
7239
|
+
const existing = new Set(specKeywords);
|
|
7240
|
+
for (const kw of contextKeywords) {
|
|
7241
|
+
if (!existing.has(kw)) {
|
|
7242
|
+
specKeywords.push(kw);
|
|
7243
|
+
existing.add(kw);
|
|
7244
|
+
}
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
const stackSignals = detectStackFromDeps(dependencies, devDependencies);
|
|
7248
|
+
const featureDomain = inferDomain(specText);
|
|
7249
|
+
return {
|
|
7250
|
+
specKeywords,
|
|
7251
|
+
specText,
|
|
7252
|
+
stackSignals,
|
|
7253
|
+
featureDomain,
|
|
7254
|
+
...taskText !== void 0 && { taskText }
|
|
7255
|
+
};
|
|
7256
|
+
}
|
|
7257
|
+
|
|
7258
|
+
// src/skill/content-matcher.ts
|
|
7259
|
+
function computeKeywordOverlap(skillKeywords, specKeywords) {
|
|
7260
|
+
if (skillKeywords.length === 0 || specKeywords.length === 0) return 0;
|
|
7261
|
+
const stemTokens = (keywords) => {
|
|
7262
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
7263
|
+
for (const kw of keywords) {
|
|
7264
|
+
const parts = kw.toLowerCase().split(/[-_\s]+/);
|
|
7265
|
+
for (const part of parts) {
|
|
7266
|
+
if (part.length > 0) {
|
|
7267
|
+
tokens.add(simpleStem(part));
|
|
7268
|
+
}
|
|
7269
|
+
}
|
|
7270
|
+
}
|
|
7271
|
+
return tokens;
|
|
7272
|
+
};
|
|
7273
|
+
const skillStems = stemTokens(skillKeywords);
|
|
7274
|
+
const specStems = stemTokens(specKeywords);
|
|
7275
|
+
let intersectionCount = 0;
|
|
7276
|
+
for (const stem of skillStems) {
|
|
7277
|
+
if (specStems.has(stem)) intersectionCount++;
|
|
7278
|
+
}
|
|
7279
|
+
const unionSize = (/* @__PURE__ */ new Set([...skillStems, ...specStems])).size;
|
|
7280
|
+
return unionSize > 0 ? intersectionCount / unionSize : 0;
|
|
7281
|
+
}
|
|
7282
|
+
function computeStackMatch(skillSignals, projectSignals) {
|
|
7283
|
+
if (skillSignals.length === 0) return 0;
|
|
7284
|
+
const projectSet = new Set(projectSignals.map((s) => s.toLowerCase()));
|
|
7285
|
+
const matched = skillSignals.filter((s) => projectSet.has(s.toLowerCase())).length;
|
|
7286
|
+
return matched / skillSignals.length;
|
|
7287
|
+
}
|
|
7288
|
+
function computeTermOverlap(skillDescription, specText) {
|
|
7289
|
+
if (!skillDescription || !specText) return 0;
|
|
7290
|
+
const tokenize = (text) => text.toLowerCase().split(/[\s\-_,.;:!?()[\]{}"'`]+/).filter((t) => t.length > 3).map(simpleStem);
|
|
7291
|
+
const descTokens = tokenize(skillDescription);
|
|
7292
|
+
if (descTokens.length === 0) return 0;
|
|
7293
|
+
const specTokenSet = new Set(tokenize(specText));
|
|
7294
|
+
const matched = descTokens.filter((t) => specTokenSet.has(t)).length;
|
|
7295
|
+
return matched / descTokens.length;
|
|
7296
|
+
}
|
|
7297
|
+
function computeDomainMatch(entry, featureDomains) {
|
|
7298
|
+
if (featureDomains.length === 0 || entry.keywords.length === 0) return 0;
|
|
7299
|
+
const skillKeywordsLower = entry.keywords.map((k) => k.toLowerCase());
|
|
7300
|
+
for (const domain of featureDomains) {
|
|
7301
|
+
const domainKeywords = DOMAIN_KEYWORD_MAP[domain];
|
|
7302
|
+
if (!domainKeywords) continue;
|
|
7303
|
+
const hasMatch = skillKeywordsLower.some(
|
|
7304
|
+
(kw) => domainKeywords.some((dk) => kw.includes(dk) || dk.includes(kw))
|
|
7305
|
+
);
|
|
7306
|
+
if (hasMatch) return 1;
|
|
7307
|
+
}
|
|
7308
|
+
return 0;
|
|
7309
|
+
}
|
|
7310
|
+
function classifyTier(score) {
|
|
7311
|
+
if (score >= TIER_THRESHOLDS.apply) return "apply";
|
|
7312
|
+
if (score >= TIER_THRESHOLDS.reference) return "reference";
|
|
7313
|
+
if (score >= TIER_THRESHOLDS.consider) return "consider";
|
|
7314
|
+
return null;
|
|
7315
|
+
}
|
|
7316
|
+
var WHEN_RULES = [
|
|
7317
|
+
{ name: /scan|audit|i18n|lint/, when: "End of phase" },
|
|
7318
|
+
{ name: /test/, keywords: /test|tdd|coverage|mock|e2e|snapshot/, when: "Testing" },
|
|
7319
|
+
{
|
|
7320
|
+
name: /a11y|contrast|wcag|color.accessib/,
|
|
7321
|
+
keywords: /contrast|wcag/,
|
|
7322
|
+
when: "After styling"
|
|
7323
|
+
},
|
|
7324
|
+
{ keywords: /css|tailwind|typography|font|color|palette/, when: "During styling" },
|
|
7325
|
+
{ keywords: /alignment|whitespace|spacing|grid/, when: "Layout review" },
|
|
7326
|
+
{ keywords: /motion|animation|transition|parallax/, when: "During polish" },
|
|
7327
|
+
{ keywords: /architect|pattern|api|schema|data.model/, when: "Architecture decisions" },
|
|
7328
|
+
{ name: /^(gof-|js-)/, when: "Architecture decisions" }
|
|
7329
|
+
];
|
|
7330
|
+
function matchesWhenRule(rule, nameLower, keywordsLower) {
|
|
7331
|
+
const nameHit = rule.name ? rule.name.test(nameLower) : false;
|
|
7332
|
+
const kwHit = rule.keywords ? rule.keywords.test(keywordsLower) : false;
|
|
7333
|
+
if (rule.name && rule.keywords) return nameHit || kwHit;
|
|
7334
|
+
return nameHit || kwHit;
|
|
7335
|
+
}
|
|
7336
|
+
function inferWhen(name, entry) {
|
|
7337
|
+
const nameLower = name.toLowerCase();
|
|
7338
|
+
const keywordsLower = entry.keywords.map((k) => k.toLowerCase()).join(" ");
|
|
7339
|
+
for (const rule of WHEN_RULES) {
|
|
7340
|
+
if (matchesWhenRule(rule, nameLower, keywordsLower)) return rule.when;
|
|
7341
|
+
}
|
|
7342
|
+
return "During implementation";
|
|
7343
|
+
}
|
|
7344
|
+
function scoreSkillByContent(entry, signals) {
|
|
7345
|
+
const keywordScore = computeKeywordOverlap(entry.keywords, signals.specKeywords);
|
|
7346
|
+
const stackScore = computeStackMatch(entry.stackSignals, signals.stackSignals);
|
|
7347
|
+
const textToMatch = signals.taskText ?? signals.specText;
|
|
7348
|
+
const descScore = computeTermOverlap(entry.description, textToMatch);
|
|
7349
|
+
const domainScore = computeDomainMatch(entry, signals.featureDomain);
|
|
7350
|
+
return SCORING_WEIGHTS.keyword * keywordScore + SCORING_WEIGHTS.stack * stackScore + SCORING_WEIGHTS.termOverlap * descScore + SCORING_WEIGHTS.domain * domainScore;
|
|
7351
|
+
}
|
|
7352
|
+
function buildMatchReasons(entry, signals) {
|
|
7353
|
+
const reasons = [];
|
|
7354
|
+
const matchedKeywords = entry.keywords.filter(
|
|
7355
|
+
(kw) => signals.specKeywords.some(
|
|
7356
|
+
(sk) => kw.toLowerCase().includes(sk.toLowerCase()) || sk.toLowerCase().includes(kw.toLowerCase())
|
|
7357
|
+
)
|
|
7358
|
+
);
|
|
7359
|
+
if (matchedKeywords.length > 0) {
|
|
7360
|
+
reasons.push(`Keywords: ${matchedKeywords.join(", ")}`);
|
|
7361
|
+
}
|
|
7362
|
+
const projectSignalSet = new Set(signals.stackSignals.map((s) => s.toLowerCase()));
|
|
7363
|
+
const matchedStack = entry.stackSignals.filter((s) => projectSignalSet.has(s.toLowerCase()));
|
|
7364
|
+
if (matchedStack.length > 0) {
|
|
7365
|
+
reasons.push(`Stack: ${matchedStack.join(", ")}`);
|
|
7366
|
+
}
|
|
7367
|
+
if (signals.featureDomain.length > 0) {
|
|
7368
|
+
reasons.push(`Domain: ${signals.featureDomain.join(", ")}`);
|
|
7369
|
+
}
|
|
7370
|
+
return reasons;
|
|
7371
|
+
}
|
|
7372
|
+
function inferCategory(entry) {
|
|
7373
|
+
const keywordsLower = entry.keywords.map((k) => k.toLowerCase()).join(" ");
|
|
7374
|
+
if (/design|layout|responsive|css|ui|ux|theme|color/.test(keywordsLower)) return "design";
|
|
7375
|
+
if (/auth|oauth|session|token|jwt|login/.test(keywordsLower)) return "security";
|
|
7376
|
+
if (/a11y|accessibility|aria|wcag/.test(keywordsLower)) return "a11y";
|
|
7377
|
+
if (/perf|performance|cache|optimization|lighthouse/.test(keywordsLower)) return "perf";
|
|
7378
|
+
if (/test|tdd|coverage|mock|e2e/.test(keywordsLower)) return "testing";
|
|
7379
|
+
if (/database|sql|orm|migration|schema/.test(keywordsLower)) return "data";
|
|
7380
|
+
if (/api|rest|graphql|endpoint/.test(keywordsLower)) return "api";
|
|
7381
|
+
if (/docker|kubernetes|deploy|ci|terraform/.test(keywordsLower)) return "infra";
|
|
7382
|
+
if (/react|vue|angular|svelte|next/.test(keywordsLower)) return "framework";
|
|
7383
|
+
return "patterns";
|
|
7384
|
+
}
|
|
7385
|
+
function scoreAllSkills(index, signals) {
|
|
7386
|
+
const scored = [];
|
|
7387
|
+
for (const [name, entry] of Object.entries(index.skills)) {
|
|
7388
|
+
const score = scoreSkillByContent(entry, signals);
|
|
7389
|
+
if (score >= TIER_THRESHOLDS.consider) {
|
|
7390
|
+
scored.push({ name, entry, score });
|
|
7391
|
+
}
|
|
7392
|
+
}
|
|
7393
|
+
return scored;
|
|
7394
|
+
}
|
|
7395
|
+
function expandRelatedSkills(scored, index) {
|
|
7396
|
+
const matchedNames = new Set(scored.map((s) => s.name));
|
|
7397
|
+
const expansions = [];
|
|
7398
|
+
for (const match of scored) {
|
|
7399
|
+
if (match.score < TIER_THRESHOLDS.reference) continue;
|
|
7400
|
+
for (const relatedName of match.entry.relatedSkills) {
|
|
7401
|
+
if (matchedNames.has(relatedName)) continue;
|
|
7402
|
+
const relatedEntry = index.skills[relatedName];
|
|
7403
|
+
if (!relatedEntry) continue;
|
|
7404
|
+
const boostedScore = match.score * 0.6;
|
|
7405
|
+
if (boostedScore >= TIER_THRESHOLDS.consider) {
|
|
7406
|
+
matchedNames.add(relatedName);
|
|
7407
|
+
expansions.push({
|
|
7408
|
+
name: relatedName,
|
|
7409
|
+
entry: relatedEntry,
|
|
7410
|
+
score: boostedScore,
|
|
7411
|
+
parentName: match.name
|
|
7412
|
+
});
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
}
|
|
7416
|
+
return expansions;
|
|
7417
|
+
}
|
|
7418
|
+
function buildMatchList(scored, expansions, signals) {
|
|
7419
|
+
const matches = [];
|
|
7420
|
+
for (const { name, entry, score } of scored) {
|
|
7421
|
+
const tier = classifyTier(score);
|
|
7422
|
+
if (!tier) continue;
|
|
7423
|
+
matches.push({
|
|
7424
|
+
skillName: name,
|
|
7425
|
+
score: Math.round(score * 100) / 100,
|
|
7426
|
+
tier,
|
|
7427
|
+
matchReasons: buildMatchReasons(entry, signals),
|
|
7428
|
+
category: inferCategory(entry),
|
|
7429
|
+
when: inferWhen(name, entry)
|
|
7430
|
+
});
|
|
7431
|
+
}
|
|
7432
|
+
for (const { name, entry, score, parentName } of expansions) {
|
|
7433
|
+
const tier = classifyTier(score);
|
|
7434
|
+
if (!tier) continue;
|
|
7435
|
+
matches.push({
|
|
7436
|
+
skillName: name,
|
|
7437
|
+
score: Math.round(score * 100) / 100,
|
|
7438
|
+
tier,
|
|
7439
|
+
matchReasons: [`Related to: ${parentName}`, ...buildMatchReasons(entry, signals)],
|
|
7440
|
+
category: inferCategory(entry),
|
|
7441
|
+
when: inferWhen(name, entry)
|
|
7442
|
+
});
|
|
7443
|
+
}
|
|
7444
|
+
matches.sort((a, b) => b.score - a.score);
|
|
7445
|
+
return matches;
|
|
7446
|
+
}
|
|
7447
|
+
function matchContent(index, signals) {
|
|
7448
|
+
const startTime = performance.now();
|
|
7449
|
+
const scored = scoreAllSkills(index, signals);
|
|
7450
|
+
const expansions = expandRelatedSkills(scored, index);
|
|
7451
|
+
const matches = buildMatchList(scored, expansions, signals);
|
|
7452
|
+
return {
|
|
7453
|
+
matches,
|
|
7454
|
+
signalsUsed: signals,
|
|
7455
|
+
scanDuration: Math.round(performance.now() - startTime)
|
|
7456
|
+
};
|
|
7457
|
+
}
|
|
7458
|
+
|
|
7459
|
+
// src/skill/skills-md-writer.ts
|
|
7460
|
+
function generateSkillsMd(featureName, result, totalSkillCount) {
|
|
7461
|
+
const lines = [];
|
|
7462
|
+
lines.push(`# Recommended Skills: ${featureName}`);
|
|
7463
|
+
lines.push("");
|
|
7464
|
+
lines.push("> Auto-generated by Pipeline Skill Advisor. Review and adjust as needed.");
|
|
7465
|
+
const apply = result.matches.filter((m) => m.tier === "apply");
|
|
7466
|
+
const reference = result.matches.filter((m) => m.tier === "reference");
|
|
7467
|
+
const consider = result.matches.filter((m) => m.tier === "consider");
|
|
7468
|
+
if (apply.length > 0) {
|
|
7469
|
+
lines.push("");
|
|
7470
|
+
lines.push("## Apply (invoke during execution)");
|
|
7471
|
+
lines.push("");
|
|
7472
|
+
lines.push(...renderTable(apply));
|
|
7473
|
+
}
|
|
7474
|
+
if (reference.length > 0) {
|
|
7475
|
+
lines.push("");
|
|
7476
|
+
lines.push("## Reference (load as context)");
|
|
7477
|
+
lines.push("");
|
|
7478
|
+
lines.push(...renderTable(reference));
|
|
7479
|
+
}
|
|
7480
|
+
if (consider.length > 0) {
|
|
7481
|
+
lines.push("");
|
|
7482
|
+
lines.push("## Consider");
|
|
7483
|
+
lines.push("");
|
|
7484
|
+
lines.push(...renderTable(consider));
|
|
7485
|
+
}
|
|
7486
|
+
lines.push("");
|
|
7487
|
+
lines.push("---");
|
|
7488
|
+
const skillsScanned = totalSkillCount ?? result.matches.length;
|
|
7489
|
+
const keywords = result.signalsUsed.specKeywords.length;
|
|
7490
|
+
const stack = result.signalsUsed.stackSignals.length;
|
|
7491
|
+
const domains = result.signalsUsed.featureDomain.length;
|
|
7492
|
+
lines.push(
|
|
7493
|
+
`*Scanned ${skillsScanned} skills in ${result.scanDuration}ms. Signals: ${keywords} keywords, ${stack} stack markers, ${domains} domains.*`
|
|
7494
|
+
);
|
|
7495
|
+
lines.push("");
|
|
7496
|
+
return lines.join("\n");
|
|
7497
|
+
}
|
|
7498
|
+
function renderTable(matches) {
|
|
7499
|
+
const lines = [];
|
|
7500
|
+
lines.push("| Skill | Purpose | When | Relevance |");
|
|
7501
|
+
lines.push("|-------|---------|------|-----------|");
|
|
7502
|
+
for (const match of matches) {
|
|
7503
|
+
const purpose = match.matchReasons.join("; ");
|
|
7504
|
+
lines.push(`| \`${match.skillName}\` | ${purpose} | ${match.when} | ${match.score} |`);
|
|
7505
|
+
}
|
|
7506
|
+
return lines;
|
|
7507
|
+
}
|
|
7508
|
+
|
|
7509
|
+
// src/commands/advise-skills.ts
|
|
7510
|
+
function readPackageDeps(cwd) {
|
|
7511
|
+
const pkgPath = path19.join(cwd, "package.json");
|
|
7512
|
+
if (!fs16.existsSync(pkgPath)) return { deps: {}, devDeps: {} };
|
|
7513
|
+
try {
|
|
7514
|
+
const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
|
|
7515
|
+
const deps = typeof pkg.dependencies === "object" && pkg.dependencies !== null ? pkg.dependencies : {};
|
|
7516
|
+
const devDeps = typeof pkg.devDependencies === "object" && pkg.devDependencies !== null ? pkg.devDependencies : {};
|
|
7517
|
+
return { deps, devDeps };
|
|
7518
|
+
} catch {
|
|
7519
|
+
return { deps: {}, devDeps: {} };
|
|
7520
|
+
}
|
|
7521
|
+
}
|
|
7522
|
+
function readSpecText(specPath) {
|
|
7523
|
+
if (!fs16.existsSync(specPath)) {
|
|
7524
|
+
throw new Error(`Spec not found: ${specPath}`);
|
|
7525
|
+
}
|
|
7526
|
+
return fs16.readFileSync(specPath, "utf-8");
|
|
7527
|
+
}
|
|
7528
|
+
function filterMatchesByTier(result, top, thorough) {
|
|
7529
|
+
const applySkills = result.matches.filter((m) => m.tier === "apply").slice(0, top);
|
|
7530
|
+
const refSkills = result.matches.filter((m) => m.tier === "reference").slice(0, top * 2);
|
|
7531
|
+
const considerSkills = thorough ? result.matches.filter((m) => m.tier === "consider").slice(0, top) : [];
|
|
7532
|
+
return { ...result, matches: [...applySkills, ...refSkills, ...considerSkills] };
|
|
7533
|
+
}
|
|
7534
|
+
function extractFeatureName(specText, specPath) {
|
|
7535
|
+
const titleMatch = specText.match(/^#\s+(.+)/m);
|
|
7536
|
+
return titleMatch?.[1] ?? path19.basename(path19.dirname(specPath));
|
|
7537
|
+
}
|
|
7538
|
+
async function runAdviseSkills(options) {
|
|
7539
|
+
const cwd = options.cwd ?? process.cwd();
|
|
7540
|
+
const specPath = path19.resolve(cwd, options.specPath);
|
|
7541
|
+
const specText = readSpecText(specPath);
|
|
7542
|
+
const { deps, devDeps } = readPackageDeps(cwd);
|
|
7543
|
+
const signals = extractSignals(specText, deps, devDeps);
|
|
7544
|
+
const configResult = resolveConfig();
|
|
7545
|
+
const tierOverrides = configResult.ok ? configResult.value.skills?.tierOverrides : void 0;
|
|
7546
|
+
const index = loadOrRebuildIndex("claude-code", cwd, tierOverrides);
|
|
7547
|
+
const totalSkills = Object.keys(index.skills).length;
|
|
7548
|
+
const result = matchContent(index, signals);
|
|
7549
|
+
const filteredResult = filterMatchesByTier(result, options.top ?? 5, !!options.thorough);
|
|
7550
|
+
const featureName = extractFeatureName(specText, specPath);
|
|
7551
|
+
const skillsMdPath = path19.join(path19.dirname(specPath), "SKILLS.md");
|
|
7552
|
+
const md = generateSkillsMd(featureName, filteredResult, totalSkills);
|
|
7553
|
+
fs16.writeFileSync(skillsMdPath, md, "utf-8");
|
|
7554
|
+
return { result: filteredResult, skillsMdPath, featureName, totalSkills };
|
|
7555
|
+
}
|
|
7556
|
+
function formatOutput(featureName, result, skillsMdPath, totalSkills) {
|
|
7557
|
+
const apply = result.matches.filter((m) => m.tier === "apply");
|
|
7558
|
+
const ref = result.matches.filter((m) => m.tier === "reference");
|
|
7559
|
+
const consider = result.matches.filter((m) => m.tier === "consider");
|
|
7560
|
+
const lines = [];
|
|
7561
|
+
lines.push(`Skill Advisor: Found ${result.matches.length} relevant skills for "${featureName}"`);
|
|
7562
|
+
lines.push("");
|
|
7563
|
+
if (apply.length > 0) {
|
|
7564
|
+
lines.push(chalk.green(` Apply (${apply.length}):`));
|
|
7565
|
+
for (const m of apply) {
|
|
7566
|
+
lines.push(` ${m.skillName} (${m.score}) \u2014 ${m.when}`);
|
|
7567
|
+
}
|
|
7568
|
+
}
|
|
7569
|
+
if (ref.length > 0) {
|
|
7570
|
+
lines.push(chalk.blue(` Reference (${ref.length}):`));
|
|
7571
|
+
for (const m of ref) {
|
|
7572
|
+
lines.push(` ${m.skillName} (${m.score}) \u2014 ${m.when}`);
|
|
7573
|
+
}
|
|
7574
|
+
}
|
|
7575
|
+
if (consider.length > 0) {
|
|
7576
|
+
lines.push(chalk.dim(` Consider (${consider.length}):`));
|
|
7577
|
+
for (const m of consider) {
|
|
7578
|
+
lines.push(` ${m.skillName} (${m.score}) \u2014 ${m.when}`);
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
lines.push("");
|
|
7582
|
+
lines.push(`Scanned ${totalSkills} skills in ${result.scanDuration}ms`);
|
|
7583
|
+
lines.push(`Written to ${skillsMdPath}`);
|
|
7584
|
+
return lines.join("\n");
|
|
7585
|
+
}
|
|
7586
|
+
function createAdviseSkillsCommand() {
|
|
7587
|
+
return new Command2("advise-skills").description("Content-based skill recommendations for a spec").requiredOption("--spec-path <path>", "Path to the spec (proposal.md)").option("--thorough", "Include Consider tier in output").option("--top <n>", "Max skills per tier (default 5)", parseInt).option("--json", "Output as JSON").action(async (opts) => {
|
|
7588
|
+
try {
|
|
7589
|
+
const { result, skillsMdPath, featureName, totalSkills } = await runAdviseSkills({
|
|
7590
|
+
specPath: opts.specPath,
|
|
7591
|
+
thorough: opts.thorough,
|
|
7592
|
+
top: opts.top
|
|
7593
|
+
});
|
|
7594
|
+
if (opts.json) {
|
|
7595
|
+
logger.info(JSON.stringify(result, null, 2));
|
|
7596
|
+
} else {
|
|
7597
|
+
logger.info(formatOutput(featureName, result, skillsMdPath, totalSkills));
|
|
7598
|
+
}
|
|
7599
|
+
} catch (err) {
|
|
7600
|
+
logger.error(err.message);
|
|
7601
|
+
process.exit(1);
|
|
7602
|
+
}
|
|
7603
|
+
});
|
|
7604
|
+
}
|
|
7605
|
+
|
|
7606
|
+
// src/mcp/tools/advise-skills.ts
|
|
7607
|
+
var adviseSkillsDefinition = {
|
|
7608
|
+
name: "advise_skills",
|
|
7609
|
+
description: "Content-based skill recommendations for a spec or feature description. Returns tiered matches with purpose and timing guidance.",
|
|
7610
|
+
inputSchema: {
|
|
7611
|
+
type: "object",
|
|
7612
|
+
properties: {
|
|
7613
|
+
path: {
|
|
7614
|
+
type: "string",
|
|
7615
|
+
description: "Project root path (defaults to cwd)"
|
|
7616
|
+
},
|
|
7617
|
+
specPath: {
|
|
7618
|
+
type: "string",
|
|
7619
|
+
description: "Path to the spec file (proposal.md), relative to project root"
|
|
7620
|
+
},
|
|
7621
|
+
thorough: {
|
|
7622
|
+
type: "boolean",
|
|
7623
|
+
description: "Include Consider tier in output"
|
|
7624
|
+
},
|
|
7625
|
+
top: {
|
|
7626
|
+
type: "number",
|
|
7627
|
+
description: "Max skills per tier (default 5 apply, 10 reference)"
|
|
7628
|
+
}
|
|
7629
|
+
},
|
|
7630
|
+
required: ["specPath"]
|
|
7631
|
+
}
|
|
7632
|
+
};
|
|
7633
|
+
async function handleAdviseSkills(input) {
|
|
7634
|
+
const projectRoot = input.path || process.cwd();
|
|
7635
|
+
const specRelPath = input.specPath;
|
|
7636
|
+
const thorough = input.thorough || false;
|
|
7637
|
+
const top = input.top || 5;
|
|
7638
|
+
try {
|
|
7639
|
+
const { result, skillsMdPath, featureName, totalSkills } = await runAdviseSkills({
|
|
7640
|
+
specPath: specRelPath,
|
|
7641
|
+
cwd: projectRoot,
|
|
7642
|
+
thorough,
|
|
7643
|
+
top
|
|
7644
|
+
});
|
|
7645
|
+
const response = {
|
|
7646
|
+
featureName,
|
|
7647
|
+
skillsPath: path20.relative(projectRoot, skillsMdPath).replaceAll("\\", "/"),
|
|
7648
|
+
totalScanned: totalSkills,
|
|
7649
|
+
scanDuration: result.scanDuration,
|
|
7650
|
+
apply: result.matches.filter((m) => m.tier === "apply").map((m) => ({
|
|
7651
|
+
skill: m.skillName,
|
|
7652
|
+
score: m.score,
|
|
7653
|
+
when: m.when,
|
|
7654
|
+
reasons: m.matchReasons
|
|
7655
|
+
})),
|
|
7656
|
+
reference: result.matches.filter((m) => m.tier === "reference").map((m) => ({
|
|
7657
|
+
skill: m.skillName,
|
|
7658
|
+
score: m.score,
|
|
7659
|
+
when: m.when,
|
|
7660
|
+
reasons: m.matchReasons
|
|
7661
|
+
})),
|
|
7662
|
+
consider: result.matches.filter((m) => m.tier === "consider").map((m) => ({
|
|
7663
|
+
skill: m.skillName,
|
|
7664
|
+
score: m.score,
|
|
7665
|
+
when: m.when,
|
|
7666
|
+
reasons: m.matchReasons
|
|
7667
|
+
}))
|
|
7668
|
+
};
|
|
7669
|
+
return {
|
|
7670
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
7671
|
+
};
|
|
7672
|
+
} catch (err) {
|
|
7673
|
+
return {
|
|
7674
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
7675
|
+
};
|
|
7676
|
+
}
|
|
7677
|
+
}
|
|
7678
|
+
|
|
7031
7679
|
// src/mcp/tools/compact.ts
|
|
7032
7680
|
init_dist();
|
|
7033
7681
|
var COMPACT_TOOL_DEFAULT_BUDGET = 2e3;
|
|
@@ -7116,7 +7764,7 @@ function handleContentMode(content, pipeline, budget, source) {
|
|
|
7116
7764
|
};
|
|
7117
7765
|
}
|
|
7118
7766
|
async function handleIntentMode(projectPath, intent, pipeline, budget, filterContent) {
|
|
7119
|
-
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-
|
|
7767
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-QEI7SYOQ.js");
|
|
7120
7768
|
const store = await loadGraphStore2(projectPath);
|
|
7121
7769
|
if (!store) {
|
|
7122
7770
|
return {
|
|
@@ -7129,7 +7777,7 @@ async function handleIntentMode(projectPath, intent, pipeline, budget, filterCon
|
|
|
7129
7777
|
isError: true
|
|
7130
7778
|
};
|
|
7131
7779
|
}
|
|
7132
|
-
const { PackedSummaryCache, FusionLayer, ContextQL } = await import("./dist-
|
|
7780
|
+
const { PackedSummaryCache, FusionLayer, ContextQL } = await import("./dist-BZS2XRLG.js");
|
|
7133
7781
|
const cache = new PackedSummaryCache(store);
|
|
7134
7782
|
const cachedEnvelope = cache.get(intent);
|
|
7135
7783
|
if (cachedEnvelope) {
|
|
@@ -7342,7 +7990,7 @@ async function handleDetectConstraintEmergence(input) {
|
|
|
7342
7990
|
}
|
|
7343
7991
|
const nodePath = await import("path");
|
|
7344
7992
|
const historyPath = nodePath.resolve(projectPath, ".harness/arch/violation-history.json");
|
|
7345
|
-
const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-
|
|
7993
|
+
const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-CPKL5Y2R.js");
|
|
7346
7994
|
const manager = new ViolationHistoryManager(historyPath);
|
|
7347
7995
|
const history = manager.load();
|
|
7348
7996
|
const options = { windowWeeks, minOccurrences };
|
|
@@ -7371,6 +8019,146 @@ async function handleDetectConstraintEmergence(input) {
|
|
|
7371
8019
|
}
|
|
7372
8020
|
}
|
|
7373
8021
|
|
|
8022
|
+
// src/mcp/tools/ci.ts
|
|
8023
|
+
var VALID_CHECKS = [
|
|
8024
|
+
"validate",
|
|
8025
|
+
"deps",
|
|
8026
|
+
"docs",
|
|
8027
|
+
"entropy",
|
|
8028
|
+
"security",
|
|
8029
|
+
"perf",
|
|
8030
|
+
"phase-gate",
|
|
8031
|
+
"arch",
|
|
8032
|
+
"traceability"
|
|
8033
|
+
];
|
|
8034
|
+
var runCIChecksDefinition = {
|
|
8035
|
+
name: "run_ci_checks",
|
|
8036
|
+
description: "Run CI/CD validation checks on a harness project. Returns pass/fail results per check with issues. Checks: validate, deps, docs, entropy, security, perf, phase-gate, arch, traceability.",
|
|
8037
|
+
inputSchema: {
|
|
8038
|
+
type: "object",
|
|
8039
|
+
properties: {
|
|
8040
|
+
path: { type: "string", description: "Path to project root directory" },
|
|
8041
|
+
checks: {
|
|
8042
|
+
type: "array",
|
|
8043
|
+
items: {
|
|
8044
|
+
type: "string",
|
|
8045
|
+
enum: VALID_CHECKS
|
|
8046
|
+
},
|
|
8047
|
+
description: "Subset of checks to run (default: all)"
|
|
8048
|
+
}
|
|
8049
|
+
},
|
|
8050
|
+
required: ["path"]
|
|
8051
|
+
}
|
|
8052
|
+
};
|
|
8053
|
+
async function handleRunCIChecks(input) {
|
|
8054
|
+
let projectPath;
|
|
8055
|
+
try {
|
|
8056
|
+
projectPath = sanitizePath(input.path);
|
|
8057
|
+
} catch (error) {
|
|
8058
|
+
return {
|
|
8059
|
+
content: [
|
|
8060
|
+
{
|
|
8061
|
+
type: "text",
|
|
8062
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
8063
|
+
}
|
|
8064
|
+
],
|
|
8065
|
+
isError: true
|
|
8066
|
+
};
|
|
8067
|
+
}
|
|
8068
|
+
const configResult = resolveProjectConfig(projectPath);
|
|
8069
|
+
if (!configResult.ok) {
|
|
8070
|
+
return {
|
|
8071
|
+
content: [
|
|
8072
|
+
{
|
|
8073
|
+
type: "text",
|
|
8074
|
+
text: `Error: ${configResult.error.message}`
|
|
8075
|
+
}
|
|
8076
|
+
],
|
|
8077
|
+
isError: true
|
|
8078
|
+
};
|
|
8079
|
+
}
|
|
8080
|
+
try {
|
|
8081
|
+
const { runCIChecks } = await import("./dist-CPKL5Y2R.js");
|
|
8082
|
+
const skip = input.checks ? VALID_CHECKS.filter((c) => !input.checks.includes(c)) : [];
|
|
8083
|
+
const result = await runCIChecks({
|
|
8084
|
+
projectRoot: projectPath,
|
|
8085
|
+
config: configResult.value,
|
|
8086
|
+
...skip.length > 0 ? { skip } : {}
|
|
8087
|
+
});
|
|
8088
|
+
if (!result.ok) {
|
|
8089
|
+
return {
|
|
8090
|
+
content: [
|
|
8091
|
+
{
|
|
8092
|
+
type: "text",
|
|
8093
|
+
text: `Error: ${result.error.message}`
|
|
8094
|
+
}
|
|
8095
|
+
],
|
|
8096
|
+
isError: true
|
|
8097
|
+
};
|
|
8098
|
+
}
|
|
8099
|
+
return {
|
|
8100
|
+
content: [{ type: "text", text: JSON.stringify(result.value) }]
|
|
8101
|
+
};
|
|
8102
|
+
} catch (error) {
|
|
8103
|
+
return {
|
|
8104
|
+
content: [
|
|
8105
|
+
{
|
|
8106
|
+
type: "text",
|
|
8107
|
+
text: `Error running CI checks: ${error instanceof Error ? error.message : String(error)}`
|
|
8108
|
+
}
|
|
8109
|
+
],
|
|
8110
|
+
isError: true
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
}
|
|
8114
|
+
|
|
8115
|
+
// src/mcp/tools/blueprint.ts
|
|
8116
|
+
var generateBlueprintDefinition = {
|
|
8117
|
+
name: "generate_blueprint",
|
|
8118
|
+
description: "Scan a project and return its blueprint data (modules, hotspots, dependencies). Returns the scan results as JSON without writing files.",
|
|
8119
|
+
inputSchema: {
|
|
8120
|
+
type: "object",
|
|
8121
|
+
properties: {
|
|
8122
|
+
path: { type: "string", description: "Path to project root directory" }
|
|
8123
|
+
},
|
|
8124
|
+
required: ["path"]
|
|
8125
|
+
}
|
|
8126
|
+
};
|
|
8127
|
+
async function handleGenerateBlueprint(input) {
|
|
8128
|
+
let projectPath;
|
|
8129
|
+
try {
|
|
8130
|
+
projectPath = sanitizePath(input.path);
|
|
8131
|
+
} catch (error) {
|
|
8132
|
+
return {
|
|
8133
|
+
content: [
|
|
8134
|
+
{
|
|
8135
|
+
type: "text",
|
|
8136
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
8137
|
+
}
|
|
8138
|
+
],
|
|
8139
|
+
isError: true
|
|
8140
|
+
};
|
|
8141
|
+
}
|
|
8142
|
+
try {
|
|
8143
|
+
const { ProjectScanner } = await import("./dist-CPKL5Y2R.js");
|
|
8144
|
+
const scanner = new ProjectScanner(projectPath);
|
|
8145
|
+
const data = await scanner.scan();
|
|
8146
|
+
return {
|
|
8147
|
+
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
8148
|
+
};
|
|
8149
|
+
} catch (error) {
|
|
8150
|
+
return {
|
|
8151
|
+
content: [
|
|
8152
|
+
{
|
|
8153
|
+
type: "text",
|
|
8154
|
+
text: `Error generating blueprint: ${error instanceof Error ? error.message : String(error)}`
|
|
8155
|
+
}
|
|
8156
|
+
],
|
|
8157
|
+
isError: true
|
|
8158
|
+
};
|
|
8159
|
+
}
|
|
8160
|
+
}
|
|
8161
|
+
|
|
7374
8162
|
// src/mcp/server.ts
|
|
7375
8163
|
var TOOL_DEFINITIONS = [
|
|
7376
8164
|
validateToolDefinition,
|
|
@@ -7427,10 +8215,13 @@ var TOOL_DEFINITIONS = [
|
|
|
7427
8215
|
checkTraceabilityDefinition,
|
|
7428
8216
|
predictFailuresDefinition,
|
|
7429
8217
|
recommendSkillsDefinition,
|
|
8218
|
+
adviseSkillsDefinition,
|
|
7430
8219
|
computeBlastRadiusDefinition,
|
|
7431
8220
|
dispatchSkillsDefinition,
|
|
7432
8221
|
compactToolDefinition,
|
|
7433
|
-
detectConstraintEmergenceDefinition
|
|
8222
|
+
detectConstraintEmergenceDefinition,
|
|
8223
|
+
runCIChecksDefinition,
|
|
8224
|
+
generateBlueprintDefinition
|
|
7434
8225
|
].map((def) => ({ ...def, trustedOutput: true }));
|
|
7435
8226
|
var TOOL_HANDLERS = {
|
|
7436
8227
|
validate_project: handleValidateProject,
|
|
@@ -7487,10 +8278,13 @@ var TOOL_HANDLERS = {
|
|
|
7487
8278
|
check_traceability: handleCheckTraceability,
|
|
7488
8279
|
predict_failures: handlePredictFailures,
|
|
7489
8280
|
recommend_skills: handleRecommendSkills,
|
|
8281
|
+
advise_skills: handleAdviseSkills,
|
|
7490
8282
|
compute_blast_radius: handleComputeBlastRadius,
|
|
7491
8283
|
dispatch_skills: handleDispatchSkills,
|
|
7492
8284
|
compact: handleCompact,
|
|
7493
|
-
detect_constraint_emergence: handleDetectConstraintEmergence
|
|
8285
|
+
detect_constraint_emergence: handleDetectConstraintEmergence,
|
|
8286
|
+
run_ci_checks: handleRunCIChecks,
|
|
8287
|
+
generate_blueprint: handleGenerateBlueprint
|
|
7494
8288
|
};
|
|
7495
8289
|
var RESOURCE_DEFINITIONS = [
|
|
7496
8290
|
{
|
|
@@ -7592,7 +8386,7 @@ async function appendUpdateNotification(result, resolvedRoot) {
|
|
|
7592
8386
|
shouldRunCheck,
|
|
7593
8387
|
readCheckState,
|
|
7594
8388
|
spawnBackgroundCheck
|
|
7595
|
-
} = await import("./dist-
|
|
8389
|
+
} = await import("./dist-CPKL5Y2R.js");
|
|
7596
8390
|
const { CLI_VERSION } = await import("./version-CUI434OP.js");
|
|
7597
8391
|
const configInterval = readConfigInterval(resolvedRoot);
|
|
7598
8392
|
const DEFAULT_INTERVAL = 864e5;
|
|
@@ -7686,6 +8480,7 @@ async function startServer(toolFilter) {
|
|
|
7686
8480
|
}
|
|
7687
8481
|
|
|
7688
8482
|
export {
|
|
8483
|
+
createAdviseSkillsCommand,
|
|
7689
8484
|
generateSlashCommands,
|
|
7690
8485
|
handleOrphanDeletion,
|
|
7691
8486
|
createGenerateSlashCommandsCommand,
|
|
@@ -7693,7 +8488,6 @@ export {
|
|
|
7693
8488
|
persistToolingConfig,
|
|
7694
8489
|
ensureHarnessGitignore,
|
|
7695
8490
|
appendFrameworkAgents,
|
|
7696
|
-
loadOrRebuildIndex,
|
|
7697
8491
|
isSnapshotFresh,
|
|
7698
8492
|
loadCachedSnapshot,
|
|
7699
8493
|
captureHealthSnapshot,
|