phasegate 0.112.0 → 0.114.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 +11 -0
- package/README.ja.md +12 -9
- package/README.md +99 -79
- package/package.json +1 -1
- package/scripts/harness/phase2-extensions/infrastructure/adapters/git-log-document-age-adapter.ts +15 -9
- package/scripts/harness/phase2-extensions/infrastructure/adapters/git-log-initial-creation-age-adapter.ts +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.114.0] - 2026-05-07
|
|
11
|
+
|
|
12
|
+
### Security
|
|
13
|
+
|
|
14
|
+
- **WI-035: phase2-extensions の git-log adapter におけるコマンドインジェクション脆弱性 (HIGH) を修正** — `/security-review` で発見。`execSync` テンプレート文字列に `documentPath` / `filePath` をダブルクオート展開していたため、ファイル名に `$()` / バッククオート / `;` 等のシェルメタ文字を含めると `/bin/sh -c` 経由で任意コードが実行される経路があった(攻撃者は POSIX 許容範囲のファイル名を含む公開リポジトリを 1 つ用意するだけで成立。clone / `gh pr checkout` でローカルに展開された時点で発火し、マージは不要)。
|
|
15
|
+
- `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-document-age-adapter.ts` の `gitLogExecutor` を `execFileSync` 配列引数形式(`('git', ['log', '--format=%ai', '-1', '--', documentPath], ...)`)に置換。
|
|
16
|
+
- `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-initial-creation-age-adapter.ts` の `gitExecutor` を同形式に置換(`runGit(args)` の signature も合わせて変更)。
|
|
17
|
+
- DI ポートの signature を `(command: string) => Buffer` から `(file: string, args: readonly string[], options) => Buffer` に変更。
|
|
18
|
+
- 悪意あるファイル名(`$()` / バッククオート / `;` / `"` / `|` 含む)でも引数が **配列要素のまま** 渡され、シェルメタ文字として評価されないことを assert する unit test を 2 ファイルに追加。
|
|
19
|
+
- 横展開監査結果: 同種パターン (`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 に記録。
|
|
20
|
+
|
|
10
21
|
## [0.110.0] - 2026-04-25
|
|
11
22
|
|
|
12
23
|
### Documentation
|
package/README.ja.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
1
3
|
# Phasegate
|
|
2
4
|
|
|
3
5
|
[](https://opensource.org/licenses/MIT)
|
|
4
6
|
[](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
|
|
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 はこれを
|
|
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
|
|
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
|
-
|
|
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
|
+

|
|
2
|
+
|
|
1
3
|
# Phasegate
|
|
2
4
|
|
|
3
5
|
[](https://opensource.org/licenses/MIT)
|
|
4
6
|
[](https://nodejs.org/)
|
|
5
7
|
|
|
6
|
-
**
|
|
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
|
-
|
|
12
|
+
[日本語版](README.ja.md) | [Developer Guide](DEVELOPMENT.md)
|
|
9
13
|
|
|
10
14
|
---
|
|
11
15
|
|
|
12
|
-
##
|
|
16
|
+
## Phasegate in 30 Seconds
|
|
13
17
|
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
101
|
+
### Update
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npm update phasegate
|
|
105
|
+
npx phasegate update-skills
|
|
106
|
+
```
|
|
55
107
|
|
|
56
|
-
|
|
108
|
+
---
|
|
57
109
|
|
|
58
|
-
|
|
110
|
+
## Core Capabilities
|
|
59
111
|
|
|
60
|
-
|
|
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)
|
|
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
|
-
|
|
168
|
+
**First step**: run `/product-architect` inside Claude Code or Codex.
|
|
108
169
|
|
|
109
|
-
|
|
|
170
|
+
| Group | Skills |
|
|
110
171
|
|---|---|
|
|
111
|
-
| `/product-architect`
|
|
112
|
-
| `/
|
|
113
|
-
| `/
|
|
114
|
-
| `/
|
|
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
|
-
|
|
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
|
-
##
|
|
512
|
+
## Known Limits and Roadmap
|
|
493
513
|
|
|
494
|
-
The
|
|
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
|
|
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
package/scripts/harness/phase2-extensions/infrastructure/adapters/git-log-document-age-adapter.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @layer infrastructure
|
|
3
3
|
* @unit phase2-extensions
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
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
|
-
|
|
22
|
+
file: string,
|
|
23
|
+
args: readonly string[],
|
|
22
24
|
options: { cwd: string; stdio?: readonly ['pipe', 'pipe', 'pipe'] },
|
|
23
|
-
) => Buffer =
|
|
25
|
+
) => Buffer = execFileSync,
|
|
24
26
|
) {}
|
|
25
27
|
|
|
26
28
|
async getAge(documentPath: string): Promise<DocumentAge> {
|
|
27
29
|
try {
|
|
28
|
-
const output = this.gitLogExecutor(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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 {
|
|
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
|
-
|
|
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 =
|
|
27
|
+
private readonly gitExecutor: GitExecutor = execFileSync,
|
|
26
28
|
) {}
|
|
27
29
|
|
|
28
30
|
async getAge(filePath: string): Promise<InitialCreationAge> {
|
|
29
|
-
const dateOutput = this.runGit(
|
|
30
|
-
const countOutput = this.runGit(
|
|
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(
|
|
47
|
+
private runGit(args: readonly string[]): string | null {
|
|
46
48
|
try {
|
|
47
|
-
return this.gitExecutor(
|
|
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,
|