phasegate 0.160.4 → 0.160.5
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 +6 -0
- package/package.json +1 -1
- package/scripts/harness/ci-governance/application/dto/scaffold-design-input.ts +2 -0
- package/scripts/harness/ci-governance/application/dto/scaffold-design-output.ts +2 -0
- package/scripts/harness/ci-governance/application/usecases/scaffold-design-usecase.ts +17 -0
- package/scripts/harness/ci-governance/presentation/handlers/scaffold-design-handler.ts +25 -3
- package/scripts/harness/integrations/pre-commit.ts +7 -1
- package/scripts/harness/main.ts +47 -7
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.160.5] - 2026-05-14
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **WI-189 — umbrella CLI UX cleanup** — aligns `validate --format json` with the global JSON contract, makes `scaffold-design` default to dry-run with explicit `--apply`, fixes bypass audit empty-range wording, and synchronizes public help for scaffold, quick-mode, and delegate commands.
|
|
15
|
+
|
|
10
16
|
## [0.160.4] - 2026-05-14
|
|
11
17
|
|
|
12
18
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// @unit ci-governance
|
|
2
2
|
// @layer application
|
|
3
|
+
// @work-item-id WI-189
|
|
3
4
|
|
|
4
5
|
export interface ScaffoldDesignOutput {
|
|
5
6
|
readonly targetPath: string;
|
|
6
7
|
readonly templatePath: string;
|
|
7
8
|
readonly unit: string;
|
|
8
9
|
readonly phase: string;
|
|
10
|
+
readonly dryRun: boolean;
|
|
9
11
|
readonly written: boolean;
|
|
10
12
|
readonly alreadyExists: boolean;
|
|
11
13
|
readonly overwritten: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @unit ci-governance
|
|
2
2
|
// @layer application
|
|
3
|
+
// @work-item-id WI-189
|
|
3
4
|
|
|
4
5
|
import { DesignPhase } from '../../domain/value-objects/design-phase.js';
|
|
5
6
|
import type { TemplateRepositoryPort } from '../../domain/ports/template-repository-port.js';
|
|
@@ -21,18 +22,33 @@ export class ScaffoldDesignUseCase {
|
|
|
21
22
|
}
|
|
22
23
|
const phase = DesignPhase.create(input.phase);
|
|
23
24
|
const unit = input.unit.trim();
|
|
25
|
+
const dryRun = input.dryRun === true;
|
|
24
26
|
const force = input.force === true;
|
|
25
27
|
|
|
26
28
|
const templatePath = this.templates.resolvePath(phase);
|
|
27
29
|
const targetPath = this.writer.resolvePath(unit, phase);
|
|
28
30
|
const alreadyExists = await this.writer.exists(unit, phase);
|
|
29
31
|
|
|
32
|
+
if (dryRun) {
|
|
33
|
+
return {
|
|
34
|
+
targetPath,
|
|
35
|
+
templatePath,
|
|
36
|
+
unit,
|
|
37
|
+
phase: phase.value,
|
|
38
|
+
dryRun: true,
|
|
39
|
+
written: false,
|
|
40
|
+
alreadyExists,
|
|
41
|
+
overwritten: false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
if (alreadyExists && !force) {
|
|
31
46
|
return {
|
|
32
47
|
targetPath,
|
|
33
48
|
templatePath,
|
|
34
49
|
unit,
|
|
35
50
|
phase: phase.value,
|
|
51
|
+
dryRun: false,
|
|
36
52
|
written: false,
|
|
37
53
|
alreadyExists: true,
|
|
38
54
|
overwritten: false,
|
|
@@ -48,6 +64,7 @@ export class ScaffoldDesignUseCase {
|
|
|
48
64
|
templatePath,
|
|
49
65
|
unit,
|
|
50
66
|
phase: phase.value,
|
|
67
|
+
dryRun: false,
|
|
51
68
|
written: true,
|
|
52
69
|
alreadyExists,
|
|
53
70
|
overwritten: alreadyExists && force,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @unit ci-governance
|
|
2
2
|
// @layer presentation
|
|
3
|
+
// @work-item-id WI-189
|
|
3
4
|
|
|
4
5
|
import { DesignPhase } from '../../domain/value-objects/design-phase.js';
|
|
5
6
|
import type { ScaffoldDesignUseCase } from '../../application/usecases/scaffold-design-usecase.js';
|
|
@@ -7,6 +8,8 @@ import type { ScaffoldDesignUseCase } from '../../application/usecases/scaffold-
|
|
|
7
8
|
export interface ScaffoldDesignHandlerArgs {
|
|
8
9
|
readonly unit?: string;
|
|
9
10
|
readonly phase?: string;
|
|
11
|
+
readonly dryRun?: boolean;
|
|
12
|
+
readonly apply?: boolean;
|
|
10
13
|
readonly force?: boolean;
|
|
11
14
|
readonly format?: 'human' | 'json';
|
|
12
15
|
}
|
|
@@ -21,6 +24,12 @@ export class ScaffoldDesignHandler {
|
|
|
21
24
|
|
|
22
25
|
async handle(args: ScaffoldDesignHandlerArgs): Promise<ScaffoldDesignHandlerResult> {
|
|
23
26
|
const format = args.format ?? 'human';
|
|
27
|
+
const apply = args.apply === true;
|
|
28
|
+
const dryRun = args.dryRun === true || !apply;
|
|
29
|
+
|
|
30
|
+
if (args.dryRun === true && apply) {
|
|
31
|
+
return this.fail(format, '--dry-run と --apply は同時に指定できません', 2);
|
|
32
|
+
}
|
|
24
33
|
|
|
25
34
|
if (!args.unit || args.unit.trim().length === 0) {
|
|
26
35
|
return this.fail(format, '--unit <unit-id> は必須です', 2);
|
|
@@ -45,6 +54,7 @@ export class ScaffoldDesignHandler {
|
|
|
45
54
|
result = await this.useCase.execute({
|
|
46
55
|
unit: args.unit,
|
|
47
56
|
phase: args.phase,
|
|
57
|
+
dryRun,
|
|
48
58
|
force: args.force,
|
|
49
59
|
});
|
|
50
60
|
} catch (err) {
|
|
@@ -61,10 +71,22 @@ export class ScaffoldDesignHandler {
|
|
|
61
71
|
|
|
62
72
|
if (result.alreadyExists && !result.written) {
|
|
63
73
|
return {
|
|
64
|
-
exitCode: 2,
|
|
74
|
+
exitCode: result.dryRun ? 0 : 2,
|
|
75
|
+
output: [
|
|
76
|
+
result.dryRun ? `dry-run: 既に存在します: ${result.targetPath}` : `既に存在します: ${result.targetPath}`,
|
|
77
|
+
result.dryRun ? '書き込むには --apply を指定してください。' : '上書きするには --force を指定してください。',
|
|
78
|
+
].join('\n'),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (result.dryRun) {
|
|
83
|
+
return {
|
|
84
|
+
exitCode: 0,
|
|
65
85
|
output: [
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
`dry-run: 設計文書を生成予定: ${result.targetPath}`,
|
|
87
|
+
`テンプレ: ${result.templatePath}`,
|
|
88
|
+
`Unit: ${result.unit} / phase: ${result.phase}`,
|
|
89
|
+
'書き込むには --apply を指定してください。',
|
|
68
90
|
].join('\n'),
|
|
69
91
|
};
|
|
70
92
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @layer presentation
|
|
4
4
|
* @work-item-id WI-141
|
|
5
5
|
* @work-item-id WI-109
|
|
6
|
+
* @work-item-id WI-189
|
|
6
7
|
*
|
|
7
8
|
* Pre-commit CLI entry.
|
|
8
9
|
* Runs L2 validators against staged TypeScript files AND design-document
|
|
@@ -533,6 +534,11 @@ function hasCompleteBypassTrailerSet(results: readonly BypassTrailerValidationRe
|
|
|
533
534
|
return results.some((result) => result.hasAnyBypassTrailer && result.complete);
|
|
534
535
|
}
|
|
535
536
|
|
|
537
|
+
function toBypassAuditStdout(stdout: string, changedFiles: readonly string[]): string {
|
|
538
|
+
if (changedFiles.length > 0) return stdout;
|
|
539
|
+
return stdout.replace("No staged files to check. Skipping.", "No changed files in range to check. Skipping.");
|
|
540
|
+
}
|
|
541
|
+
|
|
536
542
|
export async function runBypassAudit(
|
|
537
543
|
deps: PreCommitDeps,
|
|
538
544
|
options: BypassAuditOptions = {},
|
|
@@ -554,7 +560,7 @@ export async function runBypassAudit(
|
|
|
554
560
|
|
|
555
561
|
const sections = [
|
|
556
562
|
`${BOLD}[phasegate]${RESET} Bypass audit (${baseRef}..${headRef})`,
|
|
557
|
-
result.stdout,
|
|
563
|
+
toBypassAuditStdout(result.stdout, changedFiles),
|
|
558
564
|
];
|
|
559
565
|
let exitCode = result.exitCode;
|
|
560
566
|
if (result.exitCode !== 0 && !hasCompleteBypassTrailerSet(bypassResults)) {
|
package/scripts/harness/main.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @work-item-id WI-175
|
|
8
8
|
* @work-item-id WI-176
|
|
9
9
|
* @work-item-id WI-184
|
|
10
|
+
* @work-item-id WI-189
|
|
10
11
|
*
|
|
11
12
|
* Phasegate CLI エントリポイント。
|
|
12
13
|
* 各Unitの Composition Root からハンドラーを取得し、コマンドに応じてディスパッチする。
|
|
@@ -156,7 +157,8 @@ Setup:
|
|
|
156
157
|
--with-husky, --with-ci, --yes)
|
|
157
158
|
update-skills Alias for reconcile (kept for compatibility)
|
|
158
159
|
doctor Diagnose silent installation failures (--json, --strict, --agent <claude|codex|both>, --report-out <path>)
|
|
159
|
-
scaffold-wi <unit> <
|
|
160
|
+
scaffold-wi <unit|_cross> <story|issue|chore>
|
|
161
|
+
Create docs/inception/{unit}/WI-XXX/description.md
|
|
160
162
|
emit-agent-rules Print AGENTS.md / CLAUDE.md WI workflow rules block
|
|
161
163
|
install Install phasegate managed files (--dry-run|--apply, --force)
|
|
162
164
|
uninstall Uninstall phasegate managed files (--dry-run|--apply, --force)
|
|
@@ -183,8 +185,9 @@ Commands:
|
|
|
183
185
|
|
|
184
186
|
lint Run lint checks (--json, --target <path>)
|
|
185
187
|
|
|
186
|
-
validate Run validators (--layer L2|L3|L4|all; L0 prints runtime hook info, --unit, --format human|agent|ci)
|
|
188
|
+
validate Run validators (--layer L2|L3|L4|all; L0 prints runtime hook info, --unit, --format human|agent|ci|json, --json)
|
|
187
189
|
ci-check CI check (--quick for quick mode, --fail-on-reject, --dry-run, --files)
|
|
190
|
+
check-change-category Classify changed paths for quick mode (--paths <csv>, --format human|json)
|
|
188
191
|
|
|
189
192
|
phasegate:check-ready Check ready status (--json)
|
|
190
193
|
phasegate:check-phase Check phase gate (--unit <unitId>, --json)
|
|
@@ -211,7 +214,7 @@ Gate semantics:
|
|
|
211
214
|
config:plan Plan safe config changes (--intent <l4-strict|codex-hooks|ci-fail-on-warning|baseline-reset|quick-mode-strict>, --dry-run, --json)
|
|
212
215
|
ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
|
|
213
216
|
baseline Create retrofit baseline snapshot (--dry-run, --force, --paths <glob,glob,...>, --json)
|
|
214
|
-
scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --force, --json)
|
|
217
|
+
scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --dry-run|--apply, --force, --json)
|
|
215
218
|
|
|
216
219
|
skill:execute-tdd-cycle Execute TDD cycle (--unit, --story, --desc, --phase RED|GREEN|REFACTOR, --passed)
|
|
217
220
|
skill:check-coverage Check coverage (--story <storyId>, --json)
|
|
@@ -409,7 +412,8 @@ function parseValidateFormat(args: readonly string[]): "human" | "agent" | "ci"
|
|
|
409
412
|
const raw = parseFlag(args, "--format");
|
|
410
413
|
if (raw === undefined) return undefined;
|
|
411
414
|
if (raw === "human" || raw === "agent" || raw === "ci") return raw;
|
|
412
|
-
|
|
415
|
+
if (raw === "json") return "ci";
|
|
416
|
+
throw new Error(`Invalid --format value for validate: '${raw}'. Supported values: human, agent, ci, json.`);
|
|
413
417
|
}
|
|
414
418
|
|
|
415
419
|
function levenshtein(a: string, b: string): number {
|
|
@@ -546,7 +550,8 @@ Run validators against the project. Without --layer, runs all enabled validator
|
|
|
546
550
|
|
|
547
551
|
Options:
|
|
548
552
|
--layer <L0|L2|L3|L4> Run only the specified validator layer; L0 prints runtime hook info
|
|
549
|
-
--json
|
|
553
|
+
--format <human|agent|ci|json> Output format; json is an alias for ci JSON
|
|
554
|
+
--json Output machine-readable JSON when --format is omitted
|
|
550
555
|
--help, -h Show this help`,
|
|
551
556
|
lint: `Usage: phasegate lint [options]
|
|
552
557
|
|
|
@@ -626,6 +631,28 @@ Options:
|
|
|
626
631
|
Examples:
|
|
627
632
|
phasegate check-change-category --paths src/foo.ts,src/bar.ts
|
|
628
633
|
phasegate check-change-category --paths src/foo.ts --format json`,
|
|
634
|
+
"scaffold-wi": `Usage: phasegate scaffold-wi <unit|_cross> <story|issue|chore>
|
|
635
|
+
|
|
636
|
+
Create docs/inception/{unit}/WI-XXX/description.md.
|
|
637
|
+
|
|
638
|
+
Arguments:
|
|
639
|
+
<unit|_cross> Unit id or _cross for cross-cutting work items.
|
|
640
|
+
<story|issue|chore> Work item type.
|
|
641
|
+
|
|
642
|
+
Options:
|
|
643
|
+
--help, -h Show this help`,
|
|
644
|
+
"scaffold-design": `Usage: phasegate scaffold-design --unit <id> --phase <phase> [options]
|
|
645
|
+
|
|
646
|
+
Scaffold a product construction design document.
|
|
647
|
+
|
|
648
|
+
Options:
|
|
649
|
+
--unit <id> Unit id under docs/product/construction.
|
|
650
|
+
--phase <phase> logical, domain, uiux, unit-test, or it-test.
|
|
651
|
+
--dry-run Preview target and template without writing (default).
|
|
652
|
+
--apply Write the scaffold.
|
|
653
|
+
--force Overwrite an existing target when applying.
|
|
654
|
+
--json Output machine-readable JSON.
|
|
655
|
+
--help, -h Show this help`,
|
|
629
656
|
"ci:generate-template": `Usage: phasegate ci:generate-template [options]
|
|
630
657
|
|
|
631
658
|
Generates a CI template configuration.
|
|
@@ -643,6 +670,15 @@ Options:
|
|
|
643
670
|
Examples:
|
|
644
671
|
phasegate ci:generate-template --type aidlc-gate
|
|
645
672
|
phasegate ci:generate-template --preset strict --type pre-commit --render`,
|
|
673
|
+
"delegate-sonnet": `Usage: phasegate delegate-sonnet [...args]
|
|
674
|
+
|
|
675
|
+
Delegate a task to Sonnet 4.6 by forwarding all args to scripts/delegate-sonnet.sh.
|
|
676
|
+
|
|
677
|
+
Arguments:
|
|
678
|
+
[...args] Task text and options consumed by the delegate script.
|
|
679
|
+
|
|
680
|
+
Options:
|
|
681
|
+
--help, -h Show this help`,
|
|
646
682
|
};
|
|
647
683
|
|
|
648
684
|
function printSubcommandHelp(command: string): void {
|
|
@@ -2191,7 +2227,7 @@ async function main(): Promise<void> {
|
|
|
2191
2227
|
const layer = parseFlag(args, "--layer") as "L0" | "L2" | "L3" | "L4" | "all" | undefined;
|
|
2192
2228
|
const unit = parseFlag(args, "--unit");
|
|
2193
2229
|
const phase = parseFlag(args, "--phase");
|
|
2194
|
-
const format = parseValidateFormat(args);
|
|
2230
|
+
const format = parseValidateFormat(args) ?? (json ? "ci" : undefined);
|
|
2195
2231
|
// WI-094 / ADR-017: --fail-on-warning / --no-fail-on-warning / 未指定→config値
|
|
2196
2232
|
const failOnWarning = parseTriStateFlag(args, "--fail-on-warning", "--no-fail-on-warning");
|
|
2197
2233
|
const noL4 = hasFlag(args, "--no-l4");
|
|
@@ -2206,7 +2242,7 @@ async function main(): Promise<void> {
|
|
|
2206
2242
|
targetPaths,
|
|
2207
2243
|
});
|
|
2208
2244
|
console.log(result.output);
|
|
2209
|
-
if (layer === "L2" || layer === "all") {
|
|
2245
|
+
if ((layer === "L2" || layer === "all") && format !== "ci") {
|
|
2210
2246
|
await printStoryReflectionValidationSummary(rootDir, unit);
|
|
2211
2247
|
}
|
|
2212
2248
|
process.exit(result.exitCode);
|
|
@@ -2492,11 +2528,15 @@ Examples:
|
|
|
2492
2528
|
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
2493
2529
|
const unit = parseFlag(args, "--unit") ?? "";
|
|
2494
2530
|
const phase = parseFlag(args, "--phase") ?? "";
|
|
2531
|
+
const dryRun = hasFlag(args, "--dry-run");
|
|
2532
|
+
const apply = hasFlag(args, "--apply");
|
|
2495
2533
|
const force = hasFlag(args, "--force");
|
|
2496
2534
|
const format = json ? "json" : "human";
|
|
2497
2535
|
const result = await mod.scaffoldDesignHandler.handle({
|
|
2498
2536
|
unit,
|
|
2499
2537
|
phase,
|
|
2538
|
+
dryRun,
|
|
2539
|
+
apply,
|
|
2500
2540
|
force,
|
|
2501
2541
|
format,
|
|
2502
2542
|
});
|