phasegate 0.66.0 → 0.68.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/README.ja.md +25 -5
- package/README.md +17 -2
- package/docs/guide/cli-reference.md +60 -0
- package/docs/guide/configuration.md +41 -6
- package/package.json +1 -1
- package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +44 -7
- package/scripts/harness/agent-integration/domain/ports/error-guidance-query-port.ts +20 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/harness-error-guidance-adapter.ts +49 -0
- package/scripts/harness/agent-integration/presentation/pre-tool-use-hook.ts +5 -0
- package/scripts/harness/harness-error/application/dto/create-harness-error-input.ts +3 -0
- package/scripts/harness/harness-error/application/dto/harness-error-contract.ts +3 -0
- package/scripts/harness/harness-error/application/mappers/harness-error-contract-mapper.ts +9 -0
- package/scripts/harness/harness-error/application/usecases/create-harness-error-use-case.ts +3 -0
- package/scripts/harness/harness-error/domain/services/harness-error-factory.ts +12 -1
- package/scripts/harness/harness-error/domain/value-objects/error-definition.ts +30 -0
- package/scripts/harness/harness-error/domain/value-objects/harness-error.ts +31 -1
- package/scripts/harness/harness-error/infrastructure/registry/l2-error-definitions.ts +9 -0
- package/skills/skill-creator/SKILL.md +3 -3
- package/skills/skill-creator/scripts/init_skill.py +3 -3
- package/skills/skill-creator/scripts/package_skill.py +4 -4
- package/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
package/README.ja.md
CHANGED
|
@@ -196,7 +196,12 @@ npx phasegate ci:generate-template --type consistency-check --render > .github/w
|
|
|
196
196
|
"quickMode": {
|
|
197
197
|
"allowedCategories": ["bugfix", "docs", "test", "config"],
|
|
198
198
|
"maintainedLayers": ["L1", "L2"],
|
|
199
|
-
"relaxedGates": ["phase-gate", "2-phase-execution"]
|
|
199
|
+
"relaxedGates": ["phase-gate", "2-phase-execution"],
|
|
200
|
+
"fullModeRequiredWhen": {
|
|
201
|
+
"mixedCategories": true,
|
|
202
|
+
"newDomainFile": true,
|
|
203
|
+
"apiContractChange": true
|
|
204
|
+
}
|
|
200
205
|
},
|
|
201
206
|
"phaseDependencies": {
|
|
202
207
|
"preset": "standard",
|
|
@@ -204,10 +209,18 @@ npx phasegate ci:generate-template --type consistency-check --render > .github/w
|
|
|
204
209
|
},
|
|
205
210
|
"protectedFiles": {
|
|
206
211
|
"exclude": ["package.json"]
|
|
212
|
+
},
|
|
213
|
+
"baseline": {
|
|
214
|
+
"enabled": true,
|
|
215
|
+
"path": ".phasegate/baseline.json"
|
|
207
216
|
}
|
|
208
217
|
}
|
|
209
218
|
```
|
|
210
219
|
|
|
220
|
+
`quickMode.fullModeRequiredWhen` は **「Quick Mode で進めようとした変更を Full Mode に強制エスカレートする条件」** を宣言します(v0.63.0 / ISSUE-006 Story A で導入、v0.64.0 / Story B で pre-tool-use hook に統合)。3 トリガー(`mixedCategories` / `newDomainFile` / `apiContractChange`)はいずれも安全側のデフォルト `true`。プロジェクトが意図的にリスクを受け入れる場合のみ個別に `false` にできます。
|
|
221
|
+
|
|
222
|
+
`baseline` は **Phase A-2 リトロフィット grandfather** をオン/オフします(v0.65.0 / ISSUE-007 Wave 1 で導入、v0.66.0 / Wave 2 で pre-tool-use hook に統合)。`.phasegate/baseline.json` に登録済みのファイルは、構造的に編集されるまで `phase-gate` 対象から除外されます。既存リポジトリへの導入時に `npx phasegate baseline` でスナップショットを生成してください。
|
|
223
|
+
|
|
211
224
|
### project.preset -- レイヤー厳密度
|
|
212
225
|
|
|
213
226
|
| プリセット | 有効レイヤー | カバレッジ | 用途 |
|
|
@@ -343,10 +356,15 @@ Quick Mode は以下の方法で発動します:
|
|
|
343
356
|
|
|
344
357
|
`bugfix`, `docs`, `test`, `config` カテゴリの変更では、Phase Gate と 2-Phase Execution を緩和し L1/L2 のみ維持します。
|
|
345
358
|
|
|
346
|
-
**Quick Mode
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
359
|
+
**Quick Mode が拒否される条件**(`fullModeRequiredWhen` で設定駆動 / フルチェックが強制されます):
|
|
360
|
+
|
|
361
|
+
| 条件 | `fullModeRequiredWhen.*` フラグ |
|
|
362
|
+
|---|---|
|
|
363
|
+
| 複数カテゴリが混在する変更(例: `bugfix` + `api`) | `mixedCategories` |
|
|
364
|
+
| `domain/` 配下に新規ファイルを追加 | `newDomainFile` |
|
|
365
|
+
| `*port.ts` / `*adapter.ts`(API 契約)を変更 | `apiContractChange` |
|
|
366
|
+
|
|
367
|
+
事前に判定したい場合は `npx phasegate check-change-category --paths <csv>` を使います。CI で gate にしたい場合は `--fail-on-full-required` を付与してください。
|
|
350
368
|
|
|
351
369
|
### protectedFiles -- AI 書き込み保護
|
|
352
370
|
|
|
@@ -398,6 +416,8 @@ npx phasegate <command> [options]
|
|
|
398
416
|
| `ci-check` | CI フルチェック (L2-L4) | `--quick` `--dry-run` `--fail-on-reject` |
|
|
399
417
|
| `check-phase-gate` | フェーズゲートチェック | `--level 1\|2\|3` |
|
|
400
418
|
| `validate-metadata <files>` | メタデータ検証 | |
|
|
419
|
+
| `check-change-category` | 変更ファイルを Quick Mode カテゴリに分類し、`quickMode.fullModeRequiredWhen` 評価結果(Full Mode 強制が必要か)を返す(v0.63.0 / ISSUE-006 Story A) | `--paths <csv>` `--format human\|json` `--fail-on-full-required` |
|
|
420
|
+
| `baseline` | `.phasegate/baseline.json` スナップショットを生成(Phase A-2 grandfather)。登録済みファイルは構造的に編集されるまで `phase-gate` 対象から除外される(v0.65.0 / ISSUE-007 Wave 1) | `--dry-run` `--force` `--paths <glob,glob,...>` `--json` |
|
|
401
421
|
|
|
402
422
|
### phasegate コマンド
|
|
403
423
|
|
package/README.md
CHANGED
|
@@ -189,7 +189,12 @@ Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**, enforcing ph
|
|
|
189
189
|
"quickMode": {
|
|
190
190
|
"allowedCategories": ["bugfix", "docs", "test", "config"],
|
|
191
191
|
"maintainedLayers": ["L1", "L2"],
|
|
192
|
-
"relaxedGates": ["phase-gate", "2-phase-execution"]
|
|
192
|
+
"relaxedGates": ["phase-gate", "2-phase-execution"],
|
|
193
|
+
"fullModeRequiredWhen": {
|
|
194
|
+
"mixedCategories": true,
|
|
195
|
+
"newDomainFile": true,
|
|
196
|
+
"apiContractChange": true
|
|
197
|
+
}
|
|
193
198
|
},
|
|
194
199
|
"phaseDependencies": {
|
|
195
200
|
"preset": "standard",
|
|
@@ -197,10 +202,18 @@ Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**, enforcing ph
|
|
|
197
202
|
},
|
|
198
203
|
"protectedFiles": {
|
|
199
204
|
"exclude": ["tsconfig.json", "package.json"]
|
|
205
|
+
},
|
|
206
|
+
"baseline": {
|
|
207
|
+
"enabled": true,
|
|
208
|
+
"path": ".phasegate/baseline.json"
|
|
200
209
|
}
|
|
201
210
|
}
|
|
202
211
|
```
|
|
203
212
|
|
|
213
|
+
`quickMode.fullModeRequiredWhen` declares which conditions force a Quick Mode change to escalate to the full `/story-implementor` flow. All three triggers default to `true` so retrofits stay safe; flip individual flags to `false` only when a project intentionally accepts the risk.
|
|
214
|
+
|
|
215
|
+
`baseline` opts in to the **Phase A-2 retrofit grandfather**: pre-existing files captured in `.phasegate/baseline.json` are exempted from `phase-gate` until they are structurally modified. Generate the snapshot with `npx phasegate baseline` before introducing the harness to an existing repository.
|
|
216
|
+
|
|
204
217
|
---
|
|
205
218
|
|
|
206
219
|
## Configurable Phase Gates
|
|
@@ -246,7 +259,7 @@ Phasegate integrates natively with Claude Code via hooks in `.claude/settings.js
|
|
|
246
259
|
|
|
247
260
|
| Hook | Trigger | Behavior |
|
|
248
261
|
|---|---|---|
|
|
249
|
-
| `PreToolUse` | `Write`, `Edit`, or `Bash` (write operations detected) | Blocks writes to source files without design docs; protects configured files; detects Bash write operations (`sed -i`, `tee`, `cp`, etc.) |
|
|
262
|
+
| `PreToolUse` | `Write`, `Edit`, or `Bash` (write operations detected) | Blocks writes to source files without design docs; enforces `quickMode.fullModeRequiredWhen` (escalates Quick Mode → Full when triggered); skips files captured in the `.phasegate/baseline.json` snapshot until they are modified; protects configured files; detects Bash write operations (`sed -i`, `tee`, `cp`, etc.) |
|
|
250
263
|
| `PostToolUse` | `Write` or `Edit` | Auto-formats and validates metadata |
|
|
251
264
|
| `Stop` | Session end | Runs full test suite to ensure all tests pass |
|
|
252
265
|
|
|
@@ -299,6 +312,8 @@ npx phasegate <command> [options]
|
|
|
299
312
|
| `update-skills` | Update skills to latest version |
|
|
300
313
|
| `phasegate:status` | Display overall harness health summary |
|
|
301
314
|
| `phasegate:check-phase --unit <id>` | Check current phase for a Unit |
|
|
315
|
+
| `check-change-category --paths <csv>` | Classify changed files into Quick Mode categories and report whether Full Mode is required (`--format json`, `--fail-on-full-required`) |
|
|
316
|
+
| `baseline` | Create `.phasegate/baseline.json` snapshot for Phase A-2 retrofit grandfather (`--dry-run`, `--force`, `--paths <glob,glob,...>`, `--json`) |
|
|
302
317
|
| `list-errors --layer <L0-L4>` | List error definitions with fix examples |
|
|
303
318
|
| `hook <pre-tool-use\|post-tool-use\|stop>` | Run a Claude Code hook (reads JSON from stdin) |
|
|
304
319
|
| `pre-commit` | Run L2 pre-commit validators on staged files |
|
|
@@ -32,6 +32,66 @@ npx phasegate <command> [options]
|
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
+
## Quick Mode
|
|
36
|
+
|
|
37
|
+
| Command | Options | Description |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `check-change-category` | `--paths <csv>` `--format human\|json` `--fail-on-full-required` | Classify changed file paths into Quick Mode categories (`api` / `domain` / `feature` / `bugfix` / `test` / `config` / `docs`) and report whether `quickMode.fullModeRequiredWhen` forces escalation to Full Mode. |
|
|
40
|
+
|
|
41
|
+
### `check-change-category` の使い方
|
|
42
|
+
|
|
43
|
+
ISSUE-006 Story A で導入。Quick Mode で取り扱おうとしている変更が
|
|
44
|
+
`quickMode.fullModeRequiredWhen` のいずれかをトリガーするか事前に確認したいときに使う。
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# JSON 出力 (CI で消費しやすい)
|
|
48
|
+
npx phasegate check-change-category --paths src/foo.ts,src/bar.ts --format json
|
|
49
|
+
|
|
50
|
+
# Full Mode が必要なら exit 1 (PR チェック等に使える)
|
|
51
|
+
npx phasegate check-change-category \
|
|
52
|
+
--paths "$(git diff --name-only origin/main...HEAD | paste -sd, -)" \
|
|
53
|
+
--fail-on-full-required
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`--fail-on-full-required` を指定しない場合、Full Mode が必要と判定されても exit 0 を返す
|
|
57
|
+
(情報提供のみ)。CI で gate にしたいときは必ず付与すること。
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Baseline (Retrofit Grandfather)
|
|
62
|
+
|
|
63
|
+
| Command | Options | Description |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `baseline` | `--dry-run` `--force` `--paths <glob,glob,...>` `--json` | Create / refresh `.phasegate/baseline.json` snapshot. Files in the snapshot are exempted from `phase-gate` until they are structurally modified (sha1 mismatch). |
|
|
66
|
+
|
|
67
|
+
### `baseline` の使い方
|
|
68
|
+
|
|
69
|
+
ISSUE-007 Wave 1 で導入。既存リポジトリに phasegate を後付けする際、現状のコード資産を
|
|
70
|
+
"Phase A-2 grandfather" として一度だけ凍結する。
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# 現在のリポジトリ全体をスナップショット
|
|
74
|
+
npx phasegate baseline
|
|
75
|
+
|
|
76
|
+
# 何が含まれるかだけ確認 (ファイルは書かない)
|
|
77
|
+
npx phasegate baseline --dry-run --json
|
|
78
|
+
|
|
79
|
+
# 既存スナップショットを上書きして再生成
|
|
80
|
+
npx phasegate baseline --force
|
|
81
|
+
|
|
82
|
+
# 特定ディレクトリだけ含める
|
|
83
|
+
npx phasegate baseline --paths "scripts/harness/**/*.ts,src/**/*.ts"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
スナップショットに含まれるファイルは sha1 ハッシュで照合される。ファイルを構造的に
|
|
87
|
+
編集した瞬間に grandfather が外れ、通常の `phase-gate` 対象に戻る。新規ファイルは
|
|
88
|
+
最初から `phase-gate` の対象。
|
|
89
|
+
|
|
90
|
+
`baseline.enabled = false` (デフォルトは `true`) を `phasegate.config.json` に書くと
|
|
91
|
+
仕組み全体を無効化できる。スナップショットの保存先は `baseline.path` で変更可能。
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
35
95
|
## Harness API
|
|
36
96
|
|
|
37
97
|
Commands exposed as npm scripts (`npm run <command>`).
|
|
@@ -24,7 +24,12 @@ This file is the **Single Source of Truth** for all quality configuration in a P
|
|
|
24
24
|
"quickMode": {
|
|
25
25
|
"allowedCategories": ["bugfix", "docs", "test", "config"],
|
|
26
26
|
"maintainedLayers": ["L1", "L2"],
|
|
27
|
-
"relaxedGates": ["phase-gate", "2-phase-execution"]
|
|
27
|
+
"relaxedGates": ["phase-gate", "2-phase-execution"],
|
|
28
|
+
"fullModeRequiredWhen": {
|
|
29
|
+
"mixedCategories": true,
|
|
30
|
+
"newDomainFile": true,
|
|
31
|
+
"apiContractChange": true
|
|
32
|
+
}
|
|
28
33
|
},
|
|
29
34
|
"phaseDependencies": {
|
|
30
35
|
"preset": "standard", // "full" | "standard" | "minimal" | "custom" ("default" -> "full")
|
|
@@ -53,6 +58,10 @@ This file is the **Single Source of Truth** for all quality configuration in a P
|
|
|
53
58
|
"reporting": {
|
|
54
59
|
"format": "json",
|
|
55
60
|
"outputDir": "reports"
|
|
61
|
+
},
|
|
62
|
+
"baseline": {
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"path": ".phasegate/baseline.json"
|
|
56
65
|
}
|
|
57
66
|
}
|
|
58
67
|
```
|
|
@@ -105,11 +114,26 @@ The five layers are:
|
|
|
105
114
|
|
|
106
115
|
#### `quickMode`
|
|
107
116
|
|
|
108
|
-
| Sub-field
|
|
109
|
-
|
|
110
|
-
| `allowedCategories`
|
|
111
|
-
| `maintainedLayers`
|
|
112
|
-
| `relaxedGates`
|
|
117
|
+
| Sub-field | Type | Default | Description |
|
|
118
|
+
|------------------------|------------|-----------------------------------------|-----------------------------------------------------------------------------|
|
|
119
|
+
| `allowedCategories` | `string[]` | `["bugfix", "docs", "test", "config"]` | Change categories permitted under Quick Mode. Any category outside this list requires the full `story-implementor` workflow. |
|
|
120
|
+
| `maintainedLayers` | `string[]` | `["L1", "L2"]` | Layers that remain fully enforced even in Quick Mode. |
|
|
121
|
+
| `relaxedGates` | `string[]` | `["phase-gate", "2-phase-execution"]` | Gates that are relaxed (not skipped) when Quick Mode is active. |
|
|
122
|
+
| `fullModeRequiredWhen` | `object` | all flags `true` | Conditions that force a Quick Mode change to escalate to the full `/story-implementor` flow. See below. |
|
|
123
|
+
|
|
124
|
+
##### `fullModeRequiredWhen`
|
|
125
|
+
|
|
126
|
+
Introduced in ISSUE-006 Story A (v0.63.0) and wired into the pre-tool-use hook by Story B (v0.64.0). Each flag is a hard escalation rule -- when triggered, the change cannot proceed under Quick Mode regardless of the file's category.
|
|
127
|
+
|
|
128
|
+
| Flag | Default | Trigger |
|
|
129
|
+
|---------------------|---------|-----------------------------------------------------------------------------------------------|
|
|
130
|
+
| `mixedCategories` | `true` | The change set spans more than one Quick Mode category (e.g. a `bugfix` file + an `api` file).|
|
|
131
|
+
| `newDomainFile` | `true` | The change creates a new file under any `domain/` directory. |
|
|
132
|
+
| `apiContractChange` | `true` | The change modifies a Port (`*port.ts`) or Adapter (`*adapter.ts`) file. |
|
|
133
|
+
|
|
134
|
+
**Use `npx phasegate check-change-category --paths <csv>`** to dry-run the classifier against an arbitrary file list (see [CLI Reference](cli-reference.md#check-change-category-の使い方)). Combining `--fail-on-full-required` with a CI job makes "Quick Mode PR that should have been Full" a hard build failure.
|
|
135
|
+
|
|
136
|
+
Set a flag to `false` only when the project intentionally accepts the risk of merging that category of change without the design ceremony -- e.g. an early-stage prototype where new domain files are expected to churn.
|
|
113
137
|
|
|
114
138
|
#### `phaseDependencies`
|
|
115
139
|
|
|
@@ -381,6 +405,17 @@ Quick Mode with `relaxedGates: ["phase-gate"]` relaxes `storyReflection` as well
|
|
|
381
405
|
| `format` | `string` | `"json"` | Output format for validation reports. |
|
|
382
406
|
| `outputDir` | `string` | `"reports"` | Directory where reports are written. |
|
|
383
407
|
|
|
408
|
+
#### `baseline` (retrofit grandfather)
|
|
409
|
+
|
|
410
|
+
Introduced in ISSUE-007 Wave 1 (v0.65.0) and wired into the pre-tool-use hook by Wave 2 (v0.66.0). When phasegate is added to an existing repository, the `baseline` block lets you snapshot the current state of the codebase so legacy files do not trip `phase-gate` on first edit. Files in the snapshot are exempted **until they are structurally modified** (sha1 mismatch); new files are subject to `phase-gate` from the start.
|
|
411
|
+
|
|
412
|
+
| Sub-field | Type | Default | Description |
|
|
413
|
+
|-----------|-----------|-------------------------------|----------------------------------------------------------------------------------------------|
|
|
414
|
+
| `enabled` | `boolean` | `true` | Master switch. Set to `false` to disable retrofit grandfather and treat every file as new. |
|
|
415
|
+
| `path` | `string` | `".phasegate/baseline.json"` | Snapshot location. Override only if `.phasegate/` conflicts with an existing path in the repo.|
|
|
416
|
+
|
|
417
|
+
Generate or refresh the snapshot with `npx phasegate baseline` (`--dry-run` to inspect, `--force` to overwrite, `--paths <glob,glob,...>` to scope, `--json` for CI-friendly output). See the [Baseline section in CLI Reference](cli-reference.md#baseline-retrofit-grandfather) for details.
|
|
418
|
+
|
|
384
419
|
---
|
|
385
420
|
|
|
386
421
|
### Quick Mode
|
package/package.json
CHANGED
package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts
CHANGED
|
@@ -18,6 +18,10 @@ import type {
|
|
|
18
18
|
BaselineGrandfatherCheckResult,
|
|
19
19
|
BaselineGrandfatherQueryPort,
|
|
20
20
|
} from '../../domain/ports/baseline-grandfather-query-port.js';
|
|
21
|
+
import type {
|
|
22
|
+
ErrorGuidance,
|
|
23
|
+
ErrorGuidanceQueryPort,
|
|
24
|
+
} from '../../domain/ports/error-guidance-query-port.js';
|
|
21
25
|
import { WriteTargetScope } from '../../domain/value-objects/write-target-scope.js';
|
|
22
26
|
import type { HandlePreToolUseInput, HandlePreToolUseOutput } from '../dto/handle-pre-tool-use-dto.js';
|
|
23
27
|
|
|
@@ -28,6 +32,7 @@ export interface HandlePreToolUseUseCasePorts {
|
|
|
28
32
|
fullModeRequirementQueryPort?: FullModeRequirementQueryPort;
|
|
29
33
|
baselineGrandfatherQueryPort?: BaselineGrandfatherQueryPort;
|
|
30
34
|
grandfatherLogger?: (reason: string, targetFilePaths: readonly string[]) => void;
|
|
35
|
+
errorGuidanceQueryPort?: ErrorGuidanceQueryPort;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
export class HandlePreToolUseInputValidationError extends Error {
|
|
@@ -48,6 +53,7 @@ export class HandlePreToolUseUseCase {
|
|
|
48
53
|
private readonly storyReflectionQueryPort?: StoryReflectionQueryPort;
|
|
49
54
|
private readonly fullModeRequirementQueryPort?: FullModeRequirementQueryPort;
|
|
50
55
|
private readonly baselineGrandfatherQueryPort?: BaselineGrandfatherQueryPort;
|
|
56
|
+
private readonly errorGuidanceQueryPort?: ErrorGuidanceQueryPort;
|
|
51
57
|
private readonly grandfatherLogger: (
|
|
52
58
|
reason: string,
|
|
53
59
|
targetFilePaths: readonly string[],
|
|
@@ -58,6 +64,7 @@ export class HandlePreToolUseUseCase {
|
|
|
58
64
|
this.storyReflectionQueryPort = ports.storyReflectionQueryPort;
|
|
59
65
|
this.fullModeRequirementQueryPort = ports.fullModeRequirementQueryPort;
|
|
60
66
|
this.baselineGrandfatherQueryPort = ports.baselineGrandfatherQueryPort;
|
|
67
|
+
this.errorGuidanceQueryPort = ports.errorGuidanceQueryPort;
|
|
61
68
|
this.grandfatherLogger =
|
|
62
69
|
ports.grandfatherLogger ??
|
|
63
70
|
((reason, paths) =>
|
|
@@ -95,7 +102,8 @@ export class HandlePreToolUseUseCase {
|
|
|
95
102
|
this.grandfatherLogger('phase-gate', input.targetFilePaths);
|
|
96
103
|
// fallthrough: continue to full-mode / story-reflection checks (which may also grandfather)
|
|
97
104
|
} else {
|
|
98
|
-
|
|
105
|
+
const guidance = await this.resolveGuidance('L2-001');
|
|
106
|
+
return HandlePreToolUseUseCase.buildPhaseGateBlockOutput(blockedFilePath, metadata, guidance);
|
|
99
107
|
}
|
|
100
108
|
} else {
|
|
101
109
|
return {
|
|
@@ -116,9 +124,11 @@ export class HandlePreToolUseUseCase {
|
|
|
116
124
|
} else {
|
|
117
125
|
const fullModeResult = await this.fullModeRequirementQueryPort.check(input.targetFilePaths);
|
|
118
126
|
if (fullModeResult.requiresFullMode) {
|
|
127
|
+
const guidance = await this.resolveGuidance('L2-001');
|
|
119
128
|
return HandlePreToolUseUseCase.buildFullModeRequiredBlockOutput(
|
|
120
129
|
input.targetFilePaths[0],
|
|
121
130
|
fullModeResult,
|
|
131
|
+
guidance,
|
|
122
132
|
);
|
|
123
133
|
}
|
|
124
134
|
}
|
|
@@ -168,6 +178,17 @@ export class HandlePreToolUseUseCase {
|
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
180
|
|
|
181
|
+
private async resolveGuidance(errorCode: string): Promise<ErrorGuidance | null> {
|
|
182
|
+
if (this.errorGuidanceQueryPort === undefined) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
return await this.errorGuidanceQueryPort.getGuidance(errorCode);
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
171
192
|
private static buildFullModeRequiredBlockOutput(
|
|
172
193
|
blockedFilePath: string | undefined,
|
|
173
194
|
result: {
|
|
@@ -176,6 +197,7 @@ export class HandlePreToolUseUseCase {
|
|
|
176
197
|
rejectionReason?: string;
|
|
177
198
|
dominantCategory?: string;
|
|
178
199
|
},
|
|
200
|
+
guidance: ErrorGuidance | null,
|
|
179
201
|
): HandlePreToolUseOutput {
|
|
180
202
|
const fp = blockedFilePath ?? '不明なファイル';
|
|
181
203
|
const lines: string[] = [
|
|
@@ -190,7 +212,9 @@ export class HandlePreToolUseUseCase {
|
|
|
190
212
|
if (result.rejectionReason) {
|
|
191
213
|
lines.push(`理由: ${result.rejectionReason}`);
|
|
192
214
|
}
|
|
193
|
-
|
|
215
|
+
const suggestedSkill = guidance?.suggestedSkill ?? '/story-implementor';
|
|
216
|
+
lines.push(`次のアクション: ${suggestedSkill} スキルを使用して設計フェーズから開始してください。`);
|
|
217
|
+
HandlePreToolUseUseCase.appendGuidanceLines(lines, guidance);
|
|
194
218
|
|
|
195
219
|
return {
|
|
196
220
|
shouldBlock: true,
|
|
@@ -199,10 +223,20 @@ export class HandlePreToolUseUseCase {
|
|
|
199
223
|
error: { message: lines.join('\n') },
|
|
200
224
|
fullModeRejectionRule: result.rejectionRule,
|
|
201
225
|
fullModeDominantCategory: result.dominantCategory,
|
|
202
|
-
nextAction:
|
|
226
|
+
nextAction: suggestedSkill,
|
|
203
227
|
};
|
|
204
228
|
}
|
|
205
229
|
|
|
230
|
+
private static appendGuidanceLines(lines: string[], guidance: ErrorGuidance | null): void {
|
|
231
|
+
if (guidance === null) return;
|
|
232
|
+
if (guidance.scaffoldCommand !== null) {
|
|
233
|
+
lines.push(` scaffold: ${guidance.scaffoldCommand}`);
|
|
234
|
+
}
|
|
235
|
+
if (guidance.templatePath !== null) {
|
|
236
|
+
lines.push(` テンプレ: ${guidance.templatePath}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
206
240
|
private resolveStoryReflectionScope(input: HandlePreToolUseInput): WriteTargetScope | null {
|
|
207
241
|
if (!HandlePreToolUseUseCase.WRITE_TOOLS.has(input.toolName)) {
|
|
208
242
|
return null;
|
|
@@ -229,6 +263,7 @@ export class HandlePreToolUseUseCase {
|
|
|
229
263
|
private static buildPhaseGateBlockOutput(
|
|
230
264
|
blockedFilePath: string | undefined,
|
|
231
265
|
metadata: BlockMetadata,
|
|
266
|
+
guidance: ErrorGuidance | null,
|
|
232
267
|
): HandlePreToolUseOutput {
|
|
233
268
|
const levelLabel = metadata.scopeLevel
|
|
234
269
|
? HandlePreToolUseUseCase.LEVEL_LABELS[metadata.scopeLevel] ?? `Level ${metadata.scopeLevel}`
|
|
@@ -246,10 +281,12 @@ export class HandlePreToolUseUseCase {
|
|
|
246
281
|
}
|
|
247
282
|
}
|
|
248
283
|
|
|
249
|
-
|
|
284
|
+
const suggestedSkill = guidance?.suggestedSkill ?? '/story-implementor';
|
|
285
|
+
lines.push(`次のアクション: ${suggestedSkill} スキルを使用して設計フェーズから開始してください。`);
|
|
250
286
|
if (metadata.unitId) {
|
|
251
|
-
lines.push(` 実行例:
|
|
287
|
+
lines.push(` 実行例: ${suggestedSkill} --unit ${metadata.unitId}`);
|
|
252
288
|
}
|
|
289
|
+
HandlePreToolUseUseCase.appendGuidanceLines(lines, guidance);
|
|
253
290
|
|
|
254
291
|
return {
|
|
255
292
|
shouldBlock: true,
|
|
@@ -258,8 +295,8 @@ export class HandlePreToolUseUseCase {
|
|
|
258
295
|
error: { message: lines.join('\n') },
|
|
259
296
|
phaseGateBlockers: [...blockers],
|
|
260
297
|
nextAction: metadata.unitId
|
|
261
|
-
?
|
|
262
|
-
:
|
|
298
|
+
? `${suggestedSkill} --unit ${metadata.unitId}`
|
|
299
|
+
: suggestedSkill,
|
|
263
300
|
};
|
|
264
301
|
}
|
|
265
302
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @unit agent-integration
|
|
2
|
+
// @layer domain
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* phase-gate 等のエラーに紐づく actionable なガイダンス情報
|
|
6
|
+
* (harness-error Unit の ErrorDefinition.defaultSuggestedSkill 等から供給される)
|
|
7
|
+
*/
|
|
8
|
+
export interface ErrorGuidance {
|
|
9
|
+
readonly suggestedSkill: string | null;
|
|
10
|
+
readonly scaffoldCommand: string | null;
|
|
11
|
+
readonly templatePath: string | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* エラーコード → actionable guidance の lookup を行う port
|
|
16
|
+
* 実装は harness-error Unit の ErrorDefinitionRegistry を参照する
|
|
17
|
+
*/
|
|
18
|
+
export interface ErrorGuidanceQueryPort {
|
|
19
|
+
getGuidance(errorCode: string): Promise<ErrorGuidance | null>;
|
|
20
|
+
}
|
package/scripts/harness/agent-integration/infrastructure/adapters/harness-error-guidance-adapter.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @unit agent-integration
|
|
2
|
+
// @layer infrastructure
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
ErrorGuidance,
|
|
6
|
+
ErrorGuidanceQueryPort,
|
|
7
|
+
} from '../../domain/ports/error-guidance-query-port.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* harness-error Unit の ErrorDefinitionRegistry を lookup して
|
|
11
|
+
* actionable guidance を返す adapter
|
|
12
|
+
*
|
|
13
|
+
* Wave 2 の CiGovernanceBaselineGrandfatherAdapter と同じ
|
|
14
|
+
* infrastructure-to-infrastructure クロス Unit パターン
|
|
15
|
+
*/
|
|
16
|
+
export class HarnessErrorGuidanceAdapter implements ErrorGuidanceQueryPort {
|
|
17
|
+
private readonly rootDir: string;
|
|
18
|
+
|
|
19
|
+
constructor(options: { rootDir: string }) {
|
|
20
|
+
this.rootDir = options.rootDir;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async getGuidance(errorCode: string): Promise<ErrorGuidance | null> {
|
|
24
|
+
try {
|
|
25
|
+
const [{ createHarnessErrorModule }, { ErrorCode }] = await Promise.all([
|
|
26
|
+
import('../../../harness-error/composition-root.js'),
|
|
27
|
+
import('../../../harness-error/domain/value-objects/error-code.js'),
|
|
28
|
+
]);
|
|
29
|
+
const mod = createHarnessErrorModule(this.rootDir);
|
|
30
|
+
const definition = mod.errorDefinitionRegistry.getDefinition(
|
|
31
|
+
ErrorCode.create(errorCode),
|
|
32
|
+
);
|
|
33
|
+
if (
|
|
34
|
+
definition.defaultSuggestedSkill === null
|
|
35
|
+
&& definition.defaultScaffoldCommand === null
|
|
36
|
+
&& definition.defaultTemplatePath === null
|
|
37
|
+
) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
suggestedSkill: definition.defaultSuggestedSkill,
|
|
42
|
+
scaffoldCommand: definition.defaultScaffoldCommand,
|
|
43
|
+
templatePath: definition.defaultTemplatePath,
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -14,6 +14,7 @@ import { PhaseGateQueryAdapter } from '../infrastructure/adapters/phase-gate-que
|
|
|
14
14
|
import { FileSystemStoryReflectionQueryAdapter } from '../infrastructure/adapters/file-system-story-reflection-query-adapter.js';
|
|
15
15
|
import { QuickModeFullModeRequirementAdapter } from '../infrastructure/adapters/quick-mode-full-mode-requirement-adapter.js';
|
|
16
16
|
import { CiGovernanceBaselineGrandfatherAdapter } from '../infrastructure/adapters/ci-governance-baseline-grandfather-adapter.js';
|
|
17
|
+
import { HarnessErrorGuidanceAdapter } from '../infrastructure/adapters/harness-error-guidance-adapter.js';
|
|
17
18
|
import { createQuickModeCompositionRoot } from '../../quick-mode/composition-root.js';
|
|
18
19
|
import * as path from 'node:path';
|
|
19
20
|
import * as fs from 'node:fs/promises';
|
|
@@ -128,12 +129,16 @@ async function main(): Promise<void> {
|
|
|
128
129
|
baseDir: path.dirname(configPath),
|
|
129
130
|
configQueryPort,
|
|
130
131
|
});
|
|
132
|
+
const errorGuidanceQueryPort = new HarnessErrorGuidanceAdapter({
|
|
133
|
+
rootDir: path.dirname(configPath),
|
|
134
|
+
});
|
|
131
135
|
const useCase = new HandlePreToolUseUseCase({
|
|
132
136
|
configQueryPort,
|
|
133
137
|
phaseGateQueryPort,
|
|
134
138
|
storyReflectionQueryPort,
|
|
135
139
|
fullModeRequirementQueryPort,
|
|
136
140
|
baselineGrandfatherQueryPort,
|
|
141
|
+
errorGuidanceQueryPort,
|
|
137
142
|
});
|
|
138
143
|
|
|
139
144
|
const output = await useCase.execute({ toolName: effectiveToolName, targetFilePaths });
|
|
@@ -20,6 +20,15 @@ export class HarnessErrorContractMapper {
|
|
|
20
20
|
...(harnessError.fixExample !== null
|
|
21
21
|
? { fix_example: harnessError.fixExample.toString() }
|
|
22
22
|
: {}),
|
|
23
|
+
...(harnessError.suggestedSkill !== null
|
|
24
|
+
? { suggested_skill: harnessError.suggestedSkill }
|
|
25
|
+
: {}),
|
|
26
|
+
...(harnessError.scaffoldCommand !== null
|
|
27
|
+
? { scaffold_command: harnessError.scaffoldCommand }
|
|
28
|
+
: {}),
|
|
29
|
+
...(harnessError.templatePath !== null
|
|
30
|
+
? { template_path: harnessError.templatePath }
|
|
31
|
+
: {}),
|
|
23
32
|
};
|
|
24
33
|
|
|
25
34
|
return Object.freeze(contract);
|
|
@@ -34,6 +34,9 @@ export class CreateHarnessErrorUseCase {
|
|
|
34
34
|
requestedSeverity: input.severity,
|
|
35
35
|
adrRef: input.adrRef,
|
|
36
36
|
fixExample: input.fixExample,
|
|
37
|
+
suggestedSkill: input.suggestedSkill,
|
|
38
|
+
scaffoldCommand: input.scaffoldCommand,
|
|
39
|
+
templatePath: input.templatePath,
|
|
37
40
|
});
|
|
38
41
|
|
|
39
42
|
return this.contractMapper.toReadonlyContract(harnessError);
|
|
@@ -29,6 +29,9 @@ export interface CreateHarnessErrorParams {
|
|
|
29
29
|
readonly requestedSeverity?: 'error' | 'warning';
|
|
30
30
|
readonly adrRef?: string | null;
|
|
31
31
|
readonly fixExample?: string | null;
|
|
32
|
+
readonly suggestedSkill?: string | null;
|
|
33
|
+
readonly scaffoldCommand?: string | null;
|
|
34
|
+
readonly templatePath?: string | null;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
export interface HarnessErrorFactoryDeps {
|
|
@@ -119,7 +122,12 @@ export class HarnessErrorFactory {
|
|
|
119
122
|
}
|
|
120
123
|
}
|
|
121
124
|
|
|
122
|
-
// 10.
|
|
125
|
+
// 10. actionable フィールドの解決(ErrorDefinition の default と input 引数の合成)
|
|
126
|
+
const resolvedSuggestedSkill = definition.resolveSuggestedSkill(input.suggestedSkill);
|
|
127
|
+
const resolvedScaffoldCommand = definition.resolveScaffoldCommand(input.scaffoldCommand);
|
|
128
|
+
const resolvedTemplatePath = definition.resolveTemplatePath(input.templatePath);
|
|
129
|
+
|
|
130
|
+
// 11. HarnessError 生成と凍結
|
|
123
131
|
const harnessError = new HarnessError({
|
|
124
132
|
code: errorCode,
|
|
125
133
|
severity: effectiveSeverity,
|
|
@@ -127,6 +135,9 @@ export class HarnessErrorFactory {
|
|
|
127
135
|
suggestion: input.suggestion,
|
|
128
136
|
adrRef: resolvedAdrRef,
|
|
129
137
|
fixExample: resolvedFixExample,
|
|
138
|
+
suggestedSkill: resolvedSuggestedSkill,
|
|
139
|
+
scaffoldCommand: resolvedScaffoldCommand,
|
|
140
|
+
templatePath: resolvedTemplatePath,
|
|
130
141
|
});
|
|
131
142
|
|
|
132
143
|
return Object.freeze(harnessError);
|
|
@@ -31,6 +31,9 @@ export interface ErrorDefinitionProps {
|
|
|
31
31
|
readonly fixExampleRequired: boolean;
|
|
32
32
|
readonly defaultFixExample: FixExample | null;
|
|
33
33
|
readonly ownerValidatorId: string;
|
|
34
|
+
readonly defaultSuggestedSkill?: string | null;
|
|
35
|
+
readonly defaultScaffoldCommand?: string | null;
|
|
36
|
+
readonly defaultTemplatePath?: string | null;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export class ErrorDefinition {
|
|
@@ -43,6 +46,9 @@ export class ErrorDefinition {
|
|
|
43
46
|
readonly fixExampleRequired: boolean;
|
|
44
47
|
readonly defaultFixExample: FixExample | null;
|
|
45
48
|
readonly ownerValidatorId: string;
|
|
49
|
+
readonly defaultSuggestedSkill: string | null;
|
|
50
|
+
readonly defaultScaffoldCommand: string | null;
|
|
51
|
+
readonly defaultTemplatePath: string | null;
|
|
46
52
|
|
|
47
53
|
private constructor(props: ErrorDefinitionProps) {
|
|
48
54
|
this.code = props.code;
|
|
@@ -54,6 +60,9 @@ export class ErrorDefinition {
|
|
|
54
60
|
this.fixExampleRequired = props.fixExampleRequired;
|
|
55
61
|
this.defaultFixExample = props.defaultFixExample;
|
|
56
62
|
this.ownerValidatorId = props.ownerValidatorId;
|
|
63
|
+
this.defaultSuggestedSkill = props.defaultSuggestedSkill ?? null;
|
|
64
|
+
this.defaultScaffoldCommand = props.defaultScaffoldCommand ?? null;
|
|
65
|
+
this.defaultTemplatePath = props.defaultTemplatePath ?? null;
|
|
57
66
|
Object.freeze(this);
|
|
58
67
|
}
|
|
59
68
|
|
|
@@ -98,6 +107,27 @@ export class ErrorDefinition {
|
|
|
98
107
|
return this.defaultFixExample;
|
|
99
108
|
}
|
|
100
109
|
|
|
110
|
+
resolveSuggestedSkill(explicit?: string | null): string | null {
|
|
111
|
+
if (explicit) {
|
|
112
|
+
return explicit;
|
|
113
|
+
}
|
|
114
|
+
return this.defaultSuggestedSkill;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
resolveScaffoldCommand(explicit?: string | null): string | null {
|
|
118
|
+
if (explicit) {
|
|
119
|
+
return explicit;
|
|
120
|
+
}
|
|
121
|
+
return this.defaultScaffoldCommand;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
resolveTemplatePath(explicit?: string | null): string | null {
|
|
125
|
+
if (explicit) {
|
|
126
|
+
return explicit;
|
|
127
|
+
}
|
|
128
|
+
return this.defaultTemplatePath;
|
|
129
|
+
}
|
|
130
|
+
|
|
101
131
|
equals(other: ErrorDefinition): boolean {
|
|
102
132
|
const adrRefEqual =
|
|
103
133
|
this.defaultAdrRef === null && other.defaultAdrRef === null
|
|
@@ -17,6 +17,9 @@ export interface HarnessErrorContract {
|
|
|
17
17
|
readonly suggestion: string;
|
|
18
18
|
readonly adr_ref?: string;
|
|
19
19
|
readonly fix_example?: string;
|
|
20
|
+
readonly suggested_skill?: string;
|
|
21
|
+
readonly scaffold_command?: string;
|
|
22
|
+
readonly template_path?: string;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
export interface HarnessErrorProps {
|
|
@@ -26,6 +29,9 @@ export interface HarnessErrorProps {
|
|
|
26
29
|
readonly suggestion: string;
|
|
27
30
|
readonly adrRef: AdrRef | null;
|
|
28
31
|
readonly fixExample: FixExample | null;
|
|
32
|
+
readonly suggestedSkill?: string | null;
|
|
33
|
+
readonly scaffoldCommand?: string | null;
|
|
34
|
+
readonly templatePath?: string | null;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
export class HarnessError {
|
|
@@ -35,6 +41,9 @@ export class HarnessError {
|
|
|
35
41
|
readonly suggestion: string;
|
|
36
42
|
readonly adrRef: AdrRef | null;
|
|
37
43
|
readonly fixExample: FixExample | null;
|
|
44
|
+
readonly suggestedSkill: string | null;
|
|
45
|
+
readonly scaffoldCommand: string | null;
|
|
46
|
+
readonly templatePath: string | null;
|
|
38
47
|
|
|
39
48
|
constructor(props: HarnessErrorProps) {
|
|
40
49
|
this.code = props.code;
|
|
@@ -43,6 +52,9 @@ export class HarnessError {
|
|
|
43
52
|
this.suggestion = props.suggestion;
|
|
44
53
|
this.adrRef = props.adrRef;
|
|
45
54
|
this.fixExample = props.fixExample;
|
|
55
|
+
this.suggestedSkill = props.suggestedSkill ?? null;
|
|
56
|
+
this.scaffoldCommand = props.scaffoldCommand ?? null;
|
|
57
|
+
this.templatePath = props.templatePath ?? null;
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
equals(other: HarnessError): boolean {
|
|
@@ -66,7 +78,10 @@ export class HarnessError {
|
|
|
66
78
|
this.message === other.message &&
|
|
67
79
|
this.suggestion === other.suggestion &&
|
|
68
80
|
adrRefEqual &&
|
|
69
|
-
fixExampleEqual
|
|
81
|
+
fixExampleEqual &&
|
|
82
|
+
this.suggestedSkill === other.suggestedSkill &&
|
|
83
|
+
this.scaffoldCommand === other.scaffoldCommand &&
|
|
84
|
+
this.templatePath === other.templatePath
|
|
70
85
|
);
|
|
71
86
|
}
|
|
72
87
|
|
|
@@ -78,6 +93,18 @@ export class HarnessError {
|
|
|
78
93
|
return this.fixExample !== null;
|
|
79
94
|
}
|
|
80
95
|
|
|
96
|
+
hasSuggestedSkill(): boolean {
|
|
97
|
+
return this.suggestedSkill !== null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
hasScaffoldCommand(): boolean {
|
|
101
|
+
return this.scaffoldCommand !== null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
hasTemplatePath(): boolean {
|
|
105
|
+
return this.templatePath !== null;
|
|
106
|
+
}
|
|
107
|
+
|
|
81
108
|
toContract(): Readonly<HarnessErrorContract> {
|
|
82
109
|
const contract: HarnessErrorContract = {
|
|
83
110
|
code: this.code.toString(),
|
|
@@ -88,6 +115,9 @@ export class HarnessError {
|
|
|
88
115
|
...(this.fixExample !== null
|
|
89
116
|
? { fix_example: this.fixExample.toString() }
|
|
90
117
|
: {}),
|
|
118
|
+
...(this.suggestedSkill !== null ? { suggested_skill: this.suggestedSkill } : {}),
|
|
119
|
+
...(this.scaffoldCommand !== null ? { scaffold_command: this.scaffoldCommand } : {}),
|
|
120
|
+
...(this.templatePath !== null ? { template_path: this.templatePath } : {}),
|
|
91
121
|
};
|
|
92
122
|
return Object.freeze(contract);
|
|
93
123
|
}
|
|
@@ -14,6 +14,9 @@ function createDefinition(input: {
|
|
|
14
14
|
category: 'phase_gate' | 'architecture' | 'dependency' | 'quality' | 'security' | 'performance' | 'consistency' | 'metadata';
|
|
15
15
|
ownerValidatorId: string;
|
|
16
16
|
defaultFixExample: string;
|
|
17
|
+
defaultSuggestedSkill?: string;
|
|
18
|
+
defaultScaffoldCommand?: string;
|
|
19
|
+
defaultTemplatePath?: string;
|
|
17
20
|
}): ErrorDefinition {
|
|
18
21
|
return ErrorDefinition.create({
|
|
19
22
|
code: ErrorCode.create(input.code),
|
|
@@ -25,6 +28,9 @@ function createDefinition(input: {
|
|
|
25
28
|
fixExampleRequired: true,
|
|
26
29
|
defaultFixExample: FixExample.create(input.defaultFixExample),
|
|
27
30
|
ownerValidatorId: input.ownerValidatorId,
|
|
31
|
+
defaultSuggestedSkill: input.defaultSuggestedSkill ?? null,
|
|
32
|
+
defaultScaffoldCommand: input.defaultScaffoldCommand ?? null,
|
|
33
|
+
defaultTemplatePath: input.defaultTemplatePath ?? null,
|
|
28
34
|
});
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -36,6 +42,9 @@ export const L2_ERROR_DEFINITIONS = Object.freeze([
|
|
|
36
42
|
ownerValidatorId: 'phase-gate',
|
|
37
43
|
defaultFixExample:
|
|
38
44
|
"const requiredPlanPath = 'docs/inception/harness-error/it_test_logic_plan.md';",
|
|
45
|
+
defaultSuggestedSkill: '/story-implementor',
|
|
46
|
+
defaultScaffoldCommand: 'npx phasegate scaffold-design --unit <unit-id> --phase logical',
|
|
47
|
+
defaultTemplatePath: 'docs/templates/logical_design.template.md',
|
|
39
48
|
}),
|
|
40
49
|
createDefinition({
|
|
41
50
|
code: 'L2-002',
|
|
@@ -278,9 +278,9 @@ scripts/init_skill.py <skill-name> --path <output-directory> [--resources script
|
|
|
278
278
|
Examples:
|
|
279
279
|
|
|
280
280
|
```bash
|
|
281
|
-
scripts/init_skill.py my-skill --path skills
|
|
282
|
-
scripts/init_skill.py my-skill --path skills
|
|
283
|
-
scripts/init_skill.py my-skill --path skills
|
|
281
|
+
scripts/init_skill.py my-skill --path skills
|
|
282
|
+
scripts/init_skill.py my-skill --path skills --resources scripts,references
|
|
283
|
+
scripts/init_skill.py my-skill --path skills --resources scripts --examples
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
The script:
|
|
@@ -6,9 +6,9 @@ Usage:
|
|
|
6
6
|
init_skill.py <skill-name> --path <path> [--resources scripts,references,assets] [--examples]
|
|
7
7
|
|
|
8
8
|
Examples:
|
|
9
|
-
init_skill.py my-new-skill --path skills
|
|
10
|
-
init_skill.py my-new-skill --path skills
|
|
11
|
-
init_skill.py my-api-helper --path skills
|
|
9
|
+
init_skill.py my-new-skill --path skills
|
|
10
|
+
init_skill.py my-new-skill --path skills --resources scripts,references
|
|
11
|
+
init_skill.py my-api-helper --path skills --resources scripts --examples
|
|
12
12
|
init_skill.py custom-skill --path /custom/location
|
|
13
13
|
"""
|
|
14
14
|
|
|
@@ -6,8 +6,8 @@ Usage:
|
|
|
6
6
|
python utils/package_skill.py <path/to/skill-folder> [output-directory]
|
|
7
7
|
|
|
8
8
|
Example:
|
|
9
|
-
python utils/package_skill.py skills/
|
|
10
|
-
python utils/package_skill.py skills/
|
|
9
|
+
python utils/package_skill.py skills/my-skill
|
|
10
|
+
python utils/package_skill.py skills/my-skill ./dist
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
import sys
|
|
@@ -87,8 +87,8 @@ def main():
|
|
|
87
87
|
if len(sys.argv) < 2:
|
|
88
88
|
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
|
|
89
89
|
print("\nExample:")
|
|
90
|
-
print(" python utils/package_skill.py skills/
|
|
91
|
-
print(" python utils/package_skill.py skills/
|
|
90
|
+
print(" python utils/package_skill.py skills/my-skill")
|
|
91
|
+
print(" python utils/package_skill.py skills/my-skill ./dist")
|
|
92
92
|
sys.exit(1)
|
|
93
93
|
|
|
94
94
|
skill_path = sys.argv[1]
|
|
Binary file
|