phasegate 0.160.4 → 0.160.6

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 (24) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/docs/templates/ci/agent-context-refresh.yml +12 -8
  3. package/docs/templates/ci/consistency-check.yml +11 -7
  4. package/package.json +1 -1
  5. package/scripts/delegate-sonnet.sh +21 -7
  6. package/scripts/harness/ci-governance/application/dto/scaffold-design-input.ts +2 -0
  7. package/scripts/harness/ci-governance/application/dto/scaffold-design-output.ts +2 -0
  8. package/scripts/harness/ci-governance/application/usecases/refresh-claude-md-usecase.ts +6 -6
  9. package/scripts/harness/ci-governance/application/usecases/scaffold-design-usecase.ts +17 -0
  10. package/scripts/harness/ci-governance/domain/services/claude-md-composer.ts +1 -1
  11. package/scripts/harness/ci-governance/infrastructure/adapters/yaml-template-renderer-adapter.ts +1 -0
  12. package/scripts/harness/ci-governance/presentation/handlers/scaffold-design-handler.ts +25 -3
  13. package/scripts/harness/config-foundation/domain/harness-config.ts +1 -1
  14. package/scripts/harness/config-foundation/domain/value-objects/planning-mode-config.ts +2 -2
  15. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +4 -2
  16. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +4 -2
  17. package/scripts/harness/installation/application/checks/wi-workflow-drift-check.ts +2 -0
  18. package/scripts/harness/integrations/pre-commit.ts +7 -1
  19. package/scripts/harness/main.ts +88 -13
  20. package/scripts/harness/phase-dependency-model/application/services/phase-info-resolver.ts +1 -1
  21. package/scripts/harness/phase-dependency-model/domain/models/phase-structure.ts +1 -1
  22. package/scripts/harness/phase-dependency-model/domain/values/planning-mode.ts +2 -2
  23. package/scripts/harness/skill-quality/application/usecases/apply-cascade-update-usecase.ts +2 -1
  24. package/scripts/harness/skill-quality/presentation/handlers/apply-cascade-update-handler.ts +10 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.160.6] - 2026-05-14
11
+
12
+ ### Fixed
13
+
14
+ - **WI-190..WI-196 — post-0.160.5 dogfood regressions** — aligns agent context refresh with reconcile rendering, adds retrofit planning-mode config plans, makes cascade update dry-runs non-mutating and explicit, fixes doctor `_shared` drift counts, removes pnpm-only scheduled CI templates, exposes `migrate work-items` help, and accepts positional `delegate-sonnet` prompts.
15
+
16
+ ## [0.160.5] - 2026-05-14
17
+
18
+ ### Fixed
19
+
20
+ - **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.
21
+
10
22
  ## [0.160.4] - 2026-05-14
11
23
 
12
24
  ### Fixed
@@ -1,4 +1,5 @@
1
1
  # Phasegate — Agent context refresh workflow
2
+ # @work-item-id WI-194
2
3
  #
3
4
  # 使い方:
4
5
  # このファイルを .github/workflows/agent-context-refresh.yml にコピーして使用する。
@@ -32,18 +33,21 @@ jobs:
32
33
  uses: actions/setup-node@v4
33
34
  with:
34
35
  node-version: '20'
35
- cache: 'pnpm'
36
-
37
- - name: Install pnpm
38
- uses: pnpm/action-setup@v4
39
- with:
40
- version: 9
41
36
 
42
37
  - name: Install dependencies
43
- run: pnpm install --frozen-lockfile
38
+ run: |
39
+ if [ -f pnpm-lock.yaml ]; then
40
+ pnpm install --frozen-lockfile
41
+ elif [ -f yarn.lock ]; then
42
+ yarn install --immutable || yarn install --frozen-lockfile
43
+ elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then
44
+ npm ci
45
+ else
46
+ npm install
47
+ fi
44
48
 
45
49
  - name: Refresh agent context
46
- run: pnpm run harness ci:auto-refresh-agent-context --apply
50
+ run: npx phasegate ci:auto-refresh-agent-context --apply
47
51
 
48
52
  - name: Create pull request
49
53
  uses: peter-evans/create-pull-request@v6
@@ -1,4 +1,5 @@
1
1
  # Phasegate — 週次整合性チェックワークフロー
2
+ # @work-item-id WI-194
2
3
  #
3
4
  # 使い方:
