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.
Files changed (229) hide show
  1. package/README.ja.md +103 -71
  2. package/README.md +73 -13
  3. package/bin/{harness → phasegate} +1 -1
  4. package/docs/ADR/ADR-013-story-reflection-gate.md +100 -0
  5. package/docs/guide/cli-reference.md +9 -9
  6. package/docs/guide/configuration.md +245 -8
  7. package/docs/guide/hooks-integration.md +1 -1
  8. package/docs/guide/installation.md +6 -6
  9. package/docs/guide/layer-model.md +5 -5
  10. package/docs/guide/skills-overview.md +1 -1
  11. package/package.json +12 -10
  12. package/scripts/harness/adr-foundation/domain/ports/adr-document-parser-port.ts +1 -0
  13. package/scripts/harness/adr-foundation/domain/ports/adr-frontmatter-parser-port.ts +1 -0
  14. package/scripts/harness/adr-foundation/domain/ports/adr-repository-port.ts +1 -0
  15. package/scripts/harness/adr-foundation/domain/value-objects/adr-status.ts +6 -6
  16. package/scripts/harness/agent-integration/application/dto/handle-pre-tool-use-dto.ts +3 -1
  17. package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +109 -3
  18. package/scripts/harness/agent-integration/application/usecases/handle-stop-usecase.ts +1 -1
  19. package/scripts/harness/agent-integration/domain/ports/config-query-port.ts +2 -0
  20. package/scripts/harness/agent-integration/domain/ports/phase-gate-query-port.ts +1 -1
  21. package/scripts/harness/agent-integration/domain/ports/story-reflection-query-port.ts +8 -0
  22. package/scripts/harness/agent-integration/domain/services/bash-write-target-extractor.ts +258 -0
  23. package/scripts/harness/agent-integration/domain/services/hook-to-cli-translator.ts +25 -8
  24. package/scripts/harness/agent-integration/domain/value-objects/protected-file-list.ts +20 -0
  25. package/scripts/harness/agent-integration/domain/value-objects/story-reflection-query-result.ts +63 -0
  26. package/scripts/harness/agent-integration/infrastructure/adapters/child-process-cli-executor-adapter.ts +2 -2
  27. package/scripts/harness/agent-integration/infrastructure/adapters/file-system-story-reflection-query-adapter.ts +122 -0
  28. package/scripts/harness/agent-integration/infrastructure/adapters/harness-api-cli-command-registry-adapter.ts +10 -10
  29. package/scripts/harness/agent-integration/infrastructure/adapters/harness-config-config-query-adapter.ts +20 -0
  30. package/scripts/harness/agent-integration/infrastructure/adapters/phase-gate-query-adapter.ts +17 -3
  31. package/scripts/harness/agent-integration/presentation/pre-tool-use-hook.ts +29 -2
  32. package/scripts/harness/biome-ast-engine/domain/services/lint-runner.ts +24 -0
  33. package/scripts/harness/biome-ast-engine/domain/services/rule-definition-registry.ts +1 -1
  34. package/scripts/harness/biome-ast-engine/domain/value-objects/source-module-snapshot.ts +5 -2
  35. package/scripts/harness/biome-ast-engine/infrastructure/adapters/node-workspace-file-adapter.ts +1 -1
  36. package/scripts/harness/biome-ast-engine/infrastructure/adapters/typescript-source-module-analyzer-adapter.ts +1 -1
  37. package/scripts/harness/biome-ast-engine/infrastructure/parsers/unit-comment-parser.ts +12 -7
  38. package/scripts/harness/ci-governance/composition-root.ts +1 -0
  39. package/scripts/harness/ci-governance/infrastructure/adapters/agents-md-file-adapter.ts +2 -2
  40. package/scripts/harness/ci-governance/infrastructure/adapters/yaml-template-renderer-adapter.ts +2 -2
  41. package/scripts/harness/config-foundation/application/mappers/phase-config-section-mapper.ts +44 -0
  42. package/scripts/harness/config-foundation/application/usecases/load-resolved-config-use-case.ts +20 -1
  43. package/scripts/harness/config-foundation/domain/harness-config.ts +2 -1
  44. package/scripts/harness/config-foundation/domain/value-objects/phase-dependencies-config.ts +18 -4
  45. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +185 -10
  46. package/scripts/harness/config-foundation/infrastructure/validators/ajv-config-schema-validator.ts +2 -1
  47. package/scripts/harness/harness-api/application/dto/command-dispatch-input.ts +1 -0
  48. package/scripts/harness/harness-api/application/dto/command-dispatch-output.ts +1 -0
  49. package/scripts/harness/harness-api/application/dto/exit-code-decision-input.ts +1 -0
  50. package/scripts/harness/harness-api/application/dto/exit-code-decision-output.ts +1 -0
  51. package/scripts/harness/harness-api/application/dto/harness-api-response-contract.ts +1 -0
  52. package/scripts/harness/harness-api/application/dto/initialize-registry-input.ts +1 -0
  53. package/scripts/harness/harness-api/application/dto/registry-summary-output.ts +1 -0
  54. package/scripts/harness/harness-api/application/dto/status-derivation-input.ts +1 -0
  55. package/scripts/harness/harness-api/application/mappers/harness-api-response-mapper.ts +1 -0
  56. package/scripts/harness/harness-api/application/usecases/decide-exit-code-usecase.ts +4 -3
  57. package/scripts/harness/harness-api/application/usecases/derive-harness-status-usecase.ts +1 -0
  58. package/scripts/harness/harness-api/application/usecases/dispatch-command-usecase.ts +1 -0
  59. package/scripts/harness/harness-api/application/usecases/initialize-command-registry-usecase.ts +1 -0
  60. package/scripts/harness/harness-api/composition-root.ts +1 -0
  61. package/scripts/harness/harness-api/domain/ports/artifact-scanner-port.ts +1 -0
  62. package/scripts/harness/harness-api/domain/ports/biome-lint-port.ts +1 -0
  63. package/scripts/harness/harness-api/domain/ports/config-query-port.ts +1 -0
  64. package/scripts/harness/harness-api/domain/ports/impact-analysis-port.ts +1 -0
  65. package/scripts/harness/harness-api/domain/ports/phase-gate-query-port.ts +1 -0
  66. package/scripts/harness/harness-api/domain/ports/validator-execution-port.ts +1 -0
  67. package/scripts/harness/harness-api/domain/services/command-dispatch-service.ts +17 -16
  68. package/scripts/harness/harness-api/domain/services/command-registry.ts +4 -3
  69. package/scripts/harness/harness-api/domain/services/status-derivation-service.ts +1 -0
  70. package/scripts/harness/harness-api/domain/value-objects/artifact-scan-result.ts +1 -0
  71. package/scripts/harness/harness-api/domain/value-objects/check-ready-result.ts +1 -0
  72. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +1 -0
  73. package/scripts/harness/harness-api/domain/value-objects/cli-command-definition.ts +11 -10
  74. package/scripts/harness/harness-api/domain/value-objects/command-input-spec.ts +1 -0
  75. package/scripts/harness/harness-api/domain/value-objects/drift-report-summary.ts +1 -0
  76. package/scripts/harness/harness-api/domain/value-objects/exit-code-spec.ts +1 -0
  77. package/scripts/harness/harness-api/domain/value-objects/harness-api-response.ts +1 -0
  78. package/scripts/harness/harness-api/domain/value-objects/harness-status-summary.ts +1 -0
  79. package/scripts/harness/harness-api/domain/value-objects/layer-health.ts +1 -0
  80. package/scripts/harness/harness-api/domain/value-objects/phase-info.ts +1 -0
  81. package/scripts/harness/harness-api/index.ts +1 -0
  82. package/scripts/harness/harness-api/infrastructure/adapters/biome-ast-engine-lint-adapter.ts +1 -0
  83. package/scripts/harness/harness-api/infrastructure/adapters/file-system-artifact-scanner-adapter.ts +1 -0
  84. package/scripts/harness/harness-api/infrastructure/adapters/harness-config-query-adapter.ts +1 -0
  85. package/scripts/harness/harness-api/infrastructure/adapters/nyquist-validation-impact-analysis-adapter.ts +1 -0
  86. package/scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts +1 -0
  87. package/scripts/harness/harness-api/infrastructure/adapters/validator-system-execution-adapter.ts +1 -0
  88. package/scripts/harness/harness-api/presentation/dto/cli-output-options.ts +1 -0
  89. package/scripts/harness/harness-api/presentation/formatters/harness-api-json-formatter.ts +1 -0
  90. package/scripts/harness/harness-api/presentation/handlers/check-phase-handler.ts +2 -1
  91. package/scripts/harness/harness-api/presentation/handlers/check-ready-handler.ts +2 -1
  92. package/scripts/harness/harness-api/presentation/handlers/ci-check-handler.ts +2 -1
  93. package/scripts/harness/harness-api/presentation/handlers/complete-check-handler.ts +2 -1
  94. package/scripts/harness/harness-api/presentation/handlers/detect-drift-handler.ts +2 -1
  95. package/scripts/harness/harness-api/presentation/handlers/impact-analysis-handler.ts +2 -1
  96. package/scripts/harness/harness-api/presentation/handlers/lint-handler.ts +2 -1
  97. package/scripts/harness/harness-api/presentation/handlers/status-handler.ts +4 -3
  98. package/scripts/harness/harness-error/infrastructure/adapters/legacy-error-reporter-adapter.ts +7 -1
  99. package/scripts/harness/integrations/pre-commit.ts +1 -0
  100. package/scripts/harness/main.ts +173 -53
  101. package/scripts/harness/phase-dependency-model/application/dto/resolve-gate-result-dto.ts +14 -0
  102. package/scripts/harness/phase-dependency-model/application/services/phase-gate-result-mapper.ts +20 -0
  103. package/scripts/harness/phase-dependency-model/application/usecases/check-story-reflection-usecase.ts +42 -0
  104. package/scripts/harness/phase-dependency-model/application/usecases/resolve-gate-usecase.ts +161 -0
  105. package/scripts/harness/phase-dependency-model/composition-root.ts +57 -1
  106. package/scripts/harness/phase-dependency-model/domain/definitions/{default-phase-dependencies.ts → full-phase-dependencies.ts} +3 -3
  107. package/scripts/harness/phase-dependency-model/domain/definitions/{default-phase-nodes.ts → full-phase-nodes.ts} +1 -1
  108. package/scripts/harness/phase-dependency-model/domain/definitions/full-story-reflection-defaults.ts +28 -0
  109. package/scripts/harness/phase-dependency-model/domain/definitions/minimal-phase-dependencies.ts +32 -0
  110. package/scripts/harness/phase-dependency-model/domain/definitions/minimal-phase-nodes.ts +50 -0
  111. package/scripts/harness/phase-dependency-model/domain/definitions/minimal-story-reflection-defaults.ts +8 -0
  112. package/scripts/harness/phase-dependency-model/domain/definitions/standard-phase-dependencies.ts +39 -0
  113. package/scripts/harness/phase-dependency-model/domain/definitions/standard-phase-nodes.ts +118 -0
  114. package/scripts/harness/phase-dependency-model/domain/definitions/standard-story-reflection-defaults.ts +23 -0
  115. package/scripts/harness/phase-dependency-model/domain/models/phase-structure.ts +95 -23
  116. package/scripts/harness/phase-dependency-model/domain/ports/glob-matcher-port.ts +8 -0
  117. package/scripts/harness/phase-dependency-model/domain/ports/phase-config-provider-port.ts +2 -0
  118. package/scripts/harness/phase-dependency-model/domain/ports/story-annotation-verifier-port.ts +14 -0
  119. package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +16 -0
  120. package/scripts/harness/phase-dependency-model/domain/services/gate-graph.ts +223 -0
  121. package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +66 -0
  122. package/scripts/harness/phase-dependency-model/domain/values/gate-definition.ts +127 -0
  123. package/scripts/harness/phase-dependency-model/domain/values/gate-name.ts +40 -0
  124. package/scripts/harness/phase-dependency-model/domain/values/gate-story-annotation.ts +39 -0
  125. package/scripts/harness/phase-dependency-model/domain/values/phase-customization-policy.ts +16 -4
  126. package/scripts/harness/phase-dependency-model/domain/values/story-reflection-config.ts +44 -0
  127. package/scripts/harness/phase-dependency-model/domain/values/story-reflection-mapping.ts +91 -0
  128. package/scripts/harness/phase-dependency-model/domain/values/story-reflection-result.ts +55 -0
  129. package/scripts/harness/phase-dependency-model/infrastructure/adapters/picomatch-glob-matcher.ts +17 -0
  130. package/scripts/harness/phase-dependency-model/infrastructure/adapters/story-annotation-verifier-adapter.ts +46 -0
  131. package/scripts/harness/phase-dependency-model/infrastructure/config/custom-gates-config-parser.ts +22 -0
  132. package/scripts/harness/phase-dependency-model/infrastructure/config/harness-config-phase-config-provider.ts +78 -2
  133. package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +94 -0
  134. package/scripts/harness/phase-dependency-model/presentation/cli/check-phase-gate-command-handler.ts +12 -4
  135. package/scripts/harness/phase-dependency-model/presentation/cli/story-reflection-status-presenter.ts +87 -0
  136. package/scripts/harness/quick-mode/application/usecases/execute-quick-ci-check-usecase.ts +1 -1
  137. package/scripts/harness/quick-mode/presentation/handlers/ci-check-quick-mode-handler.ts +1 -1
  138. package/scripts/harness/regression-suite/application/dto/analyze-migration-input.ts +1 -0
  139. package/scripts/harness/regression-suite/application/dto/analyze-migration-output.ts +1 -0
  140. package/scripts/harness/regression-suite/application/dto/configure-ci-gate-input.ts +1 -0
  141. package/scripts/harness/regression-suite/application/dto/configure-ci-gate-output.ts +1 -0
  142. package/scripts/harness/regression-suite/application/dto/migrate-v0-tests-input.ts +1 -0
  143. package/scripts/harness/regression-suite/application/dto/migrate-v0-tests-output.ts +1 -0
  144. package/scripts/harness/regression-suite/application/dto/run-regression-suite-input.ts +1 -0
  145. package/scripts/harness/regression-suite/application/dto/run-regression-suite-output.ts +1 -0
  146. package/scripts/harness/regression-suite/application/mappers/migration-mapping-mapper.ts +1 -0
  147. package/scripts/harness/regression-suite/application/mappers/test-execution-summary-mapper.ts +1 -0
  148. package/scripts/harness/regression-suite/application/usecases/analyze-v0-migration-usecase.ts +1 -0
  149. package/scripts/harness/regression-suite/application/usecases/configure-ci-gate-usecase.ts +1 -0
  150. package/scripts/harness/regression-suite/application/usecases/migrate-v0-tests-usecase.ts +1 -0
  151. package/scripts/harness/regression-suite/application/usecases/run-agent-independence-guard-usecase.ts +1 -0
  152. package/scripts/harness/regression-suite/application/usecases/run-gng-gate-regression-usecase.ts +1 -0
  153. package/scripts/harness/regression-suite/application/usecases/run-k-requirements-regression-usecase.ts +1 -0
  154. package/scripts/harness/regression-suite/application/usecases/run-k14-k15-regression-usecase.ts +1 -0
  155. package/scripts/harness/regression-suite/composition-root.ts +1 -0
  156. package/scripts/harness/regression-suite/domain/aggregates/v0-test-migration.ts +1 -0
  157. package/scripts/harness/regression-suite/domain/ports/ci-gate-result-writer-port.ts +1 -0
  158. package/scripts/harness/regression-suite/domain/ports/config-query-port.ts +1 -0
  159. package/scripts/harness/regression-suite/domain/ports/import-analyzer-port.ts +1 -0
  160. package/scripts/harness/regression-suite/domain/ports/migration-mapping-repository-port.ts +1 -0
  161. package/scripts/harness/regression-suite/domain/ports/suite-registry-port.ts +1 -0
  162. package/scripts/harness/regression-suite/domain/ports/test-runner-port.ts +1 -0
  163. package/scripts/harness/regression-suite/domain/ports/v0-spec-reader-port.ts +1 -0
  164. package/scripts/harness/regression-suite/domain/services/import-guard-service.ts +1 -0
  165. package/scripts/harness/regression-suite/domain/services/migration-analyzer.ts +1 -0
  166. package/scripts/harness/regression-suite/domain/services/regression-runner.ts +1 -0
  167. package/scripts/harness/regression-suite/domain/value-objects/agent-independence-test.ts +1 -0
  168. package/scripts/harness/regression-suite/domain/value-objects/biome-modification-spec.ts +1 -0
  169. package/scripts/harness/regression-suite/domain/value-objects/ci-gate-config.ts +1 -0
  170. package/scripts/harness/regression-suite/domain/value-objects/coverage-rate.ts +1 -0
  171. package/scripts/harness/regression-suite/domain/value-objects/gng-condition-test.ts +1 -0
  172. package/scripts/harness/regression-suite/domain/value-objects/import-violation.ts +1 -0
  173. package/scripts/harness/regression-suite/domain/value-objects/k-requirement-test.ts +1 -0
  174. package/scripts/harness/regression-suite/domain/value-objects/migration-mapping.ts +1 -0
  175. package/scripts/harness/regression-suite/domain/value-objects/regression-suite-definition.ts +1 -0
  176. package/scripts/harness/regression-suite/domain/value-objects/suite-id.ts +1 -0
  177. package/scripts/harness/regression-suite/domain/value-objects/test-execution-summary.ts +1 -0
  178. package/scripts/harness/regression-suite/domain/value-objects/test-failure-detail.ts +1 -0
  179. package/scripts/harness/regression-suite/domain/value-objects/v0-test-id.ts +1 -0
  180. package/scripts/harness/regression-suite/domain/value-objects/v1-test-path.ts +1 -0
  181. package/scripts/harness/regression-suite/infrastructure/adapters/biome-ast-import-analyzer-adapter.ts +1 -0
  182. package/scripts/harness/regression-suite/infrastructure/adapters/file-system-v0-spec-reader-adapter.ts +1 -0
  183. package/scripts/harness/regression-suite/infrastructure/adapters/harness-config-query-adapter.ts +1 -0
  184. package/scripts/harness/regression-suite/infrastructure/adapters/json-ci-gate-result-writer-adapter.ts +1 -0
  185. package/scripts/harness/regression-suite/infrastructure/adapters/markdown-migration-mapping-repository-adapter.ts +1 -0
  186. package/scripts/harness/regression-suite/infrastructure/adapters/static-suite-registry-adapter.ts +1 -0
  187. package/scripts/harness/regression-suite/infrastructure/adapters/vitest-test-runner-adapter.ts +1 -0
  188. package/scripts/harness/regression-suite/infrastructure/registry/agent-independence-suite-definition.ts +1 -0
  189. package/scripts/harness/regression-suite/infrastructure/registry/gng-gate-suite-definition.ts +1 -0
  190. package/scripts/harness/regression-suite/infrastructure/registry/k-requirements-suite-definition.ts +1 -0
  191. package/scripts/harness/regression-suite/infrastructure/registry/v0-migration-suite-definition.ts +1 -0
  192. package/scripts/harness/setup/skill-deployer.ts +82 -5
  193. package/scripts/harness/shared-kernel/harness-api.ts +1 -0
  194. package/scripts/harness/skill-quality/composition-root.ts +1 -0
  195. package/scripts/harness/skill-quality/infrastructure/adapters/ajv-lesson-artifact-schema-adapter.ts +5 -4
  196. package/scripts/harness/traceability-model/domain/services/metadata-validator.ts +12 -10
  197. package/scripts/harness/traceability-model/infrastructure/parsers/source-metadata-parser.ts +16 -2
  198. package/scripts/harness/validator-system/composition-root.ts +3 -3
  199. package/skills/cascade-updater/SKILL.md +16 -3
  200. package/skills/codebase-mapper/SKILL.md +9 -9
  201. package/skills/codex-delegator/SKILL.md +5 -56
  202. package/skills/consistency-checker/SKILL.md +5 -9
  203. 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
  204. package/skills/doc-freshness-checker/SKILL.md +6 -6
  205. package/skills/engineering-perspective/SKILL.md +2 -58
  206. package/skills/engineering-perspective/references/domain-model.md +4 -135
  207. package/skills/implementation-readiness-checker/SKILL.md +18 -72
  208. package/skills/it-test-designer/SKILL.md +25 -161
  209. package/skills/it-test-designer/references/it-test-design-template.md +131 -0
  210. package/skills/it-test-logic-designer/SKILL.md +13 -388
  211. package/skills/it-test-logic-designer/references/controller-test-patterns.md +100 -0
  212. package/skills/it-test-logic-designer/references/repository-test-patterns.md +206 -0
  213. package/skills/it-test-logic-designer/references/usecase-test-patterns.md +87 -0
  214. package/skills/pointer-validator/SKILL.md +4 -4
  215. package/skills/scenario-test-designer/SKILL.md +4 -68
  216. package/skills/scenario-test-designer/references/scenario-test-design-template.md +41 -0
  217. package/skills/scenario-test-designer/references/scenario-test-plan-template.md +35 -0
  218. package/skills/scenario-test-logic-designer/SKILL.md +21 -304
  219. package/skills/scenario-test-logic-designer/references/msw-patterns.md +36 -0
  220. package/skills/scenario-test-logic-designer/references/playwright-patterns.md +237 -0
  221. package/skills/test-coverage-checker/SKILL.md +39 -121
  222. package/skills/test-coverage-checker/references/coverage-report-template.md +99 -0
  223. package/skills/uiux-designer/SKILL.md +27 -92
  224. package/skills/uiux-designer/references/data-testid-convention.md +38 -0
  225. package/skills/uiux-designer/references/uiux-design-template.md +105 -0
  226. package/skills/unit-test-designer/SKILL.md +5 -106
  227. package/skills/unit-test-designer/references/unit-test-design-template.md +127 -0
  228. package/skills/unit-test-logic-designer/SKILL.md +28 -250
  229. package/skills/unit-test-logic-designer/references/test-patterns.md +207 -0
