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
package/scripts/harness/agent-integration/infrastructure/adapters/phase-gate-query-adapter.ts
CHANGED
|
@@ -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({
|
|
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
|
|
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.
|
|
110
|
+
return this.hasRawLayerAnnotation;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
anyRatio(): number {
|
package/scripts/harness/biome-ast-engine/infrastructure/adapters/node-workspace-file-adapter.ts
CHANGED
|
@@ -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.
|
|
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+(
|
|
6
|
+
const UNIT_COMMENT_PATTERN = /^\s*(?:\/\/|\/\*\*?\s*|\*)\s*@unit\s+(.+)/gm;
|
|
7
7
|
|
|
8
8
|
export type UnitCommentResult = {
|
|
9
|
-
readonly
|
|
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
|
|
19
|
+
const matches = sourceCode.matchAll(UNIT_COMMENT_PATTERN);
|
|
20
|
+
const names: string[] = [];
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
28
|
+
const deduplicated = [...new Set(names)];
|
|
24
29
|
|
|
25
|
-
return {
|
|
30
|
+
return { unitNames: Object.freeze(deduplicated) };
|
|
26
31
|
};
|
|
@@ -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:([^\]]+)\]\(
|
|
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: `
|
|
58
|
+
command: `phasegate:${cmdMatch[2].trim()}`,
|
|
59
59
|
description: cmdMatch[3].trim(),
|
|
60
60
|
}));
|
|
61
61
|
} catch { /* skip invalid */ }
|
package/scripts/harness/ci-governance/infrastructure/adapters/yaml-template-renderer-adapter.ts
CHANGED
|
@@ -33,7 +33,7 @@ export class YamlTemplateRendererAdapter implements TemplateRendererPort {
|
|
|
33
33
|
'#!/bin/sh',
|
|
34
34
|
'. "$(dirname "$0")/_/husky.sh"',
|
|
35
35
|
'',
|
|
36
|
-
`npx
|
|
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
|
|
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
|
+
}
|
package/scripts/harness/config-foundation/application/usecases/load-resolved-config-use-case.ts
CHANGED
|
@@ -42,7 +42,26 @@ function formatHarnessErrors(errors: readonly HarnessError[]): string {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function toSourceDocument(document: unknown): HarnessConfigSourceDocument {
|
|
45
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
}
|