4
5
  # このファイルを .github/workflows/consistency-check.yml にコピーして使用する。
@@ -31,15 +32,18 @@ jobs:
31
32
  uses: actions/setup-node@v4
32
33
  with:
33
34
  node-version: '20'
34
- cache: 'pnpm'
35
-
36
- - name: Install pnpm
37
- uses: pnpm/action-setup@v4
38
- with:
39
- version: 9
40
35
 
41
36
  - name: Install dependencies
42
- run: pnpm install --frozen-lockfile
37
+ run: |
38
+ if [ -f pnpm-lock.yaml ]; then
39
+ pnpm install --frozen-lockfile
40
+ elif [ -f yarn.lock ]; then
41
+ yarn install --immutable || yarn install --frozen-lockfile
42
+ elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then
43
+ npm ci
44
+ else
45
+ npm install
46
+ fi
43
47
 
44
48
  # L4-001: Drift Detection(設計⇔コード双方向乖離)
45
49
  - name: L4 Drift Detection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.160.4",
3
+ "version": "0.160.6",
4
4
  "packageManager": "pnpm@10.30.1",
5
5
  "description": "Phasegate — AI-agnostic quality defense toolkit. Enforces structural integrity between design intent and code.",
6
6
  "license": "MIT",
@@ -4,11 +4,12 @@
4
4
  # Usage:
5
5
  # bash scripts/delegate-sonnet.sh --prompt "プロンプト" --output "出力パス"
6
6
  # bash scripts/delegate-sonnet.sh --prompt-file /tmp/prompt.md --output "出力パス"
7
+ # bash scripts/delegate-sonnet.sh "プロンプト" --output "出力パス"
7
8
  #
8
9
  # Options:
9
10
  # --prompt 委任プロンプト(直接指定、2000文字以下推奨)
10
11
  # --prompt-file 委任プロンプトファイル(長文の場合)
11
- # --output 出力ファイルパス
12
+ # --output 出力ファイルパス(省略時: .phasegate/delegate-sonnet-output.md)
12
13
  # --max-turns 最大ターン数(デフォルト: 30)
13
14
  # --dry-run プロンプトを表示するだけで実行しない
14
15
 
@@ -20,6 +21,7 @@ PROMPT_FILE=""
20
21
  OUTPUT_PATH=""
21
22
  MAX_TURNS=30
22
23
  DRY_RUN=false
24
+ POSITIONAL_ARGS=()
23
25
 
