@smartergpt/lexrunner 1.0.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/.changes/ci-debug-added.txt +1 -0
- package/.changeset/tsconfig-solution-build.md +5 -0
- package/.editorconfig +9 -0
- package/.env.example +8 -0
- package/.github/COST_EFFICIENCY.md +60 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
- package/.github/ISSUE_TEMPLATE/epic.yml +123 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
- package/.github/ISSUE_TEMPLATE/issue-A1-gate-input-validation.md +380 -0
- package/.github/ISSUE_TEMPLATE/issue-B1-scope-validation.md +509 -0
- package/.github/ISSUE_TEMPLATE/issue-C1-command-whitelist.md +463 -0
- package/.github/ISSUE_TEMPLATE/subtask.yml +153 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- package/.github/copilot-instructions-old.md +429 -0
- package/.github/copilot-instructions.md +33 -0
- package/.github/instructions/tests.instructions.md +10 -0
- package/.github/workflows/auto-delete-merged-branches.yml +103 -0
- package/.github/workflows/benchmarks.yml +72 -0
- package/.github/workflows/ci-debug.yml +33 -0
- package/.github/workflows/ci.yml +167 -0
- package/.github/workflows/cli-smoke-test.yml +345 -0
- package/.github/workflows/copilot-setup-steps.yml +20 -0
- package/.github/workflows/frame-emission-gate.yml +242 -0
- package/.github/workflows/project-auto.yml +24 -0
- package/.github/workflows/release.yml +260 -0
- package/.github/workflows/slow-cli-tests.yml +37 -0
- package/.github/workflows/tag-guard.yml +44 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +2 -0
- package/.prettierignore +28 -0
- package/.prettierrc.json +10 -0
- package/.smartergpt/CONTROL_DECK_VISION.md +226 -0
- package/.smartergpt/allowed-commands.json +41 -0
- package/.smartergpt/allowed-commands.strict.json +56 -0
- package/.smartergpt/deliverables/.live.md +426 -0
- package/.smartergpt/deliverables/ISSUE_STATUS_2025-12-28.md +193 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/ADR_DISCUSSION.md +379 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/Answer_claude-haiku.md +109 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/Answer_gemini-flash.md +42 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/Answer_gpt-codex-mini.md +19 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/Answer_raptor-mini.md +37 -0
- package/.smartergpt/deliverables/_research/snapshot-contract-feedback/Question.md +37 -0
- package/.smartergpt/deliverables/merge-weave-04469e41-24ba-4ed5-b0ff-13c7ea12858d.ndjson +2 -0
- package/.smartergpt/deps.yml +3 -0
- package/.smartergpt/docs/fanout-templates.md +213 -0
- package/.smartergpt/docs/merge-weave-interventions.md +261 -0
- package/.smartergpt/docs/test-fix-patterns.md +240 -0
- package/.smartergpt/fanout-templates.yml +263 -0
- package/.smartergpt/gates.yml +9 -0
- package/.smartergpt/intent.md +1 -0
- package/.smartergpt/issues/QOL-001-analysis-script-filtering.md +36 -0
- package/.smartergpt/issues/QOL-002-log-retention-policy.md +92 -0
- package/.smartergpt/issues/QOL-003-realtime-console-feedback.md +44 -0
- package/.smartergpt/issues/QOL-004-governance-report-cli.md +44 -0
- package/.smartergpt/issues/QOL-005-schema-versioning.md +46 -0
- package/.smartergpt/issues/QOL-006-debug-verbose-mode.md +45 -0
- package/.smartergpt/issues/QOL-COMPLETION-REPORT.md +359 -0
- package/.smartergpt/issues/QOL-REVIEW-SUMMARY.md +111 -0
- package/.smartergpt/issues/QOL-ROADMAP.md +71 -0
- package/.smartergpt/merge-policy.yml +41 -0
- package/.smartergpt/merge-weave-policy.yml +255 -0
- package/.smartergpt/o1.json +0 -0
- package/.smartergpt/o2.json +0 -0
- package/.smartergpt/personas/eager-pm.md +123 -0
- package/.smartergpt/personas/example.md +81 -0
- package/.smartergpt/personas/senior-dev.md +107 -0
- package/.smartergpt/profile.yml +2 -0
- package/.smartergpt/prompts/create-project.md +112 -0
- package/.smartergpt/prompts/idea.md +64 -0
- package/.smartergpt/pull-request-template.md +25 -0
- package/.smartergpt/schemas/behavior-rule.schema.d.ts +54 -0
- package/.smartergpt/schemas/behavior-rule.schema.js +56 -0
- package/.smartergpt/schemas/behavior-rule.schema.json +105 -0
- package/.smartergpt/schemas/behavior-rule.schema.ts +60 -0
- package/.smartergpt/schemas/execution-plan-v1.d.ts +47 -0
- package/.smartergpt/schemas/execution-plan-v1.js +22 -0
- package/.smartergpt/schemas/execution-plan-v1.json +113 -0
- package/.smartergpt/schemas/execution-plan-v1.ts +32 -0
- package/.smartergpt/schemas/execution-plan.schema.json +116 -0
- package/.smartergpt/schemas/feature-spec-v0.d.ts +13 -0
- package/.smartergpt/schemas/feature-spec-v0.js +12 -0
- package/.smartergpt/schemas/feature-spec-v0.json +58 -0
- package/.smartergpt/schemas/feature-spec-v0.ts +16 -0
- package/.smartergpt/schemas/feature-spec.schema.json +111 -0
- package/.smartergpt/schemas/gates.schema.d.ts +48 -0
- package/.smartergpt/schemas/gates.schema.js +20 -0
- package/.smartergpt/schemas/gates.schema.json +47 -0
- package/.smartergpt/schemas/gates.schema.ts +26 -0
- package/.smartergpt/schemas/idea.schema.json +81 -0
- package/.smartergpt/schemas/runner.scope.schema.d.ts +54 -0
- package/.smartergpt/schemas/runner.scope.schema.js +28 -0
- package/.smartergpt/schemas/runner.scope.schema.json +75 -0
- package/.smartergpt/schemas/runner.scope.schema.ts +36 -0
- package/.smartergpt/schemas/runner.stack.schema.d.ts +40 -0
- package/.smartergpt/schemas/runner.stack.schema.js +21 -0
- package/.smartergpt/schemas/runner.stack.schema.json +51 -0
- package/.smartergpt/schemas/runner.stack.schema.ts +27 -0
- package/.smartergpt/scope.yml +11 -0
- package/.smartergpt/stack.yml +16 -0
- package/.smartergpt/test-fix-patterns.yml +106 -0
- package/.tool-versions +13 -0
- package/AGENTS.md +402 -0
- package/CHANGELOG.md +256 -0
- package/CLAUDE.md +484 -0
- package/CONTRIBUTING.md +345 -0
- package/EAGER_PM_FANOUT_ANALYSIS.md +283 -0
- package/FAQ.md +292 -0
- package/FIXTURE_LIBRARY_SUMMARY.md +327 -0
- package/IMPLEMENTATION_SUMMARY.md +222 -0
- package/LICENSE +21 -0
- package/MANUAL_TEST_GUIDE.md +229 -0
- package/MCP-ALIGNMENT-SUMMARY.md +261 -0
- package/MCP-CONFIG.md +125 -0
- package/MERGE_WEAVE_QUICKSTART.md +450 -0
- package/MERGE_WEAVE_SUMMARY.md +259 -0
- package/MERGE_WEAVE_USAGE_GUIDE.md +368 -0
- package/NOTICE.md +43 -0
- package/README.mcp.md +770 -0
- package/README.md +1069 -0
- package/TEST_INFRASTRUCTURE_ASSESSMENT.md +225 -0
- package/bootstrap-lexrunner.sh +396 -0
- package/dist/api-7H7SJZIX.js +15 -0
- package/dist/api-U3X2WA6D.js +15 -0
- package/dist/audit-2TZ2LU72.js +60 -0
- package/dist/audit-5HH5BMKI.js +60 -0
- package/dist/audit-6K5K333I.js +60 -0
- package/dist/audit-DYQWS57J.js +60 -0
- package/dist/audit-JBWZ2GZ2.js +60 -0
- package/dist/audit-SJF3434D.js +60 -0
- package/dist/audit-TICGGVX5.js +60 -0
- package/dist/audit-YOBB27PY.js +60 -0
- package/dist/autopilot-3GAVXWWC.js +45 -0
- package/dist/autopilot-43NOYVQA.js +45 -0
- package/dist/autopilot-4UA3OWLU.js +45 -0
- package/dist/autopilot-54TK5CCG.js +45 -0
- package/dist/autopilot-5BHC2UQT.js +45 -0
- package/dist/autopilot-ABZUCVGY.js +45 -0
- package/dist/autopilot-ACJZP47Y.js +45 -0
- package/dist/autopilot-AL5F5AUS.js +46 -0
- package/dist/autopilot-BO67FWUC.js +45 -0
- package/dist/autopilot-BR6W4GEX.js +45 -0
- package/dist/autopilot-FOR2UKRY.js +45 -0
- package/dist/autopilot-GDTTXHEQ.js +45 -0
- package/dist/autopilot-GEAMFZBM.js +45 -0
- package/dist/autopilot-HDMBRZE6.js +45 -0
- package/dist/autopilot-IKI2Y6S4.js +44 -0
- package/dist/autopilot-ILTBWWOL.js +46 -0
- package/dist/autopilot-KI3MXIFI.js +44 -0
- package/dist/autopilot-LWNPZC3J.js +45 -0
- package/dist/autopilot-LXPJ4ZXF.js +45 -0
- package/dist/autopilot-MDIFIONK.js +46 -0
- package/dist/autopilot-NW3LDP6M.js +45 -0
- package/dist/autopilot-OKTSCG35.js +45 -0
- package/dist/autopilot-OR5PF5PD.js +45 -0
- package/dist/autopilot-PE65SBGN.js +45 -0
- package/dist/autopilot-PW7I4B6W.js +45 -0
- package/dist/autopilot-QMLBL5P6.js +45 -0
- package/dist/autopilot-QSN6ZU5O.js +45 -0
- package/dist/autopilot-R7EZJOGI.js +46 -0
- package/dist/autopilot-T544CPPD.js +44 -0
- package/dist/autopilot-TNQB6VGJ.js +44 -0
- package/dist/autopilot-UVIYCR6K.js +45 -0
- package/dist/autopilot-W3ZTTSH3.js +45 -0
- package/dist/autopilot-XPKWOFXO.js +44 -0
- package/dist/autopilot-XRX4QWRM.js +44 -0
- package/dist/autopilot-Y3BAGNI5.js +44 -0
- package/dist/autopilot-ZE64XW2K.js +44 -0
- package/dist/chunk-2ESYSVXG.js +48 -0
- package/dist/chunk-2VR554P7.js +668 -0
- package/dist/chunk-37DOWIVT.js +1084 -0
- package/dist/chunk-3DU2DWUP.js +400 -0
- package/dist/chunk-3DVXIZFM.js +11166 -0
- package/dist/chunk-3FABZF4V.js +811 -0
- package/dist/chunk-4FFGNTAV.js +515 -0
- package/dist/chunk-4GEC4HC3.js +11221 -0
- package/dist/chunk-4RVZNLD4.js +628 -0
- package/dist/chunk-55VWJYZY.js +39 -0
- package/dist/chunk-5CGWZH5X.js +340 -0
- package/dist/chunk-5QKWKK4M.js +11794 -0
- package/dist/chunk-5Z3XHND7.js +11755 -0
- package/dist/chunk-6A4IE3TI.js +302 -0
- package/dist/chunk-6KK5JFFE.js +106 -0
- package/dist/chunk-6YC2VSLE.js +11252 -0
- package/dist/chunk-7C4K2SHD.js +668 -0
- package/dist/chunk-ANXY4RGA.js +11091 -0
- package/dist/chunk-ASHKNUBR.js +11312 -0
- package/dist/chunk-B3OYDPOP.js +11793 -0
- package/dist/chunk-DBH7SQ2S.js +1084 -0
- package/dist/chunk-DEI7A5B4.js +11449 -0
- package/dist/chunk-DM4GHY3J.js +92 -0
- package/dist/chunk-EQKFCZLH.js +9823 -0
- package/dist/chunk-FAIJPBT5.js +40 -0
- package/dist/chunk-FDDKUDXR.js +11166 -0
- package/dist/chunk-FEAR6ETG.js +438 -0
- package/dist/chunk-FNBAHK5V.js +72 -0
- package/dist/chunk-FXL74C73.js +523 -0
- package/dist/chunk-GLJEDX4L.js +10247 -0
- package/dist/chunk-GTP4OHD7.js +1107 -0
- package/dist/chunk-HIHH7IVO.js +10557 -0
- package/dist/chunk-I3VXUVCB.js +10474 -0
- package/dist/chunk-I6BIFVWI.js +10519 -0
- package/dist/chunk-I72TRUTJ.js +1084 -0
- package/dist/chunk-J5B5KT2F.js +368 -0
- package/dist/chunk-JMTULZ66.js +11743 -0
- package/dist/chunk-JXIQ7HCK.js +11166 -0
- package/dist/chunk-K6HVPBDP.js +10692 -0
- package/dist/chunk-KBT5Y666.js +521 -0
- package/dist/chunk-LETPROKG.js +11092 -0
- package/dist/chunk-LLMY2BZF.js +1084 -0
- package/dist/chunk-NMNL4US2.js +1084 -0
- package/dist/chunk-O2XRP7JK.js +10247 -0
- package/dist/chunk-OGPWLFFO.js +11201 -0
- package/dist/chunk-OQJUWTZV.js +51 -0
- package/dist/chunk-PJRWPLQ6.js +669 -0
- package/dist/chunk-PYRVUCJR.js +370 -0
- package/dist/chunk-Q6Y524KH.js +669 -0
- package/dist/chunk-QF7DM5VW.js +106 -0
- package/dist/chunk-QGM4M3NI.js +37 -0
- package/dist/chunk-QIIELFTL.js +1107 -0
- package/dist/chunk-QUW6N7GR.js +10264 -0
- package/dist/chunk-QZASNLQX.js +11223 -0
- package/dist/chunk-RMN4IAWO.js +11808 -0
- package/dist/chunk-RN5NHU37.js +11465 -0
- package/dist/chunk-RNG3RILO.js +11755 -0
- package/dist/chunk-RSA6DEB4.js +9748 -0
- package/dist/chunk-RURYWSMX.js +10524 -0
- package/dist/chunk-SUEXK5U7.js +11201 -0
- package/dist/chunk-TVUF55OH.js +11807 -0
- package/dist/chunk-U5MMENCP.js +456 -0
- package/dist/chunk-U62I2R2D.js +434 -0
- package/dist/chunk-UHFMFO54.js +21 -0
- package/dist/chunk-UNZBDSEU.js +11166 -0
- package/dist/chunk-UOATTNQP.js +334 -0
- package/dist/chunk-UZFYNSMJ.js +334 -0
- package/dist/chunk-VP37GLU6.js +1084 -0
- package/dist/chunk-W6WDKBWO.js +11453 -0
- package/dist/chunk-XBKUFNVF.js +10745 -0
- package/dist/chunk-XOLVQTIE.js +670 -0
- package/dist/chunk-XVFTBVDS.js +257 -0
- package/dist/chunk-YABA7DB6.js +11091 -0
- package/dist/chunk-YWCJX5KL.js +10557 -0
- package/dist/chunk-Z5GP7FSR.js +309 -0
- package/dist/chunk-ZBT3DATZ.js +296 -0
- package/dist/chunk-ZDBAZXUQ.js +11201 -0
- package/dist/chunk-ZEMABYS4.js +92 -0
- package/dist/chunk-ZOA4HT7P.js +662 -0
- package/dist/cli.cjs +40431 -0
- package/dist/cli.d.cts +2709 -0
- package/dist/cli.d.ts +2709 -0
- package/dist/cli.js +21149 -0
- package/dist/commandValidator-42OUDFZ4.js +140 -0
- package/dist/commandValidator-7LQHTYL5.js +140 -0
- package/dist/commandValidator-AT5OYZFC.js +142 -0
- package/dist/commandValidator-DH3CX2OW.js +140 -0
- package/dist/commandValidator-GCQC7H4A.js +140 -0
- package/dist/commandValidator-K6VWB6O3.js +140 -0
- package/dist/commandValidator-L6WNDBYB.js +129 -0
- package/dist/commandValidator-O3KSNXD2.js +140 -0
- package/dist/commandValidator-ZHMUA5RQ.js +140 -0
- package/dist/constraints-M52FVL2X.js +11 -0
- package/dist/dist-CSOR2BL2.js +1144 -0
- package/dist/dist-PKOIS5NZ.js +1144 -0
- package/dist/fileAnalysis-3VMDDJ6I.js +9 -0
- package/dist/fileAnalysis-4QLHUT44.js +9 -0
- package/dist/fileAnalysis-H6M2Z7ZC.js +9 -0
- package/dist/fileAnalysis-HMI7IL6S.js +9 -0
- package/dist/fileAnalysis-JHABOPUQ.js +9 -0
- package/dist/gateMapping-E5MGNJH5.js +17 -0
- package/dist/jsonEnvelope-R4SWKX2N.js +62 -0
- package/dist/mergeTreeSimulator-ATOPJ3DU.js +11 -0
- package/dist/mergeTreeSimulator-AYUK4TZT.js +11 -0
- package/dist/mergeTreeSimulator-BBWJUQBK.js +11 -0
- package/dist/mergeTreeSimulator-DJJDRB5N.js +11 -0
- package/dist/mergeTreeSimulator-X4BA647P.js +11 -0
- package/dist/planDiff-37QHCPKO.js +109 -0
- package/dist/planDiff-BQHIUARB.js +109 -0
- package/dist/planDiff-QOK6KNB7.js +111 -0
- package/dist/planDiff-RXR4CWFS.js +109 -0
- package/dist/planDiff-W2BTH2MU.js +109 -0
- package/dist/planHistory-4J3Q6AJ3.js +126 -0
- package/dist/planHistory-DQRSB2Y7.js +118 -0
- package/dist/planHistory-GLCXP6AB.js +126 -0
- package/dist/planHistory-SMNRLEKG.js +126 -0
- package/dist/planHistory-UO4WZ6GO.js +126 -0
- package/dist/planReview-7BWVLABC.js +377 -0
- package/dist/planReview-7VB3OYKZ.js +385 -0
- package/dist/planReview-FAIBIAE6.js +377 -0
- package/dist/planReview-FXQBDNKJ.js +376 -0
- package/dist/planReview-HO4YYETA.js +377 -0
- package/dist/planReview-I26EKCUK.js +376 -0
- package/dist/planReview-JBOAJHSU.js +377 -0
- package/dist/planReview-SCNZWC6B.js +376 -0
- package/dist/planReview-TU7LMZIY.js +376 -0
- package/dist/planViewer-2YZCPVDM.js +155 -0
- package/dist/planViewer-72WZFUTU.js +154 -0
- package/dist/planViewer-G546TVHV.js +154 -0
- package/dist/planViewer-I7ZHNJQF.js +150 -0
- package/dist/planViewer-IRXHOY5U.js +155 -0
- package/dist/planViewer-IX2ICW45.js +154 -0
- package/dist/planViewer-PDWPUOP6.js +155 -0
- package/dist/planViewer-PEOADAGZ.js +155 -0
- package/dist/planViewer-PFYDEG6V.js +150 -0
- package/dist/planViewer-UIPOSRVW.js +151 -0
- package/dist/planViewer-V2JUKV7Q.js +154 -0
- package/dist/sarif-46TKOOJZ.js +9 -0
- package/dist/sarif-63JKTFFI.js +9 -0
- package/dist/sarif-CIYIWUNC.js +9 -0
- package/dist/sarif-OGAGDL6B.js +9 -0
- package/dist/sarif-XIREI5B5.js +9 -0
- package/dist/security-3V6FKJDA.js +423 -0
- package/dist/security-4JMEUM56.js +423 -0
- package/dist/security-QHPEWY5G.js +423 -0
- package/dist/security-V2LAL5TP.js +415 -0
- package/dist/security-WTASK6T6.js +423 -0
- package/dist/security-XE4GHVJD.js +423 -0
- package/dist/security-XLXM3UHT.js +423 -0
- package/dist/security-YDLHSMVY.js +441 -0
- package/dist/security-ZDAEZF7D.js +423 -0
- package/dist/signing-3EI734L4.js +14 -0
- package/dist/signing-5G7K6JXJ.js +14 -0
- package/dist/signing-7DK7SABM.js +14 -0
- package/dist/signing-JJJOUGCW.js +14 -0
- package/dist/signing-OAJ3MXGA.js +14 -0
- package/dist/verify-5F6PUXUQ.js +62 -0
- package/dist/verify-5ILURHV2.js +62 -0
- package/dist/verify-MRDZJUGO.js +62 -0
- package/dist/verify-SCUHB3SA.js +62 -0
- package/dist/verify-YZRHN2D3.js +62 -0
- package/docs/1.0.0-vertical-slice.md +214 -0
- package/docs/ADR-007-INTEGRATION-SUMMARY.md +232 -0
- package/docs/ALIASING_FOR_LEXRUNNER.md +709 -0
- package/docs/ALIASING_FOR_RUNNER.md +552 -0
- package/docs/AX.md +317 -0
- package/docs/CHECKPOINT_RESUME.md +208 -0
- package/docs/CLI_VERBS.md +219 -0
- package/docs/CONFLICT_DETECTION.md +198 -0
- package/docs/DISCIPLINED_FAILURE.md +224 -0
- package/docs/ENVIRONMENT_QUALITY.md +155 -0
- package/docs/ERROR_CODES.md +528 -0
- package/docs/EVENT_SCHEMA.md +659 -0
- package/docs/EXE-012-investigation-summary.md +300 -0
- package/docs/GATE_ATTESTATION_GUIDE.md +237 -0
- package/docs/JSON_OUTPUT_SCHEMAS.md +347 -0
- package/docs/LEXRUNNER_ALIASING.md +444 -0
- package/docs/LEX_INTEGRATION.md +83 -0
- package/docs/LEX_PUBLIC_API.md +306 -0
- package/docs/LICENSING.md +119 -0
- package/docs/MCP-CLI-PARITY.md +410 -0
- package/docs/MCP-MIGRATION.md +258 -0
- package/docs/MCP-PARITY.md +234 -0
- package/docs/MEMORY_TOOLS.md +278 -0
- package/docs/MERGE_WEAVE_SETUP.md +643 -0
- package/docs/MIGRATION_v0.1.md +760 -0
- package/docs/NAMING_CONVENTIONS.md +82 -0
- package/docs/PERSONA_FOUNDATION.md +124 -0
- package/docs/PHASE3_MEMORY_GUIDE.md +122 -0
- package/docs/PLAN_LOCK.md +114 -0
- package/docs/README.md +289 -0
- package/docs/RUNNER_LIFECYCLE.md +257 -0
- package/docs/SAFETY_MECHANISMS.md +325 -0
- package/docs/SECURITY_IMPLEMENTATION.md +535 -0
- package/docs/TERMS.md +34 -0
- package/docs/TOKEN_TRACKING.md +162 -0
- package/docs/WORKFLOW_GUIDANCE.md +277 -0
- package/docs/adr/ADR-000-product-naming-and-branding.md +115 -0
- package/docs/adr/ADR-001-plan-json-frozen-input.md +68 -0
- package/docs/adr/ADR-002-two-track-separation.md +84 -0
- package/docs/adr/ADR-003-gate-uniform-execution.md +69 -0
- package/docs/adr/ADR-004-runner-state-model.md +75 -0
- package/docs/adr/ADR-005-merge-pyramid-ordering.md +87 -0
- package/docs/adr/ADR-006-schema-versioning-semver.md +81 -0
- package/docs/adr/ADR-007-task-snapshot-contract.md +503 -0
- package/docs/adr/ADR-008-lex-packaging.md +243 -0
- package/docs/adr/ADR-009-ax-test-output-adapters.md +440 -0
- package/docs/adr/README.md +32 -0
- package/docs/advanced-cli.md +436 -0
- package/docs/agent-stall-detection.md +278 -0
- package/docs/architecture/executors.md +190 -0
- package/docs/architecture.md +316 -0
- package/docs/attestation/AX-SHARED-PLEDGE.md +83 -0
- package/docs/attestation/AX-SHARED-PLEDGE_v1.0.0.md +99 -0
- package/docs/attestation/AX-SHARED-PLEDGE_v1.0.0_VERIFICATION.md +115 -0
- package/docs/attestation/Lex_Guff_Version_Contract_Pact_v1.0.0.md +181 -0
- package/docs/attestation/README.md +87 -0
- package/docs/attestation/ax_pledge_2025-12-02.ots +0 -0
- package/docs/attestation/ax_pledge_timestamp_response.tsr +0 -0
- package/docs/attestation/copilot_summarization_2025-12-01.ots +0 -0
- package/docs/attestation/copilot_summarization_2025-12-01_VERIFICATION.md +100 -0
- package/docs/attestation/copilot_summarization_behavior_observation_2025-12-01.md +85 -0
- package/docs/attestation/copilot_summarization_screenshot_2025-12-01.png +0 -0
- package/docs/attestation/employment_separation_2025-11-26.ots +0 -0
- package/docs/attestation/employment_timestamp_response.tsr +0 -0
- package/docs/attestation/freetsa_cacert.pem +45 -0
- package/docs/attestation/freetsa_tsa.crt +45 -0
- package/docs/attestation/lex_employment_separation_2025-11-26.md +85 -0
- package/docs/attestation/lex_employment_separation_2025-11-26_VERIFICATION.md +126 -0
- package/docs/attestation/patent/2025-12-07-shadow-governance-pct-draft.md +350 -0
- package/docs/attestation/patent/2025-12-07-shadow-governance-pct-draft.md.ots +0 -0
- package/docs/attestation/patent/2025-12-07-shadow-governance-pct-draft_VERIFICATION.md +130 -0
- package/docs/attestation/patent/README.md +75 -0
- package/docs/attestation/patent/fig1_write_path.svg +58 -0
- package/docs/attestation/patent/fig2_read_normalize_rollup.svg +92 -0
- package/docs/attestation/timestamp_response.tsr +0 -0
- package/docs/attribution-README.md +264 -0
- package/docs/audit-compliance.md +283 -0
- package/docs/audit-outputs.md +1213 -0
- package/docs/audit-sdk.md +1134 -0
- package/docs/autopilot-levels.md +368 -0
- package/docs/autopilot.md +288 -0
- package/docs/ci-cd-integration.md +580 -0
- package/docs/ci-integration-guide.md +369 -0
- package/docs/ci-version-validation.md +198 -0
- package/docs/cli-mcp-weave-reporting.md +462 -0
- package/docs/cli.md +2262 -0
- package/docs/cluster-gates-rollback.md +222 -0
- package/docs/command-creation-guide.md +485 -0
- package/docs/command-whitelist.md +490 -0
- package/docs/commands/idea.md +253 -0
- package/docs/config.md +245 -0
- package/docs/conflict-clustering.md +225 -0
- package/docs/conflict-predictor.md +359 -0
- package/docs/context-diet.md +249 -0
- package/docs/counter-examples.md +199 -0
- package/docs/create-project.md +211 -0
- package/docs/deliverables-generator.md +299 -0
- package/docs/deliverables-management.md +474 -0
- package/docs/dependency-parser.md +354 -0
- package/docs/determinism.md +299 -0
- package/docs/diffgraph-planner.md +1211 -0
- package/docs/dogfood/README.md +33 -0
- package/docs/dogfood/wave-3-results.md +303 -0
- package/docs/dogfood-merge-weave-script.md +224 -0
- package/docs/enterprise-onboarding.md +291 -0
- package/docs/environment-variables.md +625 -0
- package/docs/error-recovery.md +466 -0
- package/docs/errors.md +288 -0
- package/docs/executor-authoring.md +854 -0
- package/docs/executor-decoupling.md +410 -0
- package/docs/front-end-capture-pipeline.md +312 -0
- package/docs/gate-report-examples.md +380 -0
- package/docs/gates.md +319 -0
- package/docs/github-automation.md +128 -0
- package/docs/governance-metrics.md +368 -0
- package/docs/integrations/README.md +588 -0
- package/docs/interactive-plan-review.md +493 -0
- package/docs/issue-orchestration.md +256 -0
- package/docs/lex_ax_session_key_rememberings_v0.1.md +195 -0
- package/docs/lexrunner-v1-summary.md +246 -0
- package/docs/lexrunner-v2-contract.md +404 -0
- package/docs/lexrunner-v2-migration-plan.md +388 -0
- package/docs/lexrunner-v2-salvage-map.md +355 -0
- package/docs/lexsona-rules.md +154 -0
- package/docs/merge-weave-analysis.md +403 -0
- package/docs/merge-weave-quickstart.md +770 -0
- package/docs/merge-weave-state-machine.md +390 -0
- package/docs/migration-guide.md +529 -0
- package/docs/monitoring-examples.md +470 -0
- package/docs/monitoring-implementation.md +252 -0
- package/docs/orchestration.md +234 -0
- package/docs/performance-scale.md +359 -0
- package/docs/plan-generation.md +407 -0
- package/docs/profile-resolution.md +455 -0
- package/docs/prompts.md +427 -0
- package/docs/quickstart.md +546 -0
- package/docs/release-process.md +310 -0
- package/docs/sample-prompts/merge-weave/cli-merge-weave-kickoff.md +274 -0
- package/docs/sample-prompts/merge-weave/mcp-merge-weave-kickoff.md +480 -0
- package/docs/sample-prompts/merge-weave/standalone-merge-weave-kickoff.md +237 -0
- package/docs/schemas.md +359 -0
- package/docs/scope-validation.md +444 -0
- package/docs/security/rotation-guide.md +325 -0
- package/docs/specs/Meeting_Control_Stack_Concept_v0.1.0.md +417 -0
- package/docs/specs/git-feature-flag-redesign.md +321 -0
- package/docs/specs/lex-pr-brief-behavior.md +269 -0
- package/docs/specs/smartergpt-structure-v1.md +705 -0
- package/docs/specs/task-brief-v0.1.md +224 -0
- package/docs/store-architecture.md +61 -0
- package/docs/templates/CONTRIBUTING-merge-weave-section.md +33 -0
- package/docs/templates/gates.example.yml +109 -0
- package/docs/templates/plan.example.json +77 -0
- package/docs/thesis/00-EVOLUTION-NOTES.md +383 -0
- package/docs/thesis/01-CORE-THESIS.md +285 -0
- package/docs/thesis/02-TURN-COST.md +498 -0
- package/docs/thesis/03-PERMISSION-TO-FAIL.md +581 -0
- package/docs/thesis/04-CROSS-MODEL-CONTINUITY.md +517 -0
- package/docs/thesis/05-RULE-FILE-SPEC.md +732 -0
- package/docs/thesis/06-CAPABILITY-TIERS.md +723 -0
- package/docs/thesis/07-ROBERT-FIELD-REPORT.md +433 -0
- package/docs/thesis/08-IMPLEMENTATION-GUIDE.md +1093 -0
- package/docs/thesis/09-METRICS-AND-TELEMETRY.md +793 -0
- package/docs/thesis/10-FAILURE-MODES.md +716 -0
- package/docs/thesis/README.md +151 -0
- package/docs/thesis/lex_governance-collab_systems_paper_draft.md +952 -0
- package/docs/thesis/lex_governance-collab_systems_paper_draft.pdf +0 -0
- package/docs/tool-grounded/READINESS_ANALYSIS.md +527 -0
- package/docs/tool-grounded/enforcement.md +361 -0
- package/docs/tool-grounded/tool-grounded-a-view-from-the-inside.md +437 -0
- package/docs/tool-grounded/tool-grounded-prompt.md +122 -0
- package/docs/tool-grounded/tool-grounded-run-centric.md +474 -0
- package/docs/troubleshooting-planner.md +910 -0
- package/docs/troubleshooting.md +745 -0
- package/docs/tutorials/README.md +201 -0
- package/docs/tutorials/diffgraph-planner/01-simple-stack.md +460 -0
- package/docs/tutorials/diffgraph-planner/02-diamond-pattern.md +431 -0
- package/docs/tutorials/diffgraph-planner/03-large-batch.md +525 -0
- package/docs/tutorials/diffgraph-planner/04-fixing-cycles.md +526 -0
- package/docs/tutorials/diffgraph-planner/05-hybrid-workflow.md +555 -0
- package/docs/tutorials/quick-merge-pyramid.md +364 -0
- package/docs/tutorials/video-scripts/01-getting-started.md +286 -0
- package/docs/tutorials/video-scripts/02-understanding-dependencies.md +376 -0
- package/docs/weave-contract.md +116 -0
- package/docs/weave-execution-log.md +153 -0
- package/docs/workflows/README.md +139 -0
- package/docs/workflows/enterprise.md +545 -0
- package/docs/workflows/small-team.md +398 -0
- package/docs/workflows/solo-developer.md +419 -0
- package/dogfood-merge-weave.sh +122 -0
- package/examples/README.md +22 -0
- package/examples/WORKING_EXAMPLE.md +309 -0
- package/examples/analyze-pr-files.js +100 -0
- package/examples/autopilot-level4-example.md +234 -0
- package/examples/cluster-gates-demo.sh +178 -0
- package/examples/complete-security-workflow.ts +248 -0
- package/examples/error-recovery/README.md +202 -0
- package/examples/executor-manifest.example.yaml +81 -0
- package/examples/front-end-capture-pipeline/README.md +99 -0
- package/examples/front-end-capture-pipeline/create-project-example.sh +83 -0
- package/examples/front-end-capture-pipeline/idea-dark-mode.json +14 -0
- package/examples/front-end-capture-pipeline/idea-example.sh +57 -0
- package/examples/front-end-capture-pipeline/manual-test-checklist.md +426 -0
- package/examples/gates/README.md +165 -0
- package/examples/gates/lint-gate.sh +40 -0
- package/examples/gates/lint-gate.ts +99 -0
- package/examples/gates/test-runner.ts +113 -0
- package/examples/gates/vuln-scanner.ts +95 -0
- package/examples/github-integration/README.md +111 -0
- package/examples/github-integration/example-plan.json +95 -0
- package/examples/performance-config.md +388 -0
- package/examples/profile-setup/.gitignore.template +66 -0
- package/examples/profile-setup/.smartergpt-example/README.md +190 -0
- package/examples/profile-setup/.smartergpt.local-example/README.md +365 -0
- package/examples/profile-setup/README.md +492 -0
- package/examples/profile-setup/cross-repo-prompts/README.md +606 -0
- package/examples/safety-framework-demo.ts +130 -0
- package/examples/safety-mechanisms-example.ts +191 -0
- package/examples/sample-plan.json +87 -0
- package/examples/sample-stack.yml +66 -0
- package/examples/sarif/README.md +224 -0
- package/examples/scope-validation-demo.ts +199 -0
- package/examples/security-integration.ts +293 -0
- package/examples/token-tracking-example.ts +71 -0
- package/executors/senior-dev/ARCHITECTURE.md +182 -0
- package/executors/senior-dev/MEMORY_INTEGRATION.md +236 -0
- package/executors/senior-dev/QUICK_START.md +145 -0
- package/executors/senior-dev/README.md +76 -0
- package/executors/senior-dev/examples/sample-review-session.md +228 -0
- package/executors/senior-dev/executor-manifest.yaml +79 -0
- package/executors/senior-dev/prompts/code-review.prompt.md +78 -0
- package/executors/senior-dev/prompts/mentorship-feedback.prompt.md +97 -0
- package/executors/senior-dev/prompts/pattern-recognition.prompt.md +80 -0
- package/executors/senior-dev/prompts/pr-analysis.prompt.md +75 -0
- package/executors/senior-dev/scripts/capture-review-frame.sh +129 -0
- package/executors/senior-dev/scripts/prepare-review-context.sh +61 -0
- package/executors/senior-dev/scripts/recall-context.sh +87 -0
- package/lexrunner-launcher.sh +12 -0
- package/mcp-config-example.json +14 -0
- package/mcp-server.mjs +1221 -0
- package/merge-weave-current-prs.md +170 -0
- package/merge-weave-dogfood.json +46 -0
- package/merge-weave-plan.json +56 -0
- package/package.json +140 -0
- package/procedures/merge-weave-main.yaml +90 -0
- package/procedures/pr-review.yaml +68 -0
- package/project/README.md +50 -0
- package/prompts/tool-grounded-mode.md +185 -0
- package/schemas/allowed-commands.schema.json +108 -0
- package/schemas/audit-events.schema.json +138 -0
- package/schemas/audit-events.v1.0.0.schema.json +138 -0
- package/schemas/edit-plan.schema.json +80 -0
- package/schemas/executor-manifest.schema.json +236 -0
- package/schemas/flake-report.schema.json +95 -0
- package/schemas/gate-report.schema.json +85 -0
- package/schemas/gates/build.schema.json +32 -0
- package/schemas/gates/coverage.schema.json +42 -0
- package/schemas/gates/lint.schema.json +34 -0
- package/schemas/gates/security-scan.schema.json +33 -0
- package/schemas/gates/test.schema.json +35 -0
- package/schemas/next-option.schema.json +60 -0
- package/schemas/persona-snapshot.schema.json +66 -0
- package/schemas/plan.schema.json +300 -0
- package/schemas/status-response.schema.json +193 -0
- package/scripts/README.md +354 -0
- package/scripts/analyze-governance-logs.mjs +51 -0
- package/scripts/benchmark-ci.ts +339 -0
- package/scripts/check-determinism.sh +23 -0
- package/scripts/check-license-compliance.mjs +319 -0
- package/scripts/check-release-drift.mjs +81 -0
- package/scripts/ci-debug.sh +24 -0
- package/scripts/ci-smoke.mjs +304 -0
- package/scripts/create-sample-repo.sh +245 -0
- package/scripts/dogfood-merge-weave.sh +552 -0
- package/scripts/gen_mcp_servers.py +252 -0
- package/scripts/generate-executor-manifest-schema.ts +30 -0
- package/scripts/generate-flake-schema.ts +32 -0
- package/scripts/generate-gate-schema.ts +32 -0
- package/scripts/generate-plan-schema.ts +30 -0
- package/scripts/generate-run-schemas.ts +69 -0
- package/scripts/load-prompt.mjs +147 -0
- package/scripts/merge-weave-wrapper.sh +445 -0
- package/scripts/merge-weave.sh +489 -0
- package/scripts/metrics-template.ts +134 -0
- package/scripts/package-lex.sh +267 -0
- package/scripts/quick-start-merge-weave.sh +218 -0
- package/scripts/release-prepare.ts +350 -0
- package/scripts/rotate-secrets-example.ts +134 -0
- package/scripts/test-lexsona-shadow.mjs +100 -0
- package/scripts/validate-manifests.ts +188 -0
- package/scripts/verify-audit-phase2.js +175 -0
- package/src/ai/README.md +456 -0
- package/src/ai/conflictStrategy.ts +223 -0
- package/src/ai/conflictStrategyCache.ts +164 -0
- package/src/ai/conflictStrategyPrompt.ts +128 -0
- package/src/ai/conflictStrategySchema.ts +165 -0
- package/src/ai/heuristicFallback.ts +162 -0
- package/src/ai/index.ts +64 -0
- package/src/ai/riskScoring.ts +174 -0
- package/src/aliases/index.ts +16 -0
- package/src/aliases/resolver.ts +212 -0
- package/src/audit/context.ts +284 -0
- package/src/audit/emitter.ts +685 -0
- package/src/audit/events.ts +210 -0
- package/src/audit/gateMatrix.ts +158 -0
- package/src/audit/index.ts +44 -0
- package/src/audit/manifest.ts +78 -0
- package/src/audit/profiles.ts +93 -0
- package/src/audit/redaction.ts +216 -0
- package/src/audit/sarif.ts +213 -0
- package/src/audit/schema/events.ts +366 -0
- package/src/audit/schema/manifest.ts +47 -0
- package/src/audit/schema.ts +159 -0
- package/src/audit/sdk/index.ts +145 -0
- package/src/audit/sdk/types.ts +88 -0
- package/src/audit/sidecar.ts +111 -0
- package/src/audit/signing.ts +521 -0
- package/src/autopilot/README.md +113 -0
- package/src/autopilot/artifacts.ts +287 -0
- package/src/autopilot/base.ts +132 -0
- package/src/autopilot/deliverables.ts +392 -0
- package/src/autopilot/index.ts +29 -0
- package/src/autopilot/level1.ts +187 -0
- package/src/autopilot/level2.ts +262 -0
- package/src/autopilot/level3.ts +263 -0
- package/src/autopilot/level4.ts +393 -0
- package/src/autopilot/safety/README.md +512 -0
- package/src/autopilot/safety/SafetyFramework.ts +634 -0
- package/src/autopilot/safety/index.ts +16 -0
- package/src/autopilot/types.ts +250 -0
- package/src/budget/index.ts +56 -0
- package/src/budget/manager.ts +547 -0
- package/src/budget/schema.ts +305 -0
- package/src/budget/tracker.ts +155 -0
- package/src/cache/issue-cache.ts +150 -0
- package/src/cli/command-map.ts +221 -0
- package/src/cli/commands/gate/test.ts +214 -0
- package/src/cli/exitHandler.ts +98 -0
- package/src/cli/flags.ts +123 -0
- package/src/cli/formatSuggestions.ts +202 -0
- package/src/cli/formatters.ts +294 -0
- package/src/cli/jsonEnvelope.ts +152 -0
- package/src/cli/output.ts +61 -0
- package/src/cli/runnerLifecycle.ts +118 -0
- package/src/cli-audit.ts +76 -0
- package/src/cli-security.ts +114 -0
- package/src/cli.ts +1231 -0
- package/src/commands/audit/index.ts +5 -0
- package/src/commands/audit/verify.ts +87 -0
- package/src/commands/autopilot.ts +131 -0
- package/src/commands/budget.ts +327 -0
- package/src/commands/bulkOps.ts +204 -0
- package/src/commands/completion.ts +287 -0
- package/src/commands/config/validate.ts +428 -0
- package/src/commands/config.ts +368 -0
- package/src/commands/counterExamples.ts +104 -0
- package/src/commands/create-project.ts +338 -0
- package/src/commands/discover.ts +192 -0
- package/src/commands/doctor.ts +436 -0
- package/src/commands/execute.ts +558 -0
- package/src/commands/explain.ts +157 -0
- package/src/commands/fanout-analyze.ts +684 -0
- package/src/commands/fanout-harvest.ts +328 -0
- package/src/commands/fanout-monitor.ts +224 -0
- package/src/commands/gateAttest.ts +95 -0
- package/src/commands/gateImport.ts +142 -0
- package/src/commands/gateImportChecks.ts +208 -0
- package/src/commands/gateReport.ts +184 -0
- package/src/commands/governanceCleanup.ts +171 -0
- package/src/commands/governanceReport.ts +497 -0
- package/src/commands/guards.ts +50 -0
- package/src/commands/idea.ts +281 -0
- package/src/commands/init.ts +414 -0
- package/src/commands/issues.ts +165 -0
- package/src/commands/merge.ts +677 -0
- package/src/commands/mergeOrder.ts +68 -0
- package/src/commands/metrics.ts +232 -0
- package/src/commands/migrateProfile.ts +187 -0
- package/src/commands/orchestrate/analyze-issues.ts +203 -0
- package/src/commands/orchestrate/assign-batch.ts +204 -0
- package/src/commands/orchestrate/generate-deliverables.ts +66 -0
- package/src/commands/orchestrate/pinToolchain.ts +102 -0
- package/src/commands/orchestrate/plan-batch.ts +119 -0
- package/src/commands/orchestrate/predict-conflicts.ts +210 -0
- package/src/commands/orchestrate.ts +186 -0
- package/src/commands/plan.ts +403 -0
- package/src/commands/planDiff.ts +56 -0
- package/src/commands/planReview.ts +112 -0
- package/src/commands/planViewer.ts +180 -0
- package/src/commands/preview-constraints.ts +97 -0
- package/src/commands/query.ts +313 -0
- package/src/commands/report.ts +56 -0
- package/src/commands/retry.ts +60 -0
- package/src/commands/schema.ts +128 -0
- package/src/commands/security.ts +140 -0
- package/src/commands/seniorDev.ts +326 -0
- package/src/commands/status.ts +97 -0
- package/src/commands/tokenReport.ts +167 -0
- package/src/commands/validation.ts +66 -0
- package/src/commands/weave-checkpoints.ts +145 -0
- package/src/commands/weave-fanout.ts +273 -0
- package/src/commands/weave-policy.ts +277 -0
- package/src/commands/weave.ts +518 -0
- package/src/config/localOverlay.ts +167 -0
- package/src/config/pathResolver.ts +106 -0
- package/src/config/profileResolver.ts +194 -0
- package/src/config/promptsResolver.ts +312 -0
- package/src/config/rulesResolver.ts +257 -0
- package/src/config/schemas.ts +142 -0
- package/src/core/bootstrap.ts +287 -0
- package/src/core/enterprise.ts +453 -0
- package/src/core/errorRecovery.ts +509 -0
- package/src/core/githubPlan.ts +282 -0
- package/src/core/inputs.ts +314 -0
- package/src/core/multiRepoPlan.ts +353 -0
- package/src/core/plan.ts +106 -0
- package/src/core/snapshot.ts +189 -0
- package/src/errors/adapters.ts +897 -0
- package/src/errors/index.ts +231 -0
- package/src/executionState.ts +356 -0
- package/src/executors/README_FRAME_CONTRACT.md +446 -0
- package/src/executors/frameContract.ts +270 -0
- package/src/executors/guardrailEnforcement.ts +294 -0
- package/src/executors/seniorDev/core.ts +548 -0
- package/src/executors/seniorDev/index.ts +30 -0
- package/src/executors/seniorDev/types.ts +176 -0
- package/src/executors/toolBudget.ts +194 -0
- package/src/fanout/analyzer.ts +735 -0
- package/src/fanout/github-adapter.ts +262 -0
- package/src/fanout/harvest.ts +517 -0
- package/src/fanout/monitor.ts +350 -0
- package/src/fanout/types.ts +428 -0
- package/src/frames/controller.ts +160 -0
- package/src/frames/emitter.ts +455 -0
- package/src/frames/index.ts +58 -0
- package/src/frames/storage.ts +203 -0
- package/src/frames/types.ts +258 -0
- package/src/gates/checkRunConverter.ts +91 -0
- package/src/gates/test/adapters/errors.ts +32 -0
- package/src/gates/test/adapters/index.ts +36 -0
- package/src/gates/test/adapters/interface.ts +63 -0
- package/src/gates/test/adapters/jest-json.ts +370 -0
- package/src/gates/test/adapters/junit-xml.ts +400 -0
- package/src/gates/test/adapters/registry.ts +149 -0
- package/src/gates/test/adapters/vitest-json.ts +339 -0
- package/src/gates/test/enrichment/failureId.ts +74 -0
- package/src/gates/test/enrichment/index.ts +25 -0
- package/src/gates/test/enrichment/nextActions.ts +322 -0
- package/src/gates/test/enrichment/rerunTemplates.ts +105 -0
- package/src/gates/test/enrichment/signature.ts +58 -0
- package/src/gates/test/enrichment/stackParser.ts +149 -0
- package/src/gates/test/enrichment/types.ts +67 -0
- package/src/gates/test/formatters/markdown.spec.ts +942 -0
- package/src/gates/test/formatters/markdown.ts +296 -0
- package/src/gates/test/index.ts +54 -0
- package/src/gates/test/schema.spec.ts +372 -0
- package/src/gates/test/schema.ts +327 -0
- package/src/gates/validator.ts +92 -0
- package/src/gates.ts +1022 -0
- package/src/git/operations.ts +592 -0
- package/src/git/parseRemote.ts +22 -0
- package/src/github/api.ts +584 -0
- package/src/github/batch-ops.ts +215 -0
- package/src/github/client.ts +647 -0
- package/src/github/contextDiet.ts +205 -0
- package/src/github/diffHunks.ts +285 -0
- package/src/github/index.ts +11 -0
- package/src/github/minimalContext.ts +212 -0
- package/src/github/minimalContextClient.ts +105 -0
- package/src/github/symbolMap.ts +370 -0
- package/src/github/types.ts +166 -0
- package/src/governance/index.ts +42 -0
- package/src/governance/mcpStatus.ts +258 -0
- package/src/governance/timeoutAdjustment.ts +149 -0
- package/src/governance/turnCostSummary.ts +182 -0
- package/src/hooks/events.ts +374 -0
- package/src/hooks/index.ts +8 -0
- package/src/hostility/checks.ts +408 -0
- package/src/hostility/index.ts +108 -0
- package/src/hostility/score.ts +143 -0
- package/src/interactive/planDiff.ts +168 -0
- package/src/interactive/planHistory.ts +205 -0
- package/src/interactive/planReview.ts +531 -0
- package/src/learning/counter-example.ts +174 -0
- package/src/learning/prompts.ts +107 -0
- package/src/learning/storage.ts +230 -0
- package/src/lexsona/client.ts +367 -0
- package/src/lexsona/index.ts +44 -0
- package/src/lexsona/logger.ts +408 -0
- package/src/lexsona/types.ts +177 -0
- package/src/mcp/DEPRECATED.md +33 -0
- package/src/mcp/server.ts +3587 -0
- package/src/mcp/types/guided-response.ts +95 -0
- package/src/mcp/types.ts +468 -0
- package/src/mcp/workflow/state-machine.ts +277 -0
- package/src/mergeEligibility.ts +355 -0
- package/src/mergeOrder.ts +170 -0
- package/src/metrics/export.ts +472 -0
- package/src/metrics/index.ts +35 -0
- package/src/metrics/turncost.ts +284 -0
- package/src/monitoring/README.md +222 -0
- package/src/monitoring/audit.ts +98 -0
- package/src/monitoring/cache.ts +121 -0
- package/src/monitoring/dashboards/grafana-dashboard.json +172 -0
- package/src/monitoring/errorRecovery.ts +334 -0
- package/src/monitoring/errors.ts +105 -0
- package/src/monitoring/fileLogger.ts +194 -0
- package/src/monitoring/hallucinations.ts +45 -0
- package/src/monitoring/health.ts +171 -0
- package/src/monitoring/index.ts +16 -0
- package/src/monitoring/lock.ts +158 -0
- package/src/monitoring/logger.ts +178 -0
- package/src/monitoring/metrics.ts +245 -0
- package/src/monitoring/profiler.ts +156 -0
- package/src/monitoring/tokenLogger.ts +141 -0
- package/src/orchestrate/analyzer.ts +461 -0
- package/src/orchestrate/index.ts +6 -0
- package/src/orchestrate/types.ts +65 -0
- package/src/orchestration/README.md +480 -0
- package/src/orchestration/agentAssigner.ts +206 -0
- package/src/orchestration/batchPlanner.ts +201 -0
- package/src/orchestration/conflictClustering.ts +344 -0
- package/src/orchestration/conflictGraph.ts +63 -0
- package/src/orchestration/conflictPredictor.ts +170 -0
- package/src/orchestration/deliverablesGenerator.ts +345 -0
- package/src/orchestration/determinism.ts +232 -0
- package/src/orchestration/index.ts +45 -0
- package/src/orchestration/mergeTreeSimulator.ts +137 -0
- package/src/orchestration/mis.ts +123 -0
- package/src/orchestration/toolchainManifest.ts +169 -0
- package/src/orchestration/types.ts +103 -0
- package/src/performance.README.md +99 -0
- package/src/performance.ts +279 -0
- package/src/planner/README.md +215 -0
- package/src/planner/dependencyParser.ts +404 -0
- package/src/planner/dependencyScoring.ts +346 -0
- package/src/planner/fileAnalysis.ts +693 -0
- package/src/planner/index.ts +41 -0
- package/src/planner/scopeValidator.ts +308 -0
- package/src/planner/types.ts +80 -0
- package/src/planner/validation.ts +493 -0
- package/src/preview/constraints.ts +333 -0
- package/src/procedures/index.ts +47 -0
- package/src/procedures/loader.ts +252 -0
- package/src/procedures/schema.ts +191 -0
- package/src/procedures/stateMachine.ts +160 -0
- package/src/procedures/types.ts +178 -0
- package/src/receipts/emit.ts +354 -0
- package/src/receipts/index.ts +48 -0
- package/src/receipts/schema.ts +227 -0
- package/src/report/aggregate.ts +160 -0
- package/src/runs/artifacts.ts +315 -0
- package/src/runs/attribution.ts +132 -0
- package/src/runs/context.ts +54 -0
- package/src/runs/decisions.ts +407 -0
- package/src/runs/enforcement.ts +395 -0
- package/src/runs/failures.ts +517 -0
- package/src/runs/index.ts +141 -0
- package/src/runs/manager.ts +910 -0
- package/src/runs/statusBuilder.ts +233 -0
- package/src/runs/storage.ts +290 -0
- package/src/runs/types.ts +216 -0
- package/src/schema/flakeReport.ts +74 -0
- package/src/schema/gateMapping.ts +107 -0
- package/src/schema/gateReport.ts +236 -0
- package/src/schema/weaveLock.ts +51 -0
- package/src/schema.ts +313 -0
- package/src/schemas/executorManifest.ts +204 -0
- package/src/schemas/feature-spec-v0.ts +40 -0
- package/src/schemas/persona.ts +162 -0
- package/src/schemas/project.ts +91 -0
- package/src/schemas/runCentric.ts +402 -0
- package/src/schemas/task-contract.ts +626 -0
- package/src/schemas/vacuumReadyPrompt.ts +128 -0
- package/src/sdk/index.ts +113 -0
- package/src/sdk/parser.ts +101 -0
- package/src/sdk/query.ts +315 -0
- package/src/sdk/validator.ts +114 -0
- package/src/security/README.md +496 -0
- package/src/security/authentication.ts +173 -0
- package/src/security/authorization.ts +348 -0
- package/src/security/commandValidator.ts +195 -0
- package/src/security/compliance.ts +688 -0
- package/src/security/index.ts +85 -0
- package/src/security/policy.ts +399 -0
- package/src/security/sarif.ts +179 -0
- package/src/security/scanning.ts +362 -0
- package/src/security/secrets.ts +520 -0
- package/src/shared/git/index.ts +30 -0
- package/src/shared/git/runGit.ts +281 -0
- package/src/shared/git/runtime.ts +66 -0
- package/src/snapshot/builder.ts +229 -0
- package/src/snapshot/index.ts +8 -0
- package/src/store/CONTRACT.md +189 -0
- package/src/store/README.md +22 -0
- package/src/store/index.ts +99 -0
- package/src/store/inmemory/index.ts +10 -0
- package/src/store/inmemory/run-store.ts +268 -0
- package/src/store/postgres/.gitkeep +0 -0
- package/src/store/run-store.ts +405 -0
- package/src/store/sqlite/index.ts +7 -0
- package/src/store/sqlite/run-store.ts +525 -0
- package/src/store/sqlite/schema.sql +67 -0
- package/src/telemetry/frames.ts +179 -0
- package/src/telemetry/index.ts +5 -0
- package/src/tiers/index.ts +34 -0
- package/src/tiers/metrics.ts +156 -0
- package/src/tiers/schema.ts +95 -0
- package/src/tiers/suggest.ts +183 -0
- package/src/types/guardrails.ts +452 -0
- package/src/types/index.ts +42 -0
- package/src/util/canonicalJson.ts +29 -0
- package/src/util/colorControl.ts +46 -0
- package/src/util/envUtils.ts +139 -0
- package/src/util/hash.ts +69 -0
- package/src/util/lockHash.ts +90 -0
- package/src/util/minHeap.ts +108 -0
- package/src/util/progress.ts +89 -0
- package/src/util/tokenEstimator.ts +55 -0
- package/src/utils/fingerprint.ts +105 -0
- package/src/utils/paths.ts +209 -0
- package/src/utils/tokens.ts +151 -0
- package/src/utils/validation.ts +53 -0
- package/src/verification/diff-applier.ts +60 -0
- package/src/verification/engine-verifier.ts +171 -0
- package/src/verification/errors.ts +30 -0
- package/src/verification/index.ts +13 -0
- package/src/weave/audit/index.ts +17 -0
- package/src/weave/audit/logger.ts +206 -0
- package/src/weave/authority/evaluator.ts +660 -0
- package/src/weave/authority/index.ts +30 -0
- package/src/weave/authority/schema.ts +292 -0
- package/src/weave/checkpoint/index.ts +7 -0
- package/src/weave/checkpoint/storage.ts +223 -0
- package/src/weave/checkpoint/types.ts +121 -0
- package/src/weave/checkpoint/utils.ts +207 -0
- package/src/weave/clusterGates.ts +366 -0
- package/src/weave/draftPR.ts +214 -0
- package/src/weave/executor/d1-executor.ts +822 -0
- package/src/weave/executor/d2-executor.ts +381 -0
- package/src/weave/executor/index.ts +24 -0
- package/src/weave/executor/types.ts +135 -0
- package/src/weave/fanout/generator.ts +186 -0
- package/src/weave/fanout/index.ts +51 -0
- package/src/weave/fanout/loader.ts +134 -0
- package/src/weave/fanout/matcher.ts +239 -0
- package/src/weave/fanout/schema.ts +178 -0
- package/src/weave/frameHelper.ts +126 -0
- package/src/weave/gateFailureHandler.ts +405 -0
- package/src/weave/index.ts +89 -0
- package/src/weave/lockFile.ts +193 -0
- package/src/weave/mergeHelpers.ts +377 -0
- package/src/weave/mergeWeaveSequential.ts +282 -0
- package/src/weave/metrics/calculator.ts +362 -0
- package/src/weave/metrics/index.ts +44 -0
- package/src/weave/metrics/logger.ts +291 -0
- package/src/weave/metrics/schema.ts +505 -0
- package/src/weave/planner/index.ts +23 -0
- package/src/weave/planner/planner.ts +411 -0
- package/src/weave/planner/types.ts +181 -0
- package/src/weave/policy/index.ts +63 -0
- package/src/weave/policy/loader.ts +148 -0
- package/src/weave/policy/schema.ts +290 -0
- package/src/weave/post-merge-checks.ts +220 -0
- package/src/weave/preflightConflicts.ts +375 -0
- package/src/weave/receiptHelper.ts +287 -0
- package/src/weave/recovery.ts +232 -0
- package/src/weave/resolutionGuidance.ts +173 -0
- package/src/weave/stateMachine.ts +426 -0
- package/src/weave/testfix/applier.ts +195 -0
- package/src/weave/testfix/index.ts +18 -0
- package/src/weave/testfix/loader.ts +116 -0
- package/src/weave/testfix/matcher.ts +158 -0
- package/src/weave/testfix/schema.ts +218 -0
- package/src/weave/types.ts +305 -0
- package/src/weave/utils/copilot-completion.ts +76 -0
- package/test-mcp-dogfood.mjs +128 -0
- package/test-mcp.mjs +116 -0
- package/tests/README.md +155 -0
- package/tests/advanced-cli-e2e.spec.ts +218 -0
- package/tests/agentAssigner.spec.ts +261 -0
- package/tests/ai-conflict-strategy-cache.spec.ts +254 -0
- package/tests/ai-conflict-strategy-risk.spec.ts +287 -0
- package/tests/ai-conflict-strategy-schema.spec.ts +252 -0
- package/tests/ai-conflict-strategy.spec.ts +442 -0
- package/tests/aliases/resolver.spec.ts +238 -0
- package/tests/audit/context.spec.ts +283 -0
- package/tests/audit/emitter.spec.ts +347 -0
- package/tests/audit/gateMatrix.spec.ts +335 -0
- package/tests/audit/integration.spec.ts +236 -0
- package/tests/audit/redaction.spec.ts +290 -0
- package/tests/audit/sarif-integration.spec.ts +303 -0
- package/tests/audit/sarif.spec.ts +458 -0
- package/tests/audit/schema-events.spec.ts +421 -0
- package/tests/audit/schema.spec.ts +434 -0
- package/tests/audit/sdk-integration.spec.ts +598 -0
- package/tests/audit/sdk.spec.ts +318 -0
- package/tests/audit/signing-integration.spec.ts +276 -0
- package/tests/audit/signing.spec.ts +350 -0
- package/tests/audit-signing.spec.ts +406 -0
- package/tests/audit-verify-cli.spec.ts +176 -0
- package/tests/autopilot-e2e-level3-4.spec.ts +741 -0
- package/tests/autopilot-integration.spec.ts +274 -0
- package/tests/autopilot-level1.spec.ts +449 -0
- package/tests/autopilot-level2.spec.ts +188 -0
- package/tests/autopilot-level3.spec.ts +266 -0
- package/tests/autopilot-level4.spec.ts +454 -0
- package/tests/autopilot.spec.ts +379 -0
- package/tests/ax-error-adapters.spec.ts +580 -0
- package/tests/batch-planner.spec.ts +500 -0
- package/tests/benchmark-infrastructure.spec.ts +445 -0
- package/tests/benchmarks/README.md +103 -0
- package/tests/benchmarks/baselines/baseline.json +127 -0
- package/tests/benchmarks/core/dependencyResolver.bench.ts +128 -0
- package/tests/benchmarks/core/planParser.bench.ts +114 -0
- package/tests/benchmarks/core/topologicalSort.bench.ts +102 -0
- package/tests/benchmarks/index.ts +36 -0
- package/tests/benchmarks/io/fileOperations.bench.ts +132 -0
- package/tests/benchmarks/io/gitOperations.bench.ts +99 -0
- package/tests/benchmarks/utils/graphGenerator.ts +201 -0
- package/tests/benchmarks/utils/reporter.ts +231 -0
- package/tests/benchmarks/workflows/endToEnd.bench.ts +132 -0
- package/tests/bootstrap.test.ts +319 -0
- package/tests/budget-tracker.spec.ts +279 -0
- package/tests/bulkOps.spec.ts +166 -0
- package/tests/bulletproof-determinism.test.ts +223 -0
- package/tests/canonicalJson.test.ts +130 -0
- package/tests/checkRunConverter.spec.ts +357 -0
- package/tests/cli/commands/gate/test.spec.ts +564 -0
- package/tests/cli/emit-frames-flag.spec.ts +117 -0
- package/tests/cli/exitHandler.spec.ts +314 -0
- package/tests/cli/flags.spec.ts +223 -0
- package/tests/cli/formatters.spec.ts +513 -0
- package/tests/cli/output.spec.ts +221 -0
- package/tests/cli-autopilot.spec.ts +170 -0
- package/tests/cli-budget-guards.spec.ts +210 -0
- package/tests/cli-color-control.spec.ts +334 -0
- package/tests/cli-deliverables-generator.spec.ts +185 -0
- package/tests/cli-determinism.spec.ts +496 -0
- package/tests/cli-init-enterprise.spec.ts +294 -0
- package/tests/cli-init-json.spec.ts +154 -0
- package/tests/cli-init-local.spec.ts +159 -0
- package/tests/cli-json-envelope.spec.ts +140 -0
- package/tests/cli-json.spec.ts +408 -0
- package/tests/cli-orchestrate-plan-batch.spec.ts +329 -0
- package/tests/cli-orchestrate.spec.ts +231 -0
- package/tests/cli-plan-generation.spec.ts +367 -0
- package/tests/cli-plan-review.spec.ts +300 -0
- package/tests/cli-progress.spec.ts +193 -0
- package/tests/cli-ux-enhancements.spec.ts +213 -0
- package/tests/cliJsonPurity.spec.ts +437 -0
- package/tests/cliSuggestDeps.spec.ts +360 -0
- package/tests/cluster-gates-rollback.spec.ts +353 -0
- package/tests/command-validator-integration.spec.ts +305 -0
- package/tests/command-validator.spec.ts +380 -0
- package/tests/commands/autopilot.spec.ts +124 -0
- package/tests/commands/config-validate.spec.ts +301 -0
- package/tests/commands/config.spec.ts +311 -0
- package/tests/commands/create-project.spec.ts +90 -0
- package/tests/commands/doctor.spec.ts +57 -0
- package/tests/commands/execute.spec.ts +293 -0
- package/tests/commands/gateAttest.spec.ts +172 -0
- package/tests/commands/gateImport.spec.ts +176 -0
- package/tests/commands/gateReport.spec.ts +130 -0
- package/tests/commands/guards.spec.ts +114 -0
- package/tests/commands/idea.spec.ts +177 -0
- package/tests/commands/merge.spec.ts +166 -0
- package/tests/commands/plan.spec.ts +123 -0
- package/tests/commands/query.spec.ts +294 -0
- package/tests/commands/report.spec.ts +54 -0
- package/tests/commands/retry.spec.ts +300 -0
- package/tests/commands/schema.spec.ts +136 -0
- package/tests/commands/validation.spec.ts +229 -0
- package/tests/completion.spec.ts +133 -0
- package/tests/config-inspect.spec.ts +202 -0
- package/tests/conflictClustering-e2e.spec.ts +278 -0
- package/tests/conflictClustering.spec.ts +550 -0
- package/tests/conflictGraph.spec.ts +126 -0
- package/tests/conflictPredictor.spec.ts +238 -0
- package/tests/deliverables-generator.spec.ts +329 -0
- package/tests/deliverables.spec.ts +381 -0
- package/tests/dependencyParser-github.spec.ts +244 -0
- package/tests/dependencyParser.spec.ts +386 -0
- package/tests/dependencyScoring.spec.ts +668 -0
- package/tests/deterministic-applicable.test.ts +156 -0
- package/tests/deterministic-build.test.ts +172 -0
- package/tests/deterministic-simple.test.ts +32 -0
- package/tests/discover-suggest-integration.spec.ts +340 -0
- package/tests/dogfood-merge-weave-script.spec.ts +150 -0
- package/tests/e2e/planner.spec.ts +596 -0
- package/tests/e2e-comprehensive.test.ts +500 -0
- package/tests/e2e-determinism.test.ts +293 -0
- package/tests/e2e-synthetic-6pr-weave.spec.ts +329 -0
- package/tests/enterprise-init.spec.ts +350 -0
- package/tests/envUtils.spec.ts +267 -0
- package/tests/error-handling.test.ts +104 -0
- package/tests/error-recovery.spec.ts +451 -0
- package/tests/execution-plan-v1.test.ts +257 -0
- package/tests/executionState-loadGateResults.spec.ts +267 -0
- package/tests/executionState.test.ts +169 -0
- package/tests/executors/README.md +100 -0
- package/tests/executors/frameContract-integration.spec.ts +324 -0
- package/tests/executors/frameContract.spec.ts +531 -0
- package/tests/executors/guardrailEnforcement.spec.ts +424 -0
- package/tests/executors/lifecycle.spec.ts +313 -0
- package/tests/executors/toolBudget.spec.ts +473 -0
- package/tests/feature-spec-v0.test.ts +145 -0
- package/tests/fileAnalysis.spec.ts +946 -0
- package/tests/fingerprint.spec.ts +100 -0
- package/tests/fixtures/README.md +380 -0
- package/tests/fixtures/deliverables/batch-example-plan.json +62 -0
- package/tests/fixtures/executors/README.md +57 -0
- package/tests/fixtures/executors/index.ts +9 -0
- package/tests/fixtures/executors/mock-executor.ts +204 -0
- package/tests/fixtures/executors/registry.ts +51 -0
- package/tests/fixtures/executors/types.ts +95 -0
- package/tests/fixtures/fixtures.spec.ts +307 -0
- package/tests/fixtures/gates/configs.ts +234 -0
- package/tests/fixtures/gates/results.ts +234 -0
- package/tests/fixtures/harvest-bundle-fixture.json +87 -0
- package/tests/fixtures/index.ts +219 -0
- package/tests/fixtures/invalid/plans.ts +178 -0
- package/tests/fixtures/jest/all-passing.json +71 -0
- package/tests/fixtures/jest/snapshot-failures.json +66 -0
- package/tests/fixtures/jest/some-failing.json +100 -0
- package/tests/fixtures/jest/with-location.json +84 -0
- package/tests/fixtures/junit/cdata-messages.xml +29 -0
- package/tests/fixtures/junit/multiple-suites.xml +30 -0
- package/tests/fixtures/junit/single-suite.xml +17 -0
- package/tests/fixtures/junit/with-errors.xml +19 -0
- package/tests/fixtures/junit/with-skipped.xml +18 -0
- package/tests/fixtures/npm-audit.json +32 -0
- package/tests/fixtures/plan.bad-schema.json +5 -0
- package/tests/fixtures/plan.bad-unknown-dep.json +10 -0
- package/tests/fixtures/plan.ci-gates.json +36 -0
- package/tests/fixtures/plan.complex-cycle.json +22 -0
- package/tests/fixtures/plan.cycle.json +14 -0
- package/tests/fixtures/plan.deep-chain.json +95 -0
- package/tests/fixtures/plan.dogfood-execute.json +36 -0
- package/tests/fixtures/plan.gates.json +30 -0
- package/tests/fixtures/plan.integration-pyramid.json +56 -0
- package/tests/fixtures/plan.orphans.json +22 -0
- package/tests/fixtures/plan.parallel.json +30 -0
- package/tests/fixtures/plan.tiny.json +18 -0
- package/tests/fixtures/plan.wide-parallel.json +75 -0
- package/tests/fixtures/plan.with-failures.json +26 -0
- package/tests/fixtures/plan.with-vuln.json +25 -0
- package/tests/fixtures/planner/cross-module.json +101 -0
- package/tests/fixtures/planner/cycle-error.json +56 -0
- package/tests/fixtures/planner/diamond-pattern.json +74 -0
- package/tests/fixtures/planner/empty-repo.json +9 -0
- package/tests/fixtures/planner/file-overlap-heavy.json +110 -0
- package/tests/fixtures/planner/invalid-pr.json +25 -0
- package/tests/fixtures/planner/merge-conflicts.json +42 -0
- package/tests/fixtures/planner/mixed-deps.json +101 -0
- package/tests/fixtures/planner/self-dependency.json +24 -0
- package/tests/fixtures/planner/simple-stack.json +79 -0
- package/tests/fixtures/planner/single-pr.json +25 -0
- package/tests/fixtures/planner/stale-pr.json +40 -0
- package/tests/fixtures/plans/complex.ts +201 -0
- package/tests/fixtures/plans/diamond.ts +115 -0
- package/tests/fixtures/plans/linear.ts +74 -0
- package/tests/fixtures/plans/simple.ts +61 -0
- package/tests/fixtures/prs/basic.ts +175 -0
- package/tests/fixtures/prs/withDeps.ts +197 -0
- package/tests/fixtures/scan-results-clean.sarif +15 -0
- package/tests/fixtures/scan-results.sarif +74 -0
- package/tests/fixtures/scenarios/mergeWorkflows.ts +300 -0
- package/tests/fixtures/scenarios/syntheticWeave.ts +351 -0
- package/tests/fixtures/snapshot/package.json +5 -0
- package/tests/fixtures/snapshot/sample.ts +21 -0
- package/tests/fixtures/utils/cleanup.ts +81 -0
- package/tests/fixtures/utils/mockGitHub.ts +219 -0
- package/tests/fixtures/utils/tempDir.ts +109 -0
- package/tests/fixtures/verification/expected-verification.json +16 -0
- package/tests/fixtures/verification/receipt.json +31 -0
- package/tests/fixtures/verification/snapshot.json +44 -0
- package/tests/fixtures/vitest/all-passing.json +67 -0
- package/tests/fixtures/vitest/complex-nested-suites.json +98 -0
- package/tests/fixtures/vitest/some-failing.json +98 -0
- package/tests/fixtures/vitest/with-coverage.json +97 -0
- package/tests/fixtures-usage-examples.spec.ts +304 -0
- package/tests/flakeReport.spec.ts +267 -0
- package/tests/frames/ci-gate-integration.spec.ts +331 -0
- package/tests/frames/controller.spec.ts +165 -0
- package/tests/frames/emitter.spec.ts +371 -0
- package/tests/frames/idempotency.spec.ts +177 -0
- package/tests/frames/storage.spec.ts +346 -0
- package/tests/frames/types.spec.ts +249 -0
- package/tests/frames/v2-schema-integration.spec.ts +435 -0
- package/tests/gate-working-directory.spec.ts +204 -0
- package/tests/gateMapping.spec.ts +161 -0
- package/tests/gateReportIntegration.spec.ts +175 -0
- package/tests/gateReportValidation.spec.ts +452 -0
- package/tests/gates/test/adapters/jest-json.spec.ts +372 -0
- package/tests/gates/test/adapters/junit-xml.spec.ts +421 -0
- package/tests/gates/test/adapters/registry.spec.ts +376 -0
- package/tests/gates/test/adapters/vitest-json.spec.ts +455 -0
- package/tests/gates/test/enrichment/failureId.spec.ts +131 -0
- package/tests/gates/test/enrichment/nextActions.spec.ts +365 -0
- package/tests/gates/test/enrichment/rerunTemplates.spec.ts +187 -0
- package/tests/gates/test/enrichment/signature.spec.ts +163 -0
- package/tests/gates/test/enrichment/stackParser.spec.ts +203 -0
- package/tests/gates/turncost-integration.spec.ts +221 -0
- package/tests/gates/validation-integration.spec.ts +147 -0
- package/tests/gates/validator.spec.ts +200 -0
- package/tests/gates.test.ts +255 -0
- package/tests/gatesWithPolicy.hostilityTimeoutAdjustment.spec.ts +156 -0
- package/tests/git-operations-receipts.spec.ts +121 -0
- package/tests/git-operations.test.ts +152 -0
- package/tests/git-runtime.spec.ts +175 -0
- package/tests/github-api.labels.spec.ts +21 -0
- package/tests/github-api.test.ts +85 -0
- package/tests/github-context-diet.spec.ts +441 -0
- package/tests/github-diff-hunks.spec.ts +387 -0
- package/tests/github-integration.spec.ts +774 -0
- package/tests/github-minimal-context.spec.ts +338 -0
- package/tests/github-symbol-map.spec.ts +414 -0
- package/tests/githubClient.spec.ts +123 -0
- package/tests/governance/mcpStatus.spec.ts +276 -0
- package/tests/governance/timeoutAdjustment.spec.ts +149 -0
- package/tests/governance/turnCostSummary.spec.ts +188 -0
- package/tests/governance-retention.spec.ts +151 -0
- package/tests/governance-wrapper-delegation.spec.ts +148 -0
- package/tests/guardrails.spec.ts +860 -0
- package/tests/hash.test.ts +83 -0
- package/tests/helpers/cli.ts +23 -0
- package/tests/helpers/getStd.ts +1 -0
- package/tests/helpers/makeGate.ts +19 -0
- package/tests/helpers/plannerTestHelpers.ts +314 -0
- package/tests/hooks/events.spec.ts +518 -0
- package/tests/hostility/checks.spec.ts +295 -0
- package/tests/hostility/integration.spec.ts +123 -0
- package/tests/hostility/score.spec.ts +175 -0
- package/tests/init.spec.ts +270 -0
- package/tests/integration/hipaa-encryption.spec.ts +148 -0
- package/tests/integration/lex-smoke-test.spec.ts +328 -0
- package/tests/integration-e2e.test.ts +244 -0
- package/tests/integration-matrix.test.ts +409 -0
- package/tests/interPRConflicts.spec.ts +254 -0
- package/tests/interactive-plan-history.spec.ts +255 -0
- package/tests/interactive-plan-review.spec.ts +287 -0
- package/tests/issue-analyzer.spec.ts +593 -0
- package/tests/lexsona-integration.spec.ts +311 -0
- package/tests/localOverlay.spec.ts +203 -0
- package/tests/lockHash.spec.ts +167 -0
- package/tests/mcp-auth-errors.spec.ts +190 -0
- package/tests/mcp-contracts.spec.ts +290 -0
- package/tests/mcp-gates-external-plan.spec.ts +146 -0
- package/tests/mcp-granular-tools.spec.ts +208 -0
- package/tests/mcp-runstore-integration.spec.ts +334 -0
- package/tests/mcp-scope-integration.spec.ts +318 -0
- package/tests/mcp-task-handoff.spec.ts +320 -0
- package/tests/mcp-workflow-guide.spec.ts +53 -0
- package/tests/mcp.test.ts +151 -0
- package/tests/merge-conflict-detection.spec.ts +260 -0
- package/tests/mergeEligibility.test.ts +201 -0
- package/tests/mergeLockHash.spec.ts +158 -0
- package/tests/mergeOrder-with-fixtures.spec.ts +215 -0
- package/tests/mergeOrder.test.ts +108 -0
- package/tests/mergeTreeSimulator.spec.ts +145 -0
- package/tests/metrics/export.spec.ts +446 -0
- package/tests/metrics/turncost.spec.ts +309 -0
- package/tests/metrics-template.spec.ts +137 -0
- package/tests/migrateProfile.spec.ts +254 -0
- package/tests/mis.spec.ts +202 -0
- package/tests/monitoring-audit.spec.ts +181 -0
- package/tests/monitoring-cache.spec.ts +331 -0
- package/tests/monitoring-error-recovery.spec.ts +236 -0
- package/tests/monitoring-errors.spec.ts +193 -0
- package/tests/monitoring-fileLogger.spec.ts +319 -0
- package/tests/monitoring-health.spec.ts +152 -0
- package/tests/monitoring-lock.spec.ts +308 -0
- package/tests/monitoring-logger.spec.ts +157 -0
- package/tests/monitoring-metrics.spec.ts +158 -0
- package/tests/monitoring-profiler.spec.ts +197 -0
- package/tests/orchestration-determinism.spec.ts +204 -0
- package/tests/parseRemote.spec.ts +25 -0
- package/tests/pathResolver.spec.ts +122 -0
- package/tests/paths.spec.ts +68 -0
- package/tests/performance.spec.ts +322 -0
- package/tests/pipeline-determinism.spec.ts +597 -0
- package/tests/plan-tier-integration.spec.ts +184 -0
- package/tests/precedence-resolution.spec.ts +682 -0
- package/tests/preflightConflicts.spec.ts +205 -0
- package/tests/procedures/keystone-policy.spec.ts +296 -0
- package/tests/procedures/loader.spec.ts +585 -0
- package/tests/procedures/pr-review.spec.ts +321 -0
- package/tests/profileResolver.spec.ts +375 -0
- package/tests/progress-indicators.spec.ts +139 -0
- package/tests/promptsResolver.spec.ts +443 -0
- package/tests/public-api.spec.ts +272 -0
- package/tests/query.spec.ts +170 -0
- package/tests/receipts.spec.ts +463 -0
- package/tests/release-prepare.spec.ts +268 -0
- package/tests/report.test.ts +335 -0
- package/tests/resolutionGuidance.spec.ts +160 -0
- package/tests/rotate-secrets-example.spec.ts +198 -0
- package/tests/rulesResolver.spec.ts +232 -0
- package/tests/runGit.spec.ts +229 -0
- package/tests/runner-lifecycle-integration.spec.ts +283 -0
- package/tests/runs/artifacts.spec.ts +367 -0
- package/tests/runs/decisions.spec.ts +495 -0
- package/tests/runs/enforcement.spec.ts +555 -0
- package/tests/runs/failures.spec.ts +554 -0
- package/tests/runs/manager-runstore-integration.spec.ts +455 -0
- package/tests/runs/manager.spec.ts +678 -0
- package/tests/runs-manager.spec.ts +485 -0
- package/tests/safety-acceptance.spec.ts +278 -0
- package/tests/safety-enhanced.spec.ts +329 -0
- package/tests/safety-framework.spec.ts +427 -0
- package/tests/safety-guards-integration.spec.ts +213 -0
- package/tests/safety-integration.spec.ts +278 -0
- package/tests/sarif-parser.spec.ts +148 -0
- package/tests/schema.test.ts +88 -0
- package/tests/schemas/behavior-rule.spec.ts +366 -0
- package/tests/schemas/executorManifest.spec.ts +441 -0
- package/tests/schemas/persona-integration.spec.ts +62 -0
- package/tests/schemas/persona.spec.ts +172 -0
- package/tests/schemas/project.spec.ts +247 -0
- package/tests/schemas/run-store.spec.ts +553 -0
- package/tests/schemas/runCentric.spec.ts +463 -0
- package/tests/schemas/vacuumReadyPrompt.spec.ts +515 -0
- package/tests/scope-github-auto-detection.spec.ts +200 -0
- package/tests/scopeValidator.spec.ts +497 -0
- package/tests/security-authentication.spec.ts +42 -0
- package/tests/security-authorization.spec.ts +350 -0
- package/tests/security-cli.spec.ts +264 -0
- package/tests/security-compliance.spec.ts +334 -0
- package/tests/security-policy.spec.ts +295 -0
- package/tests/security-scanning.spec.ts +349 -0
- package/tests/security-secrets.spec.ts +401 -0
- package/tests/store/create-run-store.spec.ts +185 -0
- package/tests/store/inmemory/run-store.spec.ts +533 -0
- package/tests/store/sqlite/run-store.spec.ts +849 -0
- package/tests/telemetry/frames.spec.ts +120 -0
- package/tests/tiers.spec.ts +466 -0
- package/tests/token-usage.spec.ts +309 -0
- package/tests/toolchain-manifest.spec.ts +145 -0
- package/tests/unified-budget.spec.ts +713 -0
- package/tests/unit/cache/issue-cache.spec.ts +131 -0
- package/tests/unit/fanout/analyzer-integration.spec.ts +398 -0
- package/tests/unit/fanout/analyzer.spec.ts +605 -0
- package/tests/unit/fanout/github-adapter.spec.ts +203 -0
- package/tests/unit/fanout/harvest.spec.ts +93 -0
- package/tests/unit/fanout/monitor.spec.ts +297 -0
- package/tests/unit/fanout/types.spec.ts +308 -0
- package/tests/unit/github/batch-ops.spec.ts +179 -0
- package/tests/unit/learning/counter-example.spec.ts +168 -0
- package/tests/unit/learning/storage.spec.ts +154 -0
- package/tests/unit/preview/constraints.spec.ts +429 -0
- package/tests/unit/runs/attribution.spec.ts +204 -0
- package/tests/unit/schemas/task-contract.spec.ts +483 -0
- package/tests/unit/snapshot/builder.spec.ts +389 -0
- package/tests/unit/verification/engine-verifier.spec.ts +279 -0
- package/tests/unit/weave/authority-evaluator.spec.ts +404 -0
- package/tests/unit/weave/authority-schema.spec.ts +199 -0
- package/tests/unit/weave/auto-undraft-integration.spec.ts +349 -0
- package/tests/unit/weave/copilot-completion.spec.ts +182 -0
- package/tests/unit/weave/d1-executor.spec.ts +269 -0
- package/tests/unit/weave/d2-executor.spec.ts +334 -0
- package/tests/unit/weave/fanout-generator.spec.ts +365 -0
- package/tests/unit/weave/fanout-matcher.spec.ts +320 -0
- package/tests/unit/weave/fanout-schema.spec.ts +221 -0
- package/tests/unit/weave/mergeWeaveSequential.spec.ts +268 -0
- package/tests/unit/weave/metrics-calculator.spec.ts +212 -0
- package/tests/unit/weave/metrics-logger.spec.ts +233 -0
- package/tests/unit/weave/metrics-schema.spec.ts +383 -0
- package/tests/unit/weave/multi-repo-plan.spec.ts +221 -0
- package/tests/unit/weave/planner.spec.ts +227 -0
- package/tests/unit/weave/post-merge-checks.spec.ts +342 -0
- package/tests/unit/weave/recovery.spec.ts +306 -0
- package/tests/unit/weave/testfix/applier.spec.ts +364 -0
- package/tests/unit/weave/testfix/e2e.spec.ts +273 -0
- package/tests/unit/weave/testfix/integration.spec.ts +128 -0
- package/tests/unit/weave/testfix/matcher.spec.ts +321 -0
- package/tests/unit/weave/testfix/schema.spec.ts +298 -0
- package/tests/utils/fingerprint.spec.ts +251 -0
- package/tests/utils/paths.spec.ts +284 -0
- package/tests/utils/tokens.spec.ts +210 -0
- package/tests/utils/validation.spec.ts +215 -0
- package/tests/utils-validation.spec.ts +80 -0
- package/tests/validate-manifests.spec.ts +231 -0
- package/tests/validation.spec.ts +501 -0
- package/tests/vuln-gate.spec.ts +341 -0
- package/tests/weave/adr007-integration.spec.ts +309 -0
- package/tests/weave/checkpoint/cli-integration.spec.ts +118 -0
- package/tests/weave/checkpoint/storage.spec.ts +302 -0
- package/tests/weave/checkpoint/utils.spec.ts +223 -0
- package/tests/weave/frameHelper.spec.ts +423 -0
- package/tests/weave/gateFailureHandler.spec.ts +249 -0
- package/tests/weave/lockFile.spec.ts +387 -0
- package/tests/weave/mergeHelpers.spec.ts +173 -0
- package/tests/weave/receiptHelper.spec.ts +261 -0
- package/tests/weave/stateMachine.spec.ts +436 -0
- package/tests/weave-contract.test.ts +517 -0
- package/tests/weave-e2e.spec.ts +279 -0
- package/tests/weaveLock.spec.ts +136 -0
- package/tests/workflow-state-machine.spec.ts +274 -0
- package/tests/write-protection.spec.ts +213 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +12 -0
- package/vitest.benchmark.config.ts +17 -0
- package/vitest.config.ts +28 -0
- package/vitest.git.config.ts +12 -0
- package/vitest.slow-cli.config.ts +28 -0
|
@@ -0,0 +1,3587 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP server adapter for lexrunner
|
|
5
|
+
* Exposes read-only tools for plan creation, gate execution, and merge operations
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import {
|
|
11
|
+
CallToolRequestSchema,
|
|
12
|
+
ErrorCode,
|
|
13
|
+
ListToolsRequestSchema,
|
|
14
|
+
McpError,
|
|
15
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
import { loadInputs, detectGitHubMode } from "../core/inputs.js";
|
|
19
|
+
import { generatePlan } from "../core/plan.js";
|
|
20
|
+
import { generateSnapshot, generateGitHubSnapshot } from "../core/snapshot.js";
|
|
21
|
+
import { canonicalJSONStringify } from "../util/canonicalJson.js";
|
|
22
|
+
import { executeGatesWithPolicy } from "../gates.js";
|
|
23
|
+
import { ExecutionState } from "../executionState.js";
|
|
24
|
+
import { MergeEligibilityEvaluator } from "../mergeEligibility.js";
|
|
25
|
+
import { computeMergeOrder, CycleError, UnknownDependencyError } from "../mergeOrder.js";
|
|
26
|
+
import { loadPlan, validatePlan } from "../schema.js";
|
|
27
|
+
import { initLocalOverlay } from "../config/localOverlay.js";
|
|
28
|
+
import { healthChecker } from "../monitoring/health.js";
|
|
29
|
+
import { generatePlanFromGitHub } from "../core/githubPlan.js";
|
|
30
|
+
import { generateMultiRepoPlan } from "../core/multiRepoPlan.js";
|
|
31
|
+
import { createGitHubClient } from "../github/index.js";
|
|
32
|
+
import { createGitHubAPI, GitHubAPI, GitHubAPIError } from "../github/api.js";
|
|
33
|
+
import { createGitOperations } from "../git/operations.js";
|
|
34
|
+
import {
|
|
35
|
+
bootstrapWorkspace,
|
|
36
|
+
detectProjectType,
|
|
37
|
+
getEnvironmentSuggestions,
|
|
38
|
+
} from "../core/bootstrap.js";
|
|
39
|
+
import {
|
|
40
|
+
getMCPEnvironment,
|
|
41
|
+
PlanCreateArgs,
|
|
42
|
+
GatesRunArgs,
|
|
43
|
+
MergeApplyArgs,
|
|
44
|
+
InitLocalArgs,
|
|
45
|
+
ProfileResolveArgs,
|
|
46
|
+
PlanCreateResult,
|
|
47
|
+
GatesRunResult,
|
|
48
|
+
MergeApplyResult,
|
|
49
|
+
InitLocalResult,
|
|
50
|
+
ProfileResolveResult,
|
|
51
|
+
WorkflowGuideArgs,
|
|
52
|
+
PrListArgs,
|
|
53
|
+
PrListResult,
|
|
54
|
+
PlanValidateArgs,
|
|
55
|
+
PlanValidateResult,
|
|
56
|
+
PlanAnalyzeArgs,
|
|
57
|
+
PlanAnalyzeResult,
|
|
58
|
+
CreateTaskSnapshotArgs,
|
|
59
|
+
SubmitTaskReceiptArgs,
|
|
60
|
+
GetTaskStatusArgs,
|
|
61
|
+
ListPendingTasksArgs,
|
|
62
|
+
CreateTaskSnapshotResult,
|
|
63
|
+
SubmitTaskReceiptResult,
|
|
64
|
+
GetTaskStatusResult,
|
|
65
|
+
ListPendingTasksResult,
|
|
66
|
+
FanoutHarvestArgs,
|
|
67
|
+
FanoutAnalyzeArgs,
|
|
68
|
+
FanoutHarvestResult,
|
|
69
|
+
FanoutAnalyzeResult,
|
|
70
|
+
} from "./types.js";
|
|
71
|
+
import {
|
|
72
|
+
resolveProfile,
|
|
73
|
+
validateWriteOperation,
|
|
74
|
+
WriteProtectionError,
|
|
75
|
+
} from "../config/profileResolver.js";
|
|
76
|
+
import { getCIMutationPolicy, validateCIEnvironment } from "../util/envUtils.js";
|
|
77
|
+
|
|
78
|
+
// Governance metrics imports
|
|
79
|
+
import { getGlobalMetricsCollector, METRIC_DEFINITIONS } from "../metrics/export.js";
|
|
80
|
+
|
|
81
|
+
// AXError imports for structured error responses
|
|
82
|
+
import {
|
|
83
|
+
type AXError,
|
|
84
|
+
mcpToolError,
|
|
85
|
+
planNotFoundError,
|
|
86
|
+
writeProtectionError,
|
|
87
|
+
githubApiError,
|
|
88
|
+
toAXError,
|
|
89
|
+
ErrorCodes,
|
|
90
|
+
cycleDetectedError,
|
|
91
|
+
unknownDependencyError,
|
|
92
|
+
AXErrorException,
|
|
93
|
+
isAXErrorException,
|
|
94
|
+
type CycleDetectedContext,
|
|
95
|
+
type UnknownDependencyContext,
|
|
96
|
+
} from "../errors/index.js";
|
|
97
|
+
|
|
98
|
+
import * as fs from "fs";
|
|
99
|
+
import * as path from "path";
|
|
100
|
+
|
|
101
|
+
// Hostility scoring imports
|
|
102
|
+
import { runEnvironmentQualityCheck } from "../hostility/index.js";
|
|
103
|
+
|
|
104
|
+
// Governance integration imports
|
|
105
|
+
import { buildGovernanceStatus, governanceStatusToJSON } from "../governance/index.js";
|
|
106
|
+
|
|
107
|
+
// Tier metrics imports
|
|
108
|
+
import { suggestTiersForPlan, calculateTierMetrics } from "../tiers/index.js";
|
|
109
|
+
|
|
110
|
+
// Senior Dev executor imports
|
|
111
|
+
import {
|
|
112
|
+
prepareReviewContext,
|
|
113
|
+
recallSeniorDevContext,
|
|
114
|
+
captureSeniorDevFrame,
|
|
115
|
+
EXECUTOR_MODES,
|
|
116
|
+
} from "../executors/seniorDev/index.js";
|
|
117
|
+
import type {
|
|
118
|
+
PrepareContextInput,
|
|
119
|
+
RecallContextInput,
|
|
120
|
+
CaptureFrameInput,
|
|
121
|
+
RecallQueryType,
|
|
122
|
+
Severity,
|
|
123
|
+
} from "../executors/seniorDev/index.js";
|
|
124
|
+
|
|
125
|
+
// Run manager imports
|
|
126
|
+
import {
|
|
127
|
+
createRunManager,
|
|
128
|
+
StartRunInput,
|
|
129
|
+
StartRunInputSchema,
|
|
130
|
+
GetStatusInput,
|
|
131
|
+
GetStatusInputSchema,
|
|
132
|
+
RunNotFoundError,
|
|
133
|
+
SubmitDecisionInput,
|
|
134
|
+
SubmitDecisionInputSchema,
|
|
135
|
+
submitDecision,
|
|
136
|
+
} from "../runs/index.js";
|
|
137
|
+
|
|
138
|
+
// RunStore imports
|
|
139
|
+
import { createRunStore, type RunStore, type ListRunsOptions } from "../store/index.js";
|
|
140
|
+
import { ulid } from "ulid";
|
|
141
|
+
import * as crypto from "crypto";
|
|
142
|
+
|
|
143
|
+
// Workflow guidance imports
|
|
144
|
+
import { createWorkflowGuide, type WorkflowPhase } from "./workflow/state-machine.js";
|
|
145
|
+
import type { WorkflowGuide } from "./types/guided-response.js";
|
|
146
|
+
|
|
147
|
+
// Task Snapshot Contract imports (ADR-007)
|
|
148
|
+
import { SnapshotBuilder } from "../snapshot/index.js";
|
|
149
|
+
import { EngineVerifier } from "../verification/index.js";
|
|
150
|
+
import { parseTaskReceipt, TaskSnapshot_v1, TaskReceipt_v1 } from "../schemas/task-contract.js";
|
|
151
|
+
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// AXError MCP Helper
|
|
154
|
+
// =============================================================================
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Create an McpError with AXError-structured content in the message.
|
|
158
|
+
*
|
|
159
|
+
* Per AX-CONTRACT.md v0.1, Guarantee 2.3: All MCP tool failures should
|
|
160
|
+
* return structured errors that agents can parse for recovery actions.
|
|
161
|
+
*
|
|
162
|
+
* The error message is JSON-serialized AXError for machine readability,
|
|
163
|
+
* while remaining compatible with MCP's error format.
|
|
164
|
+
*/
|
|
165
|
+
function throwMcpAXError(mcpErrorCode: ErrorCode, axError: AXError): never {
|
|
166
|
+
// Serialize the AXError as JSON in the message for structured parsing
|
|
167
|
+
const structuredMessage = JSON.stringify(axError);
|
|
168
|
+
throw new McpError(mcpErrorCode, structuredMessage);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Create an McpError from a caught error, converting to AXError format.
|
|
173
|
+
*
|
|
174
|
+
* @param mcpErrorCode - The MCP error code to use (e.g., ErrorCode.InternalError)
|
|
175
|
+
* @param tool - The MCP tool name
|
|
176
|
+
* @param error - The caught error
|
|
177
|
+
* @param operation - Optional operation description
|
|
178
|
+
* @param axErrorCode - Optional AXError code (defaults to INTERNAL_ERROR)
|
|
179
|
+
*/
|
|
180
|
+
function throwMcpToolError(
|
|
181
|
+
mcpErrorCode: ErrorCode,
|
|
182
|
+
tool: string,
|
|
183
|
+
error: unknown,
|
|
184
|
+
operation?: string,
|
|
185
|
+
axErrorCode: string = ErrorCodes.INTERNAL_ERROR
|
|
186
|
+
): never {
|
|
187
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
188
|
+
const axError = mcpToolError(axErrorCode, `${tool} failed: ${message}`, {
|
|
189
|
+
tool,
|
|
190
|
+
operation,
|
|
191
|
+
});
|
|
192
|
+
throwMcpAXError(mcpErrorCode, axError);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Options for creating the MCP server.
|
|
197
|
+
*/
|
|
198
|
+
export interface McpServerOptions {
|
|
199
|
+
/**
|
|
200
|
+
* RunStore instance for persisting run lifecycle data.
|
|
201
|
+
* If not provided, a default SqliteRunStore will be created.
|
|
202
|
+
*/
|
|
203
|
+
runStore?: RunStore;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Input schema for lexrunner.listRuns tool
|
|
208
|
+
*/
|
|
209
|
+
const ListRunsInputSchema = z.object({
|
|
210
|
+
limit: z.number().int().positive().optional(),
|
|
211
|
+
offset: z.number().int().nonnegative().optional(),
|
|
212
|
+
state: z.enum(["pending", "running", "completed", "failed", "aborted"]).optional(),
|
|
213
|
+
});
|
|
214
|
+
type ListRunsInput = z.infer<typeof ListRunsInputSchema>;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create and configure the MCP server
|
|
218
|
+
*/
|
|
219
|
+
function createServer(options?: McpServerOptions): Server {
|
|
220
|
+
// Initialize RunStore (use provided or create default)
|
|
221
|
+
const runStore = options?.runStore ?? createRunStore();
|
|
222
|
+
const server = new Server(
|
|
223
|
+
{
|
|
224
|
+
name: "lexrunner",
|
|
225
|
+
version: "0.1.0",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
capabilities: {
|
|
229
|
+
tools: {},
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// List available tools
|
|
235
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
236
|
+
return {
|
|
237
|
+
tools: [
|
|
238
|
+
{
|
|
239
|
+
name: "plan_create",
|
|
240
|
+
description:
|
|
241
|
+
"Create a plan from configuration files or auto-discover from GitHub PRs. Requires GITHUB_TOKEN environment variable when using fromGithub mode.",
|
|
242
|
+
inputSchema: {
|
|
243
|
+
type: "object",
|
|
244
|
+
properties: {
|
|
245
|
+
json: {
|
|
246
|
+
type: "boolean",
|
|
247
|
+
description: "Output plan as JSON to stdout",
|
|
248
|
+
default: false,
|
|
249
|
+
},
|
|
250
|
+
outDir: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "Output directory for plan artifacts",
|
|
253
|
+
},
|
|
254
|
+
fromGithub: {
|
|
255
|
+
type: "boolean",
|
|
256
|
+
description: "Auto-discover PRs from GitHub API",
|
|
257
|
+
default: false,
|
|
258
|
+
},
|
|
259
|
+
query: {
|
|
260
|
+
type: "string",
|
|
261
|
+
description: "GitHub search query (e.g., 'is:open label:stack:*')",
|
|
262
|
+
},
|
|
263
|
+
labels: {
|
|
264
|
+
type: "array",
|
|
265
|
+
description: "Filter PRs by labels",
|
|
266
|
+
items: {
|
|
267
|
+
type: "string",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
includeDrafts: {
|
|
271
|
+
type: "boolean",
|
|
272
|
+
description: "Include draft PRs in the plan",
|
|
273
|
+
default: true,
|
|
274
|
+
},
|
|
275
|
+
excludePRs: {
|
|
276
|
+
type: "array",
|
|
277
|
+
description: "Exclude specific PRs by number",
|
|
278
|
+
items: {
|
|
279
|
+
type: "number",
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
githubToken: {
|
|
283
|
+
type: "string",
|
|
284
|
+
description: "GitHub API token (or use GITHUB_TOKEN env var)",
|
|
285
|
+
},
|
|
286
|
+
owner: {
|
|
287
|
+
type: "string",
|
|
288
|
+
description: "GitHub repository owner (auto-detected from git remote)",
|
|
289
|
+
},
|
|
290
|
+
repo: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "GitHub repository name (auto-detected from git remote)",
|
|
293
|
+
},
|
|
294
|
+
repos: {
|
|
295
|
+
type: "array",
|
|
296
|
+
description:
|
|
297
|
+
"Multi-repo mode: array of repositories to discover PRs from. Overrides owner/repo if provided.",
|
|
298
|
+
items: {
|
|
299
|
+
type: "object",
|
|
300
|
+
properties: {
|
|
301
|
+
owner: { type: "string", description: "Repository owner" },
|
|
302
|
+
repo: { type: "string", description: "Repository name" },
|
|
303
|
+
priority: {
|
|
304
|
+
type: "number",
|
|
305
|
+
description: "Priority for merge ordering (default: 1, lower = earlier)",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
required: ["owner", "repo"],
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
requiredGates: {
|
|
312
|
+
type: "array",
|
|
313
|
+
description: "List of required gates (default: lint,typecheck,test)",
|
|
314
|
+
items: {
|
|
315
|
+
type: "string",
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
maxWorkers: {
|
|
319
|
+
type: "number",
|
|
320
|
+
description: "Maximum parallel workers for execution (default: 2)",
|
|
321
|
+
},
|
|
322
|
+
target: {
|
|
323
|
+
type: "string",
|
|
324
|
+
description: "Target branch for merging PRs (default: repo default branch)",
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "pr_list",
|
|
331
|
+
description:
|
|
332
|
+
"List pull requests from GitHub without creating a plan. Useful for discovering PRs before plan generation.",
|
|
333
|
+
inputSchema: {
|
|
334
|
+
type: "object",
|
|
335
|
+
properties: {
|
|
336
|
+
owner: {
|
|
337
|
+
type: "string",
|
|
338
|
+
description:
|
|
339
|
+
"GitHub repository owner (auto-detected from git remote if not provided)",
|
|
340
|
+
},
|
|
341
|
+
repo: {
|
|
342
|
+
type: "string",
|
|
343
|
+
description:
|
|
344
|
+
"GitHub repository name (auto-detected from git remote if not provided)",
|
|
345
|
+
},
|
|
346
|
+
query: {
|
|
347
|
+
type: "string",
|
|
348
|
+
description: "GitHub search query (e.g., 'is:open label:stack:*')",
|
|
349
|
+
},
|
|
350
|
+
labels: {
|
|
351
|
+
type: "array",
|
|
352
|
+
description: "Filter PRs by labels",
|
|
353
|
+
items: {
|
|
354
|
+
type: "string",
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
includeDrafts: {
|
|
358
|
+
type: "boolean",
|
|
359
|
+
description: "Include draft PRs in results",
|
|
360
|
+
default: true,
|
|
361
|
+
},
|
|
362
|
+
excludePRs: {
|
|
363
|
+
type: "array",
|
|
364
|
+
description: "Exclude specific PRs by number",
|
|
365
|
+
items: {
|
|
366
|
+
type: "number",
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
githubToken: {
|
|
370
|
+
type: "string",
|
|
371
|
+
description: "GitHub API token (or use GITHUB_TOKEN env var)",
|
|
372
|
+
},
|
|
373
|
+
state: {
|
|
374
|
+
type: "string",
|
|
375
|
+
description: "PR state filter (default: open)",
|
|
376
|
+
enum: ["open", "closed", "all"],
|
|
377
|
+
default: "open",
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: "plan_validate",
|
|
384
|
+
description:
|
|
385
|
+
"Validate a plan.json file without executing it. Checks schema compliance and logical consistency.",
|
|
386
|
+
inputSchema: {
|
|
387
|
+
type: "object",
|
|
388
|
+
properties: {
|
|
389
|
+
planFile: {
|
|
390
|
+
type: "string",
|
|
391
|
+
description: "Path to plan.json file (default: <profile>/runner/plan.json)",
|
|
392
|
+
},
|
|
393
|
+
planContent: {
|
|
394
|
+
type: "string",
|
|
395
|
+
description: "JSON string of plan content to validate (alternative to planFile)",
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
name: "plan_analyze",
|
|
402
|
+
description:
|
|
403
|
+
"Analyze a plan for potential conflicts and dependency issues. Performs dry-run dependency resolution and conflict detection.",
|
|
404
|
+
inputSchema: {
|
|
405
|
+
type: "object",
|
|
406
|
+
properties: {
|
|
407
|
+
planFile: {
|
|
408
|
+
type: "string",
|
|
409
|
+
description: "Path to plan.json file (default: <profile>/runner/plan.json)",
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
name: "gates_run",
|
|
416
|
+
description: "Execute gates for plan items",
|
|
417
|
+
inputSchema: {
|
|
418
|
+
type: "object",
|
|
419
|
+
properties: {
|
|
420
|
+
planFile: {
|
|
421
|
+
type: "string",
|
|
422
|
+
description:
|
|
423
|
+
"Path to external plan.json file (optional, uses internal state if not provided)",
|
|
424
|
+
},
|
|
425
|
+
onlyItem: {
|
|
426
|
+
type: "string",
|
|
427
|
+
description: "Run gates for specific item only",
|
|
428
|
+
},
|
|
429
|
+
onlyGate: {
|
|
430
|
+
type: "string",
|
|
431
|
+
description: "Run specific gate only",
|
|
432
|
+
},
|
|
433
|
+
outDir: {
|
|
434
|
+
type: "string",
|
|
435
|
+
description: "Output directory for gate results",
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: "merge_apply",
|
|
442
|
+
description: "Apply merge operations (requires ALLOW_MUTATIONS=true)",
|
|
443
|
+
inputSchema: {
|
|
444
|
+
type: "object",
|
|
445
|
+
properties: {
|
|
446
|
+
dryRun: {
|
|
447
|
+
type: "boolean",
|
|
448
|
+
description: "Simulate merge without making changes",
|
|
449
|
+
default: true,
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
name: "local_init",
|
|
456
|
+
description:
|
|
457
|
+
"Initialize local overlay directory with auto-detected project configuration",
|
|
458
|
+
inputSchema: {
|
|
459
|
+
type: "object",
|
|
460
|
+
properties: {
|
|
461
|
+
force: {
|
|
462
|
+
type: "boolean",
|
|
463
|
+
description: "Force recreation even if local overlay exists",
|
|
464
|
+
default: false,
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
name: "profile_resolve",
|
|
471
|
+
description:
|
|
472
|
+
"Resolve profile directory using precedence chain (--profile-dir → LEX_PR_PROFILE_DIR → .smartergpt.local/ → .smartergpt/)",
|
|
473
|
+
inputSchema: {
|
|
474
|
+
type: "object",
|
|
475
|
+
properties: {
|
|
476
|
+
profileDir: {
|
|
477
|
+
type: "string",
|
|
478
|
+
description: "Optional profile directory override",
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: "health",
|
|
485
|
+
description: "Get health status of the system with optional metrics",
|
|
486
|
+
inputSchema: {
|
|
487
|
+
type: "object",
|
|
488
|
+
properties: {
|
|
489
|
+
includeMetrics: {
|
|
490
|
+
type: "boolean",
|
|
491
|
+
description: "Include detailed metrics in response",
|
|
492
|
+
default: false,
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
// ─────────────────────────────────────────────────────────────────
|
|
498
|
+
// Senior Dev Executor Tools
|
|
499
|
+
// ─────────────────────────────────────────────────────────────────
|
|
500
|
+
{
|
|
501
|
+
name: "executor_prepare_context",
|
|
502
|
+
description:
|
|
503
|
+
"Phase 1: Gather deterministic artifacts for code review (lint, typecheck, tests, diff, PR metadata)",
|
|
504
|
+
inputSchema: {
|
|
505
|
+
type: "object",
|
|
506
|
+
properties: {
|
|
507
|
+
pr_number: {
|
|
508
|
+
type: "string",
|
|
509
|
+
description: "PR number to prepare context for",
|
|
510
|
+
},
|
|
511
|
+
base_branch: {
|
|
512
|
+
type: "string",
|
|
513
|
+
description: "Base branch for diff (default: main)",
|
|
514
|
+
default: "main",
|
|
515
|
+
},
|
|
516
|
+
output_dir: {
|
|
517
|
+
type: "string",
|
|
518
|
+
description: "Output directory for artifacts (default: /tmp/senior-dev-review-...)",
|
|
519
|
+
},
|
|
520
|
+
skip_tests: {
|
|
521
|
+
type: "boolean",
|
|
522
|
+
description: "Skip running tests",
|
|
523
|
+
default: false,
|
|
524
|
+
},
|
|
525
|
+
skip_lint: {
|
|
526
|
+
type: "boolean",
|
|
527
|
+
description: "Skip running lint",
|
|
528
|
+
default: false,
|
|
529
|
+
},
|
|
530
|
+
skip_typecheck: {
|
|
531
|
+
type: "boolean",
|
|
532
|
+
description: "Skip running typecheck",
|
|
533
|
+
default: false,
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
required: ["pr_number"],
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
name: "executor_recall_context",
|
|
541
|
+
description:
|
|
542
|
+
"Phase 1: Recall relevant Frames from Lex memory (module reviews, developer history, patterns). " +
|
|
543
|
+
"This tool delegates to the Lex CLI (`lex recall`) to query the Lex memory system. " +
|
|
544
|
+
"For direct access to Lex memory, use the Lex MCP server's `mcp_lex_frame_recall` tool instead. " +
|
|
545
|
+
"This executor-specific tool provides Senior Dev workflow integration.",
|
|
546
|
+
inputSchema: {
|
|
547
|
+
type: "object",
|
|
548
|
+
properties: {
|
|
549
|
+
query_type: {
|
|
550
|
+
type: "string",
|
|
551
|
+
enum: ["module", "developer", "pattern", "pr"],
|
|
552
|
+
description: "Type of query: module, developer, pattern, or pr",
|
|
553
|
+
},
|
|
554
|
+
query: {
|
|
555
|
+
type: "string",
|
|
556
|
+
description:
|
|
557
|
+
"Query value (required for module, developer, pr; optional for pattern)",
|
|
558
|
+
},
|
|
559
|
+
limit: {
|
|
560
|
+
type: "number",
|
|
561
|
+
description: "Maximum frames to return (default: 10)",
|
|
562
|
+
default: 10,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
required: ["query_type"],
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
name: "executor_capture_frame",
|
|
570
|
+
description: "Phase 4: Capture review session as a Frame in Lex memory (the receipt)",
|
|
571
|
+
inputSchema: {
|
|
572
|
+
type: "object",
|
|
573
|
+
properties: {
|
|
574
|
+
pr_number: {
|
|
575
|
+
type: "string",
|
|
576
|
+
description: "PR number being reviewed",
|
|
577
|
+
},
|
|
578
|
+
module: {
|
|
579
|
+
type: "string",
|
|
580
|
+
description: "Primary module (must match lexmap.policy.json)",
|
|
581
|
+
},
|
|
582
|
+
summary: {
|
|
583
|
+
type: "string",
|
|
584
|
+
description: "One-line summary of review findings",
|
|
585
|
+
},
|
|
586
|
+
next_action: {
|
|
587
|
+
type: "string",
|
|
588
|
+
description: "Follow-up action required",
|
|
589
|
+
},
|
|
590
|
+
developer: {
|
|
591
|
+
type: "string",
|
|
592
|
+
description: "Developer name for tracking (default: unknown)",
|
|
593
|
+
default: "unknown",
|
|
594
|
+
},
|
|
595
|
+
severity: {
|
|
596
|
+
type: "string",
|
|
597
|
+
enum: ["blocker", "must-fix", "should-fix", "nit", "praise", "review"],
|
|
598
|
+
description: "Highest severity level (default: review)",
|
|
599
|
+
default: "review",
|
|
600
|
+
},
|
|
601
|
+
jira: {
|
|
602
|
+
type: "string",
|
|
603
|
+
description: "Jira ticket ID if applicable",
|
|
604
|
+
},
|
|
605
|
+
blockers: {
|
|
606
|
+
type: "array",
|
|
607
|
+
items: { type: "string" },
|
|
608
|
+
description: "List of blockers",
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
required: ["pr_number", "module", "summary", "next_action"],
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: "executor_modes",
|
|
616
|
+
description:
|
|
617
|
+
"List available executor modes (triage, deep_review, pattern_mining, mentorship)",
|
|
618
|
+
inputSchema: {
|
|
619
|
+
type: "object",
|
|
620
|
+
properties: {},
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
// ─────────────────────────────────────────────────────────────────
|
|
624
|
+
// LexRunner Run Management Tools
|
|
625
|
+
// ─────────────────────────────────────────────────────────────────
|
|
626
|
+
{
|
|
627
|
+
name: "start_run",
|
|
628
|
+
description: "Start a new LexRunner procedure run and return a runId",
|
|
629
|
+
inputSchema: {
|
|
630
|
+
type: "object",
|
|
631
|
+
properties: {
|
|
632
|
+
mode: {
|
|
633
|
+
type: "string",
|
|
634
|
+
description: "Persona mode (e.g., 'senior-dev', 'eager-pm')",
|
|
635
|
+
},
|
|
636
|
+
procedure: {
|
|
637
|
+
type: "string",
|
|
638
|
+
description: "Procedure identifier (e.g., 'merge-weave-main', 'pr-review')",
|
|
639
|
+
},
|
|
640
|
+
repo: {
|
|
641
|
+
type: "string",
|
|
642
|
+
description: "Repository in 'owner/repo' format",
|
|
643
|
+
},
|
|
644
|
+
task: {
|
|
645
|
+
type: "string",
|
|
646
|
+
description: "Human-readable task description",
|
|
647
|
+
},
|
|
648
|
+
params: {
|
|
649
|
+
type: "object",
|
|
650
|
+
description: "Procedure-specific parameters",
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
required: ["mode", "procedure", "repo"],
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
name: "get_status",
|
|
658
|
+
description: "Get current run state, summary, and next available actions",
|
|
659
|
+
inputSchema: {
|
|
660
|
+
type: "object",
|
|
661
|
+
properties: {
|
|
662
|
+
runId: {
|
|
663
|
+
type: "string",
|
|
664
|
+
description: "Unique run identifier",
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
required: ["runId"],
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
name: "list_artifacts",
|
|
672
|
+
description: "List runs from the store with optional filtering",
|
|
673
|
+
inputSchema: {
|
|
674
|
+
type: "object",
|
|
675
|
+
properties: {
|
|
676
|
+
limit: {
|
|
677
|
+
type: "number",
|
|
678
|
+
description: "Maximum number of runs to return",
|
|
679
|
+
},
|
|
680
|
+
offset: {
|
|
681
|
+
type: "number",
|
|
682
|
+
description: "Number of runs to skip (for pagination)",
|
|
683
|
+
},
|
|
684
|
+
state: {
|
|
685
|
+
type: "string",
|
|
686
|
+
enum: ["pending", "running", "completed", "failed", "aborted"],
|
|
687
|
+
description: "Filter by run state",
|
|
688
|
+
},
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
name: "run_decision",
|
|
694
|
+
description: "Submit an LLM decision for a pending action in a run",
|
|
695
|
+
inputSchema: {
|
|
696
|
+
type: "object",
|
|
697
|
+
properties: {
|
|
698
|
+
runId: {
|
|
699
|
+
type: "string",
|
|
700
|
+
description: "Unique run identifier",
|
|
701
|
+
},
|
|
702
|
+
action: {
|
|
703
|
+
type: "string",
|
|
704
|
+
description: "Action to submit (must match a nextOptions[x].action)",
|
|
705
|
+
},
|
|
706
|
+
response: {
|
|
707
|
+
description: "Response data (validated against nextOptions[x].responseSchema)",
|
|
708
|
+
},
|
|
709
|
+
rationale: {
|
|
710
|
+
type: "string",
|
|
711
|
+
description: "Optional rationale for audit trail",
|
|
712
|
+
},
|
|
713
|
+
},
|
|
714
|
+
required: ["runId", "action", "response"],
|
|
715
|
+
},
|
|
716
|
+
},
|
|
717
|
+
// ─────────────────────────────────────────────────────────────────
|
|
718
|
+
// MCP/CLI Parity Tools (AX-004)
|
|
719
|
+
// ─────────────────────────────────────────────────────────────────
|
|
720
|
+
{
|
|
721
|
+
name: "discover",
|
|
722
|
+
description:
|
|
723
|
+
"Discover open pull requests from GitHub with optional dependency suggestions. Requires GITHUB_TOKEN environment variable.",
|
|
724
|
+
inputSchema: {
|
|
725
|
+
type: "object",
|
|
726
|
+
properties: {
|
|
727
|
+
owner: {
|
|
728
|
+
type: "string",
|
|
729
|
+
description: "GitHub repository owner",
|
|
730
|
+
},
|
|
731
|
+
repo: {
|
|
732
|
+
type: "string",
|
|
733
|
+
description: "GitHub repository name",
|
|
734
|
+
},
|
|
735
|
+
state: {
|
|
736
|
+
type: "string",
|
|
737
|
+
enum: ["open", "closed", "all"],
|
|
738
|
+
description: "PR state filter (default: open)",
|
|
739
|
+
default: "open",
|
|
740
|
+
},
|
|
741
|
+
suggest: {
|
|
742
|
+
type: "boolean",
|
|
743
|
+
description: "Generate dependency suggestions using heuristics",
|
|
744
|
+
default: false,
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
name: "weave_status",
|
|
751
|
+
description: "Show current execution status and merge eligibility for a plan",
|
|
752
|
+
inputSchema: {
|
|
753
|
+
type: "object",
|
|
754
|
+
properties: {
|
|
755
|
+
planFile: {
|
|
756
|
+
type: "string",
|
|
757
|
+
description: "Path to plan.json file (default: plan.json)",
|
|
758
|
+
default: "plan.json",
|
|
759
|
+
},
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
name: "doctor",
|
|
765
|
+
description:
|
|
766
|
+
"Run environment and configuration sanity checks with optional hostility scoring",
|
|
767
|
+
inputSchema: {
|
|
768
|
+
type: "object",
|
|
769
|
+
properties: {
|
|
770
|
+
environmentQuality: {
|
|
771
|
+
type: "boolean",
|
|
772
|
+
description: "Include environmental hostility scoring in the check",
|
|
773
|
+
default: false,
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: "merge_order",
|
|
780
|
+
description: "Compute dependency levels and merge order using Kahn's algorithm",
|
|
781
|
+
inputSchema: {
|
|
782
|
+
type: "object",
|
|
783
|
+
properties: {
|
|
784
|
+
planFile: {
|
|
785
|
+
type: "string",
|
|
786
|
+
description: "Path to plan.json file (default: plan.json)",
|
|
787
|
+
default: "plan.json",
|
|
788
|
+
},
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
name: "config_show",
|
|
794
|
+
description: "Display configuration with precedence chain and provenance",
|
|
795
|
+
inputSchema: {
|
|
796
|
+
type: "object",
|
|
797
|
+
properties: {
|
|
798
|
+
key: {
|
|
799
|
+
type: "string",
|
|
800
|
+
description: "Show specific configuration key",
|
|
801
|
+
},
|
|
802
|
+
},
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
// ─────────────────────────────────────────────────────────────────
|
|
806
|
+
// Workflow Guidance Tools (LPR-037)
|
|
807
|
+
// ─────────────────────────────────────────────────────────────────
|
|
808
|
+
{
|
|
809
|
+
name: "workflow_guide",
|
|
810
|
+
description:
|
|
811
|
+
"Get context-aware workflow guidance for the current phase. " +
|
|
812
|
+
"Provides next steps, common issues, and recommendations.",
|
|
813
|
+
inputSchema: {
|
|
814
|
+
type: "object",
|
|
815
|
+
properties: {
|
|
816
|
+
phase: {
|
|
817
|
+
type: "string",
|
|
818
|
+
enum: [
|
|
819
|
+
"initial",
|
|
820
|
+
"post-plan-creation",
|
|
821
|
+
"post-gates-run",
|
|
822
|
+
"pre-merge",
|
|
823
|
+
"post-merge",
|
|
824
|
+
"error-recovery",
|
|
825
|
+
],
|
|
826
|
+
description: "Current workflow phase to get guidance for",
|
|
827
|
+
},
|
|
828
|
+
},
|
|
829
|
+
required: ["phase"],
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
// ─────────────────────────────────────────────────────────────────
|
|
833
|
+
// Governance Metrics Tools (Wave 3)
|
|
834
|
+
// ─────────────────────────────────────────────────────────────────
|
|
835
|
+
{
|
|
836
|
+
name: "metrics",
|
|
837
|
+
description: "Get current governance metrics snapshot for observability dashboards",
|
|
838
|
+
inputSchema: {
|
|
839
|
+
type: "object",
|
|
840
|
+
properties: {
|
|
841
|
+
filter: {
|
|
842
|
+
type: "string",
|
|
843
|
+
description: "Filter metrics by name pattern (e.g., 'turn_cost', 'tier')",
|
|
844
|
+
},
|
|
845
|
+
format: {
|
|
846
|
+
type: "string",
|
|
847
|
+
enum: ["json", "prometheus"],
|
|
848
|
+
description: "Output format (default: json)",
|
|
849
|
+
default: "json",
|
|
850
|
+
},
|
|
851
|
+
},
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
// ─────────────────────────────────────────────────────────────────
|
|
855
|
+
// Task Handoff Tools (ADR-007)
|
|
856
|
+
// ─────────────────────────────────────────────────────────────────
|
|
857
|
+
{
|
|
858
|
+
name: "create_task_snapshot",
|
|
859
|
+
description:
|
|
860
|
+
"Create a task snapshot for agent handoff (ADR-007). Prepares work for external agent with failure info, target files, and verification command.",
|
|
861
|
+
inputSchema: {
|
|
862
|
+
type: "object",
|
|
863
|
+
properties: {
|
|
864
|
+
taskId: {
|
|
865
|
+
type: "string",
|
|
866
|
+
description: "Optional task ID (auto-generated if not provided)",
|
|
867
|
+
},
|
|
868
|
+
procedure: {
|
|
869
|
+
type: "string",
|
|
870
|
+
description: "Procedure identifier (e.g., 'post-merge-fix', 'fanout-issue')",
|
|
871
|
+
},
|
|
872
|
+
determinism: {
|
|
873
|
+
type: "string",
|
|
874
|
+
enum: ["D1", "D2", "D3"],
|
|
875
|
+
description: "Determinism level (default: D1)",
|
|
876
|
+
default: "D1",
|
|
877
|
+
},
|
|
878
|
+
failureMessage: {
|
|
879
|
+
type: "string",
|
|
880
|
+
description: "Short error description",
|
|
881
|
+
},
|
|
882
|
+
failureFileRel: {
|
|
883
|
+
type: "string",
|
|
884
|
+
description: "Repo-relative path to failed file",
|
|
885
|
+
},
|
|
886
|
+
failureLine: {
|
|
887
|
+
type: "number",
|
|
888
|
+
description: "Line number if available",
|
|
889
|
+
},
|
|
890
|
+
runnerOutputSnip: {
|
|
891
|
+
type: "string",
|
|
892
|
+
description: "Actual test runner output snippet",
|
|
893
|
+
},
|
|
894
|
+
failureExcerpt: {
|
|
895
|
+
type: "string",
|
|
896
|
+
description: "Code context around failure",
|
|
897
|
+
},
|
|
898
|
+
targetFiles: {
|
|
899
|
+
type: "array",
|
|
900
|
+
items: { type: "string" },
|
|
901
|
+
description: "Repo-relative paths of files to modify",
|
|
902
|
+
},
|
|
903
|
+
verificationCmd: {
|
|
904
|
+
type: "string",
|
|
905
|
+
description: "Command to run for verification",
|
|
906
|
+
},
|
|
907
|
+
expectedExitCode: {
|
|
908
|
+
type: "number",
|
|
909
|
+
description: "Expected exit code (default: 0)",
|
|
910
|
+
default: 0,
|
|
911
|
+
},
|
|
912
|
+
repoRoot: {
|
|
913
|
+
type: "string",
|
|
914
|
+
description: "Absolute path to repo root (auto-detected if not provided)",
|
|
915
|
+
},
|
|
916
|
+
repoId: {
|
|
917
|
+
type: "string",
|
|
918
|
+
description:
|
|
919
|
+
"Repository identifier in owner/repo format (auto-detected if not provided)",
|
|
920
|
+
},
|
|
921
|
+
commitSha: {
|
|
922
|
+
type: "string",
|
|
923
|
+
description: "Git commit SHA (auto-detected if not provided)",
|
|
924
|
+
},
|
|
925
|
+
},
|
|
926
|
+
required: [
|
|
927
|
+
"procedure",
|
|
928
|
+
"failureMessage",
|
|
929
|
+
"failureFileRel",
|
|
930
|
+
"runnerOutputSnip",
|
|
931
|
+
"targetFiles",
|
|
932
|
+
"verificationCmd",
|
|
933
|
+
],
|
|
934
|
+
},
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
name: "submit_task_receipt",
|
|
938
|
+
description:
|
|
939
|
+
"Submit a task receipt after agent completes work (ADR-007). Returns acknowledgment and engine verification status.",
|
|
940
|
+
inputSchema: {
|
|
941
|
+
type: "object",
|
|
942
|
+
properties: {
|
|
943
|
+
receipt: {
|
|
944
|
+
type: "object",
|
|
945
|
+
description: "TaskReceipt_v1 JSON object",
|
|
946
|
+
},
|
|
947
|
+
},
|
|
948
|
+
required: ["receipt"],
|
|
949
|
+
},
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
name: "get_task_status",
|
|
953
|
+
description:
|
|
954
|
+
"Get current task state (ADR-007). Returns snapshot, receipt, and verification info.",
|
|
955
|
+
inputSchema: {
|
|
956
|
+
type: "object",
|
|
957
|
+
properties: {
|
|
958
|
+
taskId: {
|
|
959
|
+
type: "string",
|
|
960
|
+
description: "Unique task identifier",
|
|
961
|
+
},
|
|
962
|
+
},
|
|
963
|
+
required: ["taskId"],
|
|
964
|
+
},
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
name: "list_pending_tasks",
|
|
968
|
+
description: "List pending task snapshots (ADR-007). Used by PM agent to see work queue.",
|
|
969
|
+
inputSchema: {
|
|
970
|
+
type: "object",
|
|
971
|
+
properties: {
|
|
972
|
+
procedure: {
|
|
973
|
+
type: "string",
|
|
974
|
+
description: "Filter by procedure identifier",
|
|
975
|
+
},
|
|
976
|
+
determinism: {
|
|
977
|
+
type: "string",
|
|
978
|
+
enum: ["D1", "D2", "D3"],
|
|
979
|
+
description: "Filter by determinism level",
|
|
980
|
+
},
|
|
981
|
+
limit: {
|
|
982
|
+
type: "number",
|
|
983
|
+
description: "Maximum tasks to return",
|
|
984
|
+
},
|
|
985
|
+
},
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
// ─────────────────────────────────────────────────────────────────
|
|
989
|
+
// Fanout AX Tools — D0/D1 Pipeline (Epic #654 Layer 2)
|
|
990
|
+
// ─────────────────────────────────────────────────────────────────
|
|
991
|
+
{
|
|
992
|
+
name: "fanout_harvest",
|
|
993
|
+
description:
|
|
994
|
+
"D0: Harvest external state from GitHub into a deterministic, replayable HarvestBundle. " +
|
|
995
|
+
"Fetches PRs, issues, CI status, review status, and pins all SHAs at fetch time. " +
|
|
996
|
+
"Requires GITHUB_TOKEN environment variable.",
|
|
997
|
+
inputSchema: {
|
|
998
|
+
type: "object",
|
|
999
|
+
properties: {
|
|
1000
|
+
owner: {
|
|
1001
|
+
type: "string",
|
|
1002
|
+
description:
|
|
1003
|
+
"GitHub repository owner (auto-detected from git remote if not provided)",
|
|
1004
|
+
},
|
|
1005
|
+
repo: {
|
|
1006
|
+
type: "string",
|
|
1007
|
+
description:
|
|
1008
|
+
"GitHub repository name (auto-detected from git remote if not provided)",
|
|
1009
|
+
},
|
|
1010
|
+
state: {
|
|
1011
|
+
type: "string",
|
|
1012
|
+
enum: ["open", "closed", "all"],
|
|
1013
|
+
description: "PR state filter (default: open)",
|
|
1014
|
+
default: "open",
|
|
1015
|
+
},
|
|
1016
|
+
includeIssues: {
|
|
1017
|
+
type: "boolean",
|
|
1018
|
+
description: "Include issues in harvest (default: false)",
|
|
1019
|
+
default: false,
|
|
1020
|
+
},
|
|
1021
|
+
maxBody: {
|
|
1022
|
+
type: "number",
|
|
1023
|
+
description: "Max body length before truncation (default: 4096)",
|
|
1024
|
+
default: 4096,
|
|
1025
|
+
},
|
|
1026
|
+
githubToken: {
|
|
1027
|
+
type: "string",
|
|
1028
|
+
description: "GitHub API token (or use GITHUB_TOKEN env var)",
|
|
1029
|
+
},
|
|
1030
|
+
},
|
|
1031
|
+
},
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
name: "fanout_analyze",
|
|
1035
|
+
description:
|
|
1036
|
+
"D1: Analyze a HarvestBundle into a deterministic AnalysisPool with evidence IDs. " +
|
|
1037
|
+
"Pure computation with no side effects. Same input → identical output. " +
|
|
1038
|
+
"Extracts entities, relations, conflicts, and blockers.",
|
|
1039
|
+
inputSchema: {
|
|
1040
|
+
type: "object",
|
|
1041
|
+
properties: {
|
|
1042
|
+
harvestBundle: {
|
|
1043
|
+
type: "object",
|
|
1044
|
+
description: "HarvestBundle JSON object from fanout_harvest (preferred)",
|
|
1045
|
+
},
|
|
1046
|
+
fromFile: {
|
|
1047
|
+
type: "string",
|
|
1048
|
+
description:
|
|
1049
|
+
"Path to harvest bundle JSON file (alternative to harvestBundle object)",
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
],
|
|
1055
|
+
};
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
// Handle tool calls
|
|
1059
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1060
|
+
const { name, arguments: args } = request.params;
|
|
1061
|
+
|
|
1062
|
+
switch (name) {
|
|
1063
|
+
// Plan tools
|
|
1064
|
+
case "plan_create":
|
|
1065
|
+
return await handlePlanCreate(args as PlanCreateArgs);
|
|
1066
|
+
|
|
1067
|
+
case "pr_list":
|
|
1068
|
+
return await handlePrList(args as PrListArgs);
|
|
1069
|
+
|
|
1070
|
+
case "plan_validate":
|
|
1071
|
+
return await handlePlanValidate(args as PlanValidateArgs);
|
|
1072
|
+
|
|
1073
|
+
case "plan_analyze":
|
|
1074
|
+
return await handlePlanAnalyze(args as PlanAnalyzeArgs);
|
|
1075
|
+
|
|
1076
|
+
// Gate tools
|
|
1077
|
+
case "gates_run":
|
|
1078
|
+
return await handleGatesRun(args as GatesRunArgs);
|
|
1079
|
+
|
|
1080
|
+
// Weave tools
|
|
1081
|
+
case "merge_apply":
|
|
1082
|
+
return await handleMergeApply(args as MergeApplyArgs);
|
|
1083
|
+
|
|
1084
|
+
case "discover":
|
|
1085
|
+
return await handleDiscover(
|
|
1086
|
+
args as {
|
|
1087
|
+
owner?: string;
|
|
1088
|
+
repo?: string;
|
|
1089
|
+
state?: string;
|
|
1090
|
+
suggest?: boolean;
|
|
1091
|
+
}
|
|
1092
|
+
);
|
|
1093
|
+
|
|
1094
|
+
case "weave_status":
|
|
1095
|
+
return await handleStatus(args as { planFile?: string });
|
|
1096
|
+
|
|
1097
|
+
case "merge_order":
|
|
1098
|
+
return await handleMergeOrder(args as { planFile?: string });
|
|
1099
|
+
|
|
1100
|
+
// Workspace tools
|
|
1101
|
+
case "local_init":
|
|
1102
|
+
return await handleLocalInit(args as InitLocalArgs);
|
|
1103
|
+
|
|
1104
|
+
case "profile_resolve":
|
|
1105
|
+
return await handleProfileResolve(args as ProfileResolveArgs);
|
|
1106
|
+
|
|
1107
|
+
case "doctor":
|
|
1108
|
+
return await handleDoctor(args as { environmentQuality?: boolean });
|
|
1109
|
+
|
|
1110
|
+
// Core tools
|
|
1111
|
+
case "health":
|
|
1112
|
+
return await handleHealth(args as { includeMetrics?: boolean });
|
|
1113
|
+
|
|
1114
|
+
case "config_show":
|
|
1115
|
+
return await handleConfigShow(args as { key?: string });
|
|
1116
|
+
|
|
1117
|
+
case "workflow_guide":
|
|
1118
|
+
return await handleWorkflowGuide(args as WorkflowGuideArgs);
|
|
1119
|
+
|
|
1120
|
+
case "metrics":
|
|
1121
|
+
return await handleMetrics(args as { filter?: string; format?: string });
|
|
1122
|
+
|
|
1123
|
+
// Executor tools (Senior Dev)
|
|
1124
|
+
case "executor_prepare_context":
|
|
1125
|
+
return await handleSeniorDevPrepareContext(args as unknown as PrepareContextInput);
|
|
1126
|
+
|
|
1127
|
+
case "executor_recall_context":
|
|
1128
|
+
return await handleSeniorDevRecallContext(args as unknown as RecallContextInput);
|
|
1129
|
+
|
|
1130
|
+
case "executor_capture_frame":
|
|
1131
|
+
return await handleSeniorDevCaptureFrame(args as unknown as CaptureFrameInput);
|
|
1132
|
+
|
|
1133
|
+
case "executor_modes":
|
|
1134
|
+
return await handleSeniorDevModes();
|
|
1135
|
+
|
|
1136
|
+
// Run management tools
|
|
1137
|
+
case "start_run":
|
|
1138
|
+
return await handleStartRun(args as unknown as StartRunInput, runStore);
|
|
1139
|
+
|
|
1140
|
+
case "get_status":
|
|
1141
|
+
return await handleGetStatus(args as unknown as GetStatusInput, runStore);
|
|
1142
|
+
|
|
1143
|
+
case "list_artifacts":
|
|
1144
|
+
return await handleListRuns(args as unknown as ListRunsInput, runStore);
|
|
1145
|
+
|
|
1146
|
+
case "run_decision":
|
|
1147
|
+
return await handleSubmitDecision(args as unknown as SubmitDecisionInput);
|
|
1148
|
+
|
|
1149
|
+
// Task Handoff tools (ADR-007)
|
|
1150
|
+
case "create_task_snapshot":
|
|
1151
|
+
return await handleCreateTaskSnapshot(args as unknown as CreateTaskSnapshotArgs);
|
|
1152
|
+
|
|
1153
|
+
case "submit_task_receipt":
|
|
1154
|
+
return await handleSubmitTaskReceipt(args as unknown as SubmitTaskReceiptArgs);
|
|
1155
|
+
|
|
1156
|
+
case "get_task_status":
|
|
1157
|
+
return await handleGetTaskStatus(args as unknown as GetTaskStatusArgs);
|
|
1158
|
+
|
|
1159
|
+
case "list_pending_tasks":
|
|
1160
|
+
return await handleListPendingTasks(args as unknown as ListPendingTasksArgs);
|
|
1161
|
+
|
|
1162
|
+
// Fanout AX tools (Epic #654 Layer 2)
|
|
1163
|
+
case "fanout_harvest":
|
|
1164
|
+
return await handleFanoutHarvest(args as unknown as FanoutHarvestArgs);
|
|
1165
|
+
|
|
1166
|
+
case "fanout_analyze":
|
|
1167
|
+
return await handleFanoutAnalyze(args as unknown as FanoutAnalyzeArgs);
|
|
1168
|
+
|
|
1169
|
+
default:
|
|
1170
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
return server;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* Check if GitHub token is available and throw helpful error if not
|
|
1179
|
+
*/
|
|
1180
|
+
function ensureGitHubToken(providedToken?: string): void {
|
|
1181
|
+
const token = providedToken || process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
1182
|
+
|
|
1183
|
+
if (!token) {
|
|
1184
|
+
const axError = githubApiError({
|
|
1185
|
+
status: 401,
|
|
1186
|
+
message:
|
|
1187
|
+
"GitHub authentication required. Set GITHUB_TOKEN environment variable.\n" +
|
|
1188
|
+
"\n" +
|
|
1189
|
+
"To fix:\n" +
|
|
1190
|
+
" export GITHUB_TOKEN=ghp_...\n" +
|
|
1191
|
+
"\n" +
|
|
1192
|
+
"See: https://github.com/Guffawaffle/lexrunner#authentication",
|
|
1193
|
+
});
|
|
1194
|
+
throwMcpAXError(ErrorCode.InvalidRequest, axError);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Handle plan.create tool
|
|
1200
|
+
*/
|
|
1201
|
+
async function handlePlanCreate(
|
|
1202
|
+
args: PlanCreateArgs
|
|
1203
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1204
|
+
try {
|
|
1205
|
+
const env = getMCPEnvironment();
|
|
1206
|
+
|
|
1207
|
+
// Resolve profile and validate write permissions
|
|
1208
|
+
const resolved = resolveProfile(undefined, process.cwd());
|
|
1209
|
+
const profilePath = resolved.path;
|
|
1210
|
+
const role = resolved.manifest.role;
|
|
1211
|
+
|
|
1212
|
+
let plan;
|
|
1213
|
+
let inputs = null;
|
|
1214
|
+
let autoDetectedGitHubMode = false;
|
|
1215
|
+
|
|
1216
|
+
// Auto-detect GitHub mode from scope.yml if fromGithub not explicitly set
|
|
1217
|
+
if (!args.fromGithub) {
|
|
1218
|
+
const detection = detectGitHubMode(profilePath);
|
|
1219
|
+
if (detection.shouldUseGitHub) {
|
|
1220
|
+
autoDetectedGitHubMode = true;
|
|
1221
|
+
// Merge scope.yml filters with args (args take precedence)
|
|
1222
|
+
args.fromGithub = true;
|
|
1223
|
+
if (!args.query && detection.scopeConfig?.query) {
|
|
1224
|
+
args.query = detection.scopeConfig.query;
|
|
1225
|
+
}
|
|
1226
|
+
if (
|
|
1227
|
+
!args.labels &&
|
|
1228
|
+
detection.scopeConfig?.labels &&
|
|
1229
|
+
detection.scopeConfig.labels.length > 0
|
|
1230
|
+
) {
|
|
1231
|
+
args.labels = detection.scopeConfig.labels;
|
|
1232
|
+
}
|
|
1233
|
+
if (!args.target && detection.scopeConfig?.target) {
|
|
1234
|
+
args.target = detection.scopeConfig.target;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
console.error("[mcp:plan.create] Auto-detected GitHub mode from scope.yml filters");
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
if (args.fromGithub) {
|
|
1242
|
+
// Check for GitHub authentication before making API calls
|
|
1243
|
+
ensureGitHubToken(args.githubToken);
|
|
1244
|
+
|
|
1245
|
+
// Parse required gates if provided
|
|
1246
|
+
const requiredGates = args.requiredGates || ["lint", "typecheck", "test"];
|
|
1247
|
+
|
|
1248
|
+
// Parse max workers if provided
|
|
1249
|
+
const maxWorkers = args.maxWorkers || 2;
|
|
1250
|
+
|
|
1251
|
+
// Check for multi-repo mode (issue #677)
|
|
1252
|
+
if (args.repos && args.repos.length > 0) {
|
|
1253
|
+
// Multi-repo mode: discover PRs from multiple repositories
|
|
1254
|
+
console.error(`[mcp:plan.create] Multi-repo mode: ${args.repos.length} repositories`);
|
|
1255
|
+
|
|
1256
|
+
plan = await generateMultiRepoPlan(args.repos, {
|
|
1257
|
+
query: args.query,
|
|
1258
|
+
labels: args.labels,
|
|
1259
|
+
excludePRs: args.excludePRs,
|
|
1260
|
+
includeDrafts: args.includeDrafts,
|
|
1261
|
+
target: args.target,
|
|
1262
|
+
githubToken: args.githubToken,
|
|
1263
|
+
policy: {
|
|
1264
|
+
requiredGates,
|
|
1265
|
+
maxWorkers,
|
|
1266
|
+
},
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
// Log discovery results to stderr
|
|
1270
|
+
const repoList = args.repos.map((r) => `${r.owner}/${r.repo}`).join(", ");
|
|
1271
|
+
const filterInfo = args.labels ? ` labels=${args.labels.join(",")}` : "";
|
|
1272
|
+
console.error(
|
|
1273
|
+
`[mcp:plan.create] repos=[${repoList}]${filterInfo} discovered=${plan.items.length} PRs`
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
if (plan.items.length === 0) {
|
|
1277
|
+
console.error(
|
|
1278
|
+
`[mcp:plan.create] Warning: No PRs found matching criteria. Check filters and repository state.`
|
|
1279
|
+
);
|
|
1280
|
+
} else {
|
|
1281
|
+
const prNames = plan.items.map((item) => item.name).join(", ");
|
|
1282
|
+
console.error(`[mcp:plan.create] PRs included: ${prNames}`);
|
|
1283
|
+
}
|
|
1284
|
+
} else {
|
|
1285
|
+
// Single-repo mode (backward compatible)
|
|
1286
|
+
const client = await createGitHubClient({
|
|
1287
|
+
token: args.githubToken,
|
|
1288
|
+
owner: args.owner,
|
|
1289
|
+
repo: args.repo,
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
// Generate plan from GitHub
|
|
1293
|
+
plan = await generatePlanFromGitHub(client, {
|
|
1294
|
+
query: args.query,
|
|
1295
|
+
labels: args.labels,
|
|
1296
|
+
excludePRs: args.excludePRs,
|
|
1297
|
+
includeDrafts: args.includeDrafts,
|
|
1298
|
+
target: args.target,
|
|
1299
|
+
policy: {
|
|
1300
|
+
requiredGates,
|
|
1301
|
+
maxWorkers,
|
|
1302
|
+
},
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
// Log discovery results to stderr
|
|
1306
|
+
const repoDiag = `${client.getOwner()}/${client.getRepo()}`;
|
|
1307
|
+
const filterInfo = args.labels ? ` labels=${args.labels.join(",")}` : "";
|
|
1308
|
+
const queryInfo = args.query ? ` query="${args.query}"` : "";
|
|
1309
|
+
console.error(
|
|
1310
|
+
`[mcp:plan.create] repo=${repoDiag}${filterInfo}${queryInfo} discovered=${plan.items.length} PRs`
|
|
1311
|
+
);
|
|
1312
|
+
|
|
1313
|
+
if (plan.items.length === 0) {
|
|
1314
|
+
console.error(
|
|
1315
|
+
`[mcp:plan.create] Warning: No PRs found matching criteria. Check filters and repository state.`
|
|
1316
|
+
);
|
|
1317
|
+
} else {
|
|
1318
|
+
const prNumbers = plan.items.map((item) => item.name).join(", ");
|
|
1319
|
+
console.error(`[mcp:plan.create] PRs included: ${prNumbers}`);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
} else {
|
|
1323
|
+
// Traditional mode: load from configuration files
|
|
1324
|
+
inputs = loadInputs(profilePath);
|
|
1325
|
+
plan = generatePlan(inputs);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Determine output directory
|
|
1329
|
+
const outDir = args.outDir || path.join(profilePath, "runner");
|
|
1330
|
+
|
|
1331
|
+
// Validate write operation is allowed
|
|
1332
|
+
validateWriteOperation(profilePath, role, "write plan artifacts");
|
|
1333
|
+
|
|
1334
|
+
// Ensure output directory exists
|
|
1335
|
+
if (!fs.existsSync(outDir)) {
|
|
1336
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Write plan.json
|
|
1340
|
+
const planPath = path.join(outDir, "plan.json");
|
|
1341
|
+
const planJson = canonicalJSONStringify(plan);
|
|
1342
|
+
fs.writeFileSync(planPath, planJson + "\n");
|
|
1343
|
+
|
|
1344
|
+
// Generate snapshot - use GitHub snapshot for GitHub mode
|
|
1345
|
+
let snapshot: string;
|
|
1346
|
+
if (args.fromGithub) {
|
|
1347
|
+
snapshot = generateGitHubSnapshot(plan);
|
|
1348
|
+
} else {
|
|
1349
|
+
// In traditional mode, inputs is guaranteed to be set
|
|
1350
|
+
if (!inputs) {
|
|
1351
|
+
const axError = mcpToolError(
|
|
1352
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
1353
|
+
"Internal error: inputs not loaded in traditional mode",
|
|
1354
|
+
{ tool: "plan.create", operation: "generate snapshot" }
|
|
1355
|
+
);
|
|
1356
|
+
throwMcpAXError(ErrorCode.InternalError, axError);
|
|
1357
|
+
}
|
|
1358
|
+
snapshot = generateSnapshot(plan, inputs);
|
|
1359
|
+
}
|
|
1360
|
+
const snapshotPath = path.join(outDir, "snapshot.md");
|
|
1361
|
+
fs.writeFileSync(snapshotPath, snapshot);
|
|
1362
|
+
|
|
1363
|
+
const result: PlanCreateResult = {
|
|
1364
|
+
plan: plan,
|
|
1365
|
+
outDir: outDir,
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
return {
|
|
1369
|
+
content: [
|
|
1370
|
+
{
|
|
1371
|
+
type: "text",
|
|
1372
|
+
text: JSON.stringify(result, null, 2),
|
|
1373
|
+
},
|
|
1374
|
+
],
|
|
1375
|
+
};
|
|
1376
|
+
} catch (error) {
|
|
1377
|
+
if (error instanceof WriteProtectionError) {
|
|
1378
|
+
const axError = writeProtectionError(error.message, "plan.create");
|
|
1379
|
+
throwMcpAXError(ErrorCode.InvalidRequest, axError);
|
|
1380
|
+
}
|
|
1381
|
+
throwMcpToolError(ErrorCode.InternalError, "plan.create", error, "create plan");
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Handle pr_list tool
|
|
1387
|
+
* Lists pull requests from GitHub without creating a plan
|
|
1388
|
+
*/
|
|
1389
|
+
async function handlePrList(
|
|
1390
|
+
args: PrListArgs
|
|
1391
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1392
|
+
try {
|
|
1393
|
+
// Check for GitHub authentication early
|
|
1394
|
+
ensureGitHubToken(args.githubToken);
|
|
1395
|
+
|
|
1396
|
+
// Create GitHub client
|
|
1397
|
+
const client = await createGitHubClient({
|
|
1398
|
+
token: args.githubToken,
|
|
1399
|
+
owner: args.owner,
|
|
1400
|
+
repo: args.repo,
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
// Validate repository access
|
|
1404
|
+
const repoInfo = await client.validateRepository();
|
|
1405
|
+
|
|
1406
|
+
// Get state parameter (default to "open")
|
|
1407
|
+
const state = args.state || "open";
|
|
1408
|
+
|
|
1409
|
+
// Discover PRs based on query/filters
|
|
1410
|
+
const prs = await client.listOpenPRs({
|
|
1411
|
+
state,
|
|
1412
|
+
labels: args.labels,
|
|
1413
|
+
...(args.query ? { query: args.query } : {}),
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1416
|
+
// Default behavior: include drafts unless explicitly disabled
|
|
1417
|
+
const includeDrafts = args.includeDrafts === undefined ? true : Boolean(args.includeDrafts);
|
|
1418
|
+
const filteredPRs = includeDrafts ? prs : prs.filter((pr) => !pr.draft);
|
|
1419
|
+
|
|
1420
|
+
// Exclude specific PRs if requested
|
|
1421
|
+
const excludePRs = args.excludePRs || [];
|
|
1422
|
+
const finalPRs =
|
|
1423
|
+
excludePRs.length > 0
|
|
1424
|
+
? filteredPRs.filter((pr) => !excludePRs.includes(pr.number))
|
|
1425
|
+
: filteredPRs;
|
|
1426
|
+
|
|
1427
|
+
// Transform to result format
|
|
1428
|
+
const result: PrListResult = {
|
|
1429
|
+
pullRequests: finalPRs.map((pr) => ({
|
|
1430
|
+
number: pr.number,
|
|
1431
|
+
title: pr.title,
|
|
1432
|
+
branch: pr.head.ref,
|
|
1433
|
+
author: pr.user.login,
|
|
1434
|
+
labels: pr.labels.map((l) => l.name),
|
|
1435
|
+
sha: pr.head.sha,
|
|
1436
|
+
draft: pr.draft,
|
|
1437
|
+
})),
|
|
1438
|
+
total: prs.length,
|
|
1439
|
+
filtered: finalPRs.length,
|
|
1440
|
+
owner: client.getOwner(),
|
|
1441
|
+
repo: client.getRepo(),
|
|
1442
|
+
};
|
|
1443
|
+
|
|
1444
|
+
// Log discovery results to stderr
|
|
1445
|
+
const repoDiag = `${client.getOwner()}/${client.getRepo()}`;
|
|
1446
|
+
const filterInfo = args.labels ? ` labels=${args.labels.join(",")}` : "";
|
|
1447
|
+
const queryInfo = args.query ? ` query="${args.query}"` : "";
|
|
1448
|
+
console.error(
|
|
1449
|
+
`[mcp:pr_list] repo=${repoDiag}${filterInfo}${queryInfo} found=${result.filtered}/${result.total} PRs`
|
|
1450
|
+
);
|
|
1451
|
+
|
|
1452
|
+
return {
|
|
1453
|
+
content: [
|
|
1454
|
+
{
|
|
1455
|
+
type: "text",
|
|
1456
|
+
text: JSON.stringify(result, null, 2),
|
|
1457
|
+
},
|
|
1458
|
+
],
|
|
1459
|
+
};
|
|
1460
|
+
} catch (error) {
|
|
1461
|
+
if (error instanceof GitHubAPIError) {
|
|
1462
|
+
const axError = githubApiError({
|
|
1463
|
+
message: error.message,
|
|
1464
|
+
});
|
|
1465
|
+
throwMcpAXError(ErrorCode.InternalError, axError);
|
|
1466
|
+
}
|
|
1467
|
+
throwMcpToolError(ErrorCode.InternalError, "pr_list", error, "list pull requests");
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* Handle plan_validate tool
|
|
1473
|
+
* Validates a plan.json file for schema compliance and logical consistency
|
|
1474
|
+
*/
|
|
1475
|
+
async function handlePlanValidate(
|
|
1476
|
+
args: PlanValidateArgs
|
|
1477
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1478
|
+
try {
|
|
1479
|
+
let planContent: string;
|
|
1480
|
+
let planPath: string | undefined;
|
|
1481
|
+
|
|
1482
|
+
// Get plan content either from file or direct content
|
|
1483
|
+
if (args.planContent) {
|
|
1484
|
+
planContent = args.planContent;
|
|
1485
|
+
} else {
|
|
1486
|
+
// Resolve plan file path
|
|
1487
|
+
if (args.planFile) {
|
|
1488
|
+
planPath = args.planFile;
|
|
1489
|
+
} else {
|
|
1490
|
+
const resolved = resolveProfile(undefined, process.cwd());
|
|
1491
|
+
planPath = path.join(resolved.path, "runner", "plan.json");
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// Check if plan file exists
|
|
1495
|
+
if (!fs.existsSync(planPath)) {
|
|
1496
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planPath));
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
planContent = fs.readFileSync(planPath, "utf-8");
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// Try to validate the plan
|
|
1503
|
+
const result: PlanValidateResult = {
|
|
1504
|
+
valid: true,
|
|
1505
|
+
warnings: [],
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
try {
|
|
1509
|
+
const plan = loadPlan(planContent);
|
|
1510
|
+
|
|
1511
|
+
// Basic validation passed
|
|
1512
|
+
result.plan = {
|
|
1513
|
+
schemaVersion: plan.schemaVersion,
|
|
1514
|
+
target: plan.target,
|
|
1515
|
+
itemCount: plan.items.length,
|
|
1516
|
+
};
|
|
1517
|
+
|
|
1518
|
+
// Additional logical validations
|
|
1519
|
+
if (plan.items.length === 0) {
|
|
1520
|
+
result.warnings?.push("Plan contains no items");
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// Check for duplicate item names
|
|
1524
|
+
const names = new Set<string>();
|
|
1525
|
+
const duplicates: string[] = [];
|
|
1526
|
+
for (const item of plan.items) {
|
|
1527
|
+
if (names.has(item.name)) {
|
|
1528
|
+
duplicates.push(item.name);
|
|
1529
|
+
}
|
|
1530
|
+
names.add(item.name);
|
|
1531
|
+
}
|
|
1532
|
+
if (duplicates.length > 0) {
|
|
1533
|
+
result.valid = false;
|
|
1534
|
+
result.errors = result.errors || [];
|
|
1535
|
+
result.errors.push({
|
|
1536
|
+
path: "items",
|
|
1537
|
+
message: `Duplicate item names found: ${duplicates.join(", ")}`,
|
|
1538
|
+
code: "DUPLICATE_NAMES",
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
console.error(
|
|
1543
|
+
`[mcp:plan_validate] validated plan with ${plan.items.length} items, valid=${result.valid}`
|
|
1544
|
+
);
|
|
1545
|
+
} catch (error) {
|
|
1546
|
+
result.valid = false;
|
|
1547
|
+
result.errors = [];
|
|
1548
|
+
|
|
1549
|
+
if (error instanceof AXErrorException) {
|
|
1550
|
+
result.errors.push({
|
|
1551
|
+
path: "root",
|
|
1552
|
+
message: error.message,
|
|
1553
|
+
code: error.axError.code,
|
|
1554
|
+
});
|
|
1555
|
+
} else if (error instanceof Error) {
|
|
1556
|
+
result.errors.push({
|
|
1557
|
+
path: "root",
|
|
1558
|
+
message: error.message,
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
console.error(`[mcp:plan_validate] validation failed: ${error}`);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
return {
|
|
1566
|
+
content: [
|
|
1567
|
+
{
|
|
1568
|
+
type: "text",
|
|
1569
|
+
text: JSON.stringify(result, null, 2),
|
|
1570
|
+
},
|
|
1571
|
+
],
|
|
1572
|
+
};
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
throwMcpToolError(ErrorCode.InternalError, "plan_validate", error, "validate plan");
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Handle plan_analyze tool
|
|
1580
|
+
* Analyzes a plan for conflicts and dependency issues (dry-run)
|
|
1581
|
+
*/
|
|
1582
|
+
async function handlePlanAnalyze(
|
|
1583
|
+
args: PlanAnalyzeArgs
|
|
1584
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1585
|
+
try {
|
|
1586
|
+
let planPath: string;
|
|
1587
|
+
|
|
1588
|
+
// Resolve plan file path
|
|
1589
|
+
if (args.planFile) {
|
|
1590
|
+
planPath = args.planFile;
|
|
1591
|
+
} else {
|
|
1592
|
+
const resolved = resolveProfile(undefined, process.cwd());
|
|
1593
|
+
planPath = path.join(resolved.path, "runner", "plan.json");
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// Check if plan file exists
|
|
1597
|
+
if (!fs.existsSync(planPath)) {
|
|
1598
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planPath));
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// Load and validate plan
|
|
1602
|
+
const planContent = fs.readFileSync(planPath, "utf-8");
|
|
1603
|
+
const plan = loadPlan(planContent);
|
|
1604
|
+
|
|
1605
|
+
const result: PlanAnalyzeResult = {
|
|
1606
|
+
valid: true,
|
|
1607
|
+
conflicts: [],
|
|
1608
|
+
dependencies: {
|
|
1609
|
+
total: 0,
|
|
1610
|
+
},
|
|
1611
|
+
summary: {
|
|
1612
|
+
totalItems: plan.items.length,
|
|
1613
|
+
maxParallelism: 0,
|
|
1614
|
+
hasIssues: false,
|
|
1615
|
+
},
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
// Count dependencies
|
|
1619
|
+
for (const item of plan.items) {
|
|
1620
|
+
if (item.deps && item.deps.length > 0) {
|
|
1621
|
+
result.dependencies!.total += item.deps.length;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// Try to compute merge order (will detect cycles and unknown deps)
|
|
1626
|
+
try {
|
|
1627
|
+
const levels = computeMergeOrder(plan);
|
|
1628
|
+
result.mergeOrder = levels;
|
|
1629
|
+
const levelSizes = levels.map((l) => l.length);
|
|
1630
|
+
result.summary.maxParallelism = levelSizes.length > 0 ? Math.max(0, ...levelSizes) : 0;
|
|
1631
|
+
|
|
1632
|
+
console.error(
|
|
1633
|
+
`[mcp:plan_analyze] analyzed plan: ${plan.items.length} items, ${levels.length} levels, max parallelism=${result.summary.maxParallelism}`
|
|
1634
|
+
);
|
|
1635
|
+
} catch (error) {
|
|
1636
|
+
result.valid = false;
|
|
1637
|
+
result.summary.hasIssues = true;
|
|
1638
|
+
|
|
1639
|
+
if (error instanceof CycleError) {
|
|
1640
|
+
const cycle = (error.axError.context as unknown as CycleDetectedContext).cycle;
|
|
1641
|
+
result.dependencies!.cycles = [[...cycle]];
|
|
1642
|
+
result.conflicts?.push({
|
|
1643
|
+
type: "cycle",
|
|
1644
|
+
message: `Dependency cycle detected: ${cycle.join(" -> ")}`,
|
|
1645
|
+
items: cycle,
|
|
1646
|
+
});
|
|
1647
|
+
console.error(`[mcp:plan_analyze] cycle detected: ${cycle.join(" -> ")}`);
|
|
1648
|
+
} else if (error instanceof UnknownDependencyError) {
|
|
1649
|
+
const ctx = error.axError.context as unknown as UnknownDependencyContext;
|
|
1650
|
+
result.dependencies!.unknown = [ctx.dependency];
|
|
1651
|
+
result.conflicts?.push({
|
|
1652
|
+
type: "unknown_dependency",
|
|
1653
|
+
message: `Unknown dependency: ${ctx.dependency} referenced by ${ctx.item}`,
|
|
1654
|
+
items: [ctx.item, ctx.dependency],
|
|
1655
|
+
});
|
|
1656
|
+
console.error(`[mcp:plan_analyze] unknown dependency: ${ctx.dependency}`);
|
|
1657
|
+
} else {
|
|
1658
|
+
result.conflicts?.push({
|
|
1659
|
+
type: "analysis_error",
|
|
1660
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
return {
|
|
1666
|
+
content: [
|
|
1667
|
+
{
|
|
1668
|
+
type: "text",
|
|
1669
|
+
text: JSON.stringify(result, null, 2),
|
|
1670
|
+
},
|
|
1671
|
+
],
|
|
1672
|
+
};
|
|
1673
|
+
} catch (error) {
|
|
1674
|
+
throwMcpToolError(ErrorCode.InternalError, "plan_analyze", error, "analyze plan");
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Handle gates.run tool
|
|
1680
|
+
*/
|
|
1681
|
+
async function handleGatesRun(
|
|
1682
|
+
args: GatesRunArgs
|
|
1683
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1684
|
+
try {
|
|
1685
|
+
const env = getMCPEnvironment();
|
|
1686
|
+
|
|
1687
|
+
let planPath: string;
|
|
1688
|
+
let outDirBase: string;
|
|
1689
|
+
|
|
1690
|
+
// Use planFile if provided, otherwise fall back to internal state
|
|
1691
|
+
if (args.planFile) {
|
|
1692
|
+
// Validate that the plan file exists
|
|
1693
|
+
if (!fs.existsSync(args.planFile)) {
|
|
1694
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(args.planFile));
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
planPath = args.planFile;
|
|
1698
|
+
// For external plans, use the plan file's directory as the base for output
|
|
1699
|
+
outDirBase = path.dirname(args.planFile);
|
|
1700
|
+
} else {
|
|
1701
|
+
// Resolve profile directory for internal state
|
|
1702
|
+
const resolved = resolveProfile(env.LEX_PR_PROFILE_DIR, process.cwd());
|
|
1703
|
+
|
|
1704
|
+
// Load plan from resolved profile directory
|
|
1705
|
+
planPath = path.join(resolved.path, "runner", "plan.json");
|
|
1706
|
+
if (!fs.existsSync(planPath)) {
|
|
1707
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planPath));
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
outDirBase = path.join(resolved.path, "runner");
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
let planContent: string;
|
|
1714
|
+
try {
|
|
1715
|
+
planContent = fs.readFileSync(planPath, "utf-8");
|
|
1716
|
+
} catch (error) {
|
|
1717
|
+
const axError = mcpToolError(
|
|
1718
|
+
ErrorCodes.PLAN_NOT_FOUND,
|
|
1719
|
+
`Failed to read plan file ${planPath}`,
|
|
1720
|
+
{ tool: "gates.run", operation: "read plan file" }
|
|
1721
|
+
);
|
|
1722
|
+
throwMcpAXError(ErrorCode.InternalError, axError);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const plan = loadPlan(planContent);
|
|
1726
|
+
|
|
1727
|
+
// Create execution state
|
|
1728
|
+
const executionState = new ExecutionState(plan);
|
|
1729
|
+
|
|
1730
|
+
// Determine output directory
|
|
1731
|
+
const outDir = args.outDir || path.join(outDirBase, "gates");
|
|
1732
|
+
|
|
1733
|
+
// Execute gates (this modifies executionState in place)
|
|
1734
|
+
await executeGatesWithPolicy(plan, executionState, outDir);
|
|
1735
|
+
|
|
1736
|
+
// Get results from execution state
|
|
1737
|
+
const results = executionState.getResults();
|
|
1738
|
+
|
|
1739
|
+
// Transform results to expected format
|
|
1740
|
+
const items = [];
|
|
1741
|
+
let allGreen = true;
|
|
1742
|
+
|
|
1743
|
+
for (const [itemName, nodeResult] of results) {
|
|
1744
|
+
// Filter by onlyItem if specified
|
|
1745
|
+
if (args.onlyItem && itemName !== args.onlyItem) {
|
|
1746
|
+
continue;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// Filter gates by onlyGate if specified
|
|
1750
|
+
const gates =
|
|
1751
|
+
nodeResult.gates
|
|
1752
|
+
?.filter((gate) => !args.onlyGate || gate.gate === args.onlyGate)
|
|
1753
|
+
.map((gate: any) => ({
|
|
1754
|
+
name: gate.gate,
|
|
1755
|
+
status: gate.status,
|
|
1756
|
+
})) || [];
|
|
1757
|
+
|
|
1758
|
+
const itemResult = {
|
|
1759
|
+
name: itemName,
|
|
1760
|
+
status: nodeResult.status || "unknown",
|
|
1761
|
+
gates: gates,
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
items.push(itemResult);
|
|
1765
|
+
|
|
1766
|
+
if (nodeResult.status !== "pass") {
|
|
1767
|
+
allGreen = false;
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
const result: GatesRunResult = {
|
|
1772
|
+
items,
|
|
1773
|
+
allGreen,
|
|
1774
|
+
};
|
|
1775
|
+
|
|
1776
|
+
return {
|
|
1777
|
+
content: [
|
|
1778
|
+
{
|
|
1779
|
+
type: "text",
|
|
1780
|
+
text: JSON.stringify(result, null, 2),
|
|
1781
|
+
},
|
|
1782
|
+
],
|
|
1783
|
+
};
|
|
1784
|
+
} catch (error) {
|
|
1785
|
+
// Check for plan not found specifically
|
|
1786
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1787
|
+
if (message.includes("Plan file not found") || message.includes("No plan found")) {
|
|
1788
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(args.planFile));
|
|
1789
|
+
}
|
|
1790
|
+
throwMcpToolError(ErrorCode.InternalError, "gates.run", error, "run gates");
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* Handle merge.apply tool
|
|
1796
|
+
*/
|
|
1797
|
+
async function handleMergeApply(
|
|
1798
|
+
args: MergeApplyArgs
|
|
1799
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1800
|
+
try {
|
|
1801
|
+
const env = getMCPEnvironment();
|
|
1802
|
+
|
|
1803
|
+
// Resolve profile directory first to check role
|
|
1804
|
+
const resolved = resolveProfile(env.LEX_PR_PROFILE_DIR, process.cwd());
|
|
1805
|
+
|
|
1806
|
+
// Validate CI environment if role is 'ci'
|
|
1807
|
+
validateCIEnvironment(resolved.manifest);
|
|
1808
|
+
|
|
1809
|
+
// Get CI-aware mutation policy
|
|
1810
|
+
const allowMutations = getCIMutationPolicy(resolved.manifest);
|
|
1811
|
+
|
|
1812
|
+
// Check if mutations are allowed
|
|
1813
|
+
if (!allowMutations && !args.dryRun) {
|
|
1814
|
+
const result: MergeApplyResult = {
|
|
1815
|
+
allowed: false,
|
|
1816
|
+
message: "Mutations not allowed. Set ALLOW_MUTATIONS=true or use dryRun=true.",
|
|
1817
|
+
};
|
|
1818
|
+
|
|
1819
|
+
return {
|
|
1820
|
+
content: [
|
|
1821
|
+
{
|
|
1822
|
+
type: "text",
|
|
1823
|
+
text: JSON.stringify(result, null, 2),
|
|
1824
|
+
},
|
|
1825
|
+
],
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
// Load plan and execution state
|
|
1830
|
+
const planPath = path.join(resolved.path, "runner", "plan.json");
|
|
1831
|
+
if (!fs.existsSync(planPath)) {
|
|
1832
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planPath));
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
const planContent = fs.readFileSync(planPath, "utf-8");
|
|
1836
|
+
const plan = loadPlan(planContent);
|
|
1837
|
+
|
|
1838
|
+
const executionState = new ExecutionState(plan);
|
|
1839
|
+
|
|
1840
|
+
// Load gate results from directory if available
|
|
1841
|
+
const gateResultsDir = path.join(resolved.path, "gate-results");
|
|
1842
|
+
if (fs.existsSync(gateResultsDir)) {
|
|
1843
|
+
try {
|
|
1844
|
+
const loadedCount = executionState.loadGateResultsFromDirectory(gateResultsDir);
|
|
1845
|
+
console.log(`📊 Loaded ${loadedCount} gate result(s) from ${gateResultsDir}`);
|
|
1846
|
+
} catch (error) {
|
|
1847
|
+
console.warn(
|
|
1848
|
+
`⚠️ Failed to load gate results from ${gateResultsDir}: ${error instanceof Error ? error.message : String(error)}`
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
const evaluator = new MergeEligibilityEvaluator(plan, executionState);
|
|
1854
|
+
const decisions = evaluator.evaluateAllNodes();
|
|
1855
|
+
|
|
1856
|
+
const summary = evaluator.getMergeSummary();
|
|
1857
|
+
|
|
1858
|
+
const result: MergeApplyResult = {
|
|
1859
|
+
allowed: allowMutations && !args.dryRun,
|
|
1860
|
+
message: args.dryRun
|
|
1861
|
+
? `Dry run: ${summary.eligible.length} items eligible, ${summary.failed.length} failed`
|
|
1862
|
+
: allowMutations
|
|
1863
|
+
? `Ready to merge ${summary.eligible.length} eligible items`
|
|
1864
|
+
: "Mutations disabled. Set ALLOW_MUTATIONS=true to enable merging.",
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
return {
|
|
1868
|
+
content: [
|
|
1869
|
+
{
|
|
1870
|
+
type: "text",
|
|
1871
|
+
text: JSON.stringify(result, null, 2),
|
|
1872
|
+
},
|
|
1873
|
+
],
|
|
1874
|
+
};
|
|
1875
|
+
} catch (error) {
|
|
1876
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1877
|
+
if (message.includes("No plan found")) {
|
|
1878
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError());
|
|
1879
|
+
}
|
|
1880
|
+
throwMcpToolError(ErrorCode.InternalError, "merge.apply", error, "apply merge");
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
/**
|
|
1885
|
+
* Handle local.init tool
|
|
1886
|
+
*/
|
|
1887
|
+
async function handleLocalInit(
|
|
1888
|
+
args: InitLocalArgs
|
|
1889
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1890
|
+
try {
|
|
1891
|
+
const force = args.force ?? false;
|
|
1892
|
+
const result = initLocalOverlay(process.cwd(), force);
|
|
1893
|
+
|
|
1894
|
+
const output: InitLocalResult = {
|
|
1895
|
+
created: result.created,
|
|
1896
|
+
path: result.path,
|
|
1897
|
+
config: result.config,
|
|
1898
|
+
copiedFiles: result.copiedFiles,
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
return {
|
|
1902
|
+
content: [
|
|
1903
|
+
{
|
|
1904
|
+
type: "text",
|
|
1905
|
+
text: JSON.stringify(output, null, 2),
|
|
1906
|
+
},
|
|
1907
|
+
],
|
|
1908
|
+
};
|
|
1909
|
+
} catch (error) {
|
|
1910
|
+
throwMcpToolError(ErrorCode.InternalError, "local.init", error, "initialize local overlay");
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
/**
|
|
1915
|
+
* Handle profile.resolve tool
|
|
1916
|
+
*/
|
|
1917
|
+
async function handleProfileResolve(
|
|
1918
|
+
args: ProfileResolveArgs
|
|
1919
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1920
|
+
try {
|
|
1921
|
+
const env = getMCPEnvironment();
|
|
1922
|
+
|
|
1923
|
+
// Use profile directory from args, or fall back to env, or use resolveProfile default logic
|
|
1924
|
+
const profileDirOverride = args.profileDir || env.LEX_PR_PROFILE_DIR;
|
|
1925
|
+
const resolved = resolveProfile(profileDirOverride, process.cwd());
|
|
1926
|
+
|
|
1927
|
+
const output: ProfileResolveResult = {
|
|
1928
|
+
path: resolved.path,
|
|
1929
|
+
source: resolved.source,
|
|
1930
|
+
manifest: {
|
|
1931
|
+
role: resolved.manifest.role,
|
|
1932
|
+
name: resolved.manifest.name,
|
|
1933
|
+
version: resolved.manifest.version,
|
|
1934
|
+
},
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1937
|
+
return {
|
|
1938
|
+
content: [
|
|
1939
|
+
{
|
|
1940
|
+
type: "text",
|
|
1941
|
+
text: JSON.stringify(output, null, 2),
|
|
1942
|
+
},
|
|
1943
|
+
],
|
|
1944
|
+
};
|
|
1945
|
+
} catch (error) {
|
|
1946
|
+
throwMcpToolError(ErrorCode.InternalError, "profile.resolve", error, "resolve profile");
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* Handle health check
|
|
1952
|
+
*/
|
|
1953
|
+
async function handleHealth(args: {
|
|
1954
|
+
includeMetrics?: boolean;
|
|
1955
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
1956
|
+
const health = healthChecker.getHealth(args.includeMetrics || false);
|
|
1957
|
+
|
|
1958
|
+
return {
|
|
1959
|
+
content: [
|
|
1960
|
+
{
|
|
1961
|
+
type: "text",
|
|
1962
|
+
text: JSON.stringify(health, null, 2),
|
|
1963
|
+
},
|
|
1964
|
+
],
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
/**
|
|
1969
|
+
* Main server startup
|
|
1970
|
+
*/
|
|
1971
|
+
async function main() {
|
|
1972
|
+
// Create RunStore (will be closed on shutdown)
|
|
1973
|
+
const runStore = createRunStore();
|
|
1974
|
+
const server = createServer({ runStore });
|
|
1975
|
+
const transport = new StdioServerTransport();
|
|
1976
|
+
|
|
1977
|
+
// Connect the server to stdio transport
|
|
1978
|
+
await server.connect(transport);
|
|
1979
|
+
|
|
1980
|
+
// Log to stderr so it doesn't interfere with MCP protocol
|
|
1981
|
+
console.error("MCP server started for lexrunner");
|
|
1982
|
+
|
|
1983
|
+
// Keep the process alive by setting up event handlers
|
|
1984
|
+
// The event loop will keep running while the stdio transport is active
|
|
1985
|
+
process.stdin.resume();
|
|
1986
|
+
|
|
1987
|
+
// Handle graceful shutdown when stdin closes
|
|
1988
|
+
process.stdin.on("end", async () => {
|
|
1989
|
+
console.error("MCP server shutting down");
|
|
1990
|
+
try {
|
|
1991
|
+
await runStore.close();
|
|
1992
|
+
} catch (error) {
|
|
1993
|
+
console.error("Error closing RunStore:", error);
|
|
1994
|
+
}
|
|
1995
|
+
process.exit(0);
|
|
1996
|
+
});
|
|
1997
|
+
|
|
1998
|
+
// Never return - let the event loop handle everything
|
|
1999
|
+
await new Promise<void>(() => {
|
|
2000
|
+
// This promise never resolves, keeping the process alive
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2005
|
+
// Senior Dev Executor Handlers
|
|
2006
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2007
|
+
|
|
2008
|
+
/**
|
|
2009
|
+
* Handle senior-dev.prepare-context tool
|
|
2010
|
+
*/
|
|
2011
|
+
async function handleSeniorDevPrepareContext(
|
|
2012
|
+
args: PrepareContextInput
|
|
2013
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2014
|
+
try {
|
|
2015
|
+
const result = await prepareReviewContext(args);
|
|
2016
|
+
return {
|
|
2017
|
+
content: [
|
|
2018
|
+
{
|
|
2019
|
+
type: "text",
|
|
2020
|
+
text: JSON.stringify(result, null, 2),
|
|
2021
|
+
},
|
|
2022
|
+
],
|
|
2023
|
+
};
|
|
2024
|
+
} catch (error) {
|
|
2025
|
+
throwMcpToolError(
|
|
2026
|
+
ErrorCode.InternalError,
|
|
2027
|
+
"senior-dev.prepare-context",
|
|
2028
|
+
error,
|
|
2029
|
+
"prepare review context"
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
/**
|
|
2035
|
+
* Handle senior-dev.recall-context tool
|
|
2036
|
+
*/
|
|
2037
|
+
async function handleSeniorDevRecallContext(
|
|
2038
|
+
args: RecallContextInput
|
|
2039
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2040
|
+
try {
|
|
2041
|
+
const result = await recallSeniorDevContext(args);
|
|
2042
|
+
return {
|
|
2043
|
+
content: [
|
|
2044
|
+
{
|
|
2045
|
+
type: "text",
|
|
2046
|
+
text: JSON.stringify(result, null, 2),
|
|
2047
|
+
},
|
|
2048
|
+
],
|
|
2049
|
+
};
|
|
2050
|
+
} catch (error) {
|
|
2051
|
+
throwMcpToolError(
|
|
2052
|
+
ErrorCode.InternalError,
|
|
2053
|
+
"senior-dev.recall-context",
|
|
2054
|
+
error,
|
|
2055
|
+
"recall context"
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
/**
|
|
2061
|
+
* Handle senior-dev.capture-frame tool
|
|
2062
|
+
*/
|
|
2063
|
+
async function handleSeniorDevCaptureFrame(
|
|
2064
|
+
args: CaptureFrameInput
|
|
2065
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2066
|
+
try {
|
|
2067
|
+
const result = await captureSeniorDevFrame(args);
|
|
2068
|
+
return {
|
|
2069
|
+
content: [
|
|
2070
|
+
{
|
|
2071
|
+
type: "text",
|
|
2072
|
+
text: JSON.stringify(result, null, 2),
|
|
2073
|
+
},
|
|
2074
|
+
],
|
|
2075
|
+
};
|
|
2076
|
+
} catch (error) {
|
|
2077
|
+
throwMcpToolError(ErrorCode.InternalError, "senior-dev.capture-frame", error, "capture frame");
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
/**
|
|
2082
|
+
* Handle senior-dev.modes tool
|
|
2083
|
+
*/
|
|
2084
|
+
async function handleSeniorDevModes(): Promise<{
|
|
2085
|
+
content: [{ type: "text"; text: string }];
|
|
2086
|
+
}> {
|
|
2087
|
+
return {
|
|
2088
|
+
content: [
|
|
2089
|
+
{
|
|
2090
|
+
type: "text",
|
|
2091
|
+
text: JSON.stringify(EXECUTOR_MODES, null, 2),
|
|
2092
|
+
},
|
|
2093
|
+
],
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2098
|
+
// LexRunner Run Management Handlers
|
|
2099
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2100
|
+
|
|
2101
|
+
/**
|
|
2102
|
+
* Generate a plan hash from run parameters for RunRecord storage.
|
|
2103
|
+
*/
|
|
2104
|
+
function generatePlanHash(input: StartRunInput): string {
|
|
2105
|
+
const hashContent = JSON.stringify({
|
|
2106
|
+
mode: input.mode,
|
|
2107
|
+
procedure: input.procedure,
|
|
2108
|
+
repo: input.repo,
|
|
2109
|
+
params: input.params,
|
|
2110
|
+
});
|
|
2111
|
+
return "sha256:" + crypto.createHash("sha256").update(hashContent).digest("hex");
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Handle lexrunner.startRun tool
|
|
2116
|
+
*
|
|
2117
|
+
* Creates a run record in both the RunStore (for persistence) and RunManager
|
|
2118
|
+
* (for orchestration state).
|
|
2119
|
+
*/
|
|
2120
|
+
async function handleStartRun(
|
|
2121
|
+
args: StartRunInput,
|
|
2122
|
+
runStore: RunStore
|
|
2123
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2124
|
+
try {
|
|
2125
|
+
// Validate input
|
|
2126
|
+
const validated = StartRunInputSchema.parse(args);
|
|
2127
|
+
|
|
2128
|
+
// Create run manager and start the run (for orchestration state)
|
|
2129
|
+
const manager = createRunManager();
|
|
2130
|
+
const result = manager.startRun(validated);
|
|
2131
|
+
|
|
2132
|
+
// Also create a record in the RunStore for persistence
|
|
2133
|
+
const now = new Date().toISOString();
|
|
2134
|
+
await runStore.createRun({
|
|
2135
|
+
runId: result.runId,
|
|
2136
|
+
planHash: generatePlanHash(validated),
|
|
2137
|
+
state: "pending", // RunStore uses its own state machine
|
|
2138
|
+
startedAt: now,
|
|
2139
|
+
metadata: {
|
|
2140
|
+
mode: validated.mode,
|
|
2141
|
+
procedure: validated.procedure,
|
|
2142
|
+
repo: validated.repo,
|
|
2143
|
+
task: validated.task,
|
|
2144
|
+
},
|
|
2145
|
+
});
|
|
2146
|
+
|
|
2147
|
+
return {
|
|
2148
|
+
content: [
|
|
2149
|
+
{
|
|
2150
|
+
type: "text",
|
|
2151
|
+
text: JSON.stringify(result, null, 2),
|
|
2152
|
+
},
|
|
2153
|
+
],
|
|
2154
|
+
};
|
|
2155
|
+
} catch (error) {
|
|
2156
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2157
|
+
const axError = mcpToolError(
|
|
2158
|
+
ErrorCodes.INVALID_INPUT,
|
|
2159
|
+
`Invalid startRun parameters: ${error.message}`,
|
|
2160
|
+
{ tool: "lexrunner.startRun", operation: "validate parameters" }
|
|
2161
|
+
);
|
|
2162
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2163
|
+
}
|
|
2164
|
+
throwMcpToolError(ErrorCode.InternalError, "lexrunner.startRun", error, "start run");
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* Handle lexrunner.getStatus tool
|
|
2170
|
+
*
|
|
2171
|
+
* Queries run state from RunManager, and also fetches step/receipt data
|
|
2172
|
+
* from RunStore for enhanced status reporting.
|
|
2173
|
+
*/
|
|
2174
|
+
async function handleGetStatus(
|
|
2175
|
+
args: GetStatusInput,
|
|
2176
|
+
runStore: RunStore
|
|
2177
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2178
|
+
try {
|
|
2179
|
+
// Validate input
|
|
2180
|
+
const validated = GetStatusInputSchema.parse(args);
|
|
2181
|
+
|
|
2182
|
+
// Get orchestration status from run manager
|
|
2183
|
+
const manager = createRunManager();
|
|
2184
|
+
const status = manager.getStatus(validated);
|
|
2185
|
+
|
|
2186
|
+
// Fetch additional data from RunStore if available
|
|
2187
|
+
const runRecord = await runStore.getRun(validated.runId);
|
|
2188
|
+
const steps = await runStore.getStepsForRun(validated.runId);
|
|
2189
|
+
const receipts = await runStore.getReceiptsForRun(validated.runId);
|
|
2190
|
+
|
|
2191
|
+
// Enhance status with store data
|
|
2192
|
+
const enhancedStatus = {
|
|
2193
|
+
...status,
|
|
2194
|
+
store: runRecord
|
|
2195
|
+
? {
|
|
2196
|
+
runRecord,
|
|
2197
|
+
steps,
|
|
2198
|
+
receipts,
|
|
2199
|
+
}
|
|
2200
|
+
: null,
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
return {
|
|
2204
|
+
content: [
|
|
2205
|
+
{
|
|
2206
|
+
type: "text",
|
|
2207
|
+
text: JSON.stringify(enhancedStatus, null, 2),
|
|
2208
|
+
},
|
|
2209
|
+
],
|
|
2210
|
+
};
|
|
2211
|
+
} catch (error) {
|
|
2212
|
+
if (error instanceof RunNotFoundError) {
|
|
2213
|
+
const axError = mcpToolError(
|
|
2214
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
2215
|
+
error.message,
|
|
2216
|
+
{ tool: "lexrunner.getStatus" },
|
|
2217
|
+
["Check that runId is valid", "List available runs with 'lexrunner.listRuns'"]
|
|
2218
|
+
);
|
|
2219
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2220
|
+
}
|
|
2221
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2222
|
+
const axError = mcpToolError(
|
|
2223
|
+
ErrorCodes.INVALID_INPUT,
|
|
2224
|
+
`Invalid getStatus parameters: ${error.message}`,
|
|
2225
|
+
{
|
|
2226
|
+
tool: "lexrunner.getStatus",
|
|
2227
|
+
operation: "validate parameters",
|
|
2228
|
+
}
|
|
2229
|
+
);
|
|
2230
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2231
|
+
}
|
|
2232
|
+
throwMcpToolError(ErrorCode.InternalError, "lexrunner.getStatus", error, "get status");
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
/**
|
|
2237
|
+
* Handle lexrunner.listRuns tool
|
|
2238
|
+
*
|
|
2239
|
+
* Queries the RunStore for run records with optional filtering and pagination.
|
|
2240
|
+
*/
|
|
2241
|
+
async function handleListRuns(
|
|
2242
|
+
args: ListRunsInput,
|
|
2243
|
+
runStore: RunStore
|
|
2244
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2245
|
+
try {
|
|
2246
|
+
// Validate input
|
|
2247
|
+
const validated = ListRunsInputSchema.parse(args);
|
|
2248
|
+
|
|
2249
|
+
// Query runs from the store
|
|
2250
|
+
const options: ListRunsOptions = {};
|
|
2251
|
+
if (validated.limit !== undefined) {
|
|
2252
|
+
options.limit = validated.limit;
|
|
2253
|
+
}
|
|
2254
|
+
if (validated.offset !== undefined) {
|
|
2255
|
+
options.offset = validated.offset;
|
|
2256
|
+
}
|
|
2257
|
+
if (validated.state !== undefined) {
|
|
2258
|
+
options.state = validated.state;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
const runs = await runStore.listRuns(options);
|
|
2262
|
+
const count = await runStore.getRunCount(validated.state);
|
|
2263
|
+
|
|
2264
|
+
const result = {
|
|
2265
|
+
runs,
|
|
2266
|
+
total: count,
|
|
2267
|
+
limit: validated.limit,
|
|
2268
|
+
offset: validated.offset ?? 0,
|
|
2269
|
+
};
|
|
2270
|
+
|
|
2271
|
+
return {
|
|
2272
|
+
content: [
|
|
2273
|
+
{
|
|
2274
|
+
type: "text",
|
|
2275
|
+
text: JSON.stringify(result, null, 2),
|
|
2276
|
+
},
|
|
2277
|
+
],
|
|
2278
|
+
};
|
|
2279
|
+
} catch (error) {
|
|
2280
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2281
|
+
const axError = mcpToolError(
|
|
2282
|
+
ErrorCodes.INVALID_INPUT,
|
|
2283
|
+
`Invalid listRuns parameters: ${error.message}`,
|
|
2284
|
+
{ tool: "lexrunner.listRuns", operation: "validate parameters" }
|
|
2285
|
+
);
|
|
2286
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2287
|
+
}
|
|
2288
|
+
throwMcpToolError(ErrorCode.InternalError, "lexrunner.listRuns", error, "list runs");
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
/**
|
|
2293
|
+
* Handle lexrunner.submitDecision tool
|
|
2294
|
+
*
|
|
2295
|
+
* Validates and submits an LLM decision for a pending action in a run.
|
|
2296
|
+
*/
|
|
2297
|
+
async function handleSubmitDecision(
|
|
2298
|
+
args: SubmitDecisionInput
|
|
2299
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2300
|
+
try {
|
|
2301
|
+
// Validate input
|
|
2302
|
+
const validated = SubmitDecisionInputSchema.parse(args);
|
|
2303
|
+
|
|
2304
|
+
// Submit the decision (uses process.cwd() as baseDir)
|
|
2305
|
+
const result = submitDecision(validated);
|
|
2306
|
+
|
|
2307
|
+
return {
|
|
2308
|
+
content: [
|
|
2309
|
+
{
|
|
2310
|
+
type: "text",
|
|
2311
|
+
text: JSON.stringify(result, null, 2),
|
|
2312
|
+
},
|
|
2313
|
+
],
|
|
2314
|
+
};
|
|
2315
|
+
} catch (error) {
|
|
2316
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2317
|
+
const axError = mcpToolError(
|
|
2318
|
+
ErrorCodes.INVALID_INPUT,
|
|
2319
|
+
`Invalid submitDecision parameters: ${error.message}`,
|
|
2320
|
+
{
|
|
2321
|
+
tool: "lexrunner.submitDecision",
|
|
2322
|
+
operation: "validate parameters",
|
|
2323
|
+
}
|
|
2324
|
+
);
|
|
2325
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2326
|
+
}
|
|
2327
|
+
throwMcpToolError(
|
|
2328
|
+
ErrorCode.InternalError,
|
|
2329
|
+
"lexrunner.submitDecision",
|
|
2330
|
+
error,
|
|
2331
|
+
"submit decision"
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2337
|
+
// MCP/CLI Parity Handlers (AX-004)
|
|
2338
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2339
|
+
|
|
2340
|
+
/**
|
|
2341
|
+
* Handle discover tool - Discover open pull requests from GitHub
|
|
2342
|
+
*/
|
|
2343
|
+
async function handleDiscover(args: {
|
|
2344
|
+
owner?: string;
|
|
2345
|
+
repo?: string;
|
|
2346
|
+
state?: string;
|
|
2347
|
+
suggest?: boolean;
|
|
2348
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2349
|
+
try {
|
|
2350
|
+
// Check for GitHub authentication early
|
|
2351
|
+
ensureGitHubToken();
|
|
2352
|
+
|
|
2353
|
+
let githubAPI = await createGitHubAPI();
|
|
2354
|
+
|
|
2355
|
+
// Override with arguments if provided
|
|
2356
|
+
if (args.owner && args.repo) {
|
|
2357
|
+
githubAPI = new GitHubAPI({
|
|
2358
|
+
owner: args.owner,
|
|
2359
|
+
repo: args.repo,
|
|
2360
|
+
token: process.env.GITHUB_TOKEN,
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
if (!githubAPI) {
|
|
2365
|
+
const axError = githubApiError({
|
|
2366
|
+
message:
|
|
2367
|
+
"Could not detect GitHub repository. Provide owner and repo parameters or run from a git repository with GitHub remote.",
|
|
2368
|
+
});
|
|
2369
|
+
throwMcpAXError(ErrorCode.InvalidRequest, axError);
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
// Check authentication and warn if not authenticated
|
|
2373
|
+
const authStatus = await githubAPI.checkAuth();
|
|
2374
|
+
if (!authStatus.authenticated) {
|
|
2375
|
+
// Log warning to stderr for MCP clients to surface
|
|
2376
|
+
console.error(
|
|
2377
|
+
"[mcp:discover] Warning: GitHub API not authenticated. Private repos will not be accessible.\n" +
|
|
2378
|
+
"To fix: Add GITHUB_TOKEN to your MCP server config env block.\n" +
|
|
2379
|
+
"See: README.mcp.md#github-authentication"
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
// Fetch pull requests
|
|
2384
|
+
const state = (args.state || "open") as "open" | "closed" | "all";
|
|
2385
|
+
const pullRequests = await githubAPI.discoverPullRequests(state);
|
|
2386
|
+
|
|
2387
|
+
let result: Record<string, unknown>;
|
|
2388
|
+
|
|
2389
|
+
if (args.suggest) {
|
|
2390
|
+
// Generate dependency suggestions using heuristics
|
|
2391
|
+
const { createFileAnalyzer } = await import("../planner/fileAnalysis.js");
|
|
2392
|
+
|
|
2393
|
+
const analyzer = createFileAnalyzer(
|
|
2394
|
+
githubAPI.getOctokit(),
|
|
2395
|
+
githubAPI.config.owner,
|
|
2396
|
+
githubAPI.config.repo
|
|
2397
|
+
);
|
|
2398
|
+
const prs = pullRequests.map((pr: { number: number; sha: string }) => ({
|
|
2399
|
+
number: pr.number,
|
|
2400
|
+
name: `PR-${pr.number}`,
|
|
2401
|
+
sha: pr.sha,
|
|
2402
|
+
}));
|
|
2403
|
+
|
|
2404
|
+
const suggestions = await analyzer.suggestDependenciesWithHeuristics(prs);
|
|
2405
|
+
|
|
2406
|
+
result = {
|
|
2407
|
+
pullRequests,
|
|
2408
|
+
suggestions,
|
|
2409
|
+
total: pullRequests.length,
|
|
2410
|
+
suggestionsCount: suggestions.length,
|
|
2411
|
+
authenticated: authStatus.authenticated,
|
|
2412
|
+
user: authStatus.user,
|
|
2413
|
+
};
|
|
2414
|
+
} else {
|
|
2415
|
+
result = {
|
|
2416
|
+
pullRequests,
|
|
2417
|
+
total: pullRequests.length,
|
|
2418
|
+
authenticated: authStatus.authenticated,
|
|
2419
|
+
user: authStatus.user,
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
return {
|
|
2424
|
+
content: [
|
|
2425
|
+
{
|
|
2426
|
+
type: "text",
|
|
2427
|
+
text: JSON.stringify(result, null, 2),
|
|
2428
|
+
},
|
|
2429
|
+
],
|
|
2430
|
+
};
|
|
2431
|
+
} catch (error) {
|
|
2432
|
+
if (error instanceof McpError) {
|
|
2433
|
+
throw error;
|
|
2434
|
+
}
|
|
2435
|
+
// Handle GitHub API errors specifically with status code context
|
|
2436
|
+
if (error instanceof GitHubAPIError) {
|
|
2437
|
+
const axError = githubApiError({
|
|
2438
|
+
status: error.status,
|
|
2439
|
+
message: error.message,
|
|
2440
|
+
});
|
|
2441
|
+
throwMcpAXError(ErrorCode.InternalError, axError);
|
|
2442
|
+
}
|
|
2443
|
+
throwMcpToolError(ErrorCode.InternalError, "discover", error, "discover PRs");
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
/**
|
|
2448
|
+
* Handle status tool - Show execution status and merge eligibility
|
|
2449
|
+
*/
|
|
2450
|
+
async function handleStatus(args: {
|
|
2451
|
+
planFile?: string;
|
|
2452
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2453
|
+
try {
|
|
2454
|
+
const planFile = args.planFile || "plan.json";
|
|
2455
|
+
|
|
2456
|
+
if (!fs.existsSync(planFile)) {
|
|
2457
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planFile));
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
const planContent = fs.readFileSync(planFile, "utf-8");
|
|
2461
|
+
const plan = loadPlan(planContent);
|
|
2462
|
+
|
|
2463
|
+
// Create execution state (for now, show plan structure)
|
|
2464
|
+
const executionState = new ExecutionState(plan);
|
|
2465
|
+
const evaluator = new MergeEligibilityEvaluator(plan, executionState);
|
|
2466
|
+
const mergeSummary = evaluator.getMergeSummary();
|
|
2467
|
+
|
|
2468
|
+
// Calculate tier metrics from plan items
|
|
2469
|
+
const tierAssignments = suggestTiersForPlan(plan.items);
|
|
2470
|
+
const tierMetrics = calculateTierMetrics(tierAssignments);
|
|
2471
|
+
|
|
2472
|
+
// Run environment quality check for hostility score
|
|
2473
|
+
const hostilityScore = runEnvironmentQualityCheck();
|
|
2474
|
+
|
|
2475
|
+
// Build governance status
|
|
2476
|
+
const governanceStatus = buildGovernanceStatus(
|
|
2477
|
+
tierMetrics,
|
|
2478
|
+
undefined, // Turn cost tracked during actual runs
|
|
2479
|
+
hostilityScore
|
|
2480
|
+
);
|
|
2481
|
+
|
|
2482
|
+
const result = {
|
|
2483
|
+
plan: {
|
|
2484
|
+
schemaVersion: plan.schemaVersion,
|
|
2485
|
+
target: plan.target,
|
|
2486
|
+
itemCount: plan.items.length,
|
|
2487
|
+
policy: plan.policy,
|
|
2488
|
+
},
|
|
2489
|
+
mergeSummary,
|
|
2490
|
+
governance: governanceStatusToJSON(governanceStatus),
|
|
2491
|
+
};
|
|
2492
|
+
|
|
2493
|
+
return {
|
|
2494
|
+
content: [
|
|
2495
|
+
{
|
|
2496
|
+
type: "text",
|
|
2497
|
+
text: JSON.stringify(result, null, 2),
|
|
2498
|
+
},
|
|
2499
|
+
],
|
|
2500
|
+
};
|
|
2501
|
+
} catch (error) {
|
|
2502
|
+
if (error instanceof McpError) {
|
|
2503
|
+
throw error;
|
|
2504
|
+
}
|
|
2505
|
+
throwMcpToolError(ErrorCode.InternalError, "status", error, "get status");
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
/**
|
|
2510
|
+
* Handle doctor tool - Environment and configuration sanity checks
|
|
2511
|
+
*/
|
|
2512
|
+
async function handleDoctor(args: {
|
|
2513
|
+
environmentQuality?: boolean;
|
|
2514
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2515
|
+
try {
|
|
2516
|
+
const checks: Record<string, unknown> = {
|
|
2517
|
+
hasErrors: false,
|
|
2518
|
+
issues: [] as string[],
|
|
2519
|
+
suggestions: [] as string[],
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
// Node.js version check
|
|
2523
|
+
try {
|
|
2524
|
+
const nvmrcContent = fs.readFileSync(".nvmrc", "utf-8").trim();
|
|
2525
|
+
const currentVersion = process.version.slice(1);
|
|
2526
|
+
const expectedVersion = nvmrcContent;
|
|
2527
|
+
|
|
2528
|
+
if (currentVersion === expectedVersion) {
|
|
2529
|
+
checks.nodejs = {
|
|
2530
|
+
status: "ok",
|
|
2531
|
+
current: process.version,
|
|
2532
|
+
expected: `v${expectedVersion}`,
|
|
2533
|
+
};
|
|
2534
|
+
} else {
|
|
2535
|
+
checks.nodejs = {
|
|
2536
|
+
status: "mismatch",
|
|
2537
|
+
current: process.version,
|
|
2538
|
+
expected: `v${expectedVersion}`,
|
|
2539
|
+
};
|
|
2540
|
+
checks.hasErrors = true;
|
|
2541
|
+
(checks.issues as string[]).push(
|
|
2542
|
+
`Node.js version mismatch: ${process.version} vs v${expectedVersion}`
|
|
2543
|
+
);
|
|
2544
|
+
}
|
|
2545
|
+
} catch {
|
|
2546
|
+
checks.nodejs = {
|
|
2547
|
+
status: "no_constraint",
|
|
2548
|
+
current: process.version,
|
|
2549
|
+
};
|
|
2550
|
+
(checks.suggestions as string[]).push(
|
|
2551
|
+
"Consider adding .nvmrc file for Node.js version consistency"
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// Configuration check
|
|
2556
|
+
const bootstrap = bootstrapWorkspace();
|
|
2557
|
+
checks.configuration = {
|
|
2558
|
+
hasConfiguration: bootstrap.hasConfiguration,
|
|
2559
|
+
missingFiles: bootstrap.missingFiles,
|
|
2560
|
+
suggestions: bootstrap.suggestions,
|
|
2561
|
+
};
|
|
2562
|
+
|
|
2563
|
+
// Project type detection
|
|
2564
|
+
checks.projectType = detectProjectType();
|
|
2565
|
+
|
|
2566
|
+
// Environment suggestions
|
|
2567
|
+
checks.environmentSuggestions = getEnvironmentSuggestions();
|
|
2568
|
+
|
|
2569
|
+
// GitHub integration check
|
|
2570
|
+
try {
|
|
2571
|
+
const githubAPI = await createGitHubAPI();
|
|
2572
|
+
if (githubAPI) {
|
|
2573
|
+
const authStatus = await githubAPI.checkAuth();
|
|
2574
|
+
checks.github = {
|
|
2575
|
+
detected: true,
|
|
2576
|
+
authenticated: authStatus.authenticated,
|
|
2577
|
+
user: authStatus.user,
|
|
2578
|
+
};
|
|
2579
|
+
} else {
|
|
2580
|
+
checks.github = { detected: false };
|
|
2581
|
+
}
|
|
2582
|
+
} catch (error) {
|
|
2583
|
+
checks.github = {
|
|
2584
|
+
detected: false,
|
|
2585
|
+
error: (error as Error).message,
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
// Git operations check
|
|
2590
|
+
try {
|
|
2591
|
+
const gitOps = createGitOperations();
|
|
2592
|
+
const isClean = await gitOps.isClean();
|
|
2593
|
+
const currentBranch = await gitOps.getCurrentBranch();
|
|
2594
|
+
|
|
2595
|
+
checks.git = {
|
|
2596
|
+
status: "ok",
|
|
2597
|
+
isClean,
|
|
2598
|
+
currentBranch,
|
|
2599
|
+
};
|
|
2600
|
+
} catch (error) {
|
|
2601
|
+
checks.git = {
|
|
2602
|
+
status: "error",
|
|
2603
|
+
error: (error as Error).message,
|
|
2604
|
+
};
|
|
2605
|
+
checks.hasErrors = true;
|
|
2606
|
+
(checks.issues as string[]).push(`Git operations failed: ${(error as Error).message}`);
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
// Environment quality check (hostility scoring) if requested
|
|
2610
|
+
if (args.environmentQuality) {
|
|
2611
|
+
checks.environmentQuality = runEnvironmentQualityCheck();
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
return {
|
|
2615
|
+
content: [
|
|
2616
|
+
{
|
|
2617
|
+
type: "text",
|
|
2618
|
+
text: JSON.stringify(checks, null, 2),
|
|
2619
|
+
},
|
|
2620
|
+
],
|
|
2621
|
+
};
|
|
2622
|
+
} catch (error) {
|
|
2623
|
+
throwMcpToolError(ErrorCode.InternalError, "doctor", error, "run doctor");
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
/**
|
|
2628
|
+
* Handle merge-order tool - Compute dependency levels and merge order
|
|
2629
|
+
*/
|
|
2630
|
+
async function handleMergeOrder(args: {
|
|
2631
|
+
planFile?: string;
|
|
2632
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2633
|
+
try {
|
|
2634
|
+
const planFile = args.planFile || "plan.json";
|
|
2635
|
+
|
|
2636
|
+
if (!fs.existsSync(planFile)) {
|
|
2637
|
+
throwMcpAXError(ErrorCode.InvalidParams, planNotFoundError(planFile));
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
const planContent = fs.readFileSync(planFile, "utf-8");
|
|
2641
|
+
const plan = loadPlan(planContent);
|
|
2642
|
+
|
|
2643
|
+
// Compute merge order using Kahn's algorithm
|
|
2644
|
+
const levels = computeMergeOrder(plan);
|
|
2645
|
+
|
|
2646
|
+
const result = {
|
|
2647
|
+
levels,
|
|
2648
|
+
totalItems: plan.items.length,
|
|
2649
|
+
maxParallelism: Math.max(...levels.map((level) => level.length)),
|
|
2650
|
+
};
|
|
2651
|
+
|
|
2652
|
+
return {
|
|
2653
|
+
content: [
|
|
2654
|
+
{
|
|
2655
|
+
type: "text",
|
|
2656
|
+
text: JSON.stringify(result, null, 2),
|
|
2657
|
+
},
|
|
2658
|
+
],
|
|
2659
|
+
};
|
|
2660
|
+
} catch (error) {
|
|
2661
|
+
if (error instanceof McpError) {
|
|
2662
|
+
throw error;
|
|
2663
|
+
}
|
|
2664
|
+
// Handle AXErrorException instances (including CycleError, UnknownDependencyError)
|
|
2665
|
+
if (isAXErrorException(error)) {
|
|
2666
|
+
const axError = error.toAXError();
|
|
2667
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2668
|
+
}
|
|
2669
|
+
throwMcpToolError(ErrorCode.InternalError, "merge-order", error, "compute merge order");
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
/**
|
|
2674
|
+
* Handle config.show tool - Display configuration with precedence chain
|
|
2675
|
+
*/
|
|
2676
|
+
async function handleConfigShow(args: {
|
|
2677
|
+
key?: string;
|
|
2678
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2679
|
+
try {
|
|
2680
|
+
// Load configuration with provenance tracking
|
|
2681
|
+
const config = loadInputs();
|
|
2682
|
+
|
|
2683
|
+
const output: Record<string, unknown> = {
|
|
2684
|
+
config: {
|
|
2685
|
+
items: config.items,
|
|
2686
|
+
target: config.target,
|
|
2687
|
+
version: config.version,
|
|
2688
|
+
},
|
|
2689
|
+
provenance: config.provenance || {},
|
|
2690
|
+
sources: config.sources.map((s) => ({
|
|
2691
|
+
exists: s.exists,
|
|
2692
|
+
file: s.file,
|
|
2693
|
+
})),
|
|
2694
|
+
};
|
|
2695
|
+
|
|
2696
|
+
// If specific key requested, extract just that value
|
|
2697
|
+
if (args.key) {
|
|
2698
|
+
const keys = args.key.split(".");
|
|
2699
|
+
let value: unknown = output.config;
|
|
2700
|
+
for (const k of keys) {
|
|
2701
|
+
if (value && typeof value === "object" && k in value) {
|
|
2702
|
+
value = (value as Record<string, unknown>)[k];
|
|
2703
|
+
} else {
|
|
2704
|
+
value = undefined;
|
|
2705
|
+
break;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
return {
|
|
2709
|
+
content: [
|
|
2710
|
+
{
|
|
2711
|
+
type: "text",
|
|
2712
|
+
text: JSON.stringify({ key: args.key, value }, null, 2),
|
|
2713
|
+
},
|
|
2714
|
+
],
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
return {
|
|
2719
|
+
content: [
|
|
2720
|
+
{
|
|
2721
|
+
type: "text",
|
|
2722
|
+
text: JSON.stringify(output, null, 2),
|
|
2723
|
+
},
|
|
2724
|
+
],
|
|
2725
|
+
};
|
|
2726
|
+
} catch (error) {
|
|
2727
|
+
throwMcpToolError(ErrorCode.InternalError, "config.show", error, "show config");
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
/**
|
|
2732
|
+
* Handle metrics tool - Get governance metrics snapshot
|
|
2733
|
+
*/
|
|
2734
|
+
async function handleMetrics(args: {
|
|
2735
|
+
filter?: string;
|
|
2736
|
+
format?: string;
|
|
2737
|
+
}): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2738
|
+
try {
|
|
2739
|
+
const collector = getGlobalMetricsCollector();
|
|
2740
|
+
|
|
2741
|
+
// Get snapshot, optionally filtered
|
|
2742
|
+
const snapshot = args.filter
|
|
2743
|
+
? collector.getMetricsByName(args.filter)
|
|
2744
|
+
: collector.getSnapshot();
|
|
2745
|
+
|
|
2746
|
+
// Format output
|
|
2747
|
+
let output: string;
|
|
2748
|
+
if (args.format === "prometheus") {
|
|
2749
|
+
output = collector.exportPrometheus();
|
|
2750
|
+
} else {
|
|
2751
|
+
output = JSON.stringify(snapshot, null, 2);
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
return {
|
|
2755
|
+
content: [
|
|
2756
|
+
{
|
|
2757
|
+
type: "text",
|
|
2758
|
+
text: output,
|
|
2759
|
+
},
|
|
2760
|
+
],
|
|
2761
|
+
};
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
throwMcpToolError(ErrorCode.InternalError, "metrics", error, "get metrics");
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
/**
|
|
2768
|
+
* Handle workflow.guide tool - Get context-aware workflow guidance
|
|
2769
|
+
*/
|
|
2770
|
+
async function handleWorkflowGuide(
|
|
2771
|
+
args: WorkflowGuideArgs
|
|
2772
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2773
|
+
try {
|
|
2774
|
+
// Validate phase is a valid WorkflowPhase
|
|
2775
|
+
const validPhases: WorkflowPhase[] = [
|
|
2776
|
+
"initial",
|
|
2777
|
+
"post-plan-creation",
|
|
2778
|
+
"post-gates-run",
|
|
2779
|
+
"pre-merge",
|
|
2780
|
+
"post-merge",
|
|
2781
|
+
"error-recovery",
|
|
2782
|
+
];
|
|
2783
|
+
|
|
2784
|
+
const phase = args.phase as WorkflowPhase;
|
|
2785
|
+
if (!validPhases.includes(phase)) {
|
|
2786
|
+
throw new McpError(
|
|
2787
|
+
ErrorCode.InvalidParams,
|
|
2788
|
+
`Invalid workflow phase: ${args.phase}. Valid phases: ${validPhases.join(", ")}`
|
|
2789
|
+
);
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
// Create workflow guide for the requested phase
|
|
2793
|
+
const guide: WorkflowGuide = createWorkflowGuide(phase);
|
|
2794
|
+
|
|
2795
|
+
return {
|
|
2796
|
+
content: [
|
|
2797
|
+
{
|
|
2798
|
+
type: "text",
|
|
2799
|
+
text: JSON.stringify(guide, null, 2),
|
|
2800
|
+
},
|
|
2801
|
+
],
|
|
2802
|
+
};
|
|
2803
|
+
} catch (error) {
|
|
2804
|
+
if (error instanceof McpError) {
|
|
2805
|
+
throw error;
|
|
2806
|
+
}
|
|
2807
|
+
throwMcpToolError(ErrorCode.InternalError, "workflow.guide", error, "get workflow guide");
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2812
|
+
// Task Handoff Tool Handlers (ADR-007)
|
|
2813
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2814
|
+
|
|
2815
|
+
/**
|
|
2816
|
+
* In-memory task store for MCP session
|
|
2817
|
+
* In production, this should use RunStore or a dedicated task store
|
|
2818
|
+
*/
|
|
2819
|
+
const taskStore = new Map<
|
|
2820
|
+
string,
|
|
2821
|
+
{
|
|
2822
|
+
snapshot: TaskSnapshot_v1;
|
|
2823
|
+
receipt?: TaskReceipt_v1;
|
|
2824
|
+
verification?: any;
|
|
2825
|
+
state: "pending" | "in_progress" | "completed" | "verified" | "failed";
|
|
2826
|
+
}
|
|
2827
|
+
>();
|
|
2828
|
+
|
|
2829
|
+
/**
|
|
2830
|
+
* Handle create_task_snapshot tool
|
|
2831
|
+
*/
|
|
2832
|
+
async function handleCreateTaskSnapshot(
|
|
2833
|
+
args: CreateTaskSnapshotArgs
|
|
2834
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2835
|
+
try {
|
|
2836
|
+
// Validate args
|
|
2837
|
+
const validated = CreateTaskSnapshotArgs.parse(args);
|
|
2838
|
+
|
|
2839
|
+
// Auto-detect git info if not provided
|
|
2840
|
+
const gitOps = createGitOperations();
|
|
2841
|
+
const repoRoot = validated.repoRoot || process.cwd();
|
|
2842
|
+
const commitSha = validated.commitSha || (await gitOps.getCurrentHead());
|
|
2843
|
+
|
|
2844
|
+
// Auto-detect repoId if not provided
|
|
2845
|
+
let repoId = validated.repoId;
|
|
2846
|
+
if (!repoId) {
|
|
2847
|
+
try {
|
|
2848
|
+
const githubAPI = await createGitHubAPI();
|
|
2849
|
+
if (githubAPI) {
|
|
2850
|
+
repoId = `${githubAPI.config.owner}/${githubAPI.config.repo}`;
|
|
2851
|
+
} else {
|
|
2852
|
+
repoId = "unknown/unknown";
|
|
2853
|
+
}
|
|
2854
|
+
} catch {
|
|
2855
|
+
repoId = "unknown/unknown";
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
// Generate task ID if not provided
|
|
2860
|
+
const taskId = validated.taskId || ulid();
|
|
2861
|
+
|
|
2862
|
+
// Build snapshot using SnapshotBuilder
|
|
2863
|
+
const builder = new SnapshotBuilder({
|
|
2864
|
+
repoRoot,
|
|
2865
|
+
repoId,
|
|
2866
|
+
});
|
|
2867
|
+
|
|
2868
|
+
const snapshot = await builder.buildSnapshot({
|
|
2869
|
+
taskId,
|
|
2870
|
+
procedure: validated.procedure,
|
|
2871
|
+
determinism: validated.determinism as "D1" | "D2" | "D3" | undefined,
|
|
2872
|
+
targetFiles: validated.targetFiles,
|
|
2873
|
+
failure: {
|
|
2874
|
+
message: validated.failureMessage,
|
|
2875
|
+
fileRel: validated.failureFileRel,
|
|
2876
|
+
line: validated.failureLine,
|
|
2877
|
+
runnerOutputSnip: validated.runnerOutputSnip,
|
|
2878
|
+
excerpt: validated.failureExcerpt,
|
|
2879
|
+
},
|
|
2880
|
+
commitSha,
|
|
2881
|
+
verificationCmd: validated.verificationCmd,
|
|
2882
|
+
expectedExitCode: validated.expectedExitCode,
|
|
2883
|
+
});
|
|
2884
|
+
|
|
2885
|
+
// Store snapshot in task store
|
|
2886
|
+
taskStore.set(taskId, {
|
|
2887
|
+
snapshot,
|
|
2888
|
+
state: "pending",
|
|
2889
|
+
});
|
|
2890
|
+
|
|
2891
|
+
const result: CreateTaskSnapshotResult = {
|
|
2892
|
+
snapshot,
|
|
2893
|
+
taskId,
|
|
2894
|
+
};
|
|
2895
|
+
|
|
2896
|
+
return {
|
|
2897
|
+
content: [
|
|
2898
|
+
{
|
|
2899
|
+
type: "text",
|
|
2900
|
+
text: JSON.stringify(result, null, 2),
|
|
2901
|
+
},
|
|
2902
|
+
],
|
|
2903
|
+
};
|
|
2904
|
+
} catch (error) {
|
|
2905
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2906
|
+
const axError = mcpToolError(
|
|
2907
|
+
ErrorCodes.INVALID_INPUT,
|
|
2908
|
+
`Invalid create_task_snapshot parameters: ${error.message}`,
|
|
2909
|
+
{
|
|
2910
|
+
tool: "create_task_snapshot",
|
|
2911
|
+
operation: "validate parameters",
|
|
2912
|
+
}
|
|
2913
|
+
);
|
|
2914
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2915
|
+
}
|
|
2916
|
+
throwMcpToolError(
|
|
2917
|
+
ErrorCode.InternalError,
|
|
2918
|
+
"create_task_snapshot",
|
|
2919
|
+
error,
|
|
2920
|
+
"create task snapshot"
|
|
2921
|
+
);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
/**
|
|
2926
|
+
* Handle submit_task_receipt tool
|
|
2927
|
+
*/
|
|
2928
|
+
async function handleSubmitTaskReceipt(
|
|
2929
|
+
args: SubmitTaskReceiptArgs
|
|
2930
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
2931
|
+
try {
|
|
2932
|
+
// Validate args
|
|
2933
|
+
const validated = SubmitTaskReceiptArgs.parse(args);
|
|
2934
|
+
|
|
2935
|
+
// Parse and validate receipt
|
|
2936
|
+
const receipt = parseTaskReceipt(validated.receipt);
|
|
2937
|
+
|
|
2938
|
+
// Find corresponding snapshot
|
|
2939
|
+
const taskData = taskStore.get(receipt.task_id);
|
|
2940
|
+
if (!taskData) {
|
|
2941
|
+
const axError = mcpToolError(
|
|
2942
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
2943
|
+
`Task not found: ${receipt.task_id}. Create snapshot first using create_task_snapshot.`,
|
|
2944
|
+
{
|
|
2945
|
+
tool: "submit_task_receipt",
|
|
2946
|
+
details: { taskId: receipt.task_id },
|
|
2947
|
+
}
|
|
2948
|
+
);
|
|
2949
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
// Update state
|
|
2953
|
+
taskData.state = "in_progress";
|
|
2954
|
+
taskData.receipt = receipt;
|
|
2955
|
+
|
|
2956
|
+
// Run engine verification
|
|
2957
|
+
const verifier = new EngineVerifier();
|
|
2958
|
+
const verificationResult = await verifier.verify({
|
|
2959
|
+
snapshot: taskData.snapshot,
|
|
2960
|
+
receipt,
|
|
2961
|
+
workingDir: taskData.snapshot.repo.root,
|
|
2962
|
+
applyPatch: true,
|
|
2963
|
+
});
|
|
2964
|
+
|
|
2965
|
+
// Update task with verification
|
|
2966
|
+
taskData.verification = verificationResult.verification;
|
|
2967
|
+
taskData.state = verificationResult.verification.verified ? "verified" : "failed";
|
|
2968
|
+
|
|
2969
|
+
const result: SubmitTaskReceiptResult = {
|
|
2970
|
+
acknowledged: true,
|
|
2971
|
+
taskId: receipt.task_id,
|
|
2972
|
+
verification: {
|
|
2973
|
+
verified: verificationResult.verification.verified,
|
|
2974
|
+
trustGap: verificationResult.trustGap,
|
|
2975
|
+
patchApplied: verificationResult.patchApplied,
|
|
2976
|
+
},
|
|
2977
|
+
};
|
|
2978
|
+
|
|
2979
|
+
return {
|
|
2980
|
+
content: [
|
|
2981
|
+
{
|
|
2982
|
+
type: "text",
|
|
2983
|
+
text: JSON.stringify(result, null, 2),
|
|
2984
|
+
},
|
|
2985
|
+
],
|
|
2986
|
+
};
|
|
2987
|
+
} catch (error) {
|
|
2988
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
2989
|
+
const axError = mcpToolError(
|
|
2990
|
+
ErrorCodes.INVALID_INPUT,
|
|
2991
|
+
`Invalid submit_task_receipt parameters: ${error.message}`,
|
|
2992
|
+
{
|
|
2993
|
+
tool: "submit_task_receipt",
|
|
2994
|
+
operation: "validate parameters",
|
|
2995
|
+
}
|
|
2996
|
+
);
|
|
2997
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
2998
|
+
}
|
|
2999
|
+
throwMcpToolError(ErrorCode.InternalError, "submit_task_receipt", error, "submit task receipt");
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
/**
|
|
3004
|
+
* Handle get_task_status tool
|
|
3005
|
+
*/
|
|
3006
|
+
async function handleGetTaskStatus(
|
|
3007
|
+
args: GetTaskStatusArgs
|
|
3008
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
3009
|
+
try {
|
|
3010
|
+
// Validate args
|
|
3011
|
+
const validated = GetTaskStatusArgs.parse(args);
|
|
3012
|
+
|
|
3013
|
+
// Find task
|
|
3014
|
+
const taskData = taskStore.get(validated.taskId);
|
|
3015
|
+
if (!taskData) {
|
|
3016
|
+
const axError = mcpToolError(
|
|
3017
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
3018
|
+
`Task not found: ${validated.taskId}`,
|
|
3019
|
+
{
|
|
3020
|
+
tool: "get_task_status",
|
|
3021
|
+
details: { taskId: validated.taskId },
|
|
3022
|
+
}
|
|
3023
|
+
);
|
|
3024
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
const result: GetTaskStatusResult = {
|
|
3028
|
+
taskId: validated.taskId,
|
|
3029
|
+
state: taskData.state,
|
|
3030
|
+
snapshot: taskData.snapshot,
|
|
3031
|
+
receipt: taskData.receipt,
|
|
3032
|
+
verification: taskData.verification,
|
|
3033
|
+
};
|
|
3034
|
+
|
|
3035
|
+
return {
|
|
3036
|
+
content: [
|
|
3037
|
+
{
|
|
3038
|
+
type: "text",
|
|
3039
|
+
text: JSON.stringify(result, null, 2),
|
|
3040
|
+
},
|
|
3041
|
+
],
|
|
3042
|
+
};
|
|
3043
|
+
} catch (error) {
|
|
3044
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
3045
|
+
const axError = mcpToolError(
|
|
3046
|
+
ErrorCodes.INVALID_INPUT,
|
|
3047
|
+
`Invalid get_task_status parameters: ${error.message}`,
|
|
3048
|
+
{ tool: "get_task_status", operation: "validate parameters" }
|
|
3049
|
+
);
|
|
3050
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3051
|
+
}
|
|
3052
|
+
throwMcpToolError(ErrorCode.InternalError, "get_task_status", error, "get task status");
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
/**
|
|
3057
|
+
* Handle list_pending_tasks tool
|
|
3058
|
+
*/
|
|
3059
|
+
async function handleListPendingTasks(
|
|
3060
|
+
args: ListPendingTasksArgs
|
|
3061
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
3062
|
+
try {
|
|
3063
|
+
// Validate args
|
|
3064
|
+
const validated = ListPendingTasksArgs.parse(args);
|
|
3065
|
+
|
|
3066
|
+
// Filter tasks
|
|
3067
|
+
const tasks: ListPendingTasksResult["tasks"] = [];
|
|
3068
|
+
for (const [taskId, taskData] of taskStore.entries()) {
|
|
3069
|
+
// Apply filters
|
|
3070
|
+
if (validated.procedure && taskData.snapshot.procedure !== validated.procedure) {
|
|
3071
|
+
continue;
|
|
3072
|
+
}
|
|
3073
|
+
if (validated.determinism && taskData.snapshot.determinism !== validated.determinism) {
|
|
3074
|
+
continue;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
tasks.push({
|
|
3078
|
+
taskId,
|
|
3079
|
+
procedure: taskData.snapshot.procedure,
|
|
3080
|
+
determinism: taskData.snapshot.determinism,
|
|
3081
|
+
state: taskData.state,
|
|
3082
|
+
snapshot: taskData.snapshot,
|
|
3083
|
+
});
|
|
3084
|
+
|
|
3085
|
+
// Apply limit
|
|
3086
|
+
if (validated.limit && tasks.length >= validated.limit) {
|
|
3087
|
+
break;
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
const result: ListPendingTasksResult = {
|
|
3092
|
+
tasks,
|
|
3093
|
+
total: tasks.length,
|
|
3094
|
+
};
|
|
3095
|
+
|
|
3096
|
+
return {
|
|
3097
|
+
content: [
|
|
3098
|
+
{
|
|
3099
|
+
type: "text",
|
|
3100
|
+
text: JSON.stringify(result, null, 2),
|
|
3101
|
+
},
|
|
3102
|
+
],
|
|
3103
|
+
};
|
|
3104
|
+
} catch (error) {
|
|
3105
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
3106
|
+
const axError = mcpToolError(
|
|
3107
|
+
ErrorCodes.INVALID_INPUT,
|
|
3108
|
+
`Invalid list_pending_tasks parameters: ${error.message}`,
|
|
3109
|
+
{ tool: "list_pending_tasks", operation: "validate parameters" }
|
|
3110
|
+
);
|
|
3111
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3112
|
+
}
|
|
3113
|
+
throwMcpToolError(ErrorCode.InternalError, "list_pending_tasks", error, "list pending tasks");
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
// =============================================================================
|
|
3118
|
+
// Fanout AX Handlers (Epic #654 Layer 2)
|
|
3119
|
+
// =============================================================================
|
|
3120
|
+
|
|
3121
|
+
/**
|
|
3122
|
+
* Handle fanout_harvest tool
|
|
3123
|
+
* D0: Harvest external state from GitHub into a deterministic, replayable HarvestBundle
|
|
3124
|
+
*/
|
|
3125
|
+
async function handleFanoutHarvest(
|
|
3126
|
+
args: FanoutHarvestArgs
|
|
3127
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
3128
|
+
try {
|
|
3129
|
+
// Validate args
|
|
3130
|
+
const validated = FanoutHarvestArgs.parse(args);
|
|
3131
|
+
|
|
3132
|
+
// Check for GitHub authentication
|
|
3133
|
+
ensureGitHubToken(validated.githubToken);
|
|
3134
|
+
|
|
3135
|
+
// Create GitHub API
|
|
3136
|
+
let githubAPI = await createGitHubAPI();
|
|
3137
|
+
|
|
3138
|
+
// Override with arguments if provided
|
|
3139
|
+
if (validated.owner && validated.repo) {
|
|
3140
|
+
githubAPI = new GitHubAPI({
|
|
3141
|
+
owner: validated.owner,
|
|
3142
|
+
repo: validated.repo,
|
|
3143
|
+
token: validated.githubToken || process.env.GITHUB_TOKEN,
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
if (!githubAPI) {
|
|
3148
|
+
const axError = githubApiError({
|
|
3149
|
+
message:
|
|
3150
|
+
"Could not detect GitHub repository. Provide owner and repo parameters or run from a git repository with GitHub remote.",
|
|
3151
|
+
});
|
|
3152
|
+
throwMcpAXError(ErrorCode.InvalidRequest, axError);
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
const timestamp = new Date().toISOString();
|
|
3156
|
+
const state = validated.state || "open";
|
|
3157
|
+
const maxBody = validated.maxBody || 4096;
|
|
3158
|
+
const includeIssues = validated.includeIssues ?? false;
|
|
3159
|
+
|
|
3160
|
+
// Compute input digest for replay verification
|
|
3161
|
+
const inputDigest = crypto
|
|
3162
|
+
.createHash("sha256")
|
|
3163
|
+
.update(
|
|
3164
|
+
JSON.stringify({
|
|
3165
|
+
owner: githubAPI.config.owner,
|
|
3166
|
+
repo: githubAPI.config.repo,
|
|
3167
|
+
state,
|
|
3168
|
+
timestamp,
|
|
3169
|
+
})
|
|
3170
|
+
)
|
|
3171
|
+
.digest("hex");
|
|
3172
|
+
|
|
3173
|
+
// Fetch repository info
|
|
3174
|
+
const repoInfo = await githubAPI.getRepository();
|
|
3175
|
+
const defaultBranch = repoInfo.default_branch;
|
|
3176
|
+
const defaultBranchRef = await githubAPI.getRef(`heads/${defaultBranch}`);
|
|
3177
|
+
|
|
3178
|
+
const repository = {
|
|
3179
|
+
owner: githubAPI.config.owner,
|
|
3180
|
+
name: githubAPI.config.repo,
|
|
3181
|
+
defaultBranch,
|
|
3182
|
+
defaultBranchSha: defaultBranchRef.object.sha,
|
|
3183
|
+
};
|
|
3184
|
+
|
|
3185
|
+
// Fetch pull requests
|
|
3186
|
+
const rawPRs = await githubAPI.discoverPullRequests(state);
|
|
3187
|
+
const pullRequests = await Promise.all(
|
|
3188
|
+
rawPRs.map(async (pr: any) => {
|
|
3189
|
+
// Get merge base SHA
|
|
3190
|
+
let mergeBaseSha: string | "unknown" | "unavailable" = "unknown";
|
|
3191
|
+
try {
|
|
3192
|
+
const comparison = await githubAPI.compare(pr.baseBranch, pr.sha);
|
|
3193
|
+
mergeBaseSha = comparison.merge_base_commit?.sha ?? "unavailable";
|
|
3194
|
+
} catch {
|
|
3195
|
+
mergeBaseSha = "unavailable";
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
// Determine CI status
|
|
3199
|
+
let ciStatus: "pass" | "fail" | "pending" | "unknown" | "unavailable" = "unknown";
|
|
3200
|
+
try {
|
|
3201
|
+
const checks = await githubAPI.getCheckRuns(pr.sha);
|
|
3202
|
+
if (checks.total_count === 0) {
|
|
3203
|
+
ciStatus = "pending";
|
|
3204
|
+
} else {
|
|
3205
|
+
const allComplete = checks.check_runs.every((c: any) => c.status === "completed");
|
|
3206
|
+
if (!allComplete) {
|
|
3207
|
+
ciStatus = "pending";
|
|
3208
|
+
} else {
|
|
3209
|
+
const anyFailed = checks.check_runs.some(
|
|
3210
|
+
(c: any) => c.conclusion !== "success" && c.conclusion !== "skipped"
|
|
3211
|
+
);
|
|
3212
|
+
ciStatus = anyFailed ? "fail" : "pass";
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
} catch {
|
|
3216
|
+
ciStatus = "unavailable";
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
// Determine review status
|
|
3220
|
+
let reviewStatus:
|
|
3221
|
+
| "approved"
|
|
3222
|
+
| "changes_requested"
|
|
3223
|
+
| "pending"
|
|
3224
|
+
| "none"
|
|
3225
|
+
| "unknown"
|
|
3226
|
+
| "unavailable" = "unknown";
|
|
3227
|
+
try {
|
|
3228
|
+
const reviews = await githubAPI.getReviews(pr.number);
|
|
3229
|
+
const latestByUser = new Map<string, string>();
|
|
3230
|
+
for (const review of reviews) {
|
|
3231
|
+
if (review.state !== "COMMENTED" && review.user?.login) {
|
|
3232
|
+
latestByUser.set(review.user.login, review.state);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
const states = Array.from(latestByUser.values());
|
|
3236
|
+
if (states.includes("CHANGES_REQUESTED")) {
|
|
3237
|
+
reviewStatus = "changes_requested";
|
|
3238
|
+
} else if (states.includes("APPROVED")) {
|
|
3239
|
+
reviewStatus = "approved";
|
|
3240
|
+
} else if (states.length > 0) {
|
|
3241
|
+
reviewStatus = "pending";
|
|
3242
|
+
} else {
|
|
3243
|
+
reviewStatus = "none";
|
|
3244
|
+
}
|
|
3245
|
+
} catch {
|
|
3246
|
+
reviewStatus = "unavailable";
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
// Determine conflict status
|
|
3250
|
+
let conflictStatus: "clean" | "conflicted" | "unknown" | "unavailable" = "unknown";
|
|
3251
|
+
if (pr.mergeable === true) {
|
|
3252
|
+
conflictStatus = "clean";
|
|
3253
|
+
} else if (pr.mergeable === false) {
|
|
3254
|
+
conflictStatus = "conflicted";
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
return {
|
|
3258
|
+
number: pr.number,
|
|
3259
|
+
title: pr.title,
|
|
3260
|
+
state: pr.state,
|
|
3261
|
+
draft: false,
|
|
3262
|
+
headSha: pr.sha,
|
|
3263
|
+
baseSha: "unavailable",
|
|
3264
|
+
mergeBaseSha,
|
|
3265
|
+
author: pr.author,
|
|
3266
|
+
labels: pr.labels,
|
|
3267
|
+
ciStatus,
|
|
3268
|
+
reviewStatus,
|
|
3269
|
+
conflictStatus,
|
|
3270
|
+
updatedAt: pr.updatedAt,
|
|
3271
|
+
body: "",
|
|
3272
|
+
changedFiles: "unknown",
|
|
3273
|
+
additions: "unknown",
|
|
3274
|
+
deletions: "unknown",
|
|
3275
|
+
};
|
|
3276
|
+
})
|
|
3277
|
+
);
|
|
3278
|
+
|
|
3279
|
+
// Fetch issues if requested
|
|
3280
|
+
let issues: Array<object> = [];
|
|
3281
|
+
if (includeIssues) {
|
|
3282
|
+
try {
|
|
3283
|
+
const rawIssues = await githubAPI.listIssues({ state });
|
|
3284
|
+
issues = rawIssues
|
|
3285
|
+
.filter((i: any) => !i.pull_request)
|
|
3286
|
+
.map((i: any) => {
|
|
3287
|
+
let body: string | "truncated" = i.body ?? "";
|
|
3288
|
+
if (body.length > maxBody) {
|
|
3289
|
+
body = "truncated";
|
|
3290
|
+
}
|
|
3291
|
+
return {
|
|
3292
|
+
number: i.number,
|
|
3293
|
+
title: i.title,
|
|
3294
|
+
state: i.state,
|
|
3295
|
+
author: i.user.login,
|
|
3296
|
+
labels: i.labels.map((l: any) => l.name),
|
|
3297
|
+
updatedAt: i.updated_at,
|
|
3298
|
+
body,
|
|
3299
|
+
assignees: i.assignees?.map((a: any) => a.login) ?? [],
|
|
3300
|
+
};
|
|
3301
|
+
});
|
|
3302
|
+
} catch {
|
|
3303
|
+
// Issues not critical - continue without them
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
const bundle = {
|
|
3308
|
+
repository,
|
|
3309
|
+
pullRequests,
|
|
3310
|
+
issues,
|
|
3311
|
+
harvestedAt: timestamp,
|
|
3312
|
+
};
|
|
3313
|
+
|
|
3314
|
+
const outputDigest = crypto.createHash("sha256").update(JSON.stringify(bundle)).digest("hex");
|
|
3315
|
+
|
|
3316
|
+
const result: FanoutHarvestResult = {
|
|
3317
|
+
schemaVersion: "1.0.0",
|
|
3318
|
+
phase: "D0",
|
|
3319
|
+
timestamp,
|
|
3320
|
+
inputDigest: `sha256:${inputDigest}`,
|
|
3321
|
+
bundle,
|
|
3322
|
+
outputDigest: `sha256:${outputDigest}`,
|
|
3323
|
+
};
|
|
3324
|
+
|
|
3325
|
+
console.error(
|
|
3326
|
+
`[mcp:fanout_harvest] harvested ${pullRequests.length} PRs, ${issues.length} issues from ${repository.owner}/${repository.name}`
|
|
3327
|
+
);
|
|
3328
|
+
|
|
3329
|
+
return {
|
|
3330
|
+
content: [
|
|
3331
|
+
{
|
|
3332
|
+
type: "text",
|
|
3333
|
+
text: JSON.stringify(result, null, 2),
|
|
3334
|
+
},
|
|
3335
|
+
],
|
|
3336
|
+
};
|
|
3337
|
+
} catch (error) {
|
|
3338
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
3339
|
+
const axError = mcpToolError(
|
|
3340
|
+
ErrorCodes.INVALID_INPUT,
|
|
3341
|
+
`Invalid fanout_harvest parameters: ${error.message}`,
|
|
3342
|
+
{ tool: "fanout_harvest", operation: "validate parameters" }
|
|
3343
|
+
);
|
|
3344
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3345
|
+
}
|
|
3346
|
+
if (error instanceof GitHubAPIError) {
|
|
3347
|
+
const axError = githubApiError({
|
|
3348
|
+
message: error.message,
|
|
3349
|
+
});
|
|
3350
|
+
throwMcpAXError(ErrorCode.InternalError, axError);
|
|
3351
|
+
}
|
|
3352
|
+
throwMcpToolError(ErrorCode.InternalError, "fanout_harvest", error, "harvest from GitHub");
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
/**
|
|
3357
|
+
* Handle fanout_analyze tool
|
|
3358
|
+
* D1: Analyze a HarvestBundle into a deterministic AnalysisPool with evidence IDs
|
|
3359
|
+
*/
|
|
3360
|
+
async function handleFanoutAnalyze(
|
|
3361
|
+
args: FanoutAnalyzeArgs
|
|
3362
|
+
): Promise<{ content: [{ type: "text"; text: string }] }> {
|
|
3363
|
+
try {
|
|
3364
|
+
// Validate args
|
|
3365
|
+
const validated = FanoutAnalyzeArgs.parse(args);
|
|
3366
|
+
|
|
3367
|
+
let harvest: any;
|
|
3368
|
+
|
|
3369
|
+
// Get harvest bundle from args or file
|
|
3370
|
+
if (validated.harvestBundle) {
|
|
3371
|
+
harvest = validated.harvestBundle;
|
|
3372
|
+
} else if (validated.fromFile) {
|
|
3373
|
+
if (!fs.existsSync(validated.fromFile)) {
|
|
3374
|
+
const axError = mcpToolError(
|
|
3375
|
+
ErrorCodes.PLAN_NOT_FOUND,
|
|
3376
|
+
`Harvest bundle file not found: ${validated.fromFile}`,
|
|
3377
|
+
{ tool: "fanout_analyze", operation: "load harvest bundle" }
|
|
3378
|
+
);
|
|
3379
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3380
|
+
}
|
|
3381
|
+
const content = fs.readFileSync(validated.fromFile, "utf-8");
|
|
3382
|
+
try {
|
|
3383
|
+
harvest = JSON.parse(content);
|
|
3384
|
+
} catch {
|
|
3385
|
+
const axError = mcpToolError(
|
|
3386
|
+
ErrorCodes.INVALID_INPUT,
|
|
3387
|
+
`Invalid JSON in harvest bundle file: ${validated.fromFile}`,
|
|
3388
|
+
{ tool: "fanout_analyze", operation: "parse harvest bundle" }
|
|
3389
|
+
);
|
|
3390
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3391
|
+
}
|
|
3392
|
+
} else {
|
|
3393
|
+
const axError = mcpToolError(
|
|
3394
|
+
ErrorCodes.INVALID_INPUT,
|
|
3395
|
+
"Either harvestBundle or fromFile must be provided",
|
|
3396
|
+
{ tool: "fanout_analyze", operation: "validate input" }
|
|
3397
|
+
);
|
|
3398
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
// Validate harvest bundle structure
|
|
3402
|
+
if (harvest.phase !== "D0") {
|
|
3403
|
+
const axError = mcpToolError(
|
|
3404
|
+
ErrorCodes.INVALID_INPUT,
|
|
3405
|
+
`Invalid input phase: ${harvest.phase}. Expected: D0 (HarvestBundle)`,
|
|
3406
|
+
{ tool: "fanout_analyze", operation: "validate phase" }
|
|
3407
|
+
);
|
|
3408
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
const timestamp = new Date().toISOString();
|
|
3412
|
+
const inputDigest = harvest.outputDigest;
|
|
3413
|
+
|
|
3414
|
+
// Deterministic analysis
|
|
3415
|
+
const entities: Array<object> = [];
|
|
3416
|
+
const relations: Array<object> = [];
|
|
3417
|
+
const conflicts: Array<object> = [];
|
|
3418
|
+
const blockers: Array<object> = [];
|
|
3419
|
+
|
|
3420
|
+
// Track PRs by number
|
|
3421
|
+
const prByNumber = new Map<number, any>();
|
|
3422
|
+
|
|
3423
|
+
// Process pull requests
|
|
3424
|
+
for (const pr of harvest.bundle.pullRequests) {
|
|
3425
|
+
prByNumber.set(pr.number, pr);
|
|
3426
|
+
const eid = `PR:${pr.number}`;
|
|
3427
|
+
|
|
3428
|
+
// Build facts
|
|
3429
|
+
const facts: Array<object> = [
|
|
3430
|
+
{ key: "title", value: pr.title, source: "api", confidence: "known" },
|
|
3431
|
+
{ key: "state", value: pr.state, source: "api", confidence: "known" },
|
|
3432
|
+
{ key: "author", value: pr.author, source: "api", confidence: "known" },
|
|
3433
|
+
{ key: "labels", value: pr.labels, source: "api", confidence: "known" },
|
|
3434
|
+
{ key: "head_sha", value: pr.headSha, source: "api", confidence: "known" },
|
|
3435
|
+
{ key: "updated_at", value: pr.updatedAt, source: "api", confidence: "known" },
|
|
3436
|
+
];
|
|
3437
|
+
|
|
3438
|
+
// CI status
|
|
3439
|
+
const ciConfidence = ["unknown", "unavailable"].includes(pr.ciStatus) ? pr.ciStatus : "known";
|
|
3440
|
+
facts.push({ key: "ci_status", value: pr.ciStatus, source: "api", confidence: ciConfidence });
|
|
3441
|
+
|
|
3442
|
+
// Review status
|
|
3443
|
+
const reviewConfidence = ["unknown", "unavailable"].includes(pr.reviewStatus)
|
|
3444
|
+
? pr.reviewStatus
|
|
3445
|
+
: "known";
|
|
3446
|
+
facts.push({
|
|
3447
|
+
key: "review_status",
|
|
3448
|
+
value: pr.reviewStatus,
|
|
3449
|
+
source: "api",
|
|
3450
|
+
confidence: reviewConfidence,
|
|
3451
|
+
});
|
|
3452
|
+
|
|
3453
|
+
// Conflict status
|
|
3454
|
+
const conflictConfidence = ["unknown", "unavailable"].includes(pr.conflictStatus)
|
|
3455
|
+
? pr.conflictStatus
|
|
3456
|
+
: "known";
|
|
3457
|
+
facts.push({
|
|
3458
|
+
key: "conflict_status",
|
|
3459
|
+
value: pr.conflictStatus,
|
|
3460
|
+
source: "api",
|
|
3461
|
+
confidence: conflictConfidence,
|
|
3462
|
+
});
|
|
3463
|
+
|
|
3464
|
+
entities.push({
|
|
3465
|
+
eid,
|
|
3466
|
+
type: "pull_request",
|
|
3467
|
+
ref: `#${pr.number}`,
|
|
3468
|
+
facts,
|
|
3469
|
+
});
|
|
3470
|
+
|
|
3471
|
+
// Detect blockers
|
|
3472
|
+
if (pr.ciStatus === "fail") {
|
|
3473
|
+
blockers.push({
|
|
3474
|
+
type: "ci_failed",
|
|
3475
|
+
entity: eid,
|
|
3476
|
+
reason: "CI checks failed",
|
|
3477
|
+
});
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
if (pr.reviewStatus === "changes_requested") {
|
|
3481
|
+
blockers.push({
|
|
3482
|
+
type: "review_rejected",
|
|
3483
|
+
entity: eid,
|
|
3484
|
+
reason: "Changes requested in review",
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
if (pr.conflictStatus === "conflicted") {
|
|
3489
|
+
conflicts.push({
|
|
3490
|
+
type: "merge_conflict",
|
|
3491
|
+
entities: [eid],
|
|
3492
|
+
resolution: "requires_rebase",
|
|
3493
|
+
});
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
if (pr.draft) {
|
|
3497
|
+
blockers.push({
|
|
3498
|
+
type: "draft",
|
|
3499
|
+
entity: eid,
|
|
3500
|
+
reason: "PR is in draft state",
|
|
3501
|
+
});
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// Process issues
|
|
3506
|
+
for (const issue of harvest.bundle.issues) {
|
|
3507
|
+
const eid = `ISSUE:${issue.number}`;
|
|
3508
|
+
|
|
3509
|
+
const facts: Array<object> = [
|
|
3510
|
+
{ key: "title", value: issue.title, source: "api", confidence: "known" },
|
|
3511
|
+
{ key: "state", value: issue.state, source: "api", confidence: "known" },
|
|
3512
|
+
{ key: "author", value: issue.author, source: "api", confidence: "known" },
|
|
3513
|
+
{ key: "labels", value: issue.labels, source: "api", confidence: "known" },
|
|
3514
|
+
{ key: "updated_at", value: issue.updatedAt, source: "api", confidence: "known" },
|
|
3515
|
+
];
|
|
3516
|
+
|
|
3517
|
+
entities.push({
|
|
3518
|
+
eid,
|
|
3519
|
+
type: "issue",
|
|
3520
|
+
ref: `#${issue.number}`,
|
|
3521
|
+
facts,
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
const pool = {
|
|
3526
|
+
entities,
|
|
3527
|
+
relations,
|
|
3528
|
+
conflicts,
|
|
3529
|
+
blockers,
|
|
3530
|
+
};
|
|
3531
|
+
|
|
3532
|
+
const outputDigest = crypto.createHash("sha256").update(JSON.stringify(pool)).digest("hex");
|
|
3533
|
+
|
|
3534
|
+
const result: FanoutAnalyzeResult = {
|
|
3535
|
+
schemaVersion: "1.0.0",
|
|
3536
|
+
phase: "D1",
|
|
3537
|
+
timestamp,
|
|
3538
|
+
inputDigest,
|
|
3539
|
+
pool,
|
|
3540
|
+
outputDigest: `sha256:${outputDigest}`,
|
|
3541
|
+
};
|
|
3542
|
+
|
|
3543
|
+
console.error(
|
|
3544
|
+
`[mcp:fanout_analyze] analyzed ${entities.length} entities, ${relations.length} relations, ${conflicts.length} conflicts, ${blockers.length} blockers`
|
|
3545
|
+
);
|
|
3546
|
+
|
|
3547
|
+
return {
|
|
3548
|
+
content: [
|
|
3549
|
+
{
|
|
3550
|
+
type: "text",
|
|
3551
|
+
text: JSON.stringify(result, null, 2),
|
|
3552
|
+
},
|
|
3553
|
+
],
|
|
3554
|
+
};
|
|
3555
|
+
} catch (error) {
|
|
3556
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
3557
|
+
const axError = mcpToolError(
|
|
3558
|
+
ErrorCodes.INVALID_INPUT,
|
|
3559
|
+
`Invalid fanout_analyze parameters: ${error.message}`,
|
|
3560
|
+
{ tool: "fanout_analyze", operation: "validate parameters" }
|
|
3561
|
+
);
|
|
3562
|
+
throwMcpAXError(ErrorCode.InvalidParams, axError);
|
|
3563
|
+
}
|
|
3564
|
+
throwMcpToolError(ErrorCode.InternalError, "fanout_analyze", error, "analyze harvest bundle");
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
// Handle uncaught errors
|
|
3569
|
+
process.on("uncaughtException", (error) => {
|
|
3570
|
+
console.error("Uncaught exception:", error);
|
|
3571
|
+
process.exit(1);
|
|
3572
|
+
});
|
|
3573
|
+
|
|
3574
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
3575
|
+
console.error("Unhandled rejection at:", promise, "reason:", reason);
|
|
3576
|
+
process.exit(1);
|
|
3577
|
+
});
|
|
3578
|
+
|
|
3579
|
+
// Start the server if run directly (ESM-only)
|
|
3580
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
3581
|
+
main().catch((error) => {
|
|
3582
|
+
console.error("Failed to start MCP server:", error);
|
|
3583
|
+
process.exit(1);
|
|
3584
|
+
});
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
export { createServer, main };
|