@@ -4,16 +4,26 @@
4
4
  import type { PhaseGateQueryPort } from '../../domain/ports/phase-gate-query-port.js';
5
5
  import type { WriteTargetScope } from '../../domain/value-objects/write-target-scope.js';
6
6
  import { PhaseGateQueryResult } from '../../domain/value-objects/phase-gate-query-result.js';
7
+ import { toPhaseConfigSection } from '../../../config-foundation/application/mappers/phase-config-section-mapper.js';
8
+ import { createConfigFoundationModule } from '../../../config-foundation/composition-root.js';
9
+ import { ConfigValidationError } from '../../../config-foundation/domain/errors/config-validation-error.js';
7
10
 
8
11
  export class PhaseGateQueryAdapter implements PhaseGateQueryPort {
9
- async checkGate(scope: WriteTargetScope): Promise<PhaseGateQueryResult> {
12
+ async checkGate(scope: WriteTargetScope, targetFilePath?: string): Promise<PhaseGateQueryResult> {
10
13
  try {
14
+ const configModule = createConfigFoundationModule();
15
+ const resolvedConfig = await configModule.usecases.loadResolvedConfigUseCase.execute();
11
16
  const { createPhaseDependencyModelModule } = await import('../../../phase-dependency-model/composition-root.js');
12
- const mod = createPhaseDependencyModelModule({ rootDir: process.cwd() });
17
+ const mod = createPhaseDependencyModelModule({
18
+ rootDir: process.cwd(),
19
+ phaseConfig: toPhaseConfigSection(resolvedConfig.config),
20
+ reportOutputDir: resolvedConfig.config.reporting.outputDir,
21
+ });
13
22
  const result = await mod.checkPhaseGateCommandHandler.execute({
14
23
  targetLevel: scope.level,
15
24
  unitId: scope.unitId,
16
25
  storyId: scope.storyId,
26
+ targetFilePath,
17
27
  });
18
28
 
19
29
  if (result.exitCode === 0) {
@@ -25,7 +35,11 @@ export class PhaseGateQueryAdapter implements PhaseGateQueryPort {
25
35
  }
26
36
 
27
37
  return PhaseGateQueryResult.create(true, [], ['phase gate check returned error']);
28
- } catch {
38
+ } catch (error) {
39
+ if (error instanceof ConfigValidationError) {
40
+ return PhaseGateQueryResult.create(false, [error.message], []);
41
+ }
42
+
29
43
  return PhaseGateQueryResult.create(true, [], ['phase-dependency-model not available']);
30
44
  }
31
45
  }
@@ -8,8 +8,10 @@
8
8
  */
9
9
 
10
10
  import { HandlePreToolUseUseCase } from '../application/usecases/handle-pre-tool-use-usecase.js';
11
+ import { BashWriteTargetExtractor } from '../domain/services/bash-write-target-extractor.js';
11
12
  import { HarnessConfigConfigQueryAdapter } from '../infrastructure/adapters/harness-config-config-query-adapter.js';
12
13
  import { PhaseGateQueryAdapter } from '../infrastructure/adapters/phase-gate-query-adapter.js';
14
+ import { FileSystemStoryReflectionQueryAdapter } from '../infrastructure/adapters/file-system-story-reflection-query-adapter.js';
13
15
  import * as path from 'node:path';
14
16
  import * as fs from 'node:fs/promises';
15
17
 
@@ -20,6 +22,7 @@ interface PreToolUseHookInput {
20
22
  path?: string;
21
23
  file_path?: string;
22
24
  paths?: string[];
25
+ command?: string;
23
26
  [key: string]: unknown;
24
27
  };
25
28
  }
@@ -91,13 +94,37 @@ async function main(): Promise<void> {
91
94
  targetFilePaths.push(...input.tool_input.paths.map(toRelative));
92
95
  }
93
96
 
97
+ // Bash 経由書き込みのフェーズゲート対応 (A-2.5)
98
+ // Bash command 文字列からリダイレクト・tee・sed -i・cp・mv・touch 等の
99
+ // 書き込み先ファイルパスを抽出し、フェーズゲートチェック対象に含める。
100
+ // Bash 書き込みを検出した場合、effectiveToolName を 'Write' に偽装して
101
+ // translator の WRITE_TOOLS チェックを通過させる(Bash のままではフェーズゲートが
102
+ // スキップされるため)。
103
+ let effectiveToolName = toolName;
104
+ if (toolName === 'Bash' && typeof input.tool_input?.command === 'string') {
105
+ const extractor = new BashWriteTargetExtractor();
106
+ const bashTargets = extractor.extract(input.tool_input.command);
107
+ if (bashTargets.length > 0) {
108
+ targetFilePaths.push(...bashTargets.map(toRelative));
109
+ effectiveToolName = 'Write';
110
+ }
111
+ }
112
+
94
113
  try {
95
114
  const configPath = await findConfigPath();
96
115
  const configQueryPort = new HarnessConfigConfigQueryAdapter(configPath);
97
116
  const phaseGateQueryPort = new PhaseGateQueryAdapter();
98
- const useCase = new HandlePreToolUseUseCase({ configQueryPort, phaseGateQueryPort });
117
+ const storyReflectionQueryPort = new FileSystemStoryReflectionQueryAdapter({
118
+ rootDir: path.dirname(configPath),
119
+ configPath,
120
+ });
121
+ const useCase = new HandlePreToolUseUseCase({
122
+ configQueryPort,
123
+ phaseGateQueryPort,
124
+ storyReflectionQueryPort,
125
+ });
99
126
 
100
- const output = await useCase.execute({ toolName, targetFilePaths });
127
+ const output = await useCase.execute({ toolName: effectiveToolName, targetFilePaths });
101
128
 
102
129
  if (output.shouldBlock) {
103
130
  const msg = output.error?.message
@@ -26,6 +26,9 @@ const toStringArray = (value: unknown, fallback: readonly string[]): readonly st
26
26
  ? Object.freeze([...value])
27
27
  : fallback;
28
28
 
29
+ const isTestFile = (snapshot: SourceModuleSnapshot): boolean =>
30
+ snapshot.filePath.toString().includes('__tests__/');
31
+
29
32
  export class LintRunner {
30
33
  private readonly ruleDefinitionRegistry: RuleDefinitionRegistry;
31
34
 
@@ -98,6 +101,10 @@ export class LintRunner {
98
101
  LayerBoundary.standardMatrix(),
99
102
  layerByFile
100
103
  )) {
104
+ const fromSnapshot = snapshotByPath.get(edge.from.toString());
105
+ if (fromSnapshot && isTestFile(fromSnapshot)) {
106
+ continue;
107
+ }
101
108
  ruleViolations.push(
102
109
  RuleViolation.create({
103
110
  filePath: edge.from,
@@ -112,6 +119,10 @@ export class LintRunner {
112
119
 
113
120
  for (const cycle of params.importGraph.detectCycles()) {
114
121
  const firstPath = cycle.path[0];
122
+ const firstSnapshot = snapshotByPath.get(firstPath.toString());
123
+ if (firstSnapshot && isTestFile(firstSnapshot)) {
124
+ continue;
125
+ }
115
126
  ruleViolations.push(
116
127
  RuleViolation.create({
117
128
  filePath: firstPath,
@@ -127,6 +138,9 @@ export class LintRunner {
127
138
  }
128
139
  case 'enforce-folder-structure': {
129
140
  for (const snapshot of params.snapshots) {
141
+ if (isTestFile(snapshot)) {
142
+ continue;
143
+ }
130
144
  if (snapshot.declaredLayer !== null && !snapshot.belongsToLayerDirectory()) {
131
145
  ruleViolations.push(
132
146
  RuleViolation.create({
@@ -147,6 +161,9 @@ export class LintRunner {
147
161
  const maxAnyRatio = toNumber(rule.config.maxAnyRatio, 0.05);
148
162
 
149
163
  for (const snapshot of params.snapshots) {
164
+ if (isTestFile(snapshot)) {
165
+ continue;
166
+ }
150
167
  if (
151
168
  snapshot.anyTypeCount > maxAnyCount ||
152
169
  snapshot.anyRatio() > maxAnyRatio
@@ -223,8 +240,15 @@ export class LintRunner {
223
240
  case 'no-comment-flood': {
224
241
  const maxCommentRatio = toNumber(rule.config.maxCommentRatio, 0.35);
225
242
  const maxRepeatedBlocks = toNumber(rule.config.maxRepeatedBlocks, 1);
243
+ const minLogicalLines = toNumber(rule.config.minLogicalLines, 15);
226
244
 
227
245
  for (const snapshot of params.snapshots) {
246
+ if (isTestFile(snapshot)) {
247
+ continue;
248
+ }
249
+ if (snapshot.logicalLineCount < minLogicalLines) {
250
+ continue;
251
+ }
228
252
  if (
229
253
  snapshot.commentDensity() > maxCommentRatio ||
230
254
  snapshot.repeatedCommentBlocks > maxRepeatedBlocks
@@ -92,7 +92,7 @@ export class RuleDefinitionRegistry {
92
92
  'no-comment-flood',
93
93
  'L1-008',
94
94
  Object.freeze([REQUIRED_INPUT.sourceModuleSnapshots]),
95
- Object.freeze({ maxCommentRatio: 0.35, maxRepeatedBlocks: 1 }),
95
+ Object.freeze({ maxCommentRatio: 0.35, maxRepeatedBlocks: 1, minLogicalLines: 15 }),
96
96
  'コメント過多を検出する',
97
97
  '不要なコメントを整理し自己説明的なコードへ改善する'
98
98
  ),
@@ -59,8 +59,9 @@ export class SourceModuleSnapshot {
59
59
  readonly duplicationFingerprints: readonly string[];
60
60
  readonly exportedSymbols: readonly string[];
61
61
  readonly isEntrypointCandidate: boolean;
62
+ readonly hasRawLayerAnnotation: boolean;
62
63
 
63
- private constructor(props: Omit<SourceModuleSnapshotProps, 'declaredLayer'> & { declaredLayer: LayerName | null }) {
64
+ private constructor(props: Omit<SourceModuleSnapshotProps, 'declaredLayer'> & { declaredLayer: LayerName | null; hasRawLayerAnnotation: boolean }) {
64
65
  this.filePath = props.filePath;
65
66
  this.declaredUnit = props.declaredUnit;
66
67
  this.declaredLayer = props.declaredLayer;
@@ -73,6 +74,7 @@ export class SourceModuleSnapshot {
73
74
  this.duplicationFingerprints = props.duplicationFingerprints;
74
75
  this.exportedSymbols = props.exportedSymbols;
75
76
  this.isEntrypointCandidate = props.isEntrypointCandidate;
77
+ this.hasRawLayerAnnotation = props.hasRawLayerAnnotation;
76
78
  }
77
79
 
78
80
  static create(props: SourceModuleSnapshotProps): SourceModuleSnapshot {
@@ -83,6 +85,7 @@ export class SourceModuleSnapshot {
83
85
  filePath: props.filePath,
84
86
  declaredUnit: props.declaredUnit,
85
87
  declaredLayer,
88
+ hasRawLayerAnnotation: props.declaredLayer !== null,
86
89
  imports: Object.freeze([...props.imports]),
87
90
  anyTypeCount: ensureNonNegative(props.anyTypeCount, 'anyTypeCount'),
88
91
  typedNodeCount: ensureNonNegative(props.typedNodeCount, 'typedNodeCount'),
@@ -104,7 +107,7 @@ export class SourceModuleSnapshot {
104
107
  }
105
108
 
106
109
  hasLayerComment(): boolean {
107
- return this.declaredLayer !== null;
110
+ return this.hasRawLayerAnnotation;
108
111
  }
109
112
 
110
113
  anyRatio(): number {
@@ -11,7 +11,7 @@ import { FilePath as FilePathVO } from '../../domain/value-objects/file-path.js'
11
11
  import type { WorkspaceFilePort } from '../../domain/ports/workspace-file-port.js';
12
12
 
13
13
  const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
14
- const EXCLUDED_DIRS = new Set(['node_modules', 'dist', 'coverage', '__fixtures__']);
14
+ const EXCLUDED_DIRS = new Set(['node_modules', 'dist', 'coverage', '__fixtures__', 'fixtures']);
15
15
 
16
16
  export interface NodeWorkspaceFileAdapterDeps {
17
17
  readonly rootDir: string;
@@ -64,7 +64,7 @@ export class TypeScriptSourceModuleAnalyzerAdapter implements SourceModuleAnalyz
64
64
  snapshots.push(
65
65
  SourceModuleSnapshot.create({
66
66
  filePath,
67
- declaredUnit: unitResult.unitName,
67
+ declaredUnit: unitResult.unitNames[0],
68
68
  declaredLayer: layerResult.layerName,
69
69
  imports,
70
70
  anyTypeCount: anyCount,
@@ -3,24 +3,29 @@
3
3
  * @unit biome-ast-engine
4
4
  */
5
5
 
6
- const UNIT_COMMENT_PATTERN = /^\s*(?:\/\/|\/\*\*?\s*|\*)\s*@unit\s+(\S+)/m;
6
+ const UNIT_COMMENT_PATTERN = /^\s*(?:\/\/|\/\*\*?\s*|\*)\s*@unit\s+(.+)/gm;
7
7
 
8
8
  export type UnitCommentResult = {
9
- readonly unitName: string | null;
9
+ readonly unitNames: readonly string[];
10
10
  };
11
11
 
12
12
  /**
13
13
  * ソースコードから `// @unit {unit}` コメントを抽出する。
14
14
  * JSDoc (`/** @unit ... * /`) 形式にも対応する。
15
+ * カンマ区切りで複数ユニットを指定でき、複数行の @unit も収集する。
16
+ * 結果は重複除去済み。
15
17
  */
16
18
  export const parseUnitComment = (sourceCode: string): UnitCommentResult => {
17
- const match = sourceCode.match(UNIT_COMMENT_PATTERN);
19
+ const matches = sourceCode.matchAll(UNIT_COMMENT_PATTERN);
20
+ const names: string[] = [];
18
21
 
19
- if (!match) {
20
- return { unitName: null };
22
+ for (const match of matches) {
23
+ const raw = match[1].replace(/\s*\*\/$/, '').trim();
24
+ const parts = raw.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
25
+ names.push(...parts);
21
26
  }
22
27
 
23
- const raw = match[1].replace(/\s*\*\/$/, '');
28
+ const deduplicated = [...new Set(names)];
24
29
 
25
- return { unitName: raw };
30
+ return { unitNames: Object.freeze(deduplicated) };
26
31
  };
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @layer infrastructure
2
3
  * @unit ci-governance
3
4
  *
4
5
  * Composition Root - 依存性の組み立て
@@ -50,12 +50,12 @@ export class AgentsMdFileAdapter implements AgentsMdPort {
50
50
  const adrLinks: string[] = [];
51
51
 
52
52
  for (const line of lines) {
53
- const cmdMatch = line.match(/^- \[cmd:([^\]]+)\]\(harness:([^)]+)\)\s*(.*)$/);
53
+ const cmdMatch = line.match(/^- \[cmd:([^\]]+)\]\(phasegate:([^)]+)\)\s*(.*)$/);
54
54
  if (cmdMatch) {
55
55
  try {
56
56
  pointers.push(PointerEntry.createCommand({
57
57
  key: cmdMatch[1].trim(),
58
- command: `harness:${cmdMatch[2].trim()}`,
58
+ command: `phasegate:${cmdMatch[2].trim()}`,
59
59
  description: cmdMatch[3].trim(),
60
60
  }));
61
61
  } catch { /* skip invalid */ }
@@ -33,7 +33,7 @@ export class YamlTemplateRendererAdapter implements TemplateRendererPort {
33
33
  '#!/bin/sh',
34
34
  '. "$(dirname "$0")/_/husky.sh"',
35
35
  '',
36
- `npx harness lint --validators ${config.targetValidatorIds.join(',')}`,
36
+ `npx phasegate lint --validators ${config.targetValidatorIds.join(',')}`,
37
37
  ].join('\n');
38
38
  }
39
39
 
@@ -47,7 +47,7 @@ export class YamlTemplateRendererAdapter implements TemplateRendererPort {
47
47
  ` runs-on: ubuntu-latest`,
48
48
  ` steps:`,
49
49
  ` - uses: actions/checkout@v4`,
50
- ` - run: npx harness lint --validators ${config.targetValidatorIds.join(',')}`,
50
+ ` - run: npx phasegate lint --validators ${config.targetValidatorIds.join(',')}`,
51
51
  ].filter((l) => l !== '').join('\n');
52
52
  }
53
53
  }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @layer application
3
+ * @unit config-foundation
4
+ */
5
+ import type { HarnessConfigV2 } from '../../domain/harness-config.js';
6
+
7
+ function toPhasePreset(
8
+ value: string,
9
+ ): 'default' | 'full' | 'standard' | 'minimal' | 'custom' {
10
+ if (
11
+ value === 'default'
12
+ || value === 'full'
13
+ || value === 'standard'
14
+ || value === 'minimal'
15
+ || value === 'custom'
16
+ ) {
17
+ return value;
18
+ }
19
+
20
+ return 'default';
21
+ }
22
+
23
+ type PhaseDependenciesWithGates = HarnessConfigV2['phaseDependencies'] & {
24
+ readonly gates?: readonly unknown[];
25
+ };
26
+
27
+ export function toPhaseConfigSection(resolvedConfig: HarnessConfigV2) {
28
+ const phaseDependencies = resolvedConfig.phaseDependencies as PhaseDependenciesWithGates;
29
+
30
+ return {
31
+ planningMode: resolvedConfig.planningMode,
32
+ customization: {
33
+ preset: toPhasePreset(phaseDependencies.preset),
34
+ overrideEnabled: phaseDependencies.override,
35
+ rules: phaseDependencies.customRules.map((rule) => ({
36
+ targetPhase: rule.phase,
37
+ condition: 'requires' as const,
38
+ action: rule.requires,
39
+ })),
40
+ gates: phaseDependencies.gates ?? [],
41
+ },
42
+ reportingOutputDir: resolvedConfig.reporting.outputDir,
43
+ };
44
+ }
@@ -42,7 +42,26 @@ function formatHarnessErrors(errors: readonly HarnessError[]): string {
42
42
  }
43
43
 
44
44
  function toSourceDocument(document: unknown): HarnessConfigSourceDocument {
45
- return document as HarnessConfigSourceDocument;
45
+ const sourceDocument = document as HarnessConfigSourceDocument & {
46
+ readonly phaseDependencies?: HarnessConfigSourceDocument['phaseDependencies'] & {
47
+ readonly gates?: readonly unknown[];
48
+ };
49
+ };
50
+
51
+ if (
52
+ sourceDocument.phaseDependencies === undefined
53
+ || sourceDocument.phaseDependencies.gates === undefined
54
+ ) {
55
+ return sourceDocument;
56
+ }
57
+
58
+ return {
59
+ ...sourceDocument,
60
+ phaseDependencies: {
61
+ ...sourceDocument.phaseDependencies,
62
+ gates: sourceDocument.phaseDependencies.gates ?? [],
63
+ },
64
+ } as HarnessConfigSourceDocument;
46
65
  }
47
66
 
48
67
  export function validateDocumentOrThrow(
@@ -23,6 +23,7 @@ import type { L4Config } from './value-objects/l4-config.js';
23
23
  export type LayerId = 'L1' | 'L2' | 'L3' | 'L4';
24
24
  export type PresetId = 'minimal' | 'standard' | 'strict';
25
25
  export type PlanningModeValue = 'interactive' | 'embedded-qa';
26
+ export type PhaseDependenciesPresetId = 'default' | 'full' | 'standard' | 'minimal' | 'custom';
26
27
  type DeepPartial<T> = {
27
28
  [K in keyof T]?: T[K] extends Array<infer TItem>
28
29
  ? Array<DeepPartial<TItem>>
@@ -76,7 +77,7 @@ export interface HarnessConfigResolvedDocument {
76
77
  relaxedGates: string[];
77
78
  };
78
79
  phaseDependencies: {
79
- preset: 'default' | 'custom';
80
+ preset: PhaseDependenciesPresetId;
80
81
  override: boolean;
81
82
  customRules: Array<{
82
83
  phase: string;
@@ -7,17 +7,20 @@
7
7
  */
8
8
  import { CustomPhaseRule } from './custom-phase-rule.js';
9
9
  import type { CustomPhaseRuleProps } from './custom-phase-rule.js';
10
+ import type { PhaseDependenciesPresetId } from '../harness-config.js';
10
11
 
11
12
  export interface PhaseDependenciesConfigProps {
12
- readonly preset: 'default' | 'custom';
13
+ readonly preset: PhaseDependenciesPresetId;
13
14
  readonly override: boolean;
14
15
  readonly customRules: readonly CustomPhaseRuleProps[];
16
+ readonly gates?: readonly unknown[];
15
17
  }
16
18
 
17
19
  export class PhaseDependenciesConfig {
18
- readonly preset: 'default' | 'custom';
20
+ readonly preset: PhaseDependenciesPresetId;
19
21
  readonly override: boolean;
20
22
  readonly customRules: readonly CustomPhaseRule[];
23
+ readonly gates: readonly unknown[];
21
24
 
22
25
  constructor(props: PhaseDependenciesConfigProps) {
23
26
  this.preset = props.preset;
@@ -25,6 +28,7 @@ export class PhaseDependenciesConfig {
25
28
  this.customRules = props.customRules.map(
26
29
  (rule) => new CustomPhaseRule(rule)
27
30
  );
31
+ this.gates = Object.freeze([...(props.gates ?? [])]);
28
32
  }
29
33
 
30
34
  static create(raw: PhaseDependenciesConfigProps): PhaseDependenciesConfig {
@@ -35,12 +39,22 @@ export class PhaseDependenciesConfig {
35
39
  return this.customRules.length > 0;
36
40
  }
37
41
 
42
+ hasCustomGates(): boolean {
43
+ return this.gates.length > 0;
44
+ }
45
+
38
46
  equals(other: PhaseDependenciesConfig): boolean {
39
47
  if (this.preset !== other.preset) return false;
40
48
  if (this.override !== other.override) return false;
41
49
  if (this.customRules.length !== other.customRules.length) return false;
42
- return this.customRules.every((rule, idx) =>
50
+ if (
51
+ !this.customRules.every((rule, idx) =>
43
52
  rule.equals(other.customRules[idx])
44
- );
53
+ )
54
+ ) {
55
+ return false;
56
+ }
57
+
58
+ return JSON.stringify(this.gates) === JSON.stringify(other.gates);
45
59
  }
46
60
  }