24
26
  while [[ $# -gt 0 ]]; do
25
27
  case $1 in
@@ -43,23 +45,35 @@ while [[ $# -gt 0 ]]; do
43
45
  DRY_RUN=true
44
46
  shift
45
47
  ;;
48
+ --)
49
+ shift
50
+ if [[ $# -gt 0 ]]; then
51
+ POSITIONAL_ARGS+=("$@")
52
+ fi
53
+ break
54
+ ;;
46
55
  *)
47
- echo "Unknown option: $1" >&2
48
- exit 1
56
+ if [[ "$1" == --* ]]; then
57
+ echo "Unknown option: $1" >&2
58
+ exit 1
59
+ fi
60
+ POSITIONAL_ARGS+=("$1")
61
+ shift
49
62
  ;;
50
63
  esac
51
64
  done
52
65
 
66
+ if [[ -z "$PROMPT" && ${#POSITIONAL_ARGS[@]} -gt 0 ]]; then
67
+ PROMPT="${POSITIONAL_ARGS[*]}"
68
+ fi
69
+
53
70
  # --- バリデーション ---
54
71
  if [[ -z "$PROMPT" && -z "$PROMPT_FILE" ]]; then
55
72
  echo "Error: --prompt or --prompt-file is required" >&2
56
73
  exit 1
57
74
  fi
58
75
 
59
- if [[ -z "$OUTPUT_PATH" ]]; then
60
- echo "Error: --output is required" >&2
61
- exit 1
62
- fi
76
+ OUTPUT_PATH="${OUTPUT_PATH:-.phasegate/delegate-sonnet-output.md}"
63
77
 
64
78
  if [[ -n "$PROMPT_FILE" && ! -f "$PROMPT_FILE" ]]; then
65
79
  echo "Error: Prompt file not found: $PROMPT_FILE" >&2
@@ -1,8 +1,10 @@
1
1
  // @unit ci-governance
2
2
  // @layer application
3
+ // @work-item-id WI-189
3
4
 
4
5
  export interface ScaffoldDesignInput {
5
6
  readonly unit: string;
6
7
  readonly phase: string;
8
+ readonly dryRun?: boolean;
7
9
  readonly force?: boolean;
8
10
  }
@@ -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,6 +1,7 @@
1
1
  /**
2
2
  * @layer application
3
3
  * @unit ci-governance
4
+ * @work-item-id WI-190
4
5
  */
5
6
 
6
7
  import type { AgentContextDocumentPort } from '../../domain/ports/agent-context-document-port.js';
@@ -12,12 +13,11 @@ const CLAUDE_MD_PATH = 'CLAUDE.md';
12
13
  const CLAUDE_MD_TEMPLATE_PATH = 'docs/templates/agent-context/CLAUDE.md.template.md';
13
14
 
14
15
  const PHASEGATE_COMMANDS = [
15
- 'phasegate init --with-ci',
16
- 'phasegate ci:auto-refresh-agent-context --dry-run',
17
- 'phasegate ci:auto-refresh-agent-context --apply',
18
- 'phasegate refresh-claude-md --apply',
19
- 'phasegate p2:check-agent-context',
16
+ 'phasegate doctor',
20
17
  'phasegate phasegate:check-ready',
18
+ 'phasegate validate --layer L2 --format human',
19
+ 'phasegate setup:agent --dry-run',
20
+ 'phasegate config:plan --intent l4-strict --dry-run',
21
21
  ];
22
22
 
23
23
  const PHASE_PRESETS = ['minimal', 'standard', 'full', 'custom'];
@@ -37,7 +37,7 @@ export class RefreshClaudeMdUseCase {
37
37
  ]);
38
38
  const nextContent = this.composer.compose(template, existing, {
39
39
  commands: PHASEGATE_COMMANDS,
40
- skills,
40
+ skills: ['all bundled skills'],
41
41
  presets: PHASE_PRESETS,
42
42
  });
43
43
  const changed = existing !== nextContent;
@@ -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,
@@ -11,7 +11,7 @@ export interface ClaudeMdTemplateValues {
11
11
 
12
12
  const USER_SECTION_START = '<!-- phasegate:user-section:start -->';
13
13
  const USER_SECTION_END = '<!-- phasegate:user-section:end -->';
14
- const DEFAULT_USER_SECTION = 'プロジェクト固有の指示をここに記載してください。';
14
+ const DEFAULT_USER_SECTION = 'Project-specific agent instructions go here.';
15
15
 
16
16
  export class ClaudeMdComposer {
17
17
  compose(template: string, existing: string | null, values: ClaudeMdTemplateValues): string {
@@ -2,6 +2,7 @@
2
2
  * @layer infrastructure
3
3
  * @unit ci-governance
4
4
  * @work-item-id WI-182 / WI-183
5
+ * @work-item-id WI-194
5
6
  *
6
7
  * TemplateRendererPort実装(YAML書き出し)
7
8
  */
@@ -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
- `既に存在します: ${result.targetPath}`,
67
- '上書きするには --force を指定してください。',
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
  }
@@ -29,7 +29,7 @@ import type {
29
29
 
30
30
  export type LayerId = 'L1' | 'L2' | 'L3' | 'L4';
31
31
  export type PresetId = 'minimal' | 'standard' | 'strict';
32
- export type PlanningModeValue = 'interactive' | 'embedded-qa';
32
+ export type PlanningModeValue = 'interactive' | 'embedded-qa' | 'manual';
33
33
  export type { PhaseDependenciesPresetId };
34
34
  type DeepPartial<T> = {
35
35
  [K in keyof T]?: T[K] extends Array<infer TItem>
@@ -3,11 +3,11 @@
3
3
  * @unit config-foundation
4
4
  *
5
5
  * Planning Mode設定を表す値オブジェクト
6
- * defaultMode と perPhase の値は列挙値 "interactive" | "embedded-qa" のみ許容
6
+ * defaultMode と perPhase の値は列挙値 "interactive" | "embedded-qa" | "manual" のみ許容
7
7
  */
8
8
  import { ConfigValidationError } from '../errors/config-validation-error.js';
9
9
 
10
- const VALID_MODES = ['interactive', 'embedded-qa'] as const;
10
+ const VALID_MODES = ['interactive', 'embedded-qa', 'manual'] as const;
11
11
  type PlanningMode = (typeof VALID_MODES)[number];
12
12
 
13
13
  export interface PlanningModeConfigProps {
@@ -384,7 +384,8 @@
384
384
  "type": "string",
385
385
  "enum": [
386
386
  "interactive",
387
- "embedded-qa"
387
+ "embedded-qa",
388
+ "manual"
388
389
  ]
389
390
  },
390
391
  "perPhase": {
@@ -393,7 +394,8 @@
393
394
  "type": "string",
394
395
  "enum": [
395
396
  "interactive",
396
- "embedded-qa"
397
+ "embedded-qa",
398
+ "manual"
397
399
  ]
398
400
  }
399
401
  }
@@ -394,7 +394,8 @@
394
394
  "type": "string",
395
395
  "enum": [
396
396
  "interactive",
397
- "embedded-qa"
397
+ "embedded-qa",
398
+ "manual"
398
399
  ]
399
400
  },
400
401
  "perPhase": {
@@ -403,7 +404,8 @@
403
404
  "type": "string",
404
405
  "enum": [
405
406
  "interactive",
406
- "embedded-qa"
407
+ "embedded-qa",
408
+ "manual"
407
409
  ]
408
410
  }
409
411
  }
@@ -2,6 +2,7 @@
2
2
  // @layer application
3
3
  // @work-item-id WI-143
4
4
  // @work-item-id WI-187
5
+ // @work-item-id WI-193
5
6
 
6
7
  import { join, relative, sep } from "node:path";
7
8
  import { DiagnosticFinding } from "../../domain/diagnostic-finding.js";
@@ -61,5 +62,6 @@ function isWorkItemDescription(path: string): boolean {
61
62
  function isAdHocPlan(path: string): boolean {
62
63
  if (!path.startsWith("docs/inception/")) return false;
63
64
  if (/\/WI-\d{3}\//.test(path)) return false;
65
+ if (path.startsWith("docs/inception/_shared/") && path.endsWith(".md")) return true;
64
66
  return path.includes("/codding_plan/") || path.endsWith("_plan.md");
65
67
  }
@@ -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)) {
@@ -7,6 +7,10 @@
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
11
+ * @work-item-id WI-191
12
+ * @work-item-id WI-195
13
+ * @work-item-id WI-196
10
14
  *
11
15
  * Phasegate CLI エントリポイント。
12
16
  * 各Unitの Composition Root からハンドラーを取得し、コマンドに応じてディスパッチする。
@@ -156,7 +160,8 @@ Setup:
156
160
  --with-husky, --with-ci, --yes)
157
161
  update-skills Alias for reconcile (kept for compatibility)
158
162
  doctor Diagnose silent installation failures (--json, --strict, --agent <claude|codex|both>, --report-out <path>)
159
- scaffold-wi <unit> <type> Create docs/inception/{unit}/WI-XXX/description.md
163
+ scaffold-wi <unit|_cross> <story|issue|chore>
164
+ Create docs/inception/{unit}/WI-XXX/description.md
160
165
  emit-agent-rules Print AGENTS.md / CLAUDE.md WI workflow rules block
161
166
  install Install phasegate managed files (--dry-run|--apply, --force)
162
167
  uninstall Uninstall phasegate managed files (--dry-run|--apply, --force)
@@ -169,6 +174,7 @@ Commands:
169
174
  disable-feature <name> Disable a harness feature
170
175
  list-features List available features
171
176
  migrate Migrate phasegate.config.json (--schema v3, --config <path>)
177
+ migrate work-items Migrate legacy inception work item directories (--dry-run|--apply)
172
178
  work-items:status Report or apply derived WI frontmatter status (--dry-run|--apply, --id, --fail-on-stale, --json)
173
179
 
174
180
  render-errors Render harness errors (--format human|agent|ci)
@@ -183,8 +189,9 @@ Commands:
183
189
 
184
190
  lint Run lint checks (--json, --target <path>)
185
191
 
186
- validate Run validators (--layer L2|L3|L4|all; L0 prints runtime hook info, --unit, --format human|agent|ci)
192
+ validate Run validators (--layer L2|L3|L4|all; L0 prints runtime hook info, --unit, --format human|agent|ci|json, --json)
187
193
  ci-check CI check (--quick for quick mode, --fail-on-reject, --dry-run, --files)
194
+ check-change-category Classify changed paths for quick mode (--paths <csv>, --format human|json)
188
195
 
189
196
  phasegate:check-ready Check ready status (--json)
190
197
  phasegate:check-phase Check phase gate (--unit <unitId>, --json)
@@ -208,10 +215,10 @@ Gate semantics:
208
215
  refresh-claude-md Refresh CLAUDE.md standard sections (--dry-run, --apply, --json)
209
216
  p2:check-agent-context Check AGENTS.md / CLAUDE.md freshness (--threshold-days <n>, --json)
210
217
  setup:agent Plan agent-driven setup (--intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>, --agent <claude|codex|both>, --dry-run|--apply, --json)
211
- config:plan Plan safe config changes (--intent <l4-strict|codex-hooks|ci-fail-on-warning|baseline-reset|quick-mode-strict>, --dry-run, --json)
218
+ config:plan Plan safe config changes (--intent <l4-strict|codex-hooks|ci-fail-on-warning|baseline-reset|quick-mode-strict|retrofit-bootstrap|planning-mode-relax>, --dry-run, --json)
212
219
  ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
213
220
  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)
221
+ scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --dry-run|--apply, --force, --json)
215
222
 
216
223
  skill:execute-tdd-cycle Execute TDD cycle (--unit, --story, --desc, --phase RED|GREEN|REFACTOR, --passed)
217
224
  skill:check-coverage Check coverage (--story <storyId>, --json)
@@ -409,7 +416,8 @@ function parseValidateFormat(args: readonly string[]): "human" | "agent" | "ci"
409
416
  const raw = parseFlag(args, "--format");
410
417
  if (raw === undefined) return undefined;
411
418
  if (raw === "human" || raw === "agent" || raw === "ci") return raw;
412
- throw new Error(`Invalid --format value for validate: '${raw}'. Supported values: human, agent, ci.`);
419
+ if (raw === "json") return "ci";
420
+ throw new Error(`Invalid --format value for validate: '${raw}'. Supported values: human, agent, ci, json.`);
413
421
  }
414
422
 
415
423
  function levenshtein(a: string, b: string): number {
@@ -524,7 +532,7 @@ Options:
524
532
  Produce an agent-readable configuration change plan.
525
533
 
526
534
  Intents:
527
- l4-strict, codex-hooks, ci-fail-on-warning, baseline-reset, quick-mode-strict
535
+ l4-strict, codex-hooks, ci-fail-on-warning, baseline-reset, quick-mode-strict, retrofit-bootstrap, planning-mode-relax
528
536
 
529
537
  Options:
530
538
  --dry-run
@@ -546,7 +554,8 @@ Run validators against the project. Without --layer, runs all enabled validator
546
554
 
547
555
  Options:
548
556
  --layer <L0|L2|L3|L4> Run only the specified validator layer; L0 prints runtime hook info
549
- --json Output machine-readable JSON
557
+ --format <human|agent|ci|json> Output format; json is an alias for ci JSON
558
+ --json Output machine-readable JSON when --format is omitted
550
559
  --help, -h Show this help`,
551
560
  lint: `Usage: phasegate lint [options]
552
561
 
@@ -557,10 +566,11 @@ Options:
557
566
  --help, -h Show this help`,
558
567
  migrate: `Usage: phasegate migrate [options]
559
568
 
560
- Migrate phasegate.config.json from older schema versions. Backs up the original to phasegate.config.json.bak.
569
+ Migrate phasegate.config.json from older schema versions, or migrate legacy inception work item directories.
561
570
 
562
571
  Options:
563
572
  --dry-run Preview changes without writing
573
+ --apply Apply migration when supported
564
574
  --help, -h Show this help`,
565
575
  "list-errors": `Usage: phasegate list-errors [options]
566
576
 
@@ -626,6 +636,28 @@ Options:
626
636
  Examples:
627
637
  phasegate check-change-category --paths src/foo.ts,src/bar.ts
628
638
  phasegate check-change-category --paths src/foo.ts --format json`,
639
+ "scaffold-wi": `Usage: phasegate scaffold-wi <unit|_cross> <story|issue|chore>
640
+
641
+ Create docs/inception/{unit}/WI-XXX/description.md.
642
+
643
+ Arguments:
644
+ <unit|_cross> Unit id or _cross for cross-cutting work items.
645
+ <story|issue|chore> Work item type.
646
+
647
+ Options:
648
+ --help, -h Show this help`,
649
+ "scaffold-design": `Usage: phasegate scaffold-design --unit <id> --phase <phase> [options]
650
+
651
+ Scaffold a product construction design document.
652
+
653
+ Options:
654
+ --unit <id> Unit id under docs/product/construction.
655
+ --phase <phase> logical, domain, uiux, unit-test, or it-test.
656
+ --dry-run Preview target and template without writing (default).
657
+ --apply Write the scaffold.
658
+ --force Overwrite an existing target when applying.
659
+ --json Output machine-readable JSON.
660
+ --help, -h Show this help`,
629
661
  "ci:generate-template": `Usage: phasegate ci:generate-template [options]
630
662
 
631
663
  Generates a CI template configuration.
@@ -643,6 +675,15 @@ Options:
643
675
  Examples:
644
676
  phasegate ci:generate-template --type aidlc-gate
645
677
  phasegate ci:generate-template --preset strict --type pre-commit --render`,
678
+ "delegate-sonnet": `Usage: phasegate delegate-sonnet [...args]
679
+
680
+ Delegate a task to Sonnet 4.6 by forwarding all args to scripts/delegate-sonnet.sh.
681
+
682
+ Arguments:
683
+ [...args] Task text and options consumed by the delegate script.
684
+
685
+ Options:
686
+ --help, -h Show this help`,
646
687
  };
647
688
 
648
689
  function printSubcommandHelp(command: string): void {
@@ -733,7 +774,7 @@ function parseCoverageThreshold(raw: string | undefined): number {
733
774
  type InitPhasePreset = "full" | "standard" | "minimal" | "custom";
734
775
  type AgentTarget = "claude" | "codex" | "both";
735
776
  type SetupIntent = "minimal" | "recommended" | "strict" | "ci-only" | "agent-hooks" | "retrofit";
736
- type ConfigChangeIntent = "l4-strict" | "codex-hooks" | "ci-fail-on-warning" | "baseline-reset" | "quick-mode-strict";
777
+ type ConfigChangeIntent = "l4-strict" | "codex-hooks" | "ci-fail-on-warning" | "baseline-reset" | "quick-mode-strict" | "retrofit-bootstrap" | "planning-mode-relax";
737
778
  type SetupCompletenessStatus = "configured" | "planned" | "manual" | "not-applicable" | "unknown";
738
779
 
739
780
  interface SetupCompletenessEntry {
@@ -811,7 +852,9 @@ function parseConfigChangeIntent(value: string | undefined): ConfigChangeIntent
811
852
  value === "codex-hooks" ||
812
853
  value === "ci-fail-on-warning" ||
813
854
  value === "baseline-reset" ||
814
- value === "quick-mode-strict"
855
+ value === "quick-mode-strict" ||
856
+ value === "retrofit-bootstrap" ||
857
+ value === "planning-mode-relax"
815
858
  ) {
816
859
  return value;
817
860
  }
@@ -1180,6 +1223,14 @@ function buildConfigPatchPreview(intent: ConfigChangeIntent, before: unknown | n
1180
1223
  ],
1181
1224
  "codex-hooks": [],
1182
1225
  "baseline-reset": [],
1226
+ "retrofit-bootstrap": [
1227
+ { pointer: "/planningMode/default", path: ["planningMode", "default"], value: "manual" },
1228
+ { pointer: "/phaseDependencies/override", path: ["phaseDependencies", "override"], value: true },
1229
+ { pointer: "/quickMode/relaxedGates", path: ["quickMode", "relaxedGates"], value: ["phase-gate"] },
1230
+ ],
1231
+ "planning-mode-relax": [
1232
+ { pointer: "/planningMode/default", path: ["planningMode", "default"], value: "manual" },
1233
+ ],
1183
1234
  };
1184
1235
  const changes = configIntents[intent];
1185
1236
  if (changes.length === 0) {
@@ -1267,6 +1318,22 @@ async function buildConfigChangePlan(rootDir: string, intent: ConfigChangeIntent
1267
1318
  validations: ["phasegate ci-check --quick --dry-run", "phasegate phasegate:check-ready"],
1268
1319
  risks: ["More changes will require Full Mode validation before commit."],
1269
1320
  },
1321
+ "retrofit-bootstrap": {
1322
+ targets: ["phasegate.config.json: planningMode.default", "phasegate.config.json: phaseDependencies.override", "phasegate.config.json: quickMode.relaxedGates"],
1323
+ managedTargets: ["phasegate.config.json"],
1324
+ externalActions: [],
1325
+ commands: ["phasegate baseline --dry-run", "phasegate config:plan --intent retrofit-bootstrap --json"],
1326
+ validations: ["phasegate validate-metadata docs/inception/_shared/*.md", "phasegate check-phase-gate --level 2"],
1327
+ risks: ["Manual planning mode accepts existing retrofit planning evidence; review the patch before applying it to avoid weakening greenfield projects."],
1328
+ },
1329
+ "planning-mode-relax": {
1330
+ targets: ["phasegate.config.json: planningMode.default"],
1331
+ managedTargets: ["phasegate.config.json"],
1332
+ externalActions: [],
1333
+ commands: ["phasegate config:plan --intent planning-mode-relax --json"],
1334
+ validations: ["phasegate check-phase-gate --level 2", "phasegate phasegate:check-ready"],
1335
+ risks: ["Manual planning mode reduces PhaseGate's QA enforcement for plan documents until strict planning is restored."],
1336
+ },
1270
1337
  };
1271
1338
  const before = await readProjectJson(rootDir, "phasegate.config.json");
1272
1339
  return {
@@ -2191,7 +2258,7 @@ async function main(): Promise<void> {
2191
2258
  const layer = parseFlag(args, "--layer") as "L0" | "L2" | "L3" | "L4" | "all" | undefined;
2192
2259
  const unit = parseFlag(args, "--unit");
2193
2260
  const phase = parseFlag(args, "--phase");
2194
- const format = parseValidateFormat(args);
2261
+ const format = parseValidateFormat(args) ?? (json ? "ci" : undefined);
2195
2262
  // WI-094 / ADR-017: --fail-on-warning / --no-fail-on-warning / 未指定→config値
2196
2263
  const failOnWarning = parseTriStateFlag(args, "--fail-on-warning", "--no-fail-on-warning");
2197
2264
  const noL4 = hasFlag(args, "--no-l4");
@@ -2206,7 +2273,7 @@ async function main(): Promise<void> {
2206
2273
  targetPaths,
2207
2274
  });
2208
2275
  console.log(result.output);
2209
- if (layer === "L2" || layer === "all") {
2276
+ if ((layer === "L2" || layer === "all") && format !== "ci") {
2210
2277
  await printStoryReflectionValidationSummary(rootDir, unit);
2211
2278
  }
2212
2279
  process.exit(result.exitCode);
@@ -2492,11 +2559,15 @@ Examples:
2492
2559
  const mod = buildCiGovernance(rootDir, harnessRoot);
2493
2560
  const unit = parseFlag(args, "--unit") ?? "";
2494
2561
  const phase = parseFlag(args, "--phase") ?? "";
2562
+ const dryRun = hasFlag(args, "--dry-run");
2563
+ const apply = hasFlag(args, "--apply");
2495
2564
  const force = hasFlag(args, "--force");
2496
2565
  const format = json ? "json" : "human";
2497
2566
  const result = await mod.scaffoldDesignHandler.handle({
2498
2567
  unit,
2499
2568
  phase,
2569
+ dryRun,
2570
+ apply,
2500
2571
  force,
2501
2572
  format,
2502
2573
  });
@@ -2547,7 +2618,7 @@ Examples:
2547
2618
  const mod = createSkillQualityHandlers();
2548
2619
  const storyId = parseFlag(args, "--story") ?? "";
2549
2620
  const dryRun = hasFlag(args, "--dry-run");
2550
- const result = await mod.applyCascadeUpdateHandler.handle({ storyId, dryRun });
2621
+ const result = await mod.applyCascadeUpdateHandler.handle({ storyId, dryRun, format: json ? "json" : "human" });
2551
2622
  console.log(result.message);
2552
2623
  process.exit(result.exitCode);
2553
2624
  break;
@@ -2740,6 +2811,10 @@ Examples:
2740
2811
  }
2741
2812
 
2742
2813
  case "delegate-sonnet": {
2814
+ if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
2815
+ printSubcommandHelp("delegate-sonnet");
2816
+ process.exit(0);
2817
+ }
2743
2818
  const { spawn } = await import("node:child_process");
2744
2819
  const scriptPath = join(harnessRoot, "scripts/delegate-sonnet.sh");
2745
2820
  const forwardArgs = args.slice(1);
@@ -125,7 +125,7 @@ export class PhaseInfoResolver {
125
125
  blockers.push(`QAが未完了です: ${node.nodeKey()}`);
126
126
  }
127
127
  if (!actual.planningModeMatch) {
128
- blockers.push(`Planning Mode要件を満たしていません: ${node.nodeKey()}`);
128
+ blockers.push(`Planning Mode evidence requirement is not satisfied: ${node.nodeKey()}`);
129
129
  }
130
130
  }
131
131
  }
@@ -270,7 +270,7 @@ export class PhaseStructure {
270
270
  }
271
271
 
272
272
  if (!planEvidence.planningModeMatch) {
273
- blockers.push(`Planning Mode要件を満たしていません: ${node.nodeKey()}`);
273
+ blockers.push(`Planning Mode evidence requirement is not satisfied: ${node.nodeKey()}`);
274
274
  }
275
275
  }
276
276
 
@@ -3,7 +3,7 @@
3
3
  * @unit phase-dependency-model
4
4
  */
5
5
 
6
- export type PlanningModeValue = 'interactive' | 'embedded-qa';
6
+ export type PlanningModeValue = 'interactive' | 'embedded-qa' | 'manual';
7
7
 
8
8
  export class InvalidPlanningModeError extends Error {
9
9
  constructor(value: string) {
@@ -21,7 +21,7 @@ export class PlanningMode {
21
21
  }
22
22
 
23
23
  static create(value: string): PlanningMode {
24
- if (value !== 'interactive' && value !== 'embedded-qa') {
24
+ if (value !== 'interactive' && value !== 'embedded-qa' && value !== 'manual') {
25
25
  throw new InvalidPlanningModeError(value);
26
26
  }
27
27
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @layer application
3
3
  * @unit skill-quality
4
+ * @work-item-id WI-192
4
5
  */
5
6
  import { CascadeUpdateResult } from '../../domain/value-objects/cascade-update-result.js';
6
7
  import type { CascadeUpdateService } from '../../domain/services/cascade-update-service.js';
@@ -35,7 +36,7 @@ export class ApplyCascadeUpdateUseCase {
35
36
  const updatedContent = content.includes(target.storyIdTag)
36
37
  ? content
37
38
  : `${content}\n${target.storyIdTag}`;
38
- if (!input.dryRun) {
39
+ if (!input.dryRun && updatedContent !== content) {
39
40
  await this.fileSystemPort.write(filePath, updatedContent);
40
41
  }
41
42
  updatedCount++;
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * @layer presentation
3
3
  * @unit skill-quality
4
+ * @work-item-id WI-192
4
5
  */
5
6
  import type { ApplyCascadeUpdateUseCase } from '../../application/usecases/apply-cascade-update-usecase.js';
6
7
 
7
8
  export interface ApplyCascadeUpdateArgs {
8
9
  storyId: string;
9
10
  dryRun?: boolean;
11
+ format?: 'human' | 'json';
10
12
  }
11
13
 
12
14
  export class ApplyCascadeUpdateHandler {
@@ -15,8 +17,15 @@ export class ApplyCascadeUpdateHandler {
15
17
  async handle(args: ApplyCascadeUpdateArgs): Promise<{ exitCode: number; message: string }> {
16
18
  try {
17
19
  const output = await this.useCase.execute({ storyId: args.storyId, dryRun: args.dryRun });
20
+ if (args.format === 'json') {
21
+ return {
22
+ exitCode: output.errors.length > 0 ? 1 : 0,
23
+ message: JSON.stringify({ dryRun: args.dryRun === true, ...output }, null, 2),
24
+ };
25
+ }
18
26
  const tagsLine = output.appliedStoryIds.join(', ');
19
- let msg = `Updated ${output.updatedCount} files with tags: ${tagsLine}`;
27
+ const verb = args.dryRun ? 'Would update' : 'Updated';
28
+ let msg = `${verb} ${output.updatedCount} files with tags: ${tagsLine}`;
20
29
 
21
30
  if (output.errors.length > 0) {
22
31
  const errLines = output.errors.map((e) => ` - ${e}`).join('\n');