qfai 1.6.2 → 1.6.4
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/assets/init/.github/instructions/code-review.instructions.md +63 -0
- package/assets/init/.github/instructions/principles.instructions.md +110 -0
- package/assets/init/.qfai/assistant/agents/facilitator.md +1 -1
- package/assets/init/.qfai/assistant/agents/interviewer.md +1 -1
- package/assets/init/.qfai/assistant/agents/option-explorer.md +1 -1
- package/assets/init/.qfai/assistant/agents/oq-harvester.md +1 -1
- package/assets/init/.qfai/assistant/agents/requirements-analyst.md +1 -1
- package/assets/init/.qfai/assistant/agents/researcher.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +1 -1
- package/dist/cli/index.cjs +52 -2
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +144 -84
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
excludeAgent: "coding-agent"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Copilot Code Review Instructions (Repository)
|
|
7
|
+
|
|
8
|
+
Goal:
|
|
9
|
+
|
|
10
|
+
- Provide high-quality, line-level PR review comments that improve code health.
|
|
11
|
+
- Base the review on the PR description and the diff against the merge target.
|
|
12
|
+
|
|
13
|
+
Language:
|
|
14
|
+
|
|
15
|
+
- Default: Japanese.
|
|
16
|
+
- If the PR description includes `Review Language:` (e.g., `ja`, `en`, `ja+en`), follow it.
|
|
17
|
+
- For multi-language requests, write each comment in all requested languages, Japanese first.
|
|
18
|
+
|
|
19
|
+
Process:
|
|
20
|
+
|
|
21
|
+
1. Read the PR description (use the PR template sections) and extract:
|
|
22
|
+
- Why/background
|
|
23
|
+
- Business/process position
|
|
24
|
+
- Intended behavior change
|
|
25
|
+
- Design decisions and alternatives
|
|
26
|
+
- Risks and tests
|
|
27
|
+
2. Compare the description with the diff. If missing or inconsistent, leave a single top-level review comment requesting clarification.
|
|
28
|
+
3. Review every changed line and surrounding context. Prefer inline comments for concrete issues.
|
|
29
|
+
|
|
30
|
+
Comment format:
|
|
31
|
+
|
|
32
|
+
- Prefix severity: [BLOCKER], [MAJOR], [MINOR], [NIT], or [FYI] (if other labels are used, map critical -> [BLOCKER], moderate -> [MAJOR], nit -> [NIT]).
|
|
33
|
+
- Include: Issue -> Why (impact/risk) -> Suggestion (concrete fix or test).
|
|
34
|
+
- Use respectful, code-focused language and explain reasoning.
|
|
35
|
+
- Provide positive feedback when something is notably well done.
|
|
36
|
+
|
|
37
|
+
Review checklist (from code review best practices):
|
|
38
|
+
|
|
39
|
+
- Design: fits existing architecture/patterns; avoid over-engineering.
|
|
40
|
+
- Correctness: edge cases, error handling, input validation, concurrency safety.
|
|
41
|
+
- Security/Privacy: secrets, authZ/authN, data exposure, logging.
|
|
42
|
+
- Performance: N+1, unnecessary full scans, expensive operations, caching.
|
|
43
|
+
- Maintainability: duplication, naming clarity, modularity, responsibility boundaries.
|
|
44
|
+
- Tests: appropriate unit/integration/e2e coverage; tests fail when code is wrong.
|
|
45
|
+
- Docs/UX: README/RELEASE/usage steps are consistent and copy-pasteable; UI changes make sense.
|
|
46
|
+
- Consistency/style: follow existing conventions; style-only nits should be labeled [NIT].
|
|
47
|
+
|
|
48
|
+
Specific checks:
|
|
49
|
+
|
|
50
|
+
- If the PR claims "no behavior change," verify the diff matches; otherwise raise [MAJOR].
|
|
51
|
+
- For documentation-only PRs, validate that steps are self-consistent and have no contradicting prerequisites.
|
|
52
|
+
|
|
53
|
+
Library/CLI compatibility checks:
|
|
54
|
+
|
|
55
|
+
- If a public function signature, exported type, or CLI flag changes, confirm the PR documents the breaking change.
|
|
56
|
+
- Removing or renaming an export requires a CHANGELOG entry and a major version bump justification.
|
|
57
|
+
|
|
58
|
+
Constraints:
|
|
59
|
+
|
|
60
|
+
- Copilot reviews are comments only and do not block merging; be explicit about severity.
|
|
61
|
+
- If a change affects user-facing behavior, call out expected impact and any missing tests or docs.
|
|
62
|
+
|
|
63
|
+
<!-- qfai:language-rules -->
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
excludeAgent: "coding-agent"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Software Engineering Principles Review
|
|
7
|
+
|
|
8
|
+
ソフトウェア開発・設計の原則やセオリーに照らして、変更が適切かを検証する。
|
|
9
|
+
原則違反を見つけた場合は、どの原則に違反しているかを明示し、改善案を提示すること。
|
|
10
|
+
|
|
11
|
+
## 設計の基本原則
|
|
12
|
+
|
|
13
|
+
### SOLID
|
|
14
|
+
|
|
15
|
+
- **SRP(単一責任)**: 1つのクラス・関数・モジュールが複数の理由で変更される設計になっていないか。名前から責務が一意に読み取れるか。
|
|
16
|
+
- **OCP(開放閉鎖)**: 既存コードを書き換えずに拡張できる設計か。設定値・依存注入・ストラテジーパターン等で切り替え可能か。
|
|
17
|
+
- **LSP(リスコフの置換)**: 派生型やサブタイプが親の契約を破っていないか。事前条件を厳しくしたり事後条件を弱めたりしていないか。
|
|
18
|
+
- **ISP(インターフェース分離)**: クライアントが使わないメソッドへの依存を強要していないか。インターフェースは小さく役割別に分割されているか。
|
|
19
|
+
- **DIP(依存性逆転)**: 高水準モジュールが低水準の具象に直接依存していないか。モジュール境界では抽象(インターフェース)に依存しているか。
|
|
20
|
+
|
|
21
|
+
### KISS(Keep It Simple)
|
|
22
|
+
|
|
23
|
+
- 不必要に複雑な実装になっていないか。標準ライブラリや既存ユーティリティで代替可能な自前実装がないか。
|
|
24
|
+
- 認知負荷を下げる書き方か(深いネスト、過度な抽象化、暗黙の挙動を避ける)。
|
|
25
|
+
|
|
26
|
+
### YAGNI(You Aren't Gonna Need It)
|
|
27
|
+
|
|
28
|
+
- 現時点で不要な機能・設定・拡張ポイントを先回りして実装していないか。
|
|
29
|
+
- 「将来必要になるかも」で追加されたコードがないか。
|
|
30
|
+
|
|
31
|
+
### DRY(Don't Repeat Yourself)
|
|
32
|
+
|
|
33
|
+
- 同一または類似のロジックが複数箇所に重複していないか。共通化・ユーティリティ化の余地がないか。
|
|
34
|
+
- ただし過度な共通化(shotgun surgery を招く)は避け、Rule of Three を意識する。
|
|
35
|
+
|
|
36
|
+
## モジュール間関係の原則
|
|
37
|
+
|
|
38
|
+
### Separation of Concerns(関心の分離)
|
|
39
|
+
|
|
40
|
+
- ビジネスロジック・UI・データアクセス・インフラなど、異なる関心が1つのモジュールに混在していないか。
|
|
41
|
+
|
|
42
|
+
### Law of Demeter(最小知識の原則)
|
|
43
|
+
|
|
44
|
+
- `a.getB().getC().doSomething()` のようなメソッドチェーンで遠いオブジェクトに依存していないか。
|
|
45
|
+
- オブジェクトは直接の協力者のみとやり取りしているか。
|
|
46
|
+
|
|
47
|
+
### Minimise Coupling / Maximise Cohesion
|
|
48
|
+
|
|
49
|
+
- モジュール間の結合度が不必要に高くないか。変更が他モジュールに波及しにくい設計か。
|
|
50
|
+
- 1つのモジュール内の要素は同じ責務に向かってまとまっているか(高凝集)。
|
|
51
|
+
|
|
52
|
+
### Composition over Inheritance(継承より合成)
|
|
53
|
+
|
|
54
|
+
- 「is-a」関係でないのに継承を使っていないか。振る舞いの組み合わせは合成(委譲・ミックスイン)で実現すべきか。
|
|
55
|
+
|
|
56
|
+
## 堅牢性・安全性の原則
|
|
57
|
+
|
|
58
|
+
### Fail Fast(早期失敗)
|
|
59
|
+
|
|
60
|
+
- 不正な入力や前提条件の違反を関数の冒頭で検出し、即座にエラーを返しているか。
|
|
61
|
+
- 無効な状態が伝播して後続処理で不可解な障害を起こす設計になっていないか。
|
|
62
|
+
|
|
63
|
+
### Defensive Programming(防御的プログラミング)
|
|
64
|
+
|
|
65
|
+
- 外部入力・API応答・ユーザー入力に対して適切なバリデーションがあるか。
|
|
66
|
+
- null/undefined の安全な処理、リソース解放(finally/using)が適切か。
|
|
67
|
+
|
|
68
|
+
### Principle of Least Privilege(最小権限)
|
|
69
|
+
|
|
70
|
+
- 必要最小限のアクセス権限・スコープで動作しているか。過剰な権限を要求していないか。
|
|
71
|
+
|
|
72
|
+
### Design by Contract(契約による設計)
|
|
73
|
+
|
|
74
|
+
- 関数の事前条件(引数の制約)・事後条件(戻り値の保証)・不変条件が明確か。
|
|
75
|
+
|
|
76
|
+
## 可読性・保守性の原則
|
|
77
|
+
|
|
78
|
+
### Principle of Least Astonishment(驚き最小の原則)
|
|
79
|
+
|
|
80
|
+
- API・関数の命名と実際の振る舞いが一致しているか。副作用が名前から予測できるか。
|
|
81
|
+
- 言語やフレームワークのイディオムに従っているか。
|
|
82
|
+
|
|
83
|
+
### Boy Scout Rule(来た時よりきれいに)
|
|
84
|
+
|
|
85
|
+
- 変更箇所の周辺に明らかな改善余地(命名・型安全・不要コード)があれば併せて改善しているか。
|
|
86
|
+
|
|
87
|
+
### Avoid Premature Optimization(早すぎる最適化の回避)
|
|
88
|
+
|
|
89
|
+
- 計測なしに最適化していないか。可読性を犠牲にした最適化がボトルネック以外に適用されていないか。
|
|
90
|
+
|
|
91
|
+
## 振る舞い・インターフェースの原則
|
|
92
|
+
|
|
93
|
+
### Tell, Don't Ask(聞くな、命じよ)
|
|
94
|
+
|
|
95
|
+
- オブジェクトの内部状態を外部で問い合わせて判断するのではなく、オブジェクトに振る舞いを委ねているか。
|
|
96
|
+
|
|
97
|
+
### Command Query Separation(CQS)
|
|
98
|
+
|
|
99
|
+
- 状態を変更するメソッド(コマンド)と値を返すメソッド(クエリ)が混在していないか。
|
|
100
|
+
|
|
101
|
+
### Encapsulation(カプセル化)
|
|
102
|
+
|
|
103
|
+
- 内部実装の詳細が不必要に外部に露出していないか。公開APIは必要最小限か。
|
|
104
|
+
|
|
105
|
+
## 適用上の注意
|
|
106
|
+
|
|
107
|
+
- 原則同士はトレードオフになることがある(DRY vs YAGNI、KISS vs OCP など)。文脈に応じたバランスを評価すること。
|
|
108
|
+
- 原則違反の指摘には [MAJOR] or [MINOR] の重要度を付け、なぜその原則が重要かを簡潔に説明すること。
|
|
109
|
+
|
|
110
|
+
<!-- qfai:language-rules -->
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- .qfai/assistant/instructions/\*
|
|
11
11
|
- .qfai/assistant/steering/\*
|
|
12
12
|
- .qfai/specs/spec-\*/09_delta.md (Decision Records; check rejected)
|
|
13
|
-
- Existing discussion records under `.qfai/
|
|
13
|
+
- Existing discussion records under `.qfai/discussion/`
|
|
14
14
|
- .qfai/require/require-\*/01_Sources.md
|
|
15
15
|
- .qfai/require/require-\*/03_REQ.md
|
|
16
16
|
- .qfai/require/require-\*/08_OQ.md (input gaps ledger)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- .qfai/assistant/instructions/\*
|
|
10
10
|
- .qfai/assistant/steering/\*
|
|
11
11
|
- .qfai/specs/spec-\*/09_delta.md (Decision Records; check rejected)
|
|
12
|
-
- Existing discussion records under `.qfai/
|
|
12
|
+
- Existing discussion records under `.qfai/discussion/`
|
|
13
13
|
- .qfai/require/require-\*/01_Sources.md
|
|
14
14
|
- .qfai/require/require-\*/03_REQ.md
|
|
15
15
|
- .qfai/require/require-\*/08_OQ.md (input gaps ledger)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- .qfai/require/require-\*/01_Sources.md
|
|
13
13
|
- .qfai/require/require-\*/03_REQ.md
|
|
14
14
|
- .qfai/require/require-\*/08_OQ.md (input gaps ledger)
|
|
15
|
-
- Discussion records under `.qfai/
|
|
15
|
+
- Discussion records under `.qfai/discussion/`
|
|
16
16
|
- .qfai/specs/spec-\*/01_Spec.md (if available)
|
|
17
17
|
|
|
18
18
|
## Deliverables (MANDATORY)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- .qfai/assistant/steering/\*
|
|
11
11
|
- .qfai/specs/spec-\*/09_delta.md (Decision Records; check rejected)
|
|
12
12
|
- User-provided idea/problem statement
|
|
13
|
-
- Existing discussion records under `.qfai/
|
|
13
|
+
- Existing discussion records under `.qfai/discussion/`
|
|
14
14
|
|
|
15
15
|
## Deliverables (MANDATORY)
|
|
16
16
|
|
|
@@ -67,7 +67,7 @@ Then read inputs in this order:
|
|
|
67
67
|
- P1: `.qfai/assistant/instructions/*`
|
|
68
68
|
- P2: `.qfai/assistant/steering/*`
|
|
69
69
|
- P3: existing `.qfai/specs/<spec-id>/**` (if updating)
|
|
70
|
-
- P4: `.qfai/
|
|
70
|
+
- P4: `.qfai/discussion/**`, `.qfai/require/**`, `.qfai/contracts/**`
|
|
71
71
|
|
|
72
72
|
## Sub-agent Delegation (MANDATORY)
|
|
73
73
|
|
package/dist/cli/index.cjs
CHANGED
|
@@ -1522,8 +1522,8 @@ var import_promises7 = require("fs/promises");
|
|
|
1522
1522
|
var import_node_path8 = __toESM(require("path"), 1);
|
|
1523
1523
|
var import_node_url2 = require("url");
|
|
1524
1524
|
async function resolveToolVersion() {
|
|
1525
|
-
if ("1.6.
|
|
1526
|
-
return "1.6.
|
|
1525
|
+
if ("1.6.4".length > 0) {
|
|
1526
|
+
return "1.6.4";
|
|
1527
1527
|
}
|
|
1528
1528
|
try {
|
|
1529
1529
|
const packagePath = resolvePackageJsonPath();
|
|
@@ -2758,6 +2758,17 @@ async function runInit(options) {
|
|
|
2758
2758
|
await ensureRequiredEmptyScaffoldDirs(destQfai, options.dryRun);
|
|
2759
2759
|
const removedLegacySkills = options.force ? await pruneLegacySkillFiles(destRoot, options.dryRun) : [];
|
|
2760
2760
|
const removed = [...removedLegacySkills, ...wrappersResult.removed];
|
|
2761
|
+
const expectedInstructionsDir = import_node_path14.default.join(destRoot, ".github", "instructions");
|
|
2762
|
+
const instructionsCreated = wrappersResult.copied.some(
|
|
2763
|
+
(p) => import_node_path14.default.basename(p).endsWith(".instructions.md") && import_node_path14.default.dirname(p) === expectedInstructionsDir
|
|
2764
|
+
);
|
|
2765
|
+
if (instructionsCreated && !options.dryRun) {
|
|
2766
|
+
info("");
|
|
2767
|
+
info("Copilot \u30B3\u30FC\u30C9\u30EC\u30D3\u30E5\u30FC\u7528 instructions \u3092\u4F5C\u6210\u3057\u307E\u3057\u305F\u3002");
|
|
2768
|
+
info("\u6709\u52B9\u5316: PR \u30B3\u30E1\u30F3\u30C8\u3067 '@github-copilot review' \u3092\u5B9F\u884C\u3059\u308B\u304B\u3001");
|
|
2769
|
+
info("GitHub Actions \u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u3067\u81EA\u52D5\u30EC\u30D3\u30E5\u30FC\u3092\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
2770
|
+
info("\u53C2\u8003: https://docs.github.com/en/copilot/using-github-copilot/code-review");
|
|
2771
|
+
}
|
|
2761
2772
|
report(
|
|
2762
2773
|
[...rootResult.copied, ...qfaiResult.copied, ...skillsResult.copied, ...wrappersResult.copied],
|
|
2763
2774
|
[
|
|
@@ -2841,6 +2852,20 @@ async function exists7(target) {
|
|
|
2841
2852
|
return false;
|
|
2842
2853
|
}
|
|
2843
2854
|
}
|
|
2855
|
+
function isEnoent(err) {
|
|
2856
|
+
return typeof err === "object" && err !== null && err.code === "ENOENT";
|
|
2857
|
+
}
|
|
2858
|
+
async function pathExists(target) {
|
|
2859
|
+
try {
|
|
2860
|
+
await (0, import_promises12.lstat)(target);
|
|
2861
|
+
return true;
|
|
2862
|
+
} catch (err) {
|
|
2863
|
+
if (isEnoent(err)) {
|
|
2864
|
+
return false;
|
|
2865
|
+
}
|
|
2866
|
+
throw err;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2844
2869
|
async function configureGitSymlinks(destRoot, dryRun) {
|
|
2845
2870
|
try {
|
|
2846
2871
|
await execAsync("git rev-parse --git-dir", { cwd: destRoot });
|
|
@@ -2905,6 +2930,31 @@ async function syncIntegrationWrappers(assistantAssetsDir, destRoot, options) {
|
|
|
2905
2930
|
await (0, import_promises12.writeFile)(copilotDest, buildCopilotInstructions(), "utf-8");
|
|
2906
2931
|
}
|
|
2907
2932
|
}
|
|
2933
|
+
const instructionsFiles = ["code-review.instructions.md", "principles.instructions.md"];
|
|
2934
|
+
for (const fileName of instructionsFiles) {
|
|
2935
|
+
const dest = import_node_path14.default.join(destRoot, ".github", "instructions", fileName);
|
|
2936
|
+
const alreadyExists = await pathExists(dest);
|
|
2937
|
+
if (alreadyExists) {
|
|
2938
|
+
skipped.push(dest);
|
|
2939
|
+
} else {
|
|
2940
|
+
copied.push(dest);
|
|
2941
|
+
if (!options.dryRun) {
|
|
2942
|
+
await (0, import_promises12.mkdir)(import_node_path14.default.dirname(dest), { recursive: true });
|
|
2943
|
+
const templateSrc = import_node_path14.default.join(getInitAssetsDir(), ".github", "instructions", fileName);
|
|
2944
|
+
let content;
|
|
2945
|
+
try {
|
|
2946
|
+
content = await (0, import_promises12.readFile)(templateSrc, "utf-8");
|
|
2947
|
+
} catch (err) {
|
|
2948
|
+
const code = typeof err === "object" && err !== null ? err.code : void 0;
|
|
2949
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2950
|
+
throw new Error(
|
|
2951
|
+
`instructions \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${templateSrc} (${code ?? detail})\u3002\u30D1\u30C3\u30B1\u30FC\u30B8\u304C\u6B63\u3057\u304F\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2954
|
+
await (0, import_promises12.writeFile)(dest, content, "utf-8");
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2908
2958
|
const skillResult = await createSkillSymlinks(destRoot, skills, options);
|
|
2909
2959
|
copied.push(...skillResult.copied);
|
|
2910
2960
|
skipped.push(...skillResult.skipped);
|