phasegate 0.112.0 → 0.116.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 CHANGED
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.116.0] - 2026-05-07
11
+
12
+ ### Security
13
+
14
+ - **WI-036: skill-quality の git-commit-executor adapter におけるコマンドインジェクション (HIGH) を修正** — WI-035 Phase 3 横展開監査で発見した follow-up。`execSync(\`git commit -m ${JSON.stringify(message)}\`)` を `execFileSync('git', ['commit', '-m', message], ...)` 配列引数形式に置換。`JSON.stringify` がバッククオート / `$` をエスケープせず `/bin/sh -c` 経由で評価される経路を遮断。
15
+ - `scripts/harness/skill-quality/infrastructure/adapters/git-commit-executor-adapter.ts` を `execFileSync` 化、コンストラクタに `gitExecutor` を DI 可能化(テスタビリティ向上、`CommitExecutorPort.commit()` の外部 signature は不変)。
16
+ - 悪意ある `description`(バッククオート / `$()` / `;` / `"` / 改行 / `|` 含む)が引数配列にそのまま渡されシェル評価されないことを assert する unit test (`__tests__/unit/skill-quality/git-commit-executor-adapter.test.ts`) を新規追加。
17
+ - 横展開監査 (再走査): 非テストコード `scripts/harness/**/*.ts` の `execSync(\`...${var}...\`)` パターンが **完全消滅**(WI-035 / WI-036 で網羅完了)。
18
+ - WI-035 / WI-036 の `status` を `drafted` → `implemented` に更新。
19
+
20
+ ## [0.115.0] - 2026-05-07
21
+
22
+ ### Documentation
23
+
24
+ - **WI-036 起票** — WI-035 Phase 3 横展開監査の follow-up として、`scripts/harness/skill-quality/infrastructure/adapters/git-commit-executor-adapter.ts:14` の `execSync(\`git commit -m ${JSON.stringify(message)}\`)` を同種コマンドインジェクション (HIGH) の sink として切り出し、別 WI に分離。`JSON.stringify` がバッククオート / `$` をエスケープしないため、`description` が外部入力に由来すると `/bin/sh -c` 経由で評価され得る点を文書化。修正実装は次回(`execFileSync` 配列引数化 + DI seed 化 + 悪意 description fixture テスト)。
25
+ - WI-035 description.md の Phase 3 監査結果欄を「WI-036 として起票済み」に更新。
26
+
27
+ ## [0.114.0] - 2026-05-07
28
+
29
+ ### Security
30
+
31
+ - **WI-035: phase2-extensions の git-log adapter におけるコマンドインジェクション脆弱性 (HIGH) を修正** — `/security-review` で発見。`execSync` テンプレート文字列に `documentPath` / `filePath` をダブルクオート展開していたため、ファイル名に `$()` / バッククオート / `;` 等のシェルメタ文字を含めると `/bin/sh -c` 経由で任意コードが実行される経路があった(攻撃者は POSIX 許容範囲のファイル名を含む公開リポジトリを 1 つ用意するだけで成立。clone / `gh pr checkout` でローカルに展開された時点で発火し、マージは不要)。
32
+ - `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-document-age-adapter.ts` の `gitLogExecutor` を `execFileSync` 配列引数形式(`('git', ['log', '--format=%ai', '-1', '--', documentPath], ...)`)に置換。
33
+ - `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-initial-creation-age-adapter.ts` の `gitExecutor` を同形式に置換(`runGit(args)` の signature も合わせて変更)。
34
+ - DI ポートの signature を `(command: string) => Buffer` から `(file: string, args: readonly string[], options) => Buffer` に変更。
35
+ - 悪意あるファイル名(`$()` / バッククオート / `;` / `"` / `|` 含む)でも引数が **配列要素のまま** 渡され、シェルメタ文字として評価されないことを assert する unit test を 2 ファイルに追加。
36
+ - 横展開監査結果: 同種パターン (`execSync(\`...${var}...\`)`) は他に `scripts/harness/skill-quality/infrastructure/adapters/git-commit-executor-adapter.ts:14` に 1 箇所存在(`JSON.stringify` 経由だが `$` / バッククオートが残存)。本 WI のスコープ (`affects: [phase2-extensions]`) 外のため follow-up WI として WI-035 description に記録。
37
+
10
38
  ## [0.110.0] - 2026-04-25
