phasegate 0.117.0 → 0.119.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 +19 -0
- package/package.json +1 -1
- package/scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts +21 -2
- package/scripts/harness/validator-system/infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.ts +10 -1
- package/templates/.claude/scripts/analyze-errors-hook.sh +4 -1
- package/templates/.claude/scripts/format-typescript-hook.sh +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.119.0] - 2026-05-07
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **WI-087 Phase A: `phasegate init` がデプロイする hook スクリプトが macOS 標準 bash 3.2 で silent no-op になる問題を修正** — 外部レポーター nakataj-mti が GitHub Issue [#3](https://github.com/junpei-9898/phasegate/issues/3) で報告。`templates/.claude/scripts/format-typescript-hook.sh` および `analyze-errors-hook.sh` の `mapfile -t TARGET_DIRS < <(jq ...)` が bash 4+ builtin であり、macOS 標準 `/bin/bash` (3.2.57) では `mapfile: command not found` エラーで `TARGET_DIRS` 配列が空になり、後続の `${#TARGET_DIRS[@]} -eq 0` 判定で hook が exit 0 で抜けていた。結果としてユーザーには何も表示されず、format / lint hook が deliberately quiet と誤認される状態だった。
|
|
15
|
+
- `mapfile -t ARRAY < <(...)` を bash 3.2 互換の `while IFS= read -r line; do ARRAY+=("$line"); done < <(...)` idiom に置換(`format-typescript-hook.sh` 内 2 箇所、`analyze-errors-hook.sh` 内 1 箇所)。
|
|
16
|
+
- shebang は `#!/bin/bash` を維持(追加インストール不要、既存ユーザーへの影響なし)。
|
|
17
|
+
- 検証: macOS bash 3.2.57 で `targetDirs` を含む hook-config.json をロード後、対象ディレクトリ下のファイルに対して `format-typescript-hook.sh` が `Formatted: ...` を出力、`analyze-errors-hook.sh` が `{"decision": "approve", ...}` を返すことを確認。
|
|
18
|
+
- 関連: WI-086(GitHub Issue [#2](https://github.com/junpei-9898/phasegate/issues/2), reporter: junpei-9898)の "post-tool-use がセッション中に呼ばれても通知されない" 症状の主因も同じ `mapfile` であり、本修正で副次的に解消する。
|
|
19
|
+
- スコープ外(後続フェーズで対応予定): `phasegate init` の monorepo 自動検出(WI-087 Phase B)、Quick Mode 通過時の stderr notice / Stop hook `--enforce` flag(WI-087 Phase C)、`phasegate init` の formatter 自動検出(WI-087 Phase B)。
|
|
20
|
+
|
|
21
|
+
## [0.118.0] - 2026-05-07
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **WI-085 follow-up: validator-system / harness-api 経路で `paths` config が phase-dependency-model に流入していなかった問題を修正** — v0.117.0 リリース後のセルフホスト dogfooding で発見。`scripts/harness/validator-system/infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.ts` および `scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts` が `createPhaseDependencyModelModule({ rootDir })` を `phaseConfig` 引数なしで呼んでおり、`paths.designDocs` / `paths.inceptionDocs` が L2-001 (`npx phasegate validate --layer L2`) と harness-api 経由の phase-gate query から到達できない状態だった。`agent-integration` 配下の `phase-gate-query-adapter.ts` と同等の `loadResolvedConfigUseCase` + `toPhaseConfigSection` 注入経路を 3 箇所追加。
|
|
26
|
+
- dogfood 検証: `paths.designDocs: "mydocs/product/construction"` / `paths.inceptionDocs: "mydocs/inception"` 設定で L2-001 ブロッカーが `mydocs/inception/_shared/product_overview_plan.md` 等を要求することを確認。
|
|
27
|
+
- デフォルト設定での挙動は v0.117.0 と完全互換(dogfood 復元後にベースラインブロッカー `docs/product/units/{unit}_unit.md` のみ残ることを確認)。
|
|
28
|
+
|
|
10
29
|
## [0.117.0] - 2026-05-07
|
|
11
30
|
|
|
12
31
|
### Fixed
|
package/package.json
CHANGED
package/scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @unit harness-api
|
|
1
2
|
// @layer infrastructure
|
|
2
3
|
// phase-dependency-model-query-adapter.ts — PhaseDependencyModelQueryAdapter
|
|
3
4
|
// Wave 2完了後にリアル実装へ差し替え(旧: @stub: wave2-pending)
|
|
@@ -28,8 +29,17 @@ export class PhaseDependencyModelQueryAdapter implements PhaseGateQueryPort {
|
|
|
28
29
|
const traceModule = createTraceabilityModelModule(rootDir);
|
|
29
30
|
const storyIds = await traceModule.storyCatalog.getAllStoryIds();
|
|
30
31
|
|
|
32
|
+
// WI-085: paths config を phase-dependency-model に流入させる
|
|
33
|
+
const { createConfigFoundationModule } = await import('../../../config-foundation/composition-root.js');
|
|
34
|
+
const { toPhaseConfigSection } = await import('../../../config-foundation/application/mappers/phase-config-section-mapper.js');
|
|
35
|
+
const configModule = createConfigFoundationModule();
|
|
36
|
+
const resolvedConfig = await configModule.usecases.loadResolvedConfigUseCase.execute();
|
|
31
37
|
const { createPhaseDependencyModelModule } = await import('../../../phase-dependency-model/composition-root.js');
|
|
32
|
-
const phaseModule = createPhaseDependencyModelModule({
|
|
38
|
+
const phaseModule = createPhaseDependencyModelModule({
|
|
39
|
+
rootDir,
|
|
40
|
+
phaseConfig: toPhaseConfigSection(resolvedConfig.config),
|
|
41
|
+
reportOutputDir: resolvedConfig.config.reporting.outputDir,
|
|
42
|
+
});
|
|
33
43
|
|
|
34
44
|
const results: PhaseGateStoryResult[] = [];
|
|
35
45
|
for (const sid of storyIds) {
|
|
@@ -56,8 +66,17 @@ export class PhaseDependencyModelQueryAdapter implements PhaseGateQueryPort {
|
|
|
56
66
|
|
|
57
67
|
async queryUnit(unitId: string): Promise<PhaseInfo | null> {
|
|
58
68
|
try {
|
|
69
|
+
// WI-085: paths config を phase-dependency-model に流入させる
|
|
70
|
+
const { createConfigFoundationModule } = await import('../../../config-foundation/composition-root.js');
|
|
71
|
+
const { toPhaseConfigSection } = await import('../../../config-foundation/application/mappers/phase-config-section-mapper.js');
|
|
72
|
+
const configModule = createConfigFoundationModule();
|
|
73
|
+
const resolvedConfig = await configModule.usecases.loadResolvedConfigUseCase.execute();
|
|
59
74
|
const { createPhaseDependencyModelModule } = await import('../../../phase-dependency-model/composition-root.js');
|
|
60
|
-
const phaseModule = createPhaseDependencyModelModule({
|
|
75
|
+
const phaseModule = createPhaseDependencyModelModule({
|
|
76
|
+
rootDir,
|
|
77
|
+
phaseConfig: toPhaseConfigSection(resolvedConfig.config),
|
|
78
|
+
reportOutputDir: resolvedConfig.config.reporting.outputDir,
|
|
79
|
+
});
|
|
61
80
|
const output = await phaseModule.checkPhaseGateCommandHandler.execute({
|
|
62
81
|
targetLevel: 1,
|
|
63
82
|
unitId,
|
|
@@ -13,8 +13,17 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
|
|
|
13
13
|
violations: readonly HarnessErrorLike[];
|
|
14
14
|
}> {
|
|
15
15
|
try {
|
|
16
|
+
// WI-085: paths config を phase-dependency-model に流入させる
|
|
17
|
+
const { createConfigFoundationModule } = await import('../../../config-foundation/composition-root.js');
|
|
18
|
+
const { toPhaseConfigSection } = await import('../../../config-foundation/application/mappers/phase-config-section-mapper.js');
|
|
19
|
+
const configModule = createConfigFoundationModule();
|
|
20
|
+
const resolvedConfig = await configModule.usecases.loadResolvedConfigUseCase.execute();
|
|
16
21
|
const { createPhaseDependencyModelModule } = await import('../../../phase-dependency-model/composition-root.js');
|
|
17
|
-
const mod = createPhaseDependencyModelModule({
|
|
22
|
+
const mod = createPhaseDependencyModelModule({
|
|
23
|
+
rootDir: process.cwd(),
|
|
24
|
+
phaseConfig: toPhaseConfigSection(resolvedConfig.config),
|
|
25
|
+
reportOutputDir: resolvedConfig.config.reporting.outputDir,
|
|
26
|
+
});
|
|
18
27
|
const result = await mod.checkPhaseGateCommandHandler.execute({
|
|
19
28
|
targetLevel: 2,
|
|
20
29
|
unitId: context.unitName,
|
|
@@ -15,7 +15,10 @@ CONFIG_FILE="$SCRIPT_DIR/hook-config.json"
|
|
|
15
15
|
TARGET_DIRS=()
|
|
16
16
|
|
|
17
17
|
if [[ -f "$CONFIG_FILE" ]] && command -v jq >/dev/null 2>&1; then
|
|
18
|
-
|
|
18
|
+
# bash 3.2 (macOS default) has no mapfile; use portable while-read.
|
|
19
|
+
while IFS= read -r line; do
|
|
20
|
+
[[ -n "$line" ]] && TARGET_DIRS+=("$line")
|
|
21
|
+
done < <(jq -r '.targetDirs[]' "$CONFIG_FILE" 2>/dev/null)
|
|
19
22
|
fi
|
|
20
23
|
|
|
21
24
|
if [[ ${#TARGET_DIRS[@]} -eq 0 ]]; then
|
|
@@ -17,9 +17,14 @@ FORMATTER="biome"
|
|
|
17
17
|
FORMATTER_ARGS=()
|
|
18
18
|
|
|
19
19
|
if [[ -f "$CONFIG_FILE" ]] && command -v jq &> /dev/null; then
|
|
20
|
-
|
|
20
|
+
# bash 3.2 (macOS default) has no mapfile; use portable while-read.
|
|
21
|
+
while IFS= read -r line; do
|
|
22
|
+
[[ -n "$line" ]] && TARGET_DIRS+=("$line")
|
|
23
|
+
done < <(jq -r '.targetDirs[]' "$CONFIG_FILE" 2>/dev/null)
|
|
21
24
|
FORMATTER=$(jq -r '.formatter // "biome"' "$CONFIG_FILE" 2>/dev/null)
|
|
22
|
-
|
|
25
|
+
while IFS= read -r line; do
|
|
26
|
+
[[ -n "$line" ]] && FORMATTER_ARGS+=("$line")
|
|
27
|
+
done < <(jq -r '.formatterArgs[]' "$CONFIG_FILE" 2>/dev/null)
|
|
23
28
|
fi
|
|
24
29
|
|
|
25
30
|
if [[ ${#TARGET_DIRS[@]} -eq 0 ]]; then
|