forgecraft-mcp 1.4.0 → 1.7.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/LICENSE +67 -0
- package/README.md +527 -525
- package/dist/analyzers/anchors/anchor-loader.d.ts +47 -0
- package/dist/analyzers/anchors/anchor-loader.d.ts.map +1 -0
- package/dist/analyzers/anchors/anchor-loader.js +113 -0
- package/dist/analyzers/anchors/anchor-loader.js.map +1 -0
- package/dist/analyzers/anti-pattern.d.ts.map +1 -1
- package/dist/analyzers/anti-pattern.js +38 -26
- package/dist/analyzers/anti-pattern.js.map +1 -1
- package/dist/analyzers/completeness-helpers.d.ts +5 -0
- package/dist/analyzers/completeness-helpers.d.ts.map +1 -1
- package/dist/analyzers/completeness-helpers.js +17 -0
- package/dist/analyzers/completeness-helpers.js.map +1 -1
- package/dist/analyzers/completeness.d.ts.map +1 -1
- package/dist/analyzers/completeness.js +4 -4
- package/dist/analyzers/completeness.js.map +1 -1
- package/dist/analyzers/gs-scorer.d.ts +3 -1
- package/dist/analyzers/gs-scorer.d.ts.map +1 -1
- package/dist/analyzers/gs-scorer.js +5 -2
- package/dist/analyzers/gs-scorer.js.map +1 -1
- package/dist/analyzers/package-json.d.ts.map +1 -1
- package/dist/analyzers/package-json.js +194 -34
- package/dist/analyzers/package-json.js.map +1 -1
- package/dist/analyzers/scorers/composable-scorer.d.ts +4 -2
- package/dist/analyzers/scorers/composable-scorer.d.ts.map +1 -1
- package/dist/analyzers/scorers/composable-scorer.js +50 -2
- package/dist/analyzers/scorers/composable-scorer.js.map +1 -1
- package/dist/analyzers/scorers/executable-scorer.d.ts +3 -2
- package/dist/analyzers/scorers/executable-scorer.d.ts.map +1 -1
- package/dist/analyzers/scorers/executable-scorer.js +64 -4
- package/dist/analyzers/scorers/executable-scorer.js.map +1 -1
- package/dist/analyzers/scorers/scorer-utils.d.ts +5 -3
- package/dist/analyzers/scorers/scorer-utils.d.ts.map +1 -1
- package/dist/analyzers/scorers/scorer-utils.js +34 -9
- package/dist/analyzers/scorers/scorer-utils.js.map +1 -1
- package/dist/analyzers/scorers/self-describing-scorer.d.ts +7 -4
- package/dist/analyzers/scorers/self-describing-scorer.d.ts.map +1 -1
- package/dist/analyzers/scorers/self-describing-scorer.js +17 -18
- package/dist/analyzers/scorers/self-describing-scorer.js.map +1 -1
- package/dist/cli/help.js +51 -51
- package/dist/disciplines/catalog.d.ts +16 -0
- package/dist/disciplines/catalog.d.ts.map +1 -0
- package/dist/disciplines/catalog.js +196 -0
- package/dist/disciplines/catalog.js.map +1 -0
- package/dist/disciplines/runner.d.ts +13 -0
- package/dist/disciplines/runner.d.ts.map +1 -0
- package/dist/disciplines/runner.js +35 -0
- package/dist/disciplines/runner.js.map +1 -0
- package/dist/registry/composer.d.ts.map +1 -1
- package/dist/registry/composer.js +9 -4
- package/dist/registry/composer.js.map +1 -1
- package/dist/registry/loader-tag.d.ts.map +1 -1
- package/dist/registry/loader-tag.js +1 -0
- package/dist/registry/loader-tag.js.map +1 -1
- package/dist/registry/remote-gates.js +1 -1
- package/dist/registry/remote-gates.js.map +1 -1
- package/dist/registry/renderer-skeletons.js +92 -92
- package/dist/registry/sentinel-renderer.js +299 -20
- package/dist/registry/sentinel-renderer.js.map +1 -1
- package/dist/sentinel/detect.d.ts +41 -0
- package/dist/sentinel/detect.d.ts.map +1 -0
- package/dist/sentinel/detect.js +122 -0
- package/dist/sentinel/detect.js.map +1 -0
- package/dist/sentinel/write.d.ts +54 -0
- package/dist/sentinel/write.d.ts.map +1 -0
- package/dist/sentinel/write.js +75 -0
- package/dist/sentinel/write.js.map +1 -0
- package/dist/shared/cnt-health.d.ts +16 -0
- package/dist/shared/cnt-health.d.ts.map +1 -1
- package/dist/shared/cnt-health.js +55 -8
- package/dist/shared/cnt-health.js.map +1 -1
- package/dist/shared/config.d.ts +14 -0
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +45 -0
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/gs-score-logger.js +6 -6
- package/dist/shared/hook-installer.d.ts +58 -0
- package/dist/shared/hook-installer.d.ts.map +1 -0
- package/dist/shared/hook-installer.js +316 -0
- package/dist/shared/hook-installer.js.map +1 -0
- package/dist/shared/project-gates-helpers.d.ts +9 -0
- package/dist/shared/project-gates-helpers.d.ts.map +1 -1
- package/dist/shared/project-gates-helpers.js +35 -0
- package/dist/shared/project-gates-helpers.js.map +1 -1
- package/dist/shared/types/config.d.ts +7 -1
- package/dist/shared/types/config.d.ts.map +1 -1
- package/dist/shared/types/gates.d.ts +34 -0
- package/dist/shared/types/gates.d.ts.map +1 -1
- package/dist/shared/types/project.d.ts +68 -2
- package/dist/shared/types/project.d.ts.map +1 -1
- package/dist/shared/types/project.js +1 -0
- package/dist/shared/types/project.js.map +1 -1
- package/dist/shared/types/templates.d.ts +8 -1
- package/dist/shared/types/templates.d.ts.map +1 -1
- package/dist/shared/types/verify.d.ts +51 -1
- package/dist/shared/types/verify.d.ts.map +1 -1
- package/dist/shared/types/verify.js +37 -1
- package/dist/shared/types/verify.js.map +1 -1
- package/dist/tools/add-hook.d.ts.map +1 -1
- package/dist/tools/add-hook.js +8 -1
- package/dist/tools/add-hook.js.map +1 -1
- package/dist/tools/add-module.js +123 -123
- package/dist/tools/advice-registry.d.ts.map +1 -1
- package/dist/tools/advice-registry.js +108 -18
- package/dist/tools/advice-registry.js.map +1 -1
- package/dist/tools/advise-session-advisor.d.ts +16 -0
- package/dist/tools/advise-session-advisor.d.ts.map +1 -0
- package/dist/tools/advise-session-advisor.js +89 -0
- package/dist/tools/advise-session-advisor.js.map +1 -0
- package/dist/tools/advise-session-signals.d.ts +21 -0
- package/dist/tools/advise-session-signals.d.ts.map +1 -0
- package/dist/tools/advise-session-signals.js +113 -0
- package/dist/tools/advise-session-signals.js.map +1 -0
- package/dist/tools/advise-session.d.ts +22 -0
- package/dist/tools/advise-session.d.ts.map +1 -0
- package/dist/tools/advise-session.js +31 -0
- package/dist/tools/advise-session.js.map +1 -0
- package/dist/tools/analyze-harness.d.ts +18 -0
- package/dist/tools/analyze-harness.d.ts.map +1 -0
- package/dist/tools/analyze-harness.js +298 -0
- package/dist/tools/analyze-harness.js.map +1 -0
- package/dist/tools/audit.d.ts.map +1 -1
- package/dist/tools/audit.js +19 -0
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/change-request.d.ts +53 -0
- package/dist/tools/change-request.d.ts.map +1 -0
- package/dist/tools/change-request.js +395 -0
- package/dist/tools/change-request.js.map +1 -0
- package/dist/tools/check-cascade-contracts.d.ts +13 -0
- package/dist/tools/check-cascade-contracts.d.ts.map +1 -1
- package/dist/tools/check-cascade-contracts.js +73 -2
- package/dist/tools/check-cascade-contracts.js.map +1 -1
- package/dist/tools/check-cascade-report.js +64 -64
- package/dist/tools/check-cascade-steps.d.ts +3 -0
- package/dist/tools/check-cascade-steps.d.ts.map +1 -1
- package/dist/tools/check-cascade-steps.js +104 -15
- package/dist/tools/check-cascade-steps.js.map +1 -1
- package/dist/tools/check-cascade.d.ts +4 -3
- package/dist/tools/check-cascade.d.ts.map +1 -1
- package/dist/tools/check-cascade.js +30 -12
- package/dist/tools/check-cascade.js.map +1 -1
- package/dist/tools/check-derivation-chain.d.ts +37 -0
- package/dist/tools/check-derivation-chain.d.ts.map +1 -0
- package/dist/tools/check-derivation-chain.js +418 -0
- package/dist/tools/check-derivation-chain.js.map +1 -0
- package/dist/tools/check-spec-consistency.d.ts +25 -0
- package/dist/tools/check-spec-consistency.d.ts.map +1 -0
- package/dist/tools/check-spec-consistency.js +339 -0
- package/dist/tools/check-spec-consistency.js.map +1 -0
- package/dist/tools/check-t4.d.ts +54 -0
- package/dist/tools/check-t4.d.ts.map +1 -0
- package/dist/tools/check-t4.js +305 -0
- package/dist/tools/check-t4.js.map +1 -0
- package/dist/tools/close-cycle.d.ts +11 -0
- package/dist/tools/close-cycle.d.ts.map +1 -1
- package/dist/tools/close-cycle.js +364 -4
- package/dist/tools/close-cycle.js.map +1 -1
- package/dist/tools/cnt-add-routing.d.ts +31 -0
- package/dist/tools/cnt-add-routing.d.ts.map +1 -0
- package/dist/tools/cnt-add-routing.js +99 -0
- package/dist/tools/cnt-add-routing.js.map +1 -0
- package/dist/tools/configure-mcp.d.ts.map +1 -1
- package/dist/tools/configure-mcp.js +52 -2
- package/dist/tools/configure-mcp.js.map +1 -1
- package/dist/tools/consolidate-status.d.ts +31 -0
- package/dist/tools/consolidate-status.d.ts.map +1 -1
- package/dist/tools/consolidate-status.js +105 -0
- package/dist/tools/consolidate-status.js.map +1 -1
- package/dist/tools/executable-gates.d.ts +52 -0
- package/dist/tools/executable-gates.d.ts.map +1 -0
- package/dist/tools/executable-gates.js +333 -0
- package/dist/tools/executable-gates.js.map +1 -0
- package/dist/tools/extract-adrs-from-spec.d.ts +33 -0
- package/dist/tools/extract-adrs-from-spec.d.ts.map +1 -0
- package/dist/tools/extract-adrs-from-spec.js +410 -0
- package/dist/tools/extract-adrs-from-spec.js.map +1 -0
- package/dist/tools/extract-adrs-history.d.ts +47 -0
- package/dist/tools/extract-adrs-history.d.ts.map +1 -0
- package/dist/tools/extract-adrs-history.js +265 -0
- package/dist/tools/extract-adrs-history.js.map +1 -0
- package/dist/tools/forgecraft-dispatch-extended.d.ts.map +1 -1
- package/dist/tools/forgecraft-dispatch-extended.js +137 -0
- package/dist/tools/forgecraft-dispatch-extended.js.map +1 -1
- package/dist/tools/forgecraft-dispatch.d.ts.map +1 -1
- package/dist/tools/forgecraft-dispatch.js +16 -0
- package/dist/tools/forgecraft-dispatch.js.map +1 -1
- package/dist/tools/forgecraft-schema-params.d.ts +174 -2
- package/dist/tools/forgecraft-schema-params.d.ts.map +1 -1
- package/dist/tools/forgecraft-schema-params.js +197 -0
- package/dist/tools/forgecraft-schema-params.js.map +1 -1
- package/dist/tools/forgecraft-schema.d.ts +179 -7
- package/dist/tools/forgecraft-schema.d.ts.map +1 -1
- package/dist/tools/forgecraft-schema.js +37 -0
- package/dist/tools/forgecraft-schema.js.map +1 -1
- package/dist/tools/generate-adr.js +6 -6
- package/dist/tools/generate-adr.js.map +1 -1
- package/dist/tools/generate-decision.d.ts +77 -0
- package/dist/tools/generate-decision.d.ts.map +1 -0
- package/dist/tools/generate-decision.js +162 -0
- package/dist/tools/generate-decision.js.map +1 -0
- package/dist/tools/generate-env-probe.d.ts +49 -0
- package/dist/tools/generate-env-probe.d.ts.map +1 -0
- package/dist/tools/generate-env-probe.js +365 -0
- package/dist/tools/generate-env-probe.js.map +1 -0
- package/dist/tools/generate-harness.d.ts +53 -0
- package/dist/tools/generate-harness.d.ts.map +1 -0
- package/dist/tools/generate-harness.js +395 -0
- package/dist/tools/generate-harness.js.map +1 -0
- package/dist/tools/generate-roadmap.d.ts +1 -1
- package/dist/tools/generate-roadmap.d.ts.map +1 -1
- package/dist/tools/generate-roadmap.js +38 -4
- package/dist/tools/generate-roadmap.js.map +1 -1
- package/dist/tools/generate-session-prompt.d.ts +3 -3
- package/dist/tools/generate-session-prompt.d.ts.map +1 -1
- package/dist/tools/generate-session-prompt.js +9 -1
- package/dist/tools/generate-session-prompt.js.map +1 -1
- package/dist/tools/generate-slo-probe.d.ts +53 -0
- package/dist/tools/generate-slo-probe.d.ts.map +1 -0
- package/dist/tools/generate-slo-probe.js +366 -0
- package/dist/tools/generate-slo-probe.js.map +1 -0
- package/dist/tools/layer-status-gates.d.ts +24 -0
- package/dist/tools/layer-status-gates.d.ts.map +1 -0
- package/dist/tools/layer-status-gates.js +151 -0
- package/dist/tools/layer-status-gates.js.map +1 -0
- package/dist/tools/layer-status.d.ts +126 -0
- package/dist/tools/layer-status.d.ts.map +1 -0
- package/dist/tools/layer-status.js +647 -0
- package/dist/tools/layer-status.js.map +1 -0
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +9 -5
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/postcondition-coverage.d.ts +57 -0
- package/dist/tools/postcondition-coverage.d.ts.map +1 -0
- package/dist/tools/postcondition-coverage.js +256 -0
- package/dist/tools/postcondition-coverage.js.map +1 -0
- package/dist/tools/probe-runners.d.ts +21 -0
- package/dist/tools/probe-runners.d.ts.map +1 -0
- package/dist/tools/probe-runners.js +246 -0
- package/dist/tools/probe-runners.js.map +1 -0
- package/dist/tools/probe-templates.d.ts +27 -0
- package/dist/tools/probe-templates.d.ts.map +1 -0
- package/dist/tools/probe-templates.js +279 -0
- package/dist/tools/probe-templates.js.map +1 -0
- package/dist/tools/propose-session.d.ts +28 -0
- package/dist/tools/propose-session.d.ts.map +1 -0
- package/dist/tools/propose-session.js +333 -0
- package/dist/tools/propose-session.js.map +1 -0
- package/dist/tools/refresh-output.js +14 -14
- package/dist/tools/review-stubs.d.ts +29 -0
- package/dist/tools/review-stubs.d.ts.map +1 -0
- package/dist/tools/review-stubs.js +173 -0
- package/dist/tools/review-stubs.js.map +1 -0
- package/dist/tools/roadmap-builder.d.ts +49 -1
- package/dist/tools/roadmap-builder.d.ts.map +1 -1
- package/dist/tools/roadmap-builder.js +210 -5
- package/dist/tools/roadmap-builder.js.map +1 -1
- package/dist/tools/run-env-probe.d.ts +57 -0
- package/dist/tools/run-env-probe.d.ts.map +1 -0
- package/dist/tools/run-env-probe.js +270 -0
- package/dist/tools/run-env-probe.js.map +1 -0
- package/dist/tools/run-harness.d.ts +52 -0
- package/dist/tools/run-harness.d.ts.map +1 -0
- package/dist/tools/run-harness.js +279 -0
- package/dist/tools/run-harness.js.map +1 -0
- package/dist/tools/run-slo-probe.d.ts +50 -0
- package/dist/tools/run-slo-probe.d.ts.map +1 -0
- package/dist/tools/run-slo-probe.js +281 -0
- package/dist/tools/run-slo-probe.js.map +1 -0
- package/dist/tools/scaffold-spec-stubs.js +115 -115
- package/dist/tools/scaffold-templates.js +62 -62
- package/dist/tools/scaffold-writer.d.ts.map +1 -1
- package/dist/tools/scaffold-writer.js +9 -0
- package/dist/tools/scaffold-writer.js.map +1 -1
- package/dist/tools/score-rubric.d.ts +19 -0
- package/dist/tools/score-rubric.d.ts.map +1 -0
- package/dist/tools/score-rubric.js +411 -0
- package/dist/tools/score-rubric.js.map +1 -0
- package/dist/tools/session-prompt-builders.d.ts +20 -0
- package/dist/tools/session-prompt-builders.d.ts.map +1 -1
- package/dist/tools/session-prompt-builders.js +78 -5
- package/dist/tools/session-prompt-builders.js.map +1 -1
- package/dist/tools/session-prompt-sections.d.ts +4 -2
- package/dist/tools/session-prompt-sections.d.ts.map +1 -1
- package/dist/tools/session-prompt-sections.js +22 -10
- package/dist/tools/session-prompt-sections.js.map +1 -1
- package/dist/tools/setup-artifact-writers.d.ts +69 -4
- package/dist/tools/setup-artifact-writers.d.ts.map +1 -1
- package/dist/tools/setup-artifact-writers.js +681 -5
- package/dist/tools/setup-artifact-writers.js.map +1 -1
- package/dist/tools/setup-cnt-builders.d.ts.map +1 -1
- package/dist/tools/setup-cnt-builders.js +162 -34
- package/dist/tools/setup-cnt-builders.js.map +1 -1
- package/dist/tools/setup-monitoring.d.ts +41 -0
- package/dist/tools/setup-monitoring.d.ts.map +1 -0
- package/dist/tools/setup-monitoring.js +364 -0
- package/dist/tools/setup-monitoring.js.map +1 -0
- package/dist/tools/setup-phase1.d.ts.map +1 -1
- package/dist/tools/setup-phase1.js +14 -1
- package/dist/tools/setup-phase1.js.map +1 -1
- package/dist/tools/setup-phase2.d.ts +14 -0
- package/dist/tools/setup-phase2.d.ts.map +1 -1
- package/dist/tools/setup-phase2.js +130 -3
- package/dist/tools/setup-phase2.js.map +1 -1
- package/dist/tools/setup-project.d.ts +8 -0
- package/dist/tools/setup-project.d.ts.map +1 -1
- package/dist/tools/setup-project.js +52 -2
- package/dist/tools/setup-project.js.map +1 -1
- package/dist/tools/spec-parser-tags.d.ts.map +1 -1
- package/dist/tools/spec-parser-tags.js +1 -0
- package/dist/tools/spec-parser-tags.js.map +1 -1
- package/dist/tools/verify-formatter.d.ts.map +1 -1
- package/dist/tools/verify-formatter.js +15 -1
- package/dist/tools/verify-formatter.js.map +1 -1
- package/dist/tools/verify.d.ts.map +1 -1
- package/dist/tools/verify.js +3 -0
- package/dist/tools/verify.js.map +1 -1
- package/package.json +98 -89
- package/templates/analytics/instructions.yaml +37 -37
- package/templates/analytics/mcp-servers.yaml +11 -11
- package/templates/analytics/structure.yaml +25 -25
- package/templates/api/harness/uc-template.hurl +20 -0
- package/templates/api/instructions.yaml +231 -231
- package/templates/api/mcp-servers.yaml +22 -22
- package/templates/api/nfr.yaml +23 -23
- package/templates/api/review.yaml +103 -103
- package/templates/api/structure.yaml +34 -34
- package/templates/api/verification.yaml +132 -132
- package/templates/cli/instructions.yaml +31 -31
- package/templates/cli/mcp-servers.yaml +11 -11
- package/templates/cli/review.yaml +53 -53
- package/templates/cli/structure.yaml +16 -16
- package/templates/data-lineage/instructions.yaml +28 -28
- package/templates/data-lineage/mcp-servers.yaml +22 -22
- package/templates/data-pipeline/instructions.yaml +84 -84
- package/templates/data-pipeline/mcp-servers.yaml +13 -13
- package/templates/data-pipeline/nfr.yaml +39 -39
- package/templates/data-pipeline/structure.yaml +23 -23
- package/templates/docs-manifest.yaml +227 -0
- package/templates/fintech/hooks.yaml +55 -55
- package/templates/fintech/instructions.yaml +112 -112
- package/templates/fintech/mcp-servers.yaml +13 -13
- package/templates/fintech/nfr.yaml +46 -46
- package/templates/fintech/playbook.yaml +210 -210
- package/templates/fintech/verification.yaml +239 -239
- package/templates/game/harness/uc-template.sim.ts +29 -0
- package/templates/game/instructions.yaml +289 -289
- package/templates/game/mcp-servers.yaml +38 -38
- package/templates/game/nfr.yaml +64 -64
- package/templates/game/playbook.yaml +214 -214
- package/templates/game/review.yaml +97 -97
- package/templates/game/structure.yaml +67 -67
- package/templates/game/verification.yaml +174 -174
- package/templates/healthcare/instructions.yaml +42 -42
- package/templates/healthcare/mcp-servers.yaml +13 -13
- package/templates/healthcare/nfr.yaml +47 -47
- package/templates/hipaa/instructions.yaml +41 -41
- package/templates/hipaa/mcp-servers.yaml +13 -13
- package/templates/infra/instructions.yaml +104 -104
- package/templates/infra/mcp-servers.yaml +20 -20
- package/templates/infra/nfr.yaml +46 -46
- package/templates/infra/review.yaml +65 -65
- package/templates/infra/structure.yaml +25 -25
- package/templates/library/instructions.yaml +36 -36
- package/templates/library/mcp-servers.yaml +20 -20
- package/templates/library/review.yaml +56 -56
- package/templates/library/structure.yaml +19 -19
- package/templates/medallion-architecture/instructions.yaml +41 -41
- package/templates/medallion-architecture/mcp-servers.yaml +22 -22
- package/templates/ml/instructions.yaml +85 -85
- package/templates/ml/mcp-servers.yaml +11 -11
- package/templates/ml/nfr.yaml +39 -39
- package/templates/ml/structure.yaml +25 -25
- package/templates/ml/verification.yaml +156 -156
- package/templates/mobile/instructions.yaml +44 -44
- package/templates/mobile/mcp-servers.yaml +11 -11
- package/templates/mobile/nfr.yaml +49 -49
- package/templates/mobile/structure.yaml +27 -27
- package/templates/mobile/verification.yaml +121 -121
- package/templates/observability-xray/instructions.yaml +40 -40
- package/templates/observability-xray/mcp-servers.yaml +15 -15
- package/templates/realtime/instructions.yaml +42 -42
- package/templates/realtime/mcp-servers.yaml +13 -13
- package/templates/soc2/instructions.yaml +41 -41
- package/templates/soc2/mcp-servers.yaml +24 -24
- package/templates/social/instructions.yaml +43 -43
- package/templates/social/mcp-servers.yaml +24 -24
- package/templates/state-machine/instructions.yaml +42 -42
- package/templates/state-machine/mcp-servers.yaml +11 -11
- package/templates/tools-registry.yaml +164 -164
- package/templates/universal/claude-md-blocks/layer-navigation.md +20 -0
- package/templates/universal/claude-md-blocks/nfr-contracts.md +22 -0
- package/templates/universal/hooks.yaml +879 -723
- package/templates/universal/instructions.yaml +1692 -1692
- package/templates/universal/mcp-servers.yaml +50 -50
- package/templates/universal/nfr.yaml +197 -197
- package/templates/universal/reference.yaml +326 -326
- package/templates/universal/review.yaml +204 -204
- package/templates/universal/skills.yaml +262 -262
- package/templates/universal/structure.yaml +67 -67
- package/templates/universal/verification.yaml +416 -416
- package/templates/web-next/hooks.yaml +114 -0
- package/templates/web-next/instructions.yaml +106 -0
- package/templates/web-react/harness/uc-template.spec.ts +35 -0
- package/templates/web-react/hooks.yaml +156 -44
- package/templates/web-react/instructions.yaml +296 -207
- package/templates/web-react/mcp-servers.yaml +20 -20
- package/templates/web-react/nfr.yaml +27 -27
- package/templates/web-react/review.yaml +94 -94
- package/templates/web-react/structure.yaml +46 -46
- package/templates/web-react/verification.yaml +126 -126
- package/templates/web-static/hooks.yaml +85 -0
- package/templates/web-static/instructions.yaml +204 -115
- package/templates/web-static/mcp-servers.yaml +20 -20
- package/templates/web3/instructions.yaml +44 -44
- package/templates/web3/mcp-servers.yaml +11 -11
- package/templates/web3/verification.yaml +159 -159
- package/templates/zero-trust/instructions.yaml +41 -41
- package/templates/zero-trust/mcp-servers.yaml +15 -15
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_decision tool handler.
|
|
3
|
+
*
|
|
4
|
+
* Emits a structured Decision/Post-mortem record into docs/decisions/ —
|
|
5
|
+
* the GS taxonomy slot for non-architectural one-pagers: bug-fix interpretations,
|
|
6
|
+
* operational tweaks, "we chose X over Y because Z" notes that don't warrant a
|
|
7
|
+
* full ADR.
|
|
8
|
+
*
|
|
9
|
+
* Encouraged on `fix:` commits (per cascade) and required when a bug-postmortem
|
|
10
|
+
* change_request reaches `verified` status.
|
|
11
|
+
*
|
|
12
|
+
* Output file: docs/decisions/YYYY-MM-DD-slug.md
|
|
13
|
+
* Format: Trigger / Root cause / Fix / Regression test / Chronicle link.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { createLogger } from "../shared/logger/index.js";
|
|
19
|
+
const logger = createLogger("tools/generate-decision");
|
|
20
|
+
const DECISION_DIR = join("docs", "decisions");
|
|
21
|
+
// ── Schema ───────────────────────────────────────────────────────────
|
|
22
|
+
export const generateDecisionSchema = z.object({
|
|
23
|
+
project_dir: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe("Absolute path to the project root. Decision is written to {project_dir}/docs/decisions/."),
|
|
26
|
+
title: z
|
|
27
|
+
.string()
|
|
28
|
+
.describe("Short imperative title of the decision/post-mortem (e.g. 'Drop duplicate task_id rows on import'). " +
|
|
29
|
+
"Becomes the slug in the filename and the H1 heading."),
|
|
30
|
+
trigger: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("What surfaced this decision — bug symptom, incident, support ticket, observed behavior. " +
|
|
34
|
+
"If omitted, a placeholder is written."),
|
|
35
|
+
root_cause: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Why it happened — the underlying defect, missing guard, or design oversight. " +
|
|
39
|
+
"If omitted, a placeholder is written."),
|
|
40
|
+
fix: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("What was changed (code, config, or behavior) and why this fix was chosen over alternatives. " +
|
|
44
|
+
"If omitted, a placeholder is written."),
|
|
45
|
+
regression_test: z
|
|
46
|
+
.string()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Test or gate that locks this fix in (test name, gate id, monitor). " +
|
|
49
|
+
"If omitted, a placeholder is written — required for fix: commits per cascade."),
|
|
50
|
+
chronicle_session_id: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Optional chronicle session id where the investigation was recorded. " +
|
|
54
|
+
"Links the post-mortem back to its individual-memory provenance."),
|
|
55
|
+
related_adr: z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("Optional ADR id this decision touches or refines (e.g. 'ADR-0007'). " +
|
|
59
|
+
"Use when the bug exposed an architectural assumption — promotes traceability."),
|
|
60
|
+
});
|
|
61
|
+
// ── Handler ──────────────────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Generate and write a structured decision/post-mortem file.
|
|
64
|
+
*
|
|
65
|
+
* @param args - Validated tool input
|
|
66
|
+
* @returns MCP tool response with the written file path and content
|
|
67
|
+
*/
|
|
68
|
+
export async function generateDecisionHandler(args) {
|
|
69
|
+
const { project_dir, title } = args;
|
|
70
|
+
const decisionDir = join(project_dir, DECISION_DIR);
|
|
71
|
+
if (!existsSync(decisionDir)) {
|
|
72
|
+
mkdirSync(decisionDir, { recursive: true });
|
|
73
|
+
logger.info("Created docs/decisions/ directory", { decisionDir });
|
|
74
|
+
}
|
|
75
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
76
|
+
const slug = titleToSlug(title);
|
|
77
|
+
const filename = `${date}-${slug}.md`;
|
|
78
|
+
const filePath = join(decisionDir, filename);
|
|
79
|
+
const relativePath = join(DECISION_DIR, filename).replace(/\\/g, "/");
|
|
80
|
+
if (existsSync(filePath)) {
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: `Decision file already exists: ${relativePath}\nChoose a different title or edit the existing file directly.`,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const content = renderDecision({
|
|
91
|
+
date,
|
|
92
|
+
title,
|
|
93
|
+
trigger: args.trigger,
|
|
94
|
+
root_cause: args.root_cause,
|
|
95
|
+
fix: args.fix,
|
|
96
|
+
regression_test: args.regression_test,
|
|
97
|
+
chronicle_session_id: args.chronicle_session_id,
|
|
98
|
+
related_adr: args.related_adr,
|
|
99
|
+
});
|
|
100
|
+
writeFileSync(filePath, content, "utf-8");
|
|
101
|
+
logger.info("Decision written", { filePath, date, slug });
|
|
102
|
+
const lines = [
|
|
103
|
+
`# Decision Written`,
|
|
104
|
+
``,
|
|
105
|
+
`**File:** \`${relativePath}\``,
|
|
106
|
+
`**Date:** ${date}`,
|
|
107
|
+
`**Title:** ${title}`,
|
|
108
|
+
``,
|
|
109
|
+
`## Content`,
|
|
110
|
+
``,
|
|
111
|
+
"```markdown",
|
|
112
|
+
content,
|
|
113
|
+
"```",
|
|
114
|
+
``,
|
|
115
|
+
`> **Next step:** Resolve any \`[NEEDS CLARIFICATION]\` markers — especially the regression test, which is required by the \`fix:\` cascade.`,
|
|
116
|
+
args.chronicle_session_id
|
|
117
|
+
? `> Chronicle session \`${args.chronicle_session_id}\` is linked — keep that record alive while this decision is current.`
|
|
118
|
+
: `> If this decision came out of a chronicle session, re-run with \`chronicle_session_id\` to link the investigation.`,
|
|
119
|
+
];
|
|
120
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
121
|
+
}
|
|
122
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
123
|
+
/**
|
|
124
|
+
* Convert a title string to a URL-safe kebab-case slug.
|
|
125
|
+
* Strips punctuation, lowercases, replaces spaces/underscores with hyphens.
|
|
126
|
+
*/
|
|
127
|
+
export function titleToSlug(title) {
|
|
128
|
+
return title
|
|
129
|
+
.toLowerCase()
|
|
130
|
+
.replace(/[^a-z0-9\s_-]/g, "")
|
|
131
|
+
.trim()
|
|
132
|
+
.replace(/[\s_]+/g, "-")
|
|
133
|
+
.replace(/-{2,}/g, "-")
|
|
134
|
+
.slice(0, 60);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Render a complete decision/post-mortem document from the provided fields.
|
|
138
|
+
*/
|
|
139
|
+
export function renderDecision(fields) {
|
|
140
|
+
const { date, title, trigger, root_cause, fix, regression_test, chronicle_session_id, related_adr, } = fields;
|
|
141
|
+
const lines = [
|
|
142
|
+
`# ${title}`,
|
|
143
|
+
``,
|
|
144
|
+
`**Date:** ${date}`,
|
|
145
|
+
`**Type:** Decision / Post-mortem`,
|
|
146
|
+
];
|
|
147
|
+
if (related_adr) {
|
|
148
|
+
lines.push(`**Related ADR:** ${related_adr}`);
|
|
149
|
+
}
|
|
150
|
+
if (chronicle_session_id) {
|
|
151
|
+
lines.push(`**Chronicle session:** \`${chronicle_session_id}\``);
|
|
152
|
+
}
|
|
153
|
+
lines.push(``, `## Trigger`, ``, trigger ??
|
|
154
|
+
"[NEEDS CLARIFICATION: what surfaced this — bug symptom, incident, support ticket, observed behavior]", ``, `## Root Cause`, ``, root_cause ??
|
|
155
|
+
"[NEEDS CLARIFICATION: why it happened — the underlying defect, missing guard, or design oversight]", ``, `## Fix`, ``, fix ??
|
|
156
|
+
"[NEEDS CLARIFICATION: what was changed (code, config, behavior) and why this fix was chosen]", ``, `## Regression Test`, ``, regression_test ??
|
|
157
|
+
"[NEEDS CLARIFICATION: test name, gate id, or monitor that locks this fix in — REQUIRED by fix: cascade]", ``, `## Chronicle Link`, ``, chronicle_session_id
|
|
158
|
+
? `Investigation recorded in chronicle session \`${chronicle_session_id}\`. Pull notes/prompts from there before editing this file.`
|
|
159
|
+
: "[OPTIONAL: chronicle session id if the investigation was recorded — leave empty if this was a one-shot fix]", ``, `---`, ``, `_This decision record was generated by ForgeCraft. Resolve any [NEEDS CLARIFICATION] sections before merging — the cascade gate will block a \`fix:\` PR whose regression test is unresolved._`);
|
|
160
|
+
return lines.join("\n");
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=generate-decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-decision.js","sourceRoot":"","sources":["../../src/tools/generate-decision.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_env_probe tool handler.
|
|
3
|
+
*
|
|
4
|
+
* Reads environment probe specs from .forgecraft/env/*.yaml and scaffolds
|
|
5
|
+
* executable probe files in tests/env/. Idempotent — skips existing unless force=true.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { ToolResult } from "../shared/types.js";
|
|
9
|
+
export declare const generateEnvProbeSchema: z.ZodObject<{
|
|
10
|
+
project_dir: z.ZodString;
|
|
11
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
project_dir: string;
|
|
14
|
+
force?: boolean | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
project_dir: string;
|
|
17
|
+
force?: boolean | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export type GenerateEnvProbeInput = z.infer<typeof generateEnvProbeSchema>;
|
|
20
|
+
export interface EnvProbeSpec {
|
|
21
|
+
service: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
probes?: Array<{
|
|
24
|
+
id: string;
|
|
25
|
+
type: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
vars?: string[];
|
|
29
|
+
host?: string;
|
|
30
|
+
port?: number;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
export interface EnvGenerateResult {
|
|
34
|
+
service: string;
|
|
35
|
+
probeId: string;
|
|
36
|
+
probeType: string;
|
|
37
|
+
probeFile: string;
|
|
38
|
+
status: "generated" | "skipped" | "error";
|
|
39
|
+
reason?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function envExtensionForType(probeType: string): string;
|
|
42
|
+
export declare function generateEnvProbeContent(service: string, probeId: string, probeType: string, description: string, extra?: {
|
|
43
|
+
url?: string;
|
|
44
|
+
vars?: string[];
|
|
45
|
+
host?: string;
|
|
46
|
+
port?: number;
|
|
47
|
+
}): string;
|
|
48
|
+
export declare function generateEnvProbeHandler(args: GenerateEnvProbeInput): Promise<ToolResult>;
|
|
49
|
+
//# sourceMappingURL=generate-env-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-env-probe.d.ts","sourceRoot":"","sources":["../../src/tools/generate-env-probe.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,eAAO,MAAM,sBAAsB;;;;;;;;;EAMjC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAI3E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAiB7D;AA2ND,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE,MAAM,CAsCR;AAID,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,UAAU,CAAC,CA+GrB"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_env_probe tool handler.
|
|
3
|
+
*
|
|
4
|
+
* Reads environment probe specs from .forgecraft/env/*.yaml and scaffolds
|
|
5
|
+
* executable probe files in tests/env/. Idempotent — skips existing unless force=true.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
10
|
+
import yaml from "js-yaml";
|
|
11
|
+
// ── Schema ───────────────────────────────────────────────────────────
|
|
12
|
+
export const generateEnvProbeSchema = z.object({
|
|
13
|
+
project_dir: z.string().describe("Absolute path to the project root."),
|
|
14
|
+
force: z
|
|
15
|
+
.boolean()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Overwrite existing probe files. Default: false."),
|
|
18
|
+
});
|
|
19
|
+
// ── Probe type → file extension ───────────────────────────────────────
|
|
20
|
+
export function envExtensionForType(probeType) {
|
|
21
|
+
switch (probeType) {
|
|
22
|
+
case "health_check":
|
|
23
|
+
return ".health.sh";
|
|
24
|
+
case "env_var":
|
|
25
|
+
return ".env.sh";
|
|
26
|
+
case "port_check":
|
|
27
|
+
return ".port.sh";
|
|
28
|
+
case "schema_validate":
|
|
29
|
+
return ".schema.sh";
|
|
30
|
+
case "docker_check":
|
|
31
|
+
return ".docker.sh";
|
|
32
|
+
case "migration_check":
|
|
33
|
+
return ".migration.sh";
|
|
34
|
+
default:
|
|
35
|
+
return ".sh";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ── Probe content generators ──────────────────────────────────────────
|
|
39
|
+
function generateHealthCheckContent(service, probeId, description, url) {
|
|
40
|
+
const targetUrl = url ?? "http://{{host}}:{{port}}/health";
|
|
41
|
+
return `#!/usr/bin/env bash
|
|
42
|
+
# Service: ${service}
|
|
43
|
+
# Probe: ${probeId}
|
|
44
|
+
# Type: health_check
|
|
45
|
+
# Description: ${description}
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
|
|
48
|
+
# TODO: set actual health endpoint URL
|
|
49
|
+
URL="${targetUrl}"
|
|
50
|
+
|
|
51
|
+
if ! command -v curl &>/dev/null; then
|
|
52
|
+
echo "FAIL: curl not found — cannot run health check"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL" || echo "000")
|
|
57
|
+
|
|
58
|
+
if [ "$HTTP_STATUS" = "200" ]; then
|
|
59
|
+
echo "PASS: ${probeId} — health endpoint returned 200"
|
|
60
|
+
else
|
|
61
|
+
echo "FAIL: ${probeId} — health endpoint returned $HTTP_STATUS (expected 200)"
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
function generateEnvVarContent(service, probeId, description, vars) {
|
|
67
|
+
const varList = vars && vars.length > 0 ? vars : ["# TODO: add required env var names"];
|
|
68
|
+
const checkLines = vars && vars.length > 0
|
|
69
|
+
? vars
|
|
70
|
+
.map((v) => `if [ -z "\${${v}:-}" ]; then\n echo "FAIL: ${probeId} — required env var ${v} is not set or empty"\n exit 1\nfi`)
|
|
71
|
+
.join("\n")
|
|
72
|
+
: `# TODO: check required env vars\necho "TODO: implement env var checks for ${probeId}"\nexit 1`;
|
|
73
|
+
return `#!/usr/bin/env bash
|
|
74
|
+
# Service: ${service}
|
|
75
|
+
# Probe: ${probeId}
|
|
76
|
+
# Type: env_var
|
|
77
|
+
# Description: ${description}
|
|
78
|
+
# Required vars: ${varList.join(", ")}
|
|
79
|
+
set -euo pipefail
|
|
80
|
+
|
|
81
|
+
${checkLines}
|
|
82
|
+
|
|
83
|
+
echo "PASS: ${probeId} — all required env vars are set"
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
function generatePortCheckContent(service, probeId, description, host, port) {
|
|
87
|
+
const targetHost = host ?? "{{db_host}}";
|
|
88
|
+
const targetPort = port ?? 5432;
|
|
89
|
+
return `#!/usr/bin/env bash
|
|
90
|
+
# Service: ${service}
|
|
91
|
+
# Probe: ${probeId}
|
|
92
|
+
# Type: port_check
|
|
93
|
+
# Description: ${description}
|
|
94
|
+
set -euo pipefail
|
|
95
|
+
|
|
96
|
+
# TODO: set actual host and port
|
|
97
|
+
HOST="${targetHost}"
|
|
98
|
+
PORT="${targetPort}"
|
|
99
|
+
|
|
100
|
+
if command -v nc &>/dev/null; then
|
|
101
|
+
if nc -z -w 5 "$HOST" "$PORT" 2>/dev/null; then
|
|
102
|
+
echo "PASS: ${probeId} — port $HOST:$PORT is reachable"
|
|
103
|
+
else
|
|
104
|
+
echo "FAIL: ${probeId} — port $HOST:$PORT is not reachable"
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
elif command -v curl &>/dev/null; then
|
|
108
|
+
if curl -s --max-time 5 "telnet://$HOST:$PORT" &>/dev/null || curl -s --connect-timeout 5 "$HOST:$PORT" &>/dev/null; then
|
|
109
|
+
echo "PASS: ${probeId} — port $HOST:$PORT is reachable"
|
|
110
|
+
else
|
|
111
|
+
echo "FAIL: ${probeId} — port $HOST:$PORT is not reachable"
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
else
|
|
115
|
+
echo "FAIL: ${probeId} — neither nc nor curl found"
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
function generateSchemaValidateContent(service, probeId, description) {
|
|
121
|
+
return `#!/usr/bin/env bash
|
|
122
|
+
# Service: ${service}
|
|
123
|
+
# Probe: ${probeId}
|
|
124
|
+
# Type: schema_validate
|
|
125
|
+
# Description: ${description}
|
|
126
|
+
set -euo pipefail
|
|
127
|
+
|
|
128
|
+
# TODO: set path to .env.example and actual env file
|
|
129
|
+
ENV_EXAMPLE=".env.example"
|
|
130
|
+
ENV_FILE=".env"
|
|
131
|
+
|
|
132
|
+
if [ ! -f "$ENV_EXAMPLE" ]; then
|
|
133
|
+
echo "FAIL: ${probeId} — .env.example not found at $ENV_EXAMPLE"
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
MISSING=()
|
|
138
|
+
while IFS= read -r line; do
|
|
139
|
+
# Extract var name (skip comments and empty lines)
|
|
140
|
+
[[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
|
|
141
|
+
VAR_NAME=$(echo "$line" | cut -d= -f1)
|
|
142
|
+
if [ -z "\${!VAR_NAME:-}" ]; then
|
|
143
|
+
MISSING+=("$VAR_NAME")
|
|
144
|
+
fi
|
|
145
|
+
done < "$ENV_EXAMPLE"
|
|
146
|
+
|
|
147
|
+
if [ \${#MISSING[@]} -gt 0 ]; then
|
|
148
|
+
echo "FAIL: ${probeId} — missing env vars: \${MISSING[*]}"
|
|
149
|
+
exit 1
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
echo "PASS: ${probeId} — env schema validated against .env.example"
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
function generateDockerCheckContent(service, probeId, description) {
|
|
156
|
+
return `#!/usr/bin/env bash
|
|
157
|
+
# Service: ${service}
|
|
158
|
+
# Probe: ${probeId}
|
|
159
|
+
# Type: docker_check
|
|
160
|
+
# Description: ${description}
|
|
161
|
+
set -euo pipefail
|
|
162
|
+
|
|
163
|
+
# TODO: set actual container name
|
|
164
|
+
CONTAINER_NAME="${service}"
|
|
165
|
+
|
|
166
|
+
if ! command -v docker &>/dev/null; then
|
|
167
|
+
echo "FAIL: ${probeId} — docker not found"
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
if docker compose ps --format json 2>/dev/null | grep -q "$CONTAINER_NAME"; then
|
|
172
|
+
STATUS=$(docker compose ps --format json 2>/dev/null | grep "$CONTAINER_NAME" | grep -o '"State":"[^"]*"' | head -1)
|
|
173
|
+
if echo "$STATUS" | grep -q '"running"'; then
|
|
174
|
+
echo "PASS: ${probeId} — container $CONTAINER_NAME is running"
|
|
175
|
+
else
|
|
176
|
+
echo "FAIL: ${probeId} — container $CONTAINER_NAME is not running: $STATUS"
|
|
177
|
+
exit 1
|
|
178
|
+
fi
|
|
179
|
+
elif docker ps --filter "name=$CONTAINER_NAME" --format "{{.Status}}" 2>/dev/null | grep -q "Up"; then
|
|
180
|
+
echo "PASS: ${probeId} — container $CONTAINER_NAME is running"
|
|
181
|
+
else
|
|
182
|
+
echo "FAIL: ${probeId} — container $CONTAINER_NAME is not running"
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
187
|
+
function generateMigrationCheckContent(service, probeId, description) {
|
|
188
|
+
return `#!/usr/bin/env bash
|
|
189
|
+
# Service: ${service}
|
|
190
|
+
# Probe: ${probeId}
|
|
191
|
+
# Type: migration_check
|
|
192
|
+
# Description: ${description}
|
|
193
|
+
set -euo pipefail
|
|
194
|
+
|
|
195
|
+
DB_URL="\${DATABASE_URL:-}"
|
|
196
|
+
if [ -z "$DB_URL" ]; then
|
|
197
|
+
echo "FAIL: ${probeId} — DATABASE_URL not set"
|
|
198
|
+
exit 1
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# TODO: adapt to your migration tool (prisma, flyway, liquibase, etc.)
|
|
202
|
+
if command -v prisma &>/dev/null; then
|
|
203
|
+
PENDING=$(npx prisma migrate status 2>&1 | grep -c "pending" || true)
|
|
204
|
+
if [ "$PENDING" -gt 0 ]; then
|
|
205
|
+
echo "FAIL: ${probeId} — $PENDING pending migration(s)"
|
|
206
|
+
exit 1
|
|
207
|
+
fi
|
|
208
|
+
echo "PASS: ${probeId} — no pending migrations"
|
|
209
|
+
else
|
|
210
|
+
echo "TODO: implement migration check for ${probeId} — set up migration tool"
|
|
211
|
+
exit 1
|
|
212
|
+
fi
|
|
213
|
+
`;
|
|
214
|
+
}
|
|
215
|
+
export function generateEnvProbeContent(service, probeId, probeType, description, extra) {
|
|
216
|
+
switch (probeType) {
|
|
217
|
+
case "health_check":
|
|
218
|
+
return generateHealthCheckContent(service, probeId, description, extra?.url);
|
|
219
|
+
case "env_var":
|
|
220
|
+
return generateEnvVarContent(service, probeId, description, extra?.vars);
|
|
221
|
+
case "port_check":
|
|
222
|
+
return generatePortCheckContent(service, probeId, description, extra?.host, extra?.port);
|
|
223
|
+
case "schema_validate":
|
|
224
|
+
return generateSchemaValidateContent(service, probeId, description);
|
|
225
|
+
case "docker_check":
|
|
226
|
+
return generateDockerCheckContent(service, probeId, description);
|
|
227
|
+
case "migration_check":
|
|
228
|
+
return generateMigrationCheckContent(service, probeId, description);
|
|
229
|
+
default:
|
|
230
|
+
return `#!/usr/bin/env bash
|
|
231
|
+
# Service: ${service}
|
|
232
|
+
# Probe: ${probeId}
|
|
233
|
+
# Type: ${probeType}
|
|
234
|
+
# Description: ${description}
|
|
235
|
+
set -euo pipefail
|
|
236
|
+
|
|
237
|
+
# TODO: implement probe check for ${probeId}
|
|
238
|
+
echo "TODO: implement ${probeId}"
|
|
239
|
+
exit 1
|
|
240
|
+
`;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ── Handler ───────────────────────────────────────────────────────────
|
|
244
|
+
export async function generateEnvProbeHandler(args) {
|
|
245
|
+
const projectDir = resolve(args.project_dir);
|
|
246
|
+
const force = args.force ?? false;
|
|
247
|
+
const envSpecDir = join(projectDir, ".forgecraft", "env");
|
|
248
|
+
if (!existsSync(envSpecDir)) {
|
|
249
|
+
return {
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: "No env probe specs found. Create .forgecraft/env/service.yaml to define environment contracts.",
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// Read all spec files
|
|
259
|
+
let specFiles = [];
|
|
260
|
+
try {
|
|
261
|
+
specFiles = readdirSync(envSpecDir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
specFiles = [];
|
|
265
|
+
}
|
|
266
|
+
if (specFiles.length === 0) {
|
|
267
|
+
return {
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: "text",
|
|
271
|
+
text: "No env probe specs found. Create .forgecraft/env/service.yaml to define environment contracts.",
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const envDir = join(projectDir, "tests", "env");
|
|
277
|
+
try {
|
|
278
|
+
mkdirSync(envDir, { recursive: true });
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
/* ignore */
|
|
282
|
+
}
|
|
283
|
+
const results = [];
|
|
284
|
+
for (const specFile of specFiles) {
|
|
285
|
+
let spec;
|
|
286
|
+
try {
|
|
287
|
+
const raw = readFileSync(join(envSpecDir, specFile), "utf-8");
|
|
288
|
+
spec = yaml.load(raw);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!spec?.service || !spec.probes)
|
|
294
|
+
continue;
|
|
295
|
+
for (const probe of spec.probes) {
|
|
296
|
+
const ext = envExtensionForType(probe.type);
|
|
297
|
+
const fileName = `${spec.service}-${probe.id}${ext}`;
|
|
298
|
+
const filePath = join(envDir, fileName);
|
|
299
|
+
const relPath = `tests/env/${fileName}`;
|
|
300
|
+
if (existsSync(filePath) && !force) {
|
|
301
|
+
results.push({
|
|
302
|
+
service: spec.service,
|
|
303
|
+
probeId: probe.id,
|
|
304
|
+
probeType: probe.type,
|
|
305
|
+
probeFile: relPath,
|
|
306
|
+
status: "skipped",
|
|
307
|
+
reason: "already exists",
|
|
308
|
+
});
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const content = generateEnvProbeContent(spec.service, probe.id, probe.type, probe.description ?? probe.id, {
|
|
312
|
+
url: probe.url,
|
|
313
|
+
vars: probe.vars,
|
|
314
|
+
host: probe.host,
|
|
315
|
+
port: probe.port,
|
|
316
|
+
});
|
|
317
|
+
try {
|
|
318
|
+
writeFileSync(filePath, content, "utf-8");
|
|
319
|
+
results.push({
|
|
320
|
+
service: spec.service,
|
|
321
|
+
probeId: probe.id,
|
|
322
|
+
probeType: probe.type,
|
|
323
|
+
probeFile: relPath,
|
|
324
|
+
status: "generated",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
results.push({
|
|
329
|
+
service: spec.service,
|
|
330
|
+
probeId: probe.id,
|
|
331
|
+
probeType: probe.type,
|
|
332
|
+
probeFile: relPath,
|
|
333
|
+
status: "error",
|
|
334
|
+
reason: `write failed: ${String(err)}`,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return { content: [{ type: "text", text: formatEnvReport(results) }] };
|
|
340
|
+
}
|
|
341
|
+
// ── Report formatter ──────────────────────────────────────────────────
|
|
342
|
+
function formatEnvReport(results) {
|
|
343
|
+
const generated = results.filter((r) => r.status === "generated");
|
|
344
|
+
const skipped = results.filter((r) => r.status === "skipped");
|
|
345
|
+
const noSpec = results.filter((r) => r.status === "error");
|
|
346
|
+
const lines = [
|
|
347
|
+
"## Env Probe Generation Report",
|
|
348
|
+
"",
|
|
349
|
+
`Generated: ${generated.length} Skipped: ${skipped.length} No spec: ${noSpec.length}`,
|
|
350
|
+
"",
|
|
351
|
+
"| Service | Probe | Type | File | Status |",
|
|
352
|
+
"|---|---|---|---|---|",
|
|
353
|
+
];
|
|
354
|
+
for (const r of results) {
|
|
355
|
+
const statusLabel = r.status === "generated"
|
|
356
|
+
? "✅ generated"
|
|
357
|
+
: r.status === "skipped"
|
|
358
|
+
? "⏭ skipped"
|
|
359
|
+
: `❌ error: ${r.reason ?? ""}`;
|
|
360
|
+
lines.push(`| ${r.service} | ${r.probeId} | ${r.probeType} | ${r.probeFile} | ${statusLabel} |`);
|
|
361
|
+
}
|
|
362
|
+
lines.push("", "To run: call run_env_probe");
|
|
363
|
+
return lines.join("\n");
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=generate-env-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-env-probe.js","sourceRoot":"","sources":["../../src/tools/generate-env-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_harness tool handler.
|
|
3
|
+
*
|
|
4
|
+
* Reads UC specs from docs/use-cases.md and probe blueprints from
|
|
5
|
+
* .forgecraft/harness/uc-NNN.yaml, then scaffolds executable probe files
|
|
6
|
+
* in tests/harness/. Idempotent: skips existing files unless force=true.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import type { ToolResult } from "../shared/types.js";
|
|
10
|
+
export declare const generateHarnessSchema: z.ZodObject<{
|
|
11
|
+
project_dir: z.ZodString;
|
|
12
|
+
uc_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
project_dir: string;
|
|
16
|
+
force?: boolean | undefined;
|
|
17
|
+
uc_ids?: string[] | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
project_dir: string;
|
|
20
|
+
force?: boolean | undefined;
|
|
21
|
+
uc_ids?: string[] | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
export type GenerateHarnessInput = z.infer<typeof generateHarnessSchema>;
|
|
24
|
+
export interface ProbeSpec {
|
|
25
|
+
uc: string;
|
|
26
|
+
title: string;
|
|
27
|
+
action?: string;
|
|
28
|
+
probes?: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
type: string;
|
|
31
|
+
scenario?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export type ProbeType = "playwright" | "api_call" | "hurl" | "graphql" | "file_system" | "mcp_call" | "headless_sim" | "db_query" | "message_queue" | "performance" | "websocket" | "log_assertion" | "a11y" | "contract_consumer" | "contract_provider" | "grpc" | "security_scan";
|
|
36
|
+
export interface GenerateResult {
|
|
37
|
+
ucId: string;
|
|
38
|
+
title: string;
|
|
39
|
+
status: "generated" | "skipped" | "no_spec";
|
|
40
|
+
probeFile?: string;
|
|
41
|
+
probeType?: string;
|
|
42
|
+
reason?: string;
|
|
43
|
+
autoSpec?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface ErrorCase {
|
|
46
|
+
name: string;
|
|
47
|
+
slug: string;
|
|
48
|
+
description: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function extensionForType(probeType: ProbeType): string;
|
|
51
|
+
export declare function parseErrorCases(ucSection: string): ErrorCase[];
|
|
52
|
+
export declare function generateHarnessHandler(args: GenerateHarnessInput): Promise<ToolResult>;
|
|
53
|
+
//# sourceMappingURL=generate-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-harness.d.ts","sourceRoot":"","sources":["../../src/tools/generate-harness.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAehC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIzE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,UAAU,GACV,MAAM,GACN,SAAS,GACT,aAAa,GACb,UAAU,GACV,cAAc,GACd,UAAU,GACV,eAAe,GACf,aAAa,GACb,WAAW,GACX,eAAe,GACf,MAAM,GACN,mBAAmB,GACnB,mBAAmB,GACnB,MAAM,GACN,eAAe,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AA8BD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAoC7D;AAID,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,CAyB9D;AA0ND,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,UAAU,CAAC,CAqIrB"}
|