11
39
 
12
40
  ### Documentation
package/README.ja.md CHANGED
@@ -1,10 +1,12 @@
1
+ ![Phasegate header](assets/phasegate-header.png)
2
+
1
3
  # Phasegate
2
4
 
3
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
5
7
 
6
- **AI が書いたコードに「設計してから書け」を物理的に強制するツールキット。**
7
- Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が効きます。
8
+ **AI agent に「設計してから書け」を hooks / git / CI で強制するツールキット。**
9
+ Claude Code / Codex / Cursor / Copilot — どの AI agent でも設計意図・レイヤー境界・テスト規約を守らせます。
8
10
 
9
11
  [English README](README.md) ・ [開発者ガイド](DEVELOPMENT.ja.md)
10
12
 
@@ -12,7 +14,7 @@ Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が
12
14
 
13
15
  ## 30 秒でわかる Phasegate
14
16
 
15
- 1. **AI agent が設計文書なしで実装ファイルを書こうとすると、Write/Edit/Bash がブロックされる**(PreToolUse hook
17
+ 1. **AI agent が設計文書なしで実装ファイルを書こうとすると、Write/Edit/Bash または git hook で止まる**
16
18
  2. **コミット前に L1〜L3 のバリデーションが自動で走り**、レイヤー違反・テスト品質違反・依存方向違反を弾く
17
19
  3. **ブロック時のエラーは AI が読んで自己修正できる形式**(理由・必要な設計文書・次に打つべきスキル名が出る)
18
20
 
@@ -24,7 +26,7 @@ Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が
24
26
 
25
27
  AI agent は速いが、設計を飛ばして実装に走ります。レイヤー境界を平気で越え、`any` 型で型システムを骨抜きにし、テストはあるけど実装の写経になっている — そんなコードを高速に量産します。レビューで全部捕まえるのは現実的ではありません。
26
28
 
27
- Phasegate はこれを **「人がレビューで防ぐ」のではなく「ツールがファイルシステム/git/CI レベルで防ぐ」** で解決します。設計文書がなければそもそも書けない。レイヤー違反があれば commit が通らない。AI agent 自身が「次にどの設計スキルを呼べばいいか」を読んで自走します。
29
+ Phasegate はこれを **「人がレビューで防ぐ」のではなく「ツールが hooks / git / CI レベルで防ぐ」** で解決します。設計文書がなければ書き込みまたは commit が止まる。レイヤー違反があれば CI が通らない。AI agent 自身が「次にどの設計スキルを呼べばいいか」を読んで自走します。
28
30
 
29
31
  ### こんなプロジェクトで効きます
30
32
 
@@ -51,7 +53,7 @@ AI agent が設計なしに `src/order/order-service.ts` を書こうとする
51
53
  実行例: /story-implementor --unit order
52
54
  ```
53
55
 
54
- Claude Code / Codex はこのメッセージを読んで `/story-implementor` を起動し、ドメイン設計→論理設計→TDD 実装の順で進みます。人間が「設計やってからね」と言わなくても自走します。
56
+ Claude Code / Codex はこのメッセージを読んで `/story-implementor` を起動し、ドメイン設計→論理設計→TDD 実装の順で進みます。単に失敗させるのではなく、AI agent が復帰できる形で「次に何を作るべきか」を返します。
55
57
 
56
58
  ---
57
59
 
@@ -101,7 +103,7 @@ npx phasegate init --name my-project --agent codex --with-husky
101
103
  codex features enable codex_hooks # Codex 本体の feature flag を手動で有効化
102
104
  ```
103
105
 
104
- 両方使う場合は `--agent both`。詳細は [Codex Integration Guide](docs/guide/codex-integration.md) を参照。
106
+ 両方使う場合は `--agent both`。Codex のネイティブ `apply_patch` は現時点で事前 hook を発火しないため、pre-commit (L2) で commit 時にブロックします。Bash 経由の書き込みは実行前に止まります。詳細は [Codex Integration Guide](docs/guide/codex-integration.md) を参照。
105
107
 
106
108
  ### アップデート
107
109
 
@@ -123,6 +125,7 @@ npx phasegate update-skills # スキルを最新版に再デプロイ
123
125
  | **Claude Code / Codex Hooks** | Write/Edit/Bash 時に自動でゲートチェック・lint を実行 |
124
126
  | **HarnessError 形式** | 全エラーに ADR 参照 + 修正例が含まれ、AI が自己修正できる |
125
127
  | **Baseline (retrofit)** | 既存リポジトリ導入時、`baseline` snapshot に登録した既存ファイルは構造的に編集されるまで gate 対象外 |
128
+ | **カスタム gate** | AIDLC 以外のプロジェクトでも schema-first など独自の前提条件を設定できる |
126
129
 
127
130
  ---
128
131
 
@@ -444,9 +447,9 @@ reports/
444
447
 
445
448
  ---
446
449
 
447
- ## ロードマップ
450
+ ## 既知の制約とロードマップ
448
451
 
449
- ドキュメントで言及があるが現状 partial 実装または user 配線に依存しているもの。各 Work Item は `docs/inception/_cross/WI-XXX/description.md` に起票済み。
452
+ 主要な導入パスはそのまま利用できますが、一部の機能は user 側の配線が必要、または今後の minor release での改善対象です。各 Work Item は `docs/inception/_cross/WI-XXX/description.md` に起票済みです。
450
453
 
451
454
  | Work Item | 内容 |
452
455
  |---|---|
@@ -455,7 +458,7 @@ reports/
455
458
  | **[WI-033](docs/inception/_cross/WI-033/description.md)** | `doc-freshness` / `pointer-validation` を L4 validator に昇格 |
456
459
  | **[WI-034](docs/inception/_cross/WI-034/description.md)** | L0 legacy validator (`L0-001` / `L0-002`) の撤去 |
457
460
 
458
- L3 Nyquist Validation の `requirement-test-matrix.json` 自動生成パイプラインも未完成(手動セットアップで利用可)。
461
+ L3 Nyquist Validation の `requirement-test-matrix.json` 自動生成はまだ未自動化です。現時点では手動セットアップで利用できます。
459
462
 
460
463
  ---
461
464
 
package/README.md CHANGED
@@ -1,63 +1,124 @@
1
+ ![Phasegate header](assets/phasegate-header.png)
2
+
1
3
  # Phasegate
2
4
 
3
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
5
7
 
6
- **Phasegate -- AI-agnostic quality defense toolkit.**
8
+ **A toolkit that makes AI agents design before they code.**
9
+
10
+ Phasegate adds project-local hooks, validators, and agent skills that keep generated code aligned with design intent, layer boundaries, and test discipline across Claude Code, Codex, Cursor, Copilot, and other AI coding agents.
7
11
 
8
- Enforces structural integrity between design intent and code, regardless of which AI agent you use.
12
+ [日本語版](README.ja.md) | [Developer Guide](DEVELOPMENT.md)
9
13
 
10
14
  ---
11
15
 
12
- ## Why Phasegate?
16
+ ## Phasegate in 30 Seconds
13
17
 
14
- AI coding agents are fast but unconstrained. They skip design steps, violate layer boundaries, and produce code that drifts from intent. Phasegate solves this with a portable, agent-independent defense layer that makes it **physically impossible** to implement without design, commit without validation, or merge without traceability.
18
+ 1. **When an AI agent tries to write implementation code without design docs, Phasegate blocks the write** through agent hooks or git hooks.
19
+ 2. **Before commit and CI, validators check layer boundaries, metadata, test quality, security, performance, and traceability.**
20
+ 3. **Every failure is returned in an agent-readable format** with the reason, missing artifacts, references, and the next skill or command to run.
15
21
 
16
- Works with **Claude Code, Codex, Cursor, Copilot**, or any other AI agent.
22
+ Run `npx phasegate init` once and the project gets the guardrails, skills, and configuration needed to make that flow repeatable.
17
23
 
18
24
  ---
19
25
 
20
- ## Features
26
+ ## Why Phasegate?
27
+
28
+ AI coding agents are fast, but they do not naturally protect your architecture. They skip design steps, cross layer boundaries, weaken type systems with `any`, and generate tests that mirror implementation instead of proving behavior. Human review cannot reliably catch that at AI speed.
21
29
 
22
- | Feature | Description |
30
+ Phasegate turns those expectations into enforcement. If the design is missing, the agent is told what to create first. If a change violates the architecture, commit or CI fails. If a design has not been reflected into canonical product docs, implementation is blocked until the trace exists.
31
+
32
+ ### Where it fits
33
+
34
+ | Good fit | Poor fit |
23
35
  |---|---|
24
- | **5-Layer Defense Model** | L0 through L4 validators from editor time to scheduled audits |
25
- | **28 AIDLC Skills** | Full coverage from product architecture to story implementation |
26
- | **Phase Dependency Model** | Blocks implementation when required design documents are missing |
27
- | **Quick Mode** | Lightweight gate for bugfixes, docs, tests, and config changes |
28
- | **Claude Code Hooks** | Native PreToolUse / PostToolUse / Stop hook integration |
29
- | **Codex CLI Hooks** | `PreToolUse(Bash)` / `PostToolUse(Bash)` / `Stop` hook integration (native `apply_patch` falls back to pre-commit) |
30
- | **HarnessError Format** | Every error includes ADR references and fix examples for AI self-correction |
31
- | **Configurable Phase Gates** | Define custom gates with `gates[]` in config. Default uses AIDLC phase dependencies |
32
- | **Protected File Control** | Configure which files are protected from AI writes via `protectedFiles.exclude` |
33
- | **Bash Write Detection** | Detects and blocks shell-based file writes (`sed -i`, `tee`, `cp`, `mv`, redirects) |
34
- | **Presets** | minimal, standard, and strict -- choose your quality level |
36
+ | Medium to large projects where AI agents implement multiple features | Throwaway scripts with no lasting structure |
37
+ | Clean Architecture, DDD, Hexagonal, or layered systems | Codebases where architecture is intentionally ad hoc |
38
+ | Teams that want TDD and test conventions enforced automatically | Projects that do not write automated tests |
39
+ | Products that need design-code drift detection over time | Projects where code is the only source of truth |
40
+
41
+ ---
42
+
43
+ ## What It Looks Like
44
+
45
+ When an agent tries to write `src/order/order-service.ts` before the `order` unit has design docs, Phasegate stops it:
46
+
47
+ ```text
48
+ Phase gate violation: src/order/order-service.ts
49
+ Scope: Level 3 (implementation), Unit: order
50
+ Blocked because:
51
+ - docs/product/construction/order/domain_model.md is missing
52
+ - docs/product/construction/order/logical_design.md is missing
53
+ Next action: run the /story-implementor skill and start from design.
54
+ Example: /story-implementor --unit order
55
+ ```
56
+
57
+ The point is not just to fail the edit. The error gives the AI agent enough structure to recover: create the missing design, reflect it into product docs, then implement with tests.
35
58
 
36
59
  ---
37
60
 
38
61
  ## Quick Start
39
62
 
40
- ### 1. Install
63
+ ### Requirements
64
+
65
+ Node.js >= 18, npm >= 9, TypeScript 5.x
66
+
67
+ ### 3 steps
41
68
 
42
69
  ```bash
70
+ # 1. Install
43
71
  npm install --save-dev phasegate
72
+
73
+ # 2. Initialize the project
74
+ npx phasegate init --name my-project --with-husky
75
+
76
+ # 3. Start your AI agent and begin with product design
77
+ claude
78
+ > /product-architect
44
79
  ```
45
80
 
46
- ### 2. Initialize
81
+ `init` creates:
82
+
83
+ - `phasegate.config.json` as the quality settings source of truth
84
+ - `skills/` with 28 AIDLC skills
85
+ - `.claude/skills` and/or `.codex/skills` links for agent use
86
+ - `.claude/settings.json` and/or `.codex/hooks.json` hook configuration
87
+ - `docs/principles/*.md` and `docs/folder_management_rules.md`
88
+ - `.husky/pre-commit` and `.husky/commit-msg` when `--with-husky` is passed
89
+
90
+ `init` intentionally does **not** create `docs/inception/` work item directories or `docs/product/` design documents. Those are produced later by skills such as `/product-architect`, `/domain-designer`, and `/logical-designer`. That is the core contract: no design, no code.
91
+
92
+ ### Codex CLI
47
93
 
48
94
  ```bash
49
- npx phasegate init --name my-project
95
+ npx phasegate init --name my-project --agent codex --with-husky
96
+ codex features enable codex_hooks
50
97
  ```
51
98
 
52
- This deploys 28 skills to `skills/`, creates agent-specific links such as `.claude/skills` or `.codex/skills`, installs design principles docs (`docs/principles/*.md`, `docs/folder_management_rules.md`), and generates `phasegate.config.json`.
99
+ Use `--agent both` for projects that use Claude Code and Codex together. Codex native `apply_patch` currently cannot be intercepted before the edit, so those violations are caught at pre-commit; Bash-based writes are blocked before execution.
53
100
 
54
- **`init` does NOT generate**: `docs/inception/` work item directories or `docs/product/` design documents. Those are produced later by AIDLC skills (`/product-architect`, `/domain-designer`, etc.) — that is the whole point of "no design, no code."
101
+ ### Update
102
+
103
+ ```bash
104
+ npm update phasegate
105
+ npx phasegate update-skills
106
+ ```
55
107
 
56
- Optional: add `--with-husky` to also install a `.husky/pre-commit` hook that runs L2 validators.
108
+ ---
57
109
 
58
- ### 3. Start the AIDLC
110
+ ## Core Capabilities
59
111
 
60
- Launch your AI agent and run the `/product-architect` skill to begin.
112
+ | Capability | What it does |
113
+ |---|---|
114
+ | **Phase gates** | Blocks implementation writes until required design documents exist and have been reflected into product docs |
115
+ | **5-layer validation** | Runs checks from agent runtime and editor time through pre-commit, CI, and scheduled audits |
116
+ | **28 AIDLC skills** | Guides AI agents through product architecture, story writing, domain design, test design, and TDD implementation |
117
+ | **Quick Mode** | Keeps bugfixes, docs, test-only changes, and config changes lightweight while preserving traceability |
118
+ | **Claude Code / Codex hooks** | Runs checks around Write/Edit/Bash operations and session boundaries |
119
+ | **Agent-readable HarnessError output** | Gives AI agents the reason, missing artifacts, references, and examples needed to self-correct |
120
+ | **Retrofit baseline** | Lets existing repositories adopt Phasegate gradually by grandfathering unchanged files |
121
+ | **Configurable gates** | Supports AIDLC defaults or custom gates such as schema-first API development |
61
122
 
62
123
  ---
63
124
 
@@ -102,60 +163,19 @@ Launch your AI agent and run the `/product-architect` skill to begin.
102
163
 
103
164
  ## 28 Skills
104
165
 
105
- Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**, enforcing phase dependencies so that implementation cannot begin without design.
166
+ Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**: product definition, design, test design, and TDD implementation. Each skill consumes the artifacts from the previous phase.
106
167
 
107
- ### Foundation (4)
168
+ **First step**: run `/product-architect` inside Claude Code or Codex.
108
169
 
109
- | Skill | Purpose |
170
+ | Group | Skills |
110
171
  |---|---|
111
- | `/product-architect` | Define product vision, domains, architecture, and constraints |
112
- | `/story-writer` | Create Who/What/Why user stories with acceptance criteria |
113
- | `/story-mapper` | Prioritize stories and define MVP scope |
114
- | `/unit-designer` | Group stories into independently buildable Units |
172
+ | **Foundation (4)** | `/product-architect` `/story-writer` `/story-mapper` `/unit-designer` |
173
+ | **Design (5)** | `/domain-designer` `/logical-designer` `/mock-designer` `/uiux-designer` `/environment-designer` |
174
+ | **Test Engineering (7)** | `/unit-test-designer` `/it-test-designer` `/scenario-test-designer` `/unit-test-logic-designer` `/it-test-logic-designer` `/scenario-test-logic-designer` `/test-coverage-checker` |
175
+ | **Implementation (4)** | `/story-implementor` `/quick-implementor` `/implementation-planner` `/implementation-readiness-checker` |
176
+ | **Verification (8)** | `/consistency-checker` `/cascade-updater` `/codex-delegator` `/codebase-mapper` `/doc-freshness-checker` `/pointer-validator` `/engineering-perspective` `/skill-creator` |
115
177
 
116
- ### Design (5)
117
-
118
- | Skill | Purpose |
119
- |---|---|
120
- | `/domain-designer` | DDD tactical design -- aggregates, entities, value objects, events |
121
- | `/logical-designer` | Hexagonal architecture design (ports and adapters) |
122
- | `/mock-designer` | UI mockup design for early validation |
123
- | `/uiux-designer` | Final UI/UX definition from test cases and logical design |
124
- | `/environment-designer` | Local dev environment and infrastructure design |
125
-
126
- ### Test Engineering (7)
127
-
128
- | Skill | Purpose |
129
- |---|---|
130
- | `/unit-test-designer` | Unit test case design from domain models |
131
- | `/it-test-designer` | Integration test case design from logical design |
132
- | `/scenario-test-designer` | E2E scenario test case design |
133
- | `/unit-test-logic-designer` | Vitest implementation logic with pseudocode |
134
- | `/it-test-logic-designer` | Integration test Vitest implementation logic |
135
- | `/scenario-test-logic-designer` | Playwright E2E implementation logic |
136
- | `/test-coverage-checker` | Coverage verification and Nyquist validation |
137
-
138
- ### Implementation (4)
139
-
140
- | Skill | Purpose |
141
- |---|---|
142
- | `/story-implementor` | TDD implementation (Red-Green-Refactor) with atomic commits |
143
- | `/quick-implementor` | Lightweight implementation for bugfixes, docs, tests, config |
144
- | `/implementation-planner` | Implementation plan from Unit specs and domain models |
145
- | `/implementation-readiness-checker` | Pre-implementation readiness verification |
146
-
147
- ### Verification (8)
148
-
149
- | Skill | Purpose |
150
- |---|---|
151
- | `/consistency-checker` | Cross-layer consistency check across design documents |
152
- | `/cascade-updater` | Propagate lower-phase discoveries to upstream design docs |
153
- | `/codex-delegator` | Delegate tasks to Codex CLI with quality oversight |
154
- | `/codebase-mapper` | Generate structure map from `@unit`/`@layer` annotations |
155
- | `/doc-freshness-checker` | Design document staleness detection (L4 extension) |
156
- | `/pointer-validator` | Validate file path references in design documents |
157
- | `/engineering-perspective` | Multi-perspective design review (Beck, Fowler, Martin, Evans) |
158
- | `/skill-creator` | Create or update agent skills |
178
+ Details, prerequisites, and generated artifacts: [Skills Overview](docs/guide/skills-overview.md)
159
179
 
160
180
  ---
161
181
 
@@ -489,9 +509,9 @@ Additional resources:
489
509
 
490
510
  ---
491
511
 
492
- ## Roadmap (Planned but not yet implemented)
512
+ ## Known Limits and Roadmap
493
513
 
494
- The following are documented behaviors that are partially implemented or rely on user-side wiring. Each is tracked as a Work Item and will land in a future minor release. Inception docs live under `docs/inception/_cross/WI-XXX/description.md`.
514
+ The main path is ready for project use, but a few documented behaviors still require user-side wiring or are tracked for a future minor release. Each item has a Work Item under `docs/inception/_cross/WI-XXX/description.md`.
495
515
 
496
516
  | Work Item | Title | Why it matters |
497
517
  |---|---|---|
@@ -500,7 +520,7 @@ The following are documented behaviors that are partially implemented or rely on
500
520
  | **[WI-033](docs/inception/_cross/WI-033/description.md)** | Promote `doc-freshness` / `pointer-validation` to L4 validators | Both capabilities exist as `p2:check-freshness` / `p2:validate-pointers` CLI commands but are not registered as L4 validators, so `validate --layer L4` skips them. WI-033 plumbs them through `validator-system` so they run via the standard L4 path and presets. |
501
521
  | **[WI-034](docs/inception/_cross/WI-034/description.md)** | Retire legacy L0 validators (`L0-001` / `L0-002`) | The `fuse-hook-config` / `fuse-mount-status` validator IDs are leftovers from an earlier FUSE-based design. They are disabled by default and have no actual implementation behind them. WI-034 removes them and lets the agent-integration runtime hooks be the sole L0 surface. |
502
522
 
503
- `requirement-test-matrix.json` auto-generation for L3 Nyquist Validation is also a known gap; see the L3 section above.
523
+ `requirement-test-matrix.json` auto-generation for L3 Nyquist Validation is not automated yet; see the L3 guide for the current manual setup.
504
524
 
505
525
  ---
506
526
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.112.0",
3
+ "version": "0.116.0",
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",
@@ -2,7 +2,7 @@
2
2
  * @layer infrastructure
3
3
  * @unit phase2-extensions
4
4
  */
5
- import { execSync } from 'node:child_process';
5
+ import { execFileSync } from 'node:child_process';
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import type { DocumentAgePort } from '../../domain/ports/document-age-port.js';
@@ -17,20 +17,26 @@ export class GitLogDocumentAgeAdapter implements DocumentAgePort {
17
17
  constructor(
18
18
  private readonly projectRoot: string,
19
19
  private readonly nowProvider: () => Date = () => new Date(),
20
+ // WI-035: 配列引数で execFileSync を直接呼ぶことでシェル経由のメタ文字評価を遮断する。
20
21
  private readonly gitLogExecutor: (
21
- command: string,
22
+ file: string,
23
+ args: readonly string[],
22
24
  options: { cwd: string; stdio?: readonly ['pipe', 'pipe', 'pipe'] },
23
- ) => Buffer = execSync,
25
+ ) => Buffer = execFileSync,
24
26
  ) {}
25
27
 
26
28
  async getAge(documentPath: string): Promise<DocumentAge> {
27
29
  try {
28
- const output = this.gitLogExecutor(`git log --format=%ai -1 -- "${documentPath}"`, {
29
- cwd: this.projectRoot,
30
- // ISSUE-005 P1-3: fresh repo では "fatal: your current branch ... does not have
31
- // any commits yet" が 34回 stderr に漏れる。pipe に束ねて静音化する。
32
- stdio: ['pipe', 'pipe', 'pipe'] as const,
33
- })
30
+ const output = this.gitLogExecutor(
31
+ 'git',
32
+ ['log', '--format=%ai', '-1', '--', documentPath],
33
+ {
34
+ cwd: this.projectRoot,
35
+ // ISSUE-005 P1-3: fresh repo では "fatal: your current branch ... does not have
36
+ // any commits yet" が 34回 stderr に漏れる。pipe に束ねて静音化する。
37
+ stdio: ['pipe', 'pipe', 'pipe'] as const,
38
+ },
39
+ )
34
40
  .toString()
35
41
  .trim();
36
42
 
@@ -2,14 +2,16 @@
2
2
  * @layer infrastructure
3
3
  * @unit phase2-extensions
4
4
  */
5
- import { execSync } from 'node:child_process';
5
+ import { execFileSync } from 'node:child_process';
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import type { InitialCreationAgePort } from '../../domain/ports/initial-creation-age-port.js';
9
9
  import { InitialCreationAge } from '../../domain/value-objects/initial-creation-age.js';
10
10
 
11
+ // WI-035: 配列引数で execFileSync を直接呼ぶことでシェル経由のメタ文字評価を遮断する。
11
12
  type GitExecutor = (
12
- command: string,
13
+ file: string,
14
+ args: readonly string[],
13
15
  options: { cwd: string; stdio?: readonly ['pipe', 'pipe', 'pipe'] },
14
16
  ) => Buffer;
15
17
 
@@ -22,12 +24,12 @@ export class GitLogInitialCreationAgeAdapter implements InitialCreationAgePort {
22
24
  constructor(
23
25
  private readonly projectRoot: string,
24
26
  private readonly nowProvider: () => Date = () => new Date(),
25
- private readonly gitExecutor: GitExecutor = execSync,
27
+ private readonly gitExecutor: GitExecutor = execFileSync,
26
28
  ) {}
27
29
 
28
30
  async getAge(filePath: string): Promise<InitialCreationAge> {
29
- const dateOutput = this.runGit(`git log --diff-filter=A --format=%ai -- "${filePath}"`);
30
- const countOutput = this.runGit(`git rev-list --count HEAD -- "${filePath}"`);
31
+ const dateOutput = this.runGit(['log', '--diff-filter=A', '--format=%ai', '--', filePath]);
32
+ const countOutput = this.runGit(['rev-list', '--count', 'HEAD', '--', filePath]);
31
33
 
32
34
  if (dateOutput !== null && dateOutput.length > 0) {
33
35
  const commitCount = this.parseCount(countOutput);
@@ -42,9 +44,9 @@ export class GitLogInitialCreationAgeAdapter implements InitialCreationAgePort {
42
44
  return this.fileMtimeFallback(filePath);
43
45
  }
44
46
 
45
- private runGit(command: string): string | null {
47
+ private runGit(args: readonly string[]): string | null {
46
48
  try {
47
- return this.gitExecutor(command, {
49
+ return this.gitExecutor('git', args, {
48
50
  cwd: this.projectRoot,
49
51
  // ISSUE-005 P1-3 と同様に、fresh repo の fatal stderr を静音化する。
50
52
  stdio: ['pipe', 'pipe', 'pipe'] as const,
@@ -2,16 +2,21 @@
2
2
  * @layer infrastructure
3
3
  * @unit skill-quality
4
4
  */
5
- import { execSync } from 'node:child_process';
5
+ import { execFileSync } from 'node:child_process';
6
6
  import type { CommitExecutorPort } from '../../domain/ports/commit-executor-port.js';
7
7
  import type { CommitMessage } from '../../domain/value-objects/commit-message.js';
8
8
  import { SkillQualityError } from '../../domain/errors/skill-quality-error.js';
9
9
 
10
+ // WI-036: 配列引数で execFileSync を直接呼ぶことでシェル経由のメタ文字評価を遮断する。
11
+ type GitExecutor = (file: string, args: readonly string[], options: { stdio: 'pipe' }) => Buffer;
12
+
10
13
  export class GitCommitExecutorAdapter implements CommitExecutorPort {
14
+ constructor(private readonly gitExecutor: GitExecutor = execFileSync) {}
15
+
11
16
  async commit(commitMessage: CommitMessage): Promise<void> {
12
17
  const message = commitMessage.format();
13
18
  try {
14
- execSync(`git commit -m ${JSON.stringify(message)}`, { stdio: 'pipe' });
19
+ this.gitExecutor('git', ['commit', '-m', message], { stdio: 'pipe' });
15
20
  } catch (err) {
16
21
  const rawMessage = err instanceof Error ? err.message : String(err);
17
22
  // "nothing to commit" を検出して分かりやすいメッセージに変換