phasegate 0.91.0 → 0.107.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/CHANGELOG.md +169 -0
- package/README.ja.md +15 -7
- package/README.md +24 -4
- package/docs/ADR/ADR-015-architecture-preset.md +183 -0
- package/docs/guide/codex-integration.md +7 -2
- package/docs/guide/installation.md +10 -2
- package/docs/guide/preset-selection.md +170 -0
- package/docs/guide/quick-vs-full-mode.md +3 -3
- package/docs/guide/retrofit-adoption.md +19 -2
- package/docs/guide/skills-overview.md +1 -1
- package/package.json +7 -1
- package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +108 -100
- package/scripts/harness/agent-integration/domain/ports/phase-gate-query-port.ts +3 -3
- package/scripts/harness/agent-integration/domain/value-objects/write-target-scope.ts +26 -30
- package/scripts/harness/agent-integration/infrastructure/adapters/file-system-story-reflection-query-adapter.ts +6 -2
- package/scripts/harness/biome-ast-engine/application/dto/analyze-import-graph-input.ts +3 -0
- package/scripts/harness/biome-ast-engine/application/dto/resolve-enabled-rules-output.ts +2 -0
- package/scripts/harness/biome-ast-engine/application/mappers/resolve-enabled-rules-output-mapper.ts +4 -1
- package/scripts/harness/biome-ast-engine/application/usecases/analyze-import-graph-usecase.ts +4 -1
- package/scripts/harness/biome-ast-engine/application/usecases/execute-lint-usecase.ts +2 -0
- package/scripts/harness/biome-ast-engine/application/usecases/resolve-enabled-rules-usecase.ts +31 -3
- package/scripts/harness/biome-ast-engine/composition-root.ts +10 -2
- package/scripts/harness/biome-ast-engine/domain/ports/rule-config-provider-port.ts +16 -0
- package/scripts/harness/biome-ast-engine/domain/ports/source-module-analyzer-port.ts +5 -1
- package/scripts/harness/biome-ast-engine/domain/services/lint-runner.ts +5 -1
- package/scripts/harness/biome-ast-engine/domain/value-objects/architecture-spec.ts +38 -0
- package/scripts/harness/biome-ast-engine/domain/value-objects/layer-boundary.ts +7 -8
- package/scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts +15 -23
- package/scripts/harness/biome-ast-engine/domain/value-objects/source-module-snapshot.ts +11 -4
- package/scripts/harness/biome-ast-engine/infrastructure/adapters/harness-config-provider-adapter.ts +29 -3
- package/scripts/harness/biome-ast-engine/infrastructure/adapters/typescript-source-module-analyzer-adapter.ts +22 -15
- package/scripts/harness/biome-ast-engine/infrastructure/mappers/source-module-snapshot-mapper.ts +26 -17
- package/scripts/harness/config-foundation/application/dto/resolved-config-output.ts +1 -0
- package/scripts/harness/config-foundation/application/usecases/load-resolved-config-use-case.ts +34 -2
- package/scripts/harness/config-foundation/application/usecases/migrate-schema-use-case.ts +89 -0
- package/scripts/harness/config-foundation/composition-root.ts +8 -0
- package/scripts/harness/config-foundation/domain/harness-config.ts +6 -0
- package/scripts/harness/config-foundation/domain/services/architecture-resolution-service.ts +257 -0
- package/scripts/harness/config-foundation/domain/value-objects/architecture-config.ts +66 -0
- package/scripts/harness/config-foundation/domain/value-objects/architecture-preset-catalog.ts +75 -0
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +546 -0
- package/scripts/harness/config-foundation/infrastructure/validators/ajv-config-schema-validator.ts +18 -6
- package/scripts/harness/config-foundation/presentation/cli/migrate-schema-command-handler.ts +83 -0
- package/scripts/harness/integrations/pre-commit.ts +211 -52
- package/scripts/harness/main.ts +460 -340
- package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +2 -4
- package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +54 -17
- package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +154 -36
- package/scripts/harness/setup/skill-deployer.ts +140 -102
- package/scripts/harness/skill-quality/domain/errors/skill-quality-error.ts +24 -23
- package/scripts/harness/skill-quality/domain/value-objects/commit-message.ts +23 -7
- package/scripts/harness/traceability-model/application/usecases/apply-work-item-migration-usecase.ts +52 -0
- package/scripts/harness/traceability-model/application/usecases/plan-work-item-migration-usecase.ts +29 -0
- package/scripts/harness/traceability-model/application/usecases/validate-design-story-annotations-usecase.ts +83 -18
- package/scripts/harness/traceability-model/composition-root.ts +48 -30
- package/scripts/harness/traceability-model/domain/ports/design-document-port.ts +9 -15
- package/scripts/harness/traceability-model/domain/ports/work-item-migration-apply-port.ts +11 -0
- package/scripts/harness/traceability-model/domain/ports/work-item-migration-source-port.ts +9 -0
- package/scripts/harness/traceability-model/domain/services/work-item-migration-planner.ts +162 -0
- package/scripts/harness/traceability-model/domain/value-objects/work-item-frontmatter.ts +57 -0
- package/scripts/harness/traceability-model/domain/value-objects/work-item-migration-candidate.ts +47 -0
- package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-migration-apply-gateway.ts +110 -0
- package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-migration-source-gateway.ts +182 -0
- package/scripts/harness/traceability-model/infrastructure/gateways/markdown-design-document-gateway.ts +29 -43
- package/scripts/harness/traceability-model/infrastructure/parsers/work-item-frontmatter-parser.ts +136 -0
- package/scripts/harness/traceability-model/presentation/cli/migrate-work-items-command-handler.ts +186 -0
- package/skills/quick-implementor/SKILL.md +17 -1
- package/templates/.husky/commit-msg +1 -0
|
@@ -13,33 +13,108 @@
|
|
|
13
13
|
* 2 = runtime error
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { execSync } from
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import type {
|
|
20
|
-
import type {
|
|
21
|
-
import {
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'.spec.tsx',
|
|
37
|
-
]);
|
|
16
|
+
import { execSync } from "node:child_process";
|
|
17
|
+
import { readFile } from "node:fs/promises";
|
|
18
|
+
import { createTraceabilityModelModule } from "../traceability-model/composition-root.js";
|
|
19
|
+
import type { ValidateMetadataCommandOutput } from "../traceability-model/presentation/cli/validate-metadata-command-handler.js";
|
|
20
|
+
import type { AggregatedValidationReport } from "../validator-system/application/dto/aggregated-validation-report.js";
|
|
21
|
+
import type { ValidationResultContract } from "../validator-system/application/dto/validation-result-contract.js";
|
|
22
|
+
import { createValidatorSystemModule } from "../validator-system/composition-root.js";
|
|
23
|
+
import { HumanValidationResultFormatter } from "../validator-system/presentation/formatters/human-validation-result-formatter.js";
|
|
24
|
+
|
|
25
|
+
const GREEN = "\x1b[32m";
|
|
26
|
+
const RED = "\x1b[31m";
|
|
27
|
+
const BOLD = "\x1b[1m";
|
|
28
|
+
const DIM = "\x1b[2m";
|
|
29
|
+
const RESET = "\x1b[0m";
|
|
30
|
+
|
|
31
|
+
const TS_EXTENSION = ".ts";
|
|
32
|
+
const MD_EXTENSION = ".md";
|
|
33
|
+
const WORK_ITEM_PATH_PATTERN = /(?:^|\/)WI-\d+(?:\/|$)/;
|
|
34
|
+
const WORK_ITEM_TRAILER_PATTERN = /^Work-Item:\s*WI-\d+\s*$/m;
|
|
35
|
+
const TEST_FILE_SUFFIXES = Object.freeze([".test.ts", ".test.tsx", ".spec.ts", ".spec.tsx"]);
|
|
38
36
|
|
|
39
37
|
function isTestFile(path: string): boolean {
|
|
40
38
|
return TEST_FILE_SUFFIXES.some((suffix) => path.endsWith(suffix));
|
|
41
39
|
}
|
|
42
40
|
|
|
41
|
+
function isMetadataMarkdownFile(path: string): boolean {
|
|
42
|
+
return path.startsWith("docs/inception/") || path.startsWith("docs/product/");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const HARNESS_ROOT_PREFIX = "scripts/harness/";
|
|
46
|
+
const TESTS_SEGMENT = "__tests__";
|
|
47
|
+
const UNIT_ANNOTATION_PATTERN = /^\s*(?:\/\/|\*)\s*@unit\s+(\S+)/m;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* staged TS file path から所属 Unit 名を導出する。
|
|
51
|
+
* scripts/harness/{unit}/... → unit
|
|
52
|
+
* scripts/harness/__tests__/{unit|integration}/{unit}/...
|
|
53
|
+
* → unit
|
|
54
|
+
* 上記パターンに合致しないパス(例: scripts/harness/integrations/pre-commit.ts)は
|
|
55
|
+
* undefined を返し、呼び出し側が file 内 `@unit` コメントにフォールバックする。
|
|
56
|
+
*/
|
|
57
|
+
function deriveUnitNameFromPath(filePath: string): string | undefined {
|
|
58
|
+
if (!filePath.startsWith(HARNESS_ROOT_PREFIX)) return undefined;
|
|
59
|
+
const parts = filePath.slice(HARNESS_ROOT_PREFIX.length).split("/");
|
|
60
|
+
if (parts.length < 2) return undefined;
|
|
61
|
+
if (parts[0] === TESTS_SEGMENT) {
|
|
62
|
+
return parts.length >= 3 ? parts[2] : undefined;
|
|
63
|
+
}
|
|
64
|
+
return parts[0];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* ファイル本体から `// @unit <name>` / `* @unit <name>` を抽出する。
|
|
69
|
+
* 読み込み失敗や annotation 不在時は undefined。
|
|
70
|
+
*/
|
|
71
|
+
async function deriveUnitNameFromFile(filePath: string): Promise<string | undefined> {
|
|
72
|
+
try {
|
|
73
|
+
const content = await readFile(filePath, "utf-8");
|
|
74
|
+
const match = UNIT_ANNOTATION_PATTERN.exec(content);
|
|
75
|
+
return match?.[1];
|
|
76
|
+
} catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* path-based 推定と file-based 推定を組み合わせて Unit 名を解決する。
|
|
83
|
+
* `@unit` アノテーションが存在する場合はそれを正として採用し、
|
|
84
|
+
* 無い場合のみ path-based 推定にフォールバックする(cross-cutting dir 対応)。
|
|
85
|
+
*/
|
|
86
|
+
async function resolveUnitName(filePath: string): Promise<string | undefined> {
|
|
87
|
+
const fileUnit = await deriveUnitNameFromFile(filePath);
|
|
88
|
+
if (fileUnit) return fileUnit;
|
|
89
|
+
return deriveUnitNameFromPath(filePath);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 複数 Unit の L2 validator 実行結果を、ValidatorId 単位で集約する。
|
|
94
|
+
* 同じ ValidatorId に対して、どの Unit でも 1 件でも fail / skip があれば
|
|
95
|
+
* fail / skip を優先(厳しい側を採用)。
|
|
96
|
+
*/
|
|
97
|
+
function mergePerUnitResults(
|
|
98
|
+
runs: readonly (readonly ValidationResultContract[])[],
|
|
99
|
+
): readonly ValidationResultContract[] {
|
|
100
|
+
const byId = new Map<string, ValidationResultContract>();
|
|
101
|
+
for (const run of runs) {
|
|
102
|
+
for (const result of run) {
|
|
103
|
+
const existing = byId.get(result.validatorId);
|
|
104
|
+
if (!existing) {
|
|
105
|
+
byId.set(result.validatorId, result);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const existingFailed = !existing.passed && !existing.skipped;
|
|
109
|
+
const incomingFailed = !result.passed && !result.skipped;
|
|
110
|
+
if (incomingFailed && !existingFailed) {
|
|
111
|
+
byId.set(result.validatorId, result);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return [...byId.values()];
|
|
116
|
+
}
|
|
117
|
+
|
|
43
118
|
interface RunL2Input {
|
|
44
119
|
readonly targetPaths: readonly string[];
|
|
45
120
|
readonly unitName: string;
|
|
@@ -69,14 +144,23 @@ export interface PreCommitResult {
|
|
|
69
144
|
readonly stdout: string;
|
|
70
145
|
}
|
|
71
146
|
|
|
147
|
+
export interface PreCommitOptions {
|
|
148
|
+
/**
|
|
149
|
+
* Optional commit message supplied by CI / commit-msg style callers.
|
|
150
|
+
* Native pre-commit hooks run before Git creates the message, so this is
|
|
151
|
+
* intentionally opt-in and preserves existing local pre-commit behavior.
|
|
152
|
+
*/
|
|
153
|
+
readonly commitMessage?: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
72
156
|
function getStagedFiles(): string[] {
|
|
73
157
|
try {
|
|
74
|
-
const output = execSync(
|
|
75
|
-
encoding:
|
|
76
|
-
stdio: [
|
|
158
|
+
const output = execSync("git diff --cached --name-only --diff-filter=ACM", {
|
|
159
|
+
encoding: "utf-8",
|
|
160
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
77
161
|
});
|
|
78
162
|
return output
|
|
79
|
-
.split(
|
|
163
|
+
.split("\n")
|
|
80
164
|
.map((f) => f.trim())
|
|
81
165
|
.filter((f) => f.length > 0);
|
|
82
166
|
} catch {
|
|
@@ -84,15 +168,13 @@ function getStagedFiles(): string[] {
|
|
|
84
168
|
}
|
|
85
169
|
}
|
|
86
170
|
|
|
87
|
-
function buildReport(
|
|
88
|
-
results: readonly ValidationResultContract[],
|
|
89
|
-
): AggregatedValidationReport {
|
|
171
|
+
function buildReport(results: readonly ValidationResultContract[]): AggregatedValidationReport {
|
|
90
172
|
const passed = results.filter((r) => r.passed && !r.skipped).length;
|
|
91
173
|
const failed = results.filter((r) => !r.passed && !r.skipped).length;
|
|
92
174
|
const skipped = results.filter((r) => r.skipped).length;
|
|
93
175
|
const allErrors = results.flatMap((r) => r.errors);
|
|
94
|
-
const errorCount = allErrors.filter((e) => e.severity ===
|
|
95
|
-
const warnCount = allErrors.filter((e) => e.severity ===
|
|
176
|
+
const errorCount = allErrors.filter((e) => e.severity === "error").length;
|
|
177
|
+
const warnCount = allErrors.filter((e) => e.severity === "warning").length;
|
|
96
178
|
return {
|
|
97
179
|
overallPassed: failed === 0,
|
|
98
180
|
totalValidators: results.length,
|
|
@@ -110,15 +192,26 @@ function buildReport(
|
|
|
110
192
|
}
|
|
111
193
|
|
|
112
194
|
function maxExitCode(a: 0 | 1 | 2, b: 0 | 1 | 2): 0 | 1 | 2 {
|
|
113
|
-
return
|
|
195
|
+
return Math.max(a, b) as 0 | 1 | 2;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function requiresWorkItemTrailer(stagedFiles: readonly string[]): boolean {
|
|
199
|
+
return stagedFiles.some(
|
|
200
|
+
(filePath) => filePath.startsWith("docs/inception/") && WORK_ITEM_PATH_PATTERN.test(filePath),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function hasWorkItemTrailer(commitMessage: string): boolean {
|
|
205
|
+
return WORK_ITEM_TRAILER_PATTERN.test(commitMessage);
|
|
114
206
|
}
|
|
115
207
|
|
|
116
208
|
export async function runPreCommit(
|
|
117
209
|
stagedFiles: readonly string[],
|
|
118
210
|
deps: PreCommitDeps,
|
|
211
|
+
options: PreCommitOptions = {},
|
|
119
212
|
): Promise<PreCommitResult> {
|
|
120
213
|
const tsFiles = stagedFiles.filter((f) => f.endsWith(TS_EXTENSION));
|
|
121
|
-
const mdFiles = stagedFiles.filter((f) => f.endsWith(MD_EXTENSION));
|
|
214
|
+
const mdFiles = stagedFiles.filter((f) => f.endsWith(MD_EXTENSION) && isMetadataMarkdownFile(f));
|
|
122
215
|
const testFiles = tsFiles.filter((f) => isTestFile(f));
|
|
123
216
|
const metadataFiles = [...mdFiles, ...testFiles];
|
|
124
217
|
|
|
@@ -131,20 +224,39 @@ export async function runPreCommit(
|
|
|
131
224
|
|
|
132
225
|
const sections: string[] = [];
|
|
133
226
|
sections.push(
|
|
134
|
-
`${BOLD}[phasegate]${RESET} Pre-commit check ` +
|
|
135
|
-
`(${tsFiles.length} .ts file(s), ${mdFiles.length} .md file(s))`,
|
|
227
|
+
`${BOLD}[phasegate]${RESET} Pre-commit check ` + `(${tsFiles.length} .ts file(s), ${mdFiles.length} .md file(s))`,
|
|
136
228
|
);
|
|
137
229
|
|
|
138
230
|
let exitCode: 0 | 1 | 2 = 0;
|
|
139
231
|
|
|
140
232
|
if (tsFiles.length > 0) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
233
|
+
// staged TS file を Unit ごとにグルーピングし、Unit 単位で L2 phase gate
|
|
234
|
+
// (L2-001 の `{unit}_unit.md` 等)を評価する。Unit を特定できないファイルは
|
|
235
|
+
// 別グループ(unitName='')として従来挙動で評価する。
|
|
236
|
+
const filesByUnit = new Map<string, string[]>();
|
|
237
|
+
for (const f of tsFiles) {
|
|
238
|
+
const unit = (await resolveUnitName(f)) ?? "";
|
|
239
|
+
const bucket = filesByUnit.get(unit);
|
|
240
|
+
if (bucket) {
|
|
241
|
+
bucket.push(f);
|
|
242
|
+
} else {
|
|
243
|
+
filesByUnit.set(unit, [f]);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const runs: (readonly ValidationResultContract[])[] = [];
|
|
248
|
+
for (const [unitName, unitFiles] of filesByUnit) {
|
|
249
|
+
const results = await deps.runL2ValidatorsUseCase.execute({
|
|
250
|
+
targetPaths: unitFiles,
|
|
251
|
+
unitName,
|
|
252
|
+
currentPhase: "",
|
|
253
|
+
});
|
|
254
|
+
runs.push(results);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const merged = mergePerUnitResults(runs);
|
|
258
|
+
const report = buildReport(merged);
|
|
259
|
+
sections.push("");
|
|
148
260
|
sections.push(`${BOLD}== TypeScript 実装 (${tsFiles.length} file(s)) ==${RESET}`);
|
|
149
261
|
sections.push(new HumanValidationResultFormatter().format(report));
|
|
150
262
|
if (!report.overallPassed) {
|
|
@@ -156,15 +268,26 @@ export async function runPreCommit(
|
|
|
156
268
|
const metadataResult = await deps.validateMetadataCommandHandler.execute({
|
|
157
269
|
filePaths: metadataFiles,
|
|
158
270
|
});
|
|
159
|
-
sections.push(
|
|
160
|
-
sections.push(
|
|
161
|
-
`${BOLD}== 設計 / テスト メタデータ注釈 (${metadataFiles.length} file(s)) ==${RESET}`,
|
|
162
|
-
);
|
|
271
|
+
sections.push("");
|
|
272
|
+
sections.push(`${BOLD}== 設計 / テスト メタデータ注釈 (${metadataFiles.length} file(s)) ==${RESET}`);
|
|
163
273
|
sections.push(metadataResult.text);
|
|
164
274
|
exitCode = maxExitCode(exitCode, metadataResult.exitCode);
|
|
165
275
|
}
|
|
166
276
|
|
|
167
|
-
|
|
277
|
+
if (options.commitMessage !== undefined && requiresWorkItemTrailer(stagedFiles)) {
|
|
278
|
+
sections.push("");
|
|
279
|
+
sections.push(`${BOLD}== Work-Item trailer ==${RESET}`);
|
|
280
|
+
if (hasWorkItemTrailer(options.commitMessage)) {
|
|
281
|
+
sections.push(`${GREEN}PASS${RESET} Work-Item trailer is present.`);
|
|
282
|
+
} else {
|
|
283
|
+
sections.push(
|
|
284
|
+
`${RED}FAIL${RESET} Commit message must include \`Work-Item: WI-XXX\` when WI documents are staged.`,
|
|
285
|
+
);
|
|
286
|
+
exitCode = maxExitCode(exitCode, 1);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
sections.push("");
|
|
168
291
|
if (exitCode === 0) {
|
|
169
292
|
sections.push(`${GREEN}[phasegate]${RESET} All checks passed.`);
|
|
170
293
|
} else {
|
|
@@ -173,7 +296,7 @@ export async function runPreCommit(
|
|
|
173
296
|
|
|
174
297
|
return {
|
|
175
298
|
exitCode,
|
|
176
|
-
stdout: sections.join(
|
|
299
|
+
stdout: sections.join("\n"),
|
|
177
300
|
};
|
|
178
301
|
}
|
|
179
302
|
|
|
@@ -183,10 +306,46 @@ export async function runPreCommitCli(): Promise<void> {
|
|
|
183
306
|
const validatorMod = createValidatorSystemModule();
|
|
184
307
|
const traceabilityMod = createTraceabilityModelModule(process.cwd());
|
|
185
308
|
|
|
186
|
-
const result = await runPreCommit(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
309
|
+
const result = await runPreCommit(
|
|
310
|
+
stagedFiles,
|
|
311
|
+
{
|
|
312
|
+
runL2ValidatorsUseCase: validatorMod.runL2ValidatorsUseCase,
|
|
313
|
+
validateMetadataCommandHandler: traceabilityMod.validateMetadataCommandHandler,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
commitMessage: process.env.PHASEGATE_COMMIT_MESSAGE,
|
|
317
|
+
},
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
process.stdout.write(`${result.stdout}\n`);
|
|
321
|
+
process.exit(result.exitCode);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
324
|
+
process.stderr.write(`${RED}[phasegate] Unexpected error:${RESET} ${msg}\n`);
|
|
325
|
+
process.exit(2);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export async function runCommitMsgCli(commitMessagePath: string | undefined): Promise<void> {
|
|
330
|
+
try {
|
|
331
|
+
if (!commitMessagePath) {
|
|
332
|
+
process.stderr.write(`${RED}[phasegate] commit-msg requires a commit message file path.${RESET}\n`);
|
|
333
|
+
process.exit(2);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const stagedFiles = getStagedFiles();
|
|
337
|
+
const commitMessage = await readFile(commitMessagePath, "utf-8");
|
|
338
|
+
const validatorMod = createValidatorSystemModule();
|
|
339
|
+
const traceabilityMod = createTraceabilityModelModule(process.cwd());
|
|
340
|
+
|
|
341
|
+
const result = await runPreCommit(
|
|
342
|
+
stagedFiles,
|
|
343
|
+
{
|
|
344
|
+
runL2ValidatorsUseCase: validatorMod.runL2ValidatorsUseCase,
|
|
345
|
+
validateMetadataCommandHandler: traceabilityMod.validateMetadataCommandHandler,
|
|
346
|
+
},
|
|
347
|
+
{ commitMessage },
|
|
348
|
+
);
|
|
190
349
|
|
|
191
350
|
process.stdout.write(`${result.stdout}\n`);
|
|
192
351
|
process.exit(result.exitCode);
|