phasegate 0.15.0 → 0.31.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/README.ja.md +103 -71
- package/README.md +73 -13
- package/bin/{harness → phasegate} +1 -1
- package/docs/ADR/ADR-013-story-reflection-gate.md +100 -0
- package/docs/guide/cli-reference.md +9 -9
- package/docs/guide/configuration.md +245 -8
- package/docs/guide/hooks-integration.md +1 -1
- package/docs/guide/installation.md +6 -6
- package/docs/guide/layer-model.md +5 -5
- package/docs/guide/skills-overview.md +1 -1
- package/package.json +12 -10
- package/scripts/harness/adr-foundation/domain/ports/adr-document-parser-port.ts +1 -0
- package/scripts/harness/adr-foundation/domain/ports/adr-frontmatter-parser-port.ts +1 -0
- package/scripts/harness/adr-foundation/domain/ports/adr-repository-port.ts +1 -0
- package/scripts/harness/adr-foundation/domain/value-objects/adr-status.ts +6 -6
- package/scripts/harness/agent-integration/application/dto/handle-pre-tool-use-dto.ts +3 -1
- package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +109 -3
- package/scripts/harness/agent-integration/application/usecases/handle-stop-usecase.ts +1 -1
- package/scripts/harness/agent-integration/domain/ports/config-query-port.ts +2 -0
- package/scripts/harness/agent-integration/domain/ports/phase-gate-query-port.ts +1 -1
- package/scripts/harness/agent-integration/domain/ports/story-reflection-query-port.ts +8 -0
- package/scripts/harness/agent-integration/domain/services/bash-write-target-extractor.ts +258 -0
- package/scripts/harness/agent-integration/domain/services/hook-to-cli-translator.ts +25 -8
- package/scripts/harness/agent-integration/domain/value-objects/protected-file-list.ts +20 -0
- package/scripts/harness/agent-integration/domain/value-objects/story-reflection-query-result.ts +63 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/child-process-cli-executor-adapter.ts +2 -2
- package/scripts/harness/agent-integration/infrastructure/adapters/file-system-story-reflection-query-adapter.ts +122 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/harness-api-cli-command-registry-adapter.ts +10 -10
- package/scripts/harness/agent-integration/infrastructure/adapters/harness-config-config-query-adapter.ts +20 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/phase-gate-query-adapter.ts +17 -3
- package/scripts/harness/agent-integration/presentation/pre-tool-use-hook.ts +29 -2
- package/scripts/harness/biome-ast-engine/domain/services/lint-runner.ts +24 -0
- package/scripts/harness/biome-ast-engine/domain/services/rule-definition-registry.ts +1 -1
- package/scripts/harness/biome-ast-engine/domain/value-objects/source-module-snapshot.ts +5 -2
- package/scripts/harness/biome-ast-engine/infrastructure/adapters/node-workspace-file-adapter.ts +1 -1
- package/scripts/harness/biome-ast-engine/infrastructure/adapters/typescript-source-module-analyzer-adapter.ts +1 -1
- package/scripts/harness/biome-ast-engine/infrastructure/parsers/unit-comment-parser.ts +12 -7
- package/scripts/harness/ci-governance/composition-root.ts +1 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/agents-md-file-adapter.ts +2 -2
- package/scripts/harness/ci-governance/infrastructure/adapters/yaml-template-renderer-adapter.ts +2 -2
- package/scripts/harness/config-foundation/application/mappers/phase-config-section-mapper.ts +44 -0
- package/scripts/harness/config-foundation/application/usecases/load-resolved-config-use-case.ts +20 -1
- package/scripts/harness/config-foundation/domain/harness-config.ts +2 -1
- package/scripts/harness/config-foundation/domain/value-objects/phase-dependencies-config.ts +18 -4
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +185 -10
- package/scripts/harness/config-foundation/infrastructure/validators/ajv-config-schema-validator.ts +2 -1
- package/scripts/harness/harness-api/application/dto/command-dispatch-input.ts +1 -0
- package/scripts/harness/harness-api/application/dto/command-dispatch-output.ts +1 -0
- package/scripts/harness/harness-api/application/dto/exit-code-decision-input.ts +1 -0
- package/scripts/harness/harness-api/application/dto/exit-code-decision-output.ts +1 -0
- package/scripts/harness/harness-api/application/dto/harness-api-response-contract.ts +1 -0
- package/scripts/harness/harness-api/application/dto/initialize-registry-input.ts +1 -0
- package/scripts/harness/harness-api/application/dto/registry-summary-output.ts +1 -0
- package/scripts/harness/harness-api/application/dto/status-derivation-input.ts +1 -0
- package/scripts/harness/harness-api/application/mappers/harness-api-response-mapper.ts +1 -0
- package/scripts/harness/harness-api/application/usecases/decide-exit-code-usecase.ts +4 -3
- package/scripts/harness/harness-api/application/usecases/derive-harness-status-usecase.ts +1 -0
- package/scripts/harness/harness-api/application/usecases/dispatch-command-usecase.ts +1 -0
- package/scripts/harness/harness-api/application/usecases/initialize-command-registry-usecase.ts +1 -0
- package/scripts/harness/harness-api/composition-root.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/artifact-scanner-port.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/biome-lint-port.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/config-query-port.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/impact-analysis-port.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/phase-gate-query-port.ts +1 -0
- package/scripts/harness/harness-api/domain/ports/validator-execution-port.ts +1 -0
- package/scripts/harness/harness-api/domain/services/command-dispatch-service.ts +17 -16
- package/scripts/harness/harness-api/domain/services/command-registry.ts +4 -3
- package/scripts/harness/harness-api/domain/services/status-derivation-service.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/artifact-scan-result.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/check-ready-result.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/cli-command-definition.ts +11 -10
- package/scripts/harness/harness-api/domain/value-objects/command-input-spec.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/drift-report-summary.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/exit-code-spec.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/harness-api-response.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/harness-status-summary.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/layer-health.ts +1 -0
- package/scripts/harness/harness-api/domain/value-objects/phase-info.ts +1 -0
- package/scripts/harness/harness-api/index.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/biome-ast-engine-lint-adapter.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/file-system-artifact-scanner-adapter.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/harness-config-query-adapter.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/nyquist-validation-impact-analysis-adapter.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts +1 -0
- package/scripts/harness/harness-api/infrastructure/adapters/validator-system-execution-adapter.ts +1 -0
- package/scripts/harness/harness-api/presentation/dto/cli-output-options.ts +1 -0
- package/scripts/harness/harness-api/presentation/formatters/harness-api-json-formatter.ts +1 -0
- package/scripts/harness/harness-api/presentation/handlers/check-phase-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/check-ready-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/ci-check-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/complete-check-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/detect-drift-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/impact-analysis-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/lint-handler.ts +2 -1
- package/scripts/harness/harness-api/presentation/handlers/status-handler.ts +4 -3
- package/scripts/harness/harness-error/infrastructure/adapters/legacy-error-reporter-adapter.ts +7 -1
- package/scripts/harness/integrations/pre-commit.ts +1 -0
- package/scripts/harness/main.ts +173 -53
- package/scripts/harness/phase-dependency-model/application/dto/resolve-gate-result-dto.ts +14 -0
- package/scripts/harness/phase-dependency-model/application/services/phase-gate-result-mapper.ts +20 -0
- package/scripts/harness/phase-dependency-model/application/usecases/check-story-reflection-usecase.ts +42 -0
- package/scripts/harness/phase-dependency-model/application/usecases/resolve-gate-usecase.ts +161 -0
- package/scripts/harness/phase-dependency-model/composition-root.ts +57 -1
- package/scripts/harness/phase-dependency-model/domain/definitions/{default-phase-dependencies.ts → full-phase-dependencies.ts} +3 -3
- package/scripts/harness/phase-dependency-model/domain/definitions/{default-phase-nodes.ts → full-phase-nodes.ts} +1 -1
- package/scripts/harness/phase-dependency-model/domain/definitions/full-story-reflection-defaults.ts +28 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/minimal-phase-dependencies.ts +32 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/minimal-phase-nodes.ts +50 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/minimal-story-reflection-defaults.ts +8 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/standard-phase-dependencies.ts +39 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/standard-phase-nodes.ts +118 -0
- package/scripts/harness/phase-dependency-model/domain/definitions/standard-story-reflection-defaults.ts +23 -0
- package/scripts/harness/phase-dependency-model/domain/models/phase-structure.ts +95 -23
- package/scripts/harness/phase-dependency-model/domain/ports/glob-matcher-port.ts +8 -0
- package/scripts/harness/phase-dependency-model/domain/ports/phase-config-provider-port.ts +2 -0
- package/scripts/harness/phase-dependency-model/domain/ports/story-annotation-verifier-port.ts +14 -0
- package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +16 -0
- package/scripts/harness/phase-dependency-model/domain/services/gate-graph.ts +223 -0
- package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +66 -0
- package/scripts/harness/phase-dependency-model/domain/values/gate-definition.ts +127 -0
- package/scripts/harness/phase-dependency-model/domain/values/gate-name.ts +40 -0
- package/scripts/harness/phase-dependency-model/domain/values/gate-story-annotation.ts +39 -0
- package/scripts/harness/phase-dependency-model/domain/values/phase-customization-policy.ts +16 -4
- package/scripts/harness/phase-dependency-model/domain/values/story-reflection-config.ts +44 -0
- package/scripts/harness/phase-dependency-model/domain/values/story-reflection-mapping.ts +91 -0
- package/scripts/harness/phase-dependency-model/domain/values/story-reflection-result.ts +55 -0
- package/scripts/harness/phase-dependency-model/infrastructure/adapters/picomatch-glob-matcher.ts +17 -0
- package/scripts/harness/phase-dependency-model/infrastructure/adapters/story-annotation-verifier-adapter.ts +46 -0
- package/scripts/harness/phase-dependency-model/infrastructure/config/custom-gates-config-parser.ts +22 -0
- package/scripts/harness/phase-dependency-model/infrastructure/config/harness-config-phase-config-provider.ts +78 -2
- package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +94 -0
- package/scripts/harness/phase-dependency-model/presentation/cli/check-phase-gate-command-handler.ts +12 -4
- package/scripts/harness/phase-dependency-model/presentation/cli/story-reflection-status-presenter.ts +87 -0
- package/scripts/harness/quick-mode/application/usecases/execute-quick-ci-check-usecase.ts +1 -1
- package/scripts/harness/quick-mode/presentation/handlers/ci-check-quick-mode-handler.ts +1 -1
- package/scripts/harness/regression-suite/application/dto/analyze-migration-input.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/analyze-migration-output.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/configure-ci-gate-input.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/configure-ci-gate-output.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/migrate-v0-tests-input.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/migrate-v0-tests-output.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/run-regression-suite-input.ts +1 -0
- package/scripts/harness/regression-suite/application/dto/run-regression-suite-output.ts +1 -0
- package/scripts/harness/regression-suite/application/mappers/migration-mapping-mapper.ts +1 -0
- package/scripts/harness/regression-suite/application/mappers/test-execution-summary-mapper.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/analyze-v0-migration-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/configure-ci-gate-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/migrate-v0-tests-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/run-agent-independence-guard-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/run-gng-gate-regression-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/run-k-requirements-regression-usecase.ts +1 -0
- package/scripts/harness/regression-suite/application/usecases/run-k14-k15-regression-usecase.ts +1 -0
- package/scripts/harness/regression-suite/composition-root.ts +1 -0
- package/scripts/harness/regression-suite/domain/aggregates/v0-test-migration.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/ci-gate-result-writer-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/config-query-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/import-analyzer-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/migration-mapping-repository-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/suite-registry-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/test-runner-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/ports/v0-spec-reader-port.ts +1 -0
- package/scripts/harness/regression-suite/domain/services/import-guard-service.ts +1 -0
- package/scripts/harness/regression-suite/domain/services/migration-analyzer.ts +1 -0
- package/scripts/harness/regression-suite/domain/services/regression-runner.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/agent-independence-test.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/biome-modification-spec.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/ci-gate-config.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/coverage-rate.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/gng-condition-test.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/import-violation.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/k-requirement-test.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/migration-mapping.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/regression-suite-definition.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/suite-id.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/test-execution-summary.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/test-failure-detail.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/v0-test-id.ts +1 -0
- package/scripts/harness/regression-suite/domain/value-objects/v1-test-path.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/biome-ast-import-analyzer-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/file-system-v0-spec-reader-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/harness-config-query-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/json-ci-gate-result-writer-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/markdown-migration-mapping-repository-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/static-suite-registry-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/adapters/vitest-test-runner-adapter.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/registry/agent-independence-suite-definition.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/registry/gng-gate-suite-definition.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/registry/k-requirements-suite-definition.ts +1 -0
- package/scripts/harness/regression-suite/infrastructure/registry/v0-migration-suite-definition.ts +1 -0
- package/scripts/harness/setup/skill-deployer.ts +82 -5
- package/scripts/harness/shared-kernel/harness-api.ts +1 -0
- package/scripts/harness/skill-quality/composition-root.ts +1 -0
- package/scripts/harness/skill-quality/infrastructure/adapters/ajv-lesson-artifact-schema-adapter.ts +5 -4
- package/scripts/harness/traceability-model/domain/services/metadata-validator.ts +12 -10
- package/scripts/harness/traceability-model/infrastructure/parsers/source-metadata-parser.ts +16 -2
- package/scripts/harness/validator-system/composition-root.ts +3 -3
- package/skills/cascade-updater/SKILL.md +16 -3
- package/skills/codebase-mapper/SKILL.md +9 -9
- package/skills/codex-delegator/SKILL.md +5 -56
- package/skills/consistency-checker/SKILL.md +5 -9
- package/skills/consistency-checker/references//343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +6 -3
- package/skills/doc-freshness-checker/SKILL.md +6 -6
- package/skills/engineering-perspective/SKILL.md +2 -58
- package/skills/engineering-perspective/references/domain-model.md +4 -135
- package/skills/implementation-readiness-checker/SKILL.md +18 -72
- package/skills/it-test-designer/SKILL.md +25 -161
- package/skills/it-test-designer/references/it-test-design-template.md +131 -0
- package/skills/it-test-logic-designer/SKILL.md +13 -388
- package/skills/it-test-logic-designer/references/controller-test-patterns.md +100 -0
- package/skills/it-test-logic-designer/references/repository-test-patterns.md +206 -0
- package/skills/it-test-logic-designer/references/usecase-test-patterns.md +87 -0
- package/skills/pointer-validator/SKILL.md +4 -4
- package/skills/scenario-test-designer/SKILL.md +4 -68
- package/skills/scenario-test-designer/references/scenario-test-design-template.md +41 -0
- package/skills/scenario-test-designer/references/scenario-test-plan-template.md +35 -0
- package/skills/scenario-test-logic-designer/SKILL.md +21 -304
- package/skills/scenario-test-logic-designer/references/msw-patterns.md +36 -0
- package/skills/scenario-test-logic-designer/references/playwright-patterns.md +237 -0
- package/skills/test-coverage-checker/SKILL.md +39 -121
- package/skills/test-coverage-checker/references/coverage-report-template.md +99 -0
- package/skills/uiux-designer/SKILL.md +27 -92
- package/skills/uiux-designer/references/data-testid-convention.md +38 -0
- package/skills/uiux-designer/references/uiux-design-template.md +105 -0
- package/skills/unit-test-designer/SKILL.md +5 -106
- package/skills/unit-test-designer/references/unit-test-design-template.md +127 -0
- package/skills/unit-test-logic-designer/SKILL.md +28 -250
- package/skills/unit-test-logic-designer/references/test-patterns.md +207 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## phasegate.config.json
|
|
4
4
|
|
|
5
|
-
Place at project root. Generated by `npx
|
|
5
|
+
Place at project root. Generated by `npx phasegate init`.
|
|
6
6
|
|
|
7
7
|
This file is the **Single Source of Truth** for all quality configuration in a Phasegate project. Every layer validator, skill, and harness behavior reads from this file.
|
|
8
8
|
|
|
@@ -27,9 +27,14 @@ This file is the **Single Source of Truth** for all quality configuration in a P
|
|
|
27
27
|
"relaxedGates": ["phase-gate", "2-phase-execution"]
|
|
28
28
|
},
|
|
29
29
|
"phaseDependencies": {
|
|
30
|
-
"preset": "
|
|
30
|
+
"preset": "standard", // "full" | "standard" | "minimal" | "custom" ("default" -> "full")
|
|
31
31
|
"override": false,
|
|
32
|
-
"customRules": []
|
|
32
|
+
"customRules": [],
|
|
33
|
+
"gates": [], // Optional. Custom phase gates (preset: "custom"). See gates[] reference below.
|
|
34
|
+
"storyReflection": { // Optional. Defaults per preset when omitted.
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"mappings": [] // Omit to use the preset's built-in mappings.
|
|
37
|
+
}
|
|
33
38
|
},
|
|
34
39
|
"planningMode": {
|
|
35
40
|
"default": "interactive", // "interactive" | "embedded-qa"
|
|
@@ -108,11 +113,243 @@ The five layers are:
|
|
|
108
113
|
|
|
109
114
|
#### `phaseDependencies`
|
|
110
115
|
|
|
111
|
-
| Sub-field
|
|
112
|
-
|
|
113
|
-
| `preset`
|
|
114
|
-
| `override`
|
|
115
|
-
| `customRules`
|
|
116
|
+
| Sub-field | Type | Default | Description |
|
|
117
|
+
|--------------------|------------|--------------|--------------------------------------------------------------------|
|
|
118
|
+
| `preset` | `string` | `"standard"` | One of `"full"`, `"standard"`, `"minimal"`, `"custom"`. `"default"` is accepted for backward compatibility and falls back to `"full"`. |
|
|
119
|
+
| `override` | `boolean` | `false` | When `true`, custom rules fully replace the default graph instead of extending it. Required when `preset` is `"custom"`. |
|
|
120
|
+
| `customRules` | `array` | `[]` | Array of custom phase dependency rules. Only used when `preset` is `"custom"`. |
|
|
121
|
+
| `gates` | `array` | `[]` | Array of custom phase gate definitions. See [gates\[\]](#gates-custom-phase-gates) below. Optional; defaults to empty. |
|
|
122
|
+
| `storyReflection` | `object` | preset-based | See [storyReflection](#storyreflection-inception--product-gate) below. Omit entirely for zero-config defaults per preset. |
|
|
123
|
+
|
|
124
|
+
##### Phase Dependency Presets
|
|
125
|
+
|
|
126
|
+
| Preset | Phase 3 Gates | storyReflection default | Use Case |
|
|
127
|
+
|------------|---------------|-------------------------------------------------------------------------|----------------------------------------------------|
|
|
128
|
+
| `full` | All gates | **Enabled** -- `logical_design.md` + `domain_model.md` required, `uiux_design.md` optional | AIDLC full ceremony; mission-critical systems |
|
|
129
|
+
| `standard` | Core gates | **Enabled** -- `logical_design.md` required, `domain_model.md` optional | Production development with moderate rigor |
|
|
130
|
+
| `minimal` | None | **Disabled** | Prototyping / exploration (trade-off: no reflection enforcement) |
|
|
131
|
+
| `custom` | User-defined | User-defined (zero or explicit `mappings`) | Full control via `customRules` and `storyReflection.mappings` |
|
|
132
|
+
|
|
133
|
+
> `"default"` is accepted as an alias for `"full"` so existing `phasegate.config.json` files keep working after the upgrade.
|
|
134
|
+
|
|
135
|
+
#### `gates[]` (custom phase gates)
|
|
136
|
+
|
|
137
|
+
`gates[]` lets a project declare **additional phase gates** that fire when a write targets specific file globs. Each gate is checked at the pre-tool-use hook (and via `check-phase-gate` CLI) and blocks the write if its preconditions are not met.
|
|
138
|
+
|
|
139
|
+
`gates[]` is typically combined with `preset: "custom"` and `override: true` when the project wants full control over the phase dependency graph. It is also valid to layer a small number of gates on top of `preset: "custom"` without replacing the full graph.
|
|
140
|
+
|
|
141
|
+
**Validation is fail-fast**: a malformed `gates[]` entry (e.g. `level: 99`, unknown dependency) causes `loadResolvedConfig()` to exit with code `2` and prints `Invalid phasegate.config.json: ...` to stderr. The same error surfaces as a `blocker` in the hook path.
|
|
142
|
+
|
|
143
|
+
##### Gate definition schema
|
|
144
|
+
|
|
145
|
+
Each entry in `gates[]` is an object with:
|
|
146
|
+
|
|
147
|
+
| Field | Type | Required | Description |
|
|
148
|
+
|-------------------|------------|----------|-------------------------------------------------------------------------------------------------------------------|
|
|
149
|
+
| `name` | `string` | yes | Unique gate identifier. Must match `^[a-z][a-z0-9-]*$`. |
|
|
150
|
+
| `level` | `integer` | yes | Phase level this gate belongs to. One of `1`, `2`, `3`. |
|
|
151
|
+
| `requires` | `object[]` | yes | Required artifacts. Each entry is `{ "path": "<glob or path>", "required": <boolean> }`. |
|
|
152
|
+
| `blocks` | `string[]` | yes | Glob patterns of files the gate guards. A write targeting any matching file triggers this gate. |
|
|
153
|
+
| `dependsOn` | `string[]` | yes | Names of other gates that must pass first. Forms a DAG; cycles are rejected at load time. |
|
|
154
|
+
| `storyAnnotation` | `object` | no | `{ "required": <boolean>, "tag": "<tag-name>" }`. When `required: true`, matched files must contain the tag (e.g. `@story-id H01-01`). Only valid when `level: 3`. |
|
|
155
|
+
|
|
156
|
+
**Rules:**
|
|
157
|
+
|
|
158
|
+
- `name` must be unique across the whole `gates[]` array.
|
|
159
|
+
- `level` is restricted to `1`, `2`, or `3`. `level: 99` or similar is a schema violation.
|
|
160
|
+
- `dependsOn` must reference existing gate names and must not form a cycle.
|
|
161
|
+
- `storyAnnotation` may only appear on `level: 3` gates (schema-enforced).
|
|
162
|
+
- `blocks` uses picomatch glob syntax (e.g. `"src/**/*.ts"`, `"scripts/harness/order/**"`).
|
|
163
|
+
|
|
164
|
+
##### Example 1 — single level-3 story gate
|
|
165
|
+
|
|
166
|
+
Enforce that any write under `scripts/harness/order/**` carries an `@story-id` annotation:
|
|
167
|
+
|
|
168
|
+
```jsonc
|
|
169
|
+
{
|
|
170
|
+
"phaseDependencies": {
|
|
171
|
+
"preset": "custom",
|
|
172
|
+
"override": true,
|
|
173
|
+
"customRules": [],
|
|
174
|
+
"gates": [
|
|
175
|
+
{
|
|
176
|
+
"name": "order-story-impl",
|
|
177
|
+
"level": 3,
|
|
178
|
+
"requires": [
|
|
179
|
+
{ "path": "docs/product/user_stories.md", "required": true }
|
|
180
|
+
],
|
|
181
|
+
"blocks": ["scripts/harness/order/**/*.ts"],
|
|
182
|
+
"dependsOn": [],
|
|
183
|
+
"storyAnnotation": { "required": true, "tag": "@story-id" }
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
##### Example 2 — diamond DAG with multiple chains
|
|
191
|
+
|
|
192
|
+
Two level-1 gates feed into a level-2 aggregate, which gates a level-3 implementation:
|
|
193
|
+
|
|
194
|
+
```jsonc
|
|
195
|
+
{
|
|
196
|
+
"phaseDependencies": {
|
|
197
|
+
"preset": "custom",
|
|
198
|
+
"override": true,
|
|
199
|
+
"customRules": [],
|
|
200
|
+
"gates": [
|
|
201
|
+
{
|
|
202
|
+
"name": "logical-design",
|
|
203
|
+
"level": 1,
|
|
204
|
+
"requires": [
|
|
205
|
+
{ "path": "docs/product/construction/{unit}/logical_design.md", "required": true }
|
|
206
|
+
],
|
|
207
|
+
"blocks": [],
|
|
208
|
+
"dependsOn": []
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "domain-model",
|
|
212
|
+
"level": 1,
|
|
213
|
+
"requires": [
|
|
214
|
+
{ "path": "docs/product/construction/{unit}/domain_model.md", "required": true }
|
|
215
|
+
],
|
|
216
|
+
"blocks": [],
|
|
217
|
+
"dependsOn": []
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "tdd-plan",
|
|
221
|
+
"level": 2,
|
|
222
|
+
"requires": [
|
|
223
|
+
{ "path": "docs/inception/{unit}/{storyId}/tdd_implementation_plan.md", "required": true }
|
|
224
|
+
],
|
|
225
|
+
"blocks": [],
|
|
226
|
+
"dependsOn": ["logical-design", "domain-model"]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"name": "story-impl",
|
|
230
|
+
"level": 3,
|
|
231
|
+
"requires": [],
|
|
232
|
+
"blocks": ["scripts/harness/**/*.ts"],
|
|
233
|
+
"dependsOn": ["tdd-plan"],
|
|
234
|
+
"storyAnnotation": { "required": true, "tag": "@story-id" }
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
##### Example 3 — minimal level-1 gate (no storyAnnotation)
|
|
242
|
+
|
|
243
|
+
Block commits that touch a protected path unless a design artifact exists — no story-id enforcement:
|
|
244
|
+
|
|
245
|
+
```jsonc
|
|
246
|
+
{
|
|
247
|
+
"phaseDependencies": {
|
|
248
|
+
"preset": "custom",
|
|
249
|
+
"override": true,
|
|
250
|
+
"customRules": [],
|
|
251
|
+
"gates": [
|
|
252
|
+
{
|
|
253
|
+
"name": "schema-guard",
|
|
254
|
+
"level": 1,
|
|
255
|
+
"requires": [
|
|
256
|
+
{ "path": "docs/schema/migration-notes.md", "required": true }
|
|
257
|
+
],
|
|
258
|
+
"blocks": ["db/migrations/**/*.sql"],
|
|
259
|
+
"dependsOn": []
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### `storyReflection` (inception -> product gate)
|
|
267
|
+
|
|
268
|
+
`storyReflection` enforces that every US / issue under `docs/inception/{unit}/{storyId}/` has been **cascaded into the accumulating product design documents** (`docs/product/construction/{unit}/`) before source code under `src/{unit}/` or `scripts/harness/{unit}/` can be written or edited.
|
|
269
|
+
|
|
270
|
+
The check fires at the pre-tool-use hook and blocks `Write`/`Edit` (and their Bash equivalents such as `cat > file`, `tee`, heredoc, `sed -i`, `cp`, `mv`, `touch`) whenever an inception design exists but its `@story-id` is not reflected in the corresponding product file.
|
|
271
|
+
|
|
272
|
+
**Zero-config**: omitting the `storyReflection` block, or specifying it without `mappings`, applies the preset's built-in mappings automatically.
|
|
273
|
+
|
|
274
|
+
| Sub-field | Type | Default | Description |
|
|
275
|
+
|-------------|------------|-------------------------|------------------------------------------------------------------------------|
|
|
276
|
+
| `enabled` | `boolean` | preset-dependent | Master switch. `full` / `standard` default to `true`; `minimal` defaults to `false`. |
|
|
277
|
+
| `mappings` | `array` | preset-dependent | Array of inception -> product file mappings. Omit to use the preset default. |
|
|
278
|
+
|
|
279
|
+
Each mapping entry:
|
|
280
|
+
|
|
281
|
+
| Field | Type | Description |
|
|
282
|
+
|-------------|-----------|-----------------------------------------------------------------------------|
|
|
283
|
+
| `inception` | `string` | Template path, e.g. `"docs/inception/{unit}/{storyId}/logical_design.md"`. |
|
|
284
|
+
| `product` | `string` | Template path, e.g. `"docs/product/construction/{unit}/logical_design.md"`.|
|
|
285
|
+
| `required` | `boolean` | When `true`, missing reflection blocks the write. When `false`, it is tolerated (optional mapping). |
|
|
286
|
+
|
|
287
|
+
##### Preset defaults (hard-coded)
|
|
288
|
+
|
|
289
|
+
**`full`** -- AIDLC recommended (product-accumulated design documents only; test designs are out of scope because they live per-US inside `inception/`):
|
|
290
|
+
|
|
291
|
+
```jsonc
|
|
292
|
+
[
|
|
293
|
+
{ "inception": "docs/inception/{unit}/{storyId}/logical_design.md",
|
|
294
|
+
"product": "docs/product/construction/{unit}/logical_design.md",
|
|
295
|
+
"required": true },
|
|
296
|
+
{ "inception": "docs/inception/{unit}/{storyId}/domain_model.md",
|
|
297
|
+
"product": "docs/product/construction/{unit}/domain_model.md",
|
|
298
|
+
"required": true },
|
|
299
|
+
{ "inception": "docs/inception/{unit}/{storyId}/uiux_design.md",
|
|
300
|
+
"product": "docs/product/construction/{unit}/uiux_design.md",
|
|
301
|
+
"required": false }
|
|
302
|
+
]
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**`standard`**:
|
|
306
|
+
|
|
307
|
+
```jsonc
|
|
308
|
+
[
|
|
309
|
+
{ "inception": "docs/inception/{unit}/{storyId}/logical_design.md",
|
|
310
|
+
"product": "docs/product/construction/{unit}/logical_design.md",
|
|
311
|
+
"required": true },
|
|
312
|
+
{ "inception": "docs/inception/{unit}/{storyId}/domain_model.md",
|
|
313
|
+
"product": "docs/product/construction/{unit}/domain_model.md",
|
|
314
|
+
"required": false }
|
|
315
|
+
]
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**`minimal`**: `enabled: false`. No storyReflection checking.
|
|
319
|
+
|
|
320
|
+
##### Custom mappings example
|
|
321
|
+
|
|
322
|
+
Override the preset defaults only when your project needs a different policy:
|
|
323
|
+
|
|
324
|
+
```jsonc
|
|
325
|
+
{
|
|
326
|
+
"phaseDependencies": {
|
|
327
|
+
"preset": "standard",
|
|
328
|
+
"storyReflection": {
|
|
329
|
+
"enabled": true,
|
|
330
|
+
"mappings": [
|
|
331
|
+
{ "inception": "docs/inception/{unit}/{storyId}/logical_design.md",
|
|
332
|
+
"product": "docs/product/construction/{unit}/logical_design.md",
|
|
333
|
+
"required": true }
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
##### How the check fires
|
|
341
|
+
|
|
342
|
+
1. `Write` / `Edit` (or a Bash write such as `cat > src/order/foo.ts`) targets a source file under a Unit.
|
|
343
|
+
2. `WriteTargetScope` resolves the `@unit` annotation (comma-separated and multi-line `@unit` are both supported; **all** listed units are checked).
|
|
344
|
+
3. For each unit, every `storyId` directory under `docs/inception/{unit}/` is enumerated.
|
|
345
|
+
4. For each required mapping, the pre-tool-use hook checks that the target product document contains `@story-id {storyId}`.
|
|
346
|
+
5. Any missing reflection produces a `STORY_REFLECTION` block reason with a fix hint that points to the `cascade-updater` skill and [ADR-013](../ADR/ADR-013-story-reflection-gate.md).
|
|
347
|
+
|
|
348
|
+
##### Passing the gate
|
|
349
|
+
|
|
350
|
+
`cascade-updater` is the **standard means of passing the storyReflection gate**: run it to propagate the new US / issue design into the accumulating product documents. Manual editing of the product file with an appended `@story-id` tag is also accepted.
|
|
351
|
+
|
|
352
|
+
Quick Mode with `relaxedGates: ["phase-gate"]` relaxes `storyReflection` as well (see [Quick Mode](#quick-mode)). L1 and L2 `metadata` / `test-quality` checks remain fully enforced.
|
|
116
353
|
|
|
117
354
|
#### `planningMode`
|
|
118
355
|
|
|
@@ -72,7 +72,7 @@ Use /quick-implementor skill for version changes in package.json.
|
|
|
72
72
|
- Provides immediate feedback on violations
|
|
73
73
|
|
|
74
74
|
### Stop (before session end)
|
|
75
|
-
- Runs `
|
|
75
|
+
- Runs `phasegate:complete-check` (L2-L4 full validation)
|
|
76
76
|
- Session end is held if checks are not all green
|
|
77
77
|
|
|
78
78
|
## Optional Shell Script Hooks
|
|
@@ -33,7 +33,7 @@ npm install
|
|
|
33
33
|
### 1. Initialize
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npx
|
|
36
|
+
npx phasegate init --name <project-name>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
This deploys 28 skills to `.claude/skills/` and generates `phasegate.config.json`.
|
|
@@ -62,14 +62,14 @@ Run `/product-architect` to begin the AIDLC process.
|
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
64
|
npm update phasegate
|
|
65
|
-
npx
|
|
65
|
+
npx phasegate update-skills
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
## Recommended .gitignore additions
|
|
69
69
|
|
|
70
70
|
```
|
|
71
71
|
node_modules/
|
|
72
|
-
.claude/skills/ # regenerated by npx
|
|
72
|
+
.claude/skills/ # regenerated by npx phasegate init
|
|
73
73
|
dist/
|
|
74
74
|
reports/
|
|
75
75
|
.harness/
|
|
@@ -78,7 +78,7 @@ reports/
|
|
|
78
78
|
## Verify Installation
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
npx
|
|
82
|
-
npx
|
|
83
|
-
npm run
|
|
81
|
+
npx phasegate --version
|
|
82
|
+
npx phasegate lint
|
|
83
|
+
npm run phasegate:status
|
|
84
84
|
```
|
|
@@ -31,7 +31,7 @@ The Hooks Engine validates agent hook configuration and enforces completion gate
|
|
|
31
31
|
**Command:**
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
npx
|
|
34
|
+
npx phasegate validate --layer L0
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
---
|
|
@@ -68,7 +68,7 @@ L1 rules run in real-time as code is written. They are implemented as Biome AST
|
|
|
68
68
|
**Command:**
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
npx
|
|
71
|
+
npx phasegate lint
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
---
|
|
@@ -86,7 +86,7 @@ L2 validators run before every commit. They enforce process discipline and test
|
|
|
86
86
|
**Command:**
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
npx
|
|
89
|
+
npx phasegate validate --layer L2
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
---
|
|
@@ -105,7 +105,7 @@ L3 validators run in the CI/CD pipeline before a merge is permitted. They cover
|
|
|
105
105
|
**Command:**
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
npx
|
|
108
|
+
npx phasegate validate --layer L3
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
---
|
|
@@ -123,7 +123,7 @@ L4 validators run on a weekly schedule. They detect slow-moving drift that accum
|
|
|
123
123
|
**Command:**
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
npx
|
|
126
|
+
npx phasegate validate --layer L4
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Skills Overview
|
|
2
2
|
|
|
3
|
-
Phasegate provides 28 skills covering the full AIDLC (AI-Driven Development Life Cycle). Skills are deployed to `.claude/skills/` by `npx
|
|
3
|
+
Phasegate provides 28 skills covering the full AIDLC (AI-Driven Development Life Cycle). Skills are deployed to `.claude/skills/` by `npx phasegate init` and invoked as slash commands in AI agent sessions.
|
|
4
4
|
|
|
5
5
|
## AIDLC Process — Skill Execution Order
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phasegate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"packageManager": "pnpm@10.30.1",
|
|
5
5
|
"description": "Phasegate — AI-agnostic quality defense toolkit. Enforces structural integrity between design intent and code.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
28
|
"files": [
|
|
29
|
-
"bin/
|
|
29
|
+
"bin/phasegate",
|
|
30
30
|
"scripts/harness/**/*.ts",
|
|
31
31
|
"!scripts/harness/__tests__/**",
|
|
32
32
|
"scripts/harness/**/*.json",
|
|
@@ -40,23 +40,25 @@
|
|
|
40
40
|
"CHANGELOG.md"
|
|
41
41
|
],
|
|
42
42
|
"bin": {
|
|
43
|
-
"
|
|
43
|
+
"phasegate": "./bin/phasegate"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"test": "vitest run --config scripts/harness/__tests__/vitest.config.ts"
|
|
46
|
+
"phasegate": "npx tsx scripts/harness/main.ts",
|
|
47
|
+
"phasegate:status": "npx tsx scripts/harness/main.ts harness:status",
|
|
48
|
+
"phasegate:enable": "npx tsx scripts/harness/main.ts enable-feature",
|
|
49
|
+
"phasegate:disable": "npx tsx scripts/harness/main.ts disable-feature",
|
|
50
|
+
"phasegate:check-phase": "npx tsx scripts/harness/main.ts harness:check-phase",
|
|
51
|
+
"phasegate:check-ready": "npx tsx scripts/harness/main.ts harness:check-ready",
|
|
52
|
+
"test": "vitest run --config scripts/harness/__tests__/vitest.config.forks.ts && vitest run --config scripts/harness/__tests__/vitest.config.ts"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"ajv": "^8.18.0",
|
|
56
|
+
"picomatch": "^4.0.4",
|
|
56
57
|
"tsx": "^4.0.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
60
|
"@biomejs/biome": "^2.4.7",
|
|
61
|
+
"@types/picomatch": "^4.0.0",
|
|
60
62
|
"@types/node": "^25.3.5",
|
|
61
63
|
"typescript": "^5.0.0",
|
|
62
64
|
"vitest": "^3.0.0"
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
const ALLOWED_STATUSES = ['Proposed', 'Accepted', 'Deprecated', 'Superseded'] as const;
|
|
6
6
|
type AdrStatusValue = (typeof ALLOWED_STATUSES)[number];
|
|
7
7
|
|
|
8
|
-
const TRANSITIONS
|
|
9
|
-
Proposed: Object.freeze(['Accepted', 'Deprecated']),
|
|
10
|
-
Accepted: Object.freeze(['Deprecated', 'Superseded']),
|
|
11
|
-
Deprecated: Object.freeze(['Proposed']),
|
|
12
|
-
Superseded: Object.freeze([]),
|
|
8
|
+
const TRANSITIONS = Object.freeze({
|
|
9
|
+
Proposed: Object.freeze(['Accepted', 'Deprecated'] as const),
|
|
10
|
+
Accepted: Object.freeze(['Deprecated', 'Superseded'] as const),
|
|
11
|
+
Deprecated: Object.freeze(['Proposed'] as const),
|
|
12
|
+
Superseded: Object.freeze([] as const),
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
export class InvalidAdrStatusError extends Error {
|
|
@@ -52,7 +52,7 @@ export class AdrStatus {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
canTransitionTo(target: AdrStatus): boolean {
|
|
55
|
-
return TRANSITIONS[this.value].includes(target.value);
|
|
55
|
+
return (TRANSITIONS[this.value] as readonly string[]).includes(target.value);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
equals(other: AdrStatus): boolean {
|
|
@@ -11,8 +11,10 @@ export interface HandlePreToolUseInput {
|
|
|
11
11
|
export interface HandlePreToolUseOutput {
|
|
12
12
|
shouldBlock: boolean;
|
|
13
13
|
blockedFilePath?: string;
|
|
14
|
-
blockReason?: 'PROTECTED_FILE' | 'PHASE_GATE';
|
|
14
|
+
blockReason?: 'PROTECTED_FILE' | 'PHASE_GATE' | 'STORY_REFLECTION';
|
|
15
15
|
error?: { message: string };
|
|
16
16
|
phaseGateBlockers?: string[];
|
|
17
|
+
storyReflectionBlockers?: string[];
|
|
18
|
+
storyReflectionWarnings?: string[];
|
|
17
19
|
nextAction?: string;
|
|
18
20
|
}
|
package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts
CHANGED
|
@@ -9,15 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
import { AsyncHookToCliTranslator } from '../../domain/services/hook-to-cli-translator.js';
|
|
11
11
|
import { HookEvent } from '../../domain/value-objects/hook-event.js';
|
|
12
|
-
import { ProtectedFileList } from '../../domain/value-objects/protected-file-list.js';
|
|
13
12
|
import type { BlockMetadata } from '../../domain/value-objects/hook-translation-result.js';
|
|
14
13
|
import type { ConfigQueryPort } from '../../domain/ports/config-query-port.js';
|
|
15
14
|
import type { PhaseGateQueryPort } from '../../domain/ports/phase-gate-query-port.js';
|
|
15
|
+
import type { StoryReflectionQueryPort } from '../../domain/ports/story-reflection-query-port.js';
|
|
16
|
+
import { WriteTargetScope } from '../../domain/value-objects/write-target-scope.js';
|
|
16
17
|
import type { HandlePreToolUseInput, HandlePreToolUseOutput } from '../dto/handle-pre-tool-use-dto.js';
|
|
17
18
|
|
|
18
19
|
export interface HandlePreToolUseUseCasePorts {
|
|
19
20
|
configQueryPort: ConfigQueryPort;
|
|
20
21
|
phaseGateQueryPort: PhaseGateQueryPort;
|
|
22
|
+
storyReflectionQueryPort?: StoryReflectionQueryPort;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export class HandlePreToolUseInputValidationError extends Error {
|
|
@@ -29,11 +31,17 @@ export class HandlePreToolUseInputValidationError extends Error {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export class HandlePreToolUseUseCase {
|
|
34
|
+
private static readonly WRITE_TOOLS: ReadonlySet<string> = new Set([
|
|
35
|
+
'Write', 'Edit', 'NotebookEdit', 'str_replace_editor',
|
|
36
|
+
]);
|
|
37
|
+
|
|
32
38
|
private readonly translator: AsyncHookToCliTranslator;
|
|
33
39
|
private readonly configQueryPort: ConfigQueryPort;
|
|
40
|
+
private readonly storyReflectionQueryPort?: StoryReflectionQueryPort;
|
|
34
41
|
|
|
35
42
|
constructor(ports: HandlePreToolUseUseCasePorts) {
|
|
36
43
|
this.configQueryPort = ports.configQueryPort;
|
|
44
|
+
this.storyReflectionQueryPort = ports.storyReflectionQueryPort;
|
|
37
45
|
this.translator = new AsyncHookToCliTranslator({
|
|
38
46
|
configQueryPort: ports.configQueryPort,
|
|
39
47
|
reentryGuard: { isActive: () => false } as never,
|
|
@@ -71,7 +79,39 @@ export class HandlePreToolUseUseCase {
|
|
|
71
79
|
};
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
|
|
82
|
+
const scope = this.resolveStoryReflectionScope(input);
|
|
83
|
+
if (scope === null || this.storyReflectionQueryPort === undefined) {
|
|
84
|
+
return { shouldBlock: false };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const reflectionResult = await this.storyReflectionQueryPort.checkReflection(scope.unitId!);
|
|
88
|
+
|
|
89
|
+
if (reflectionResult.skipped || reflectionResult.passed) {
|
|
90
|
+
return { shouldBlock: false };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return HandlePreToolUseUseCase.buildStoryReflectionBlockOutput(
|
|
94
|
+
input.targetFilePaths[0],
|
|
95
|
+
reflectionResult.blockers,
|
|
96
|
+
reflectionResult.warnings,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private resolveStoryReflectionScope(input: HandlePreToolUseInput): WriteTargetScope | null {
|
|
101
|
+
if (!HandlePreToolUseUseCase.WRITE_TOOLS.has(input.toolName)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const projectPaths = this.configQueryPort.getProjectPaths();
|
|
106
|
+
|
|
107
|
+
for (const targetFilePath of input.targetFilePaths) {
|
|
108
|
+
const scope = WriteTargetScope.fromPath(targetFilePath, projectPaths);
|
|
109
|
+
if (scope?.level === 3 && scope.unitId !== undefined) {
|
|
110
|
+
return scope;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return null;
|
|
75
115
|
}
|
|
76
116
|
|
|
77
117
|
private static readonly LEVEL_LABELS: Record<number, string> = {
|
|
@@ -129,7 +169,7 @@ export class HandlePreToolUseUseCase {
|
|
|
129
169
|
{
|
|
130
170
|
pattern: /(?:^|\/)harness\.config\.json$/,
|
|
131
171
|
message: (fp) =>
|
|
132
|
-
`保護ファイルへの書き込みがブロックされました: ${fp}\nハーネス設定は CLI 経由で変更してください: npx
|
|
172
|
+
`保護ファイルへの書き込みがブロックされました: ${fp}\nハーネス設定は CLI 経由で変更してください: npx phasegate config ...`,
|
|
133
173
|
},
|
|
134
174
|
{
|
|
135
175
|
pattern: /(?:^|\/)\.claude\/settings\.json$/,
|
|
@@ -161,4 +201,70 @@ export class HandlePreToolUseUseCase {
|
|
|
161
201
|
error: { message },
|
|
162
202
|
};
|
|
163
203
|
}
|
|
204
|
+
|
|
205
|
+
private static buildStoryReflectionBlockOutput(
|
|
206
|
+
blockedFilePath: string | undefined,
|
|
207
|
+
blockers: readonly string[],
|
|
208
|
+
warnings: readonly string[],
|
|
209
|
+
): HandlePreToolUseOutput {
|
|
210
|
+
return {
|
|
211
|
+
shouldBlock: true,
|
|
212
|
+
blockedFilePath,
|
|
213
|
+
blockReason: 'STORY_REFLECTION',
|
|
214
|
+
error: {
|
|
215
|
+
message: HandlePreToolUseUseCase.buildStoryReflectionErrorMessage(blockers),
|
|
216
|
+
},
|
|
217
|
+
storyReflectionBlockers: [...blockers],
|
|
218
|
+
storyReflectionWarnings: [...warnings],
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private static buildStoryReflectionErrorMessage(blockers: readonly string[]): string {
|
|
223
|
+
const firstBlocker = blockers[0];
|
|
224
|
+
const details = firstBlocker === undefined
|
|
225
|
+
? null
|
|
226
|
+
: HandlePreToolUseUseCase.extractStoryReflectionDetails(firstBlocker);
|
|
227
|
+
const lines: string[] = [];
|
|
228
|
+
|
|
229
|
+
if (details !== null) {
|
|
230
|
+
lines.push(`[L2-STORY-REFLECTION] ${details.productPath} に`);
|
|
231
|
+
lines.push(`@story-id ${details.storyId} が反映されていません。`);
|
|
232
|
+
lines.push('');
|
|
233
|
+
} else {
|
|
234
|
+
lines.push('[L2-STORY-REFLECTION] product 文書に @story-id が反映されていません。');
|
|
235
|
+
lines.push('');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (const blocker of blockers) {
|
|
239
|
+
lines.push(`- ${blocker}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
lines.push('');
|
|
243
|
+
lines.push('修正方法:');
|
|
244
|
+
lines.push(' 1. cascade-updater を実行して product 文書を更新');
|
|
245
|
+
lines.push(
|
|
246
|
+
` 2. または手動で該当 product 文書に @story-id ${details?.storyId ?? '<STORY-ID>'} を追加`,
|
|
247
|
+
);
|
|
248
|
+
lines.push('');
|
|
249
|
+
lines.push('参照: ADR-XXX');
|
|
250
|
+
|
|
251
|
+
return lines.join('\n');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private static extractStoryReflectionDetails(
|
|
255
|
+
blocker: string,
|
|
256
|
+
): { productPath: string; storyId: string } | null {
|
|
257
|
+
const productPathMatch = blocker.match(/docs\/product\/construction\/[^\s]+\.md/);
|
|
258
|
+
const storyIdMatch = blocker.match(/@story-id\s+([A-Z][\w-]*-\d+)|\b([A-Z][\w-]*-\d+)\b/);
|
|
259
|
+
const storyId = storyIdMatch?.[1] ?? storyIdMatch?.[2];
|
|
260
|
+
|
|
261
|
+
if (productPathMatch === null || storyId === undefined) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
productPath: productPathMatch[0],
|
|
267
|
+
storyId,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
164
270
|
}
|
|
@@ -68,7 +68,7 @@ export class HandleStopUseCase {
|
|
|
68
68
|
await this.reentryGuardStatePort.writeActive();
|
|
69
69
|
|
|
70
70
|
try {
|
|
71
|
-
const cliResult = await this.cliExecutorPort.execute('
|
|
71
|
+
const cliResult = await this.cliExecutorPort.execute('phasegate:complete-check', []);
|
|
72
72
|
return {
|
|
73
73
|
executed: true,
|
|
74
74
|
cliResult,
|
|
@@ -8,5 +8,7 @@ export type HookType = 'pre-tool-use' | 'post-tool-use' | 'stop';
|
|
|
8
8
|
export interface ConfigQueryPort {
|
|
9
9
|
isHookEnabled(hookType: HookType): Promise<boolean>;
|
|
10
10
|
getProtectedFilePatterns(): Promise<string[]>;
|
|
11
|
+
getProtectedFileExclusions(): Promise<string[]>;
|
|
12
|
+
getRelaxedGates(): Promise<readonly string[]>;
|
|
11
13
|
getProjectPaths(): ProjectPaths;
|
|
12
14
|
}
|