sdd-forge 0.1.0-alpha.2 → 0.1.0-alpha.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/README.md +14 -9
- package/package.json +9 -6
- package/src/README.md +169 -0
- package/src/docs/commands/agents.js +370 -0
- package/src/docs/commands/changelog.js +252 -0
- package/src/{engine/populate.js → docs/commands/data.js} +40 -16
- package/src/{projects/setdefault.js → docs/commands/default-project.js} +10 -2
- package/src/{forge → docs/commands}/forge.js +138 -20
- package/src/docs/commands/init.js +590 -0
- package/src/{engine → docs/commands}/readme.js +61 -35
- package/src/docs/commands/review.js +106 -0
- package/src/docs/commands/scan.js +174 -0
- package/src/docs/commands/setup.js +664 -0
- package/src/{engine/tfill.js → docs/commands/text.js} +178 -61
- package/src/docs/lib/directive-parser.js +181 -0
- package/src/docs/lib/resolver-base.js +229 -0
- package/src/docs/lib/resolver-factory.js +102 -0
- package/src/docs/lib/scanner.js +509 -0
- package/src/docs/lib/template-merger.js +257 -0
- package/src/docs/presets/registry.js +75 -0
- package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-controllers.js +1 -1
- package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-extras.js +1 -1
- package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-models.js +1 -1
- package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-routes.js +1 -1
- package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-shells.js +1 -1
- package/src/docs/presets/webapp/cakephp2/resolver.js +328 -0
- package/src/docs/presets/webapp/cakephp2/scanner.js +74 -0
- package/src/docs/presets/webapp/laravel/analyze-config.js +124 -0
- package/src/docs/presets/webapp/laravel/analyze-controllers.js +86 -0
- package/src/docs/presets/webapp/laravel/analyze-migrations.js +147 -0
- package/src/docs/presets/webapp/laravel/analyze-models.js +173 -0
- package/src/docs/presets/webapp/laravel/analyze-routes.js +121 -0
- package/src/docs/presets/webapp/laravel/resolver.js +234 -0
- package/src/docs/presets/webapp/laravel/scanner.js +104 -0
- package/src/docs/presets/webapp/symfony/analyze-config.js +136 -0
- package/src/docs/presets/webapp/symfony/analyze-controllers.js +105 -0
- package/src/docs/presets/webapp/symfony/analyze-entities.js +152 -0
- package/src/docs/presets/webapp/symfony/analyze-migrations.js +149 -0
- package/src/docs/presets/webapp/symfony/analyze-routes.js +207 -0
- package/src/docs/presets/webapp/symfony/resolver.js +223 -0
- package/src/docs/presets/webapp/symfony/scanner.js +104 -0
- package/src/docs.js +103 -0
- package/src/{flow/flow.js → flow.js} +50 -11
- package/src/help.js +42 -31
- package/src/lib/agent.js +54 -0
- package/src/lib/cli.js +35 -0
- package/src/lib/config.js +70 -2
- package/src/lib/flow-state.js +56 -0
- package/src/lib/i18n.js +137 -0
- package/src/{projects → lib}/projects.js +46 -10
- package/src/lib/types.js +215 -0
- package/src/sdd-forge.js +106 -0
- package/src/spec.js +31 -0
- package/src/{spec → specs/commands}/gate.js +9 -2
- package/src/specs/commands/init.js +271 -0
- package/src/templates/config.example.json +31 -0
- package/src/templates/locale/en/ui.json +103 -0
- package/src/templates/locale/ja/base/01_overview.md +33 -0
- package/src/templates/locale/ja/base/02_stack_and_ops.md +33 -0
- package/src/templates/locale/ja/base/03_project_structure.md +27 -0
- package/src/templates/locale/ja/base/04_development.md +40 -0
- package/src/templates/locale/ja/base/AGENTS.sdd.md +84 -0
- package/src/templates/locale/ja/cli/05_commands.md +33 -0
- package/src/templates/locale/ja/cli/06_config.md +33 -0
- package/src/templates/locale/ja/cli/README.md +31 -0
- package/src/templates/locale/ja/cli/node-cli/01_overview.md +23 -0
- package/src/templates/locale/ja/cli/node-cli/02_cli_commands.md +23 -0
- package/src/templates/locale/ja/cli/node-cli/03_configuration.md +23 -0
- package/src/templates/locale/ja/cli/node-cli/04_internal_design.md +30 -0
- package/src/templates/locale/ja/cli/node-cli/05_development.md +49 -0
- package/src/templates/locale/ja/library/05_public_api.md +27 -0
- package/src/templates/locale/ja/library/06_usage.md +33 -0
- package/src/templates/locale/ja/library/README.md +18 -0
- package/src/templates/locale/ja/prompts.json +1 -1
- package/src/templates/locale/ja/ui.json +103 -0
- package/src/templates/locale/ja/webapp/05_auth_and_session.md +37 -0
- package/src/templates/locale/ja/webapp/06_database_architecture.md +33 -0
- package/src/templates/locale/ja/webapp/07_db_tables.md +27 -0
- package/src/templates/locale/ja/webapp/08_controller_routes.md +41 -0
- package/src/templates/locale/ja/webapp/09_business_logic.md +37 -0
- package/src/templates/locale/ja/webapp/10_batch_and_shell.md +35 -0
- package/src/templates/locale/ja/{php-mvc → webapp}/README.md +2 -2
- package/src/templates/locale/ja/webapp/cakephp2/02_stack_and_ops.md +41 -0
- package/src/templates/locale/ja/webapp/cakephp2/03_project_structure.md +46 -0
- package/src/templates/locale/ja/webapp/cakephp2/04_development.md +58 -0
- package/src/templates/locale/ja/webapp/cakephp2/05_auth_and_session.md +22 -0
- package/src/templates/locale/ja/webapp/cakephp2/07_db_tables.md +19 -0
- package/src/templates/locale/ja/webapp/cakephp2/08_controller_routes.md +11 -0
- package/src/templates/locale/ja/webapp/chapters.json +4 -0
- package/src/templates/locale/ja/webapp/laravel/02_stack_and_ops.md +35 -0
- package/src/templates/locale/ja/webapp/laravel/03_project_structure.md +11 -0
- package/src/templates/locale/ja/webapp/laravel/05_auth_and_session.md +25 -0
- package/src/templates/locale/ja/webapp/laravel/07_db_tables.md +19 -0
- package/src/templates/locale/ja/webapp/laravel/08_controller_routes.md +37 -0
- package/src/templates/locale/ja/webapp/symfony/02_stack_and_ops.md +35 -0
- package/src/templates/locale/ja/webapp/symfony/03_project_structure.md +11 -0
- package/src/templates/locale/ja/webapp/symfony/05_auth_and_session.md +25 -0
- package/src/templates/locale/ja/webapp/symfony/07_db_tables.md +25 -0
- package/src/templates/locale/ja/webapp/symfony/08_controller_routes.md +35 -0
- package/src/templates/skills/sdd-flow-close/SKILL.md +53 -0
- package/src/templates/skills/sdd-flow-start/SKILL.md +58 -0
- package/src/analyzers/scan.js +0 -116
- package/src/bin/sdd-forge.js +0 -129
- package/src/engine/directive-parser.js +0 -72
- package/src/engine/init.js +0 -253
- package/src/engine/resolver.js +0 -568
- package/src/projects/add.js +0 -73
- package/src/spec/spec.js +0 -198
- package/src/templates/checks/check-controller-coverage.sh +0 -46
- package/src/templates/checks/check-db-coverage.sh +0 -87
- package/src/templates/checks/check-node-cli-docs.sh +0 -125
- package/src/templates/checks/check-temp-docs.sh +0 -100
- package/src/templates/checks/generate-change-log.sh +0 -142
- package/src/templates/checks/self-review-temp-docs.sh +0 -18
- package/src/templates/locale/ja/node-cli/01_overview.md +0 -23
- package/src/templates/locale/ja/node-cli/02_cli_commands.md +0 -23
- package/src/templates/locale/ja/node-cli/03_configuration.md +0 -23
- package/src/templates/locale/ja/node-cli/04_internal_design.md +0 -30
- package/src/templates/locale/ja/node-cli/05_development.md +0 -49
- package/src/templates/locale/ja/php-mvc/01_architecture.md +0 -23
- package/src/templates/locale/ja/php-mvc/02_stack_and_ops.md +0 -45
- package/src/templates/locale/ja/php-mvc/03_project_structure.md +0 -46
- package/src/templates/locale/ja/php-mvc/04_development.md +0 -69
- package/src/templates/locale/ja/php-mvc/05_auth_and_session.md +0 -48
- package/src/templates/locale/ja/php-mvc/06_database_architecture.md +0 -23
- package/src/templates/locale/ja/php-mvc/07_db_tables.md +0 -31
- package/src/templates/locale/ja/php-mvc/08_controller_routes.md +0 -33
- package/src/templates/locale/ja/php-mvc/09_business_logic.md +0 -27
- package/src/templates/locale/ja/php-mvc/10_batch_and_shell.md +0 -25
- /package/src/{analyzers → docs}/lib/php-array-parser.js +0 -0
- /package/src/{engine → docs/lib}/renderers.js +0 -0
- /package/src/templates/locale/ja/{node-cli → cli/node-cli}/README.md +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# sdd-forge
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Spec-Driven Development tooling for automated documentation generation
|
|
4
4
|
|
|
5
5
|
## 技術スタック
|
|
6
6
|
|
|
@@ -13,19 +13,24 @@
|
|
|
13
13
|
## クイックスタート
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install -g
|
|
17
|
-
|
|
16
|
+
npm install -g sdd-forge
|
|
17
|
+
sdd-forge help
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## ドキュメント
|
|
21
21
|
|
|
22
22
|
| 章 | 概要 |
|
|
23
23
|
|----|------|
|
|
24
|
-
| [01. ツール概要とアーキテクチャ](docs/01_overview.md) |
|
|
25
|
-
| [02. CLI コマンドリファレンス](docs/02_cli_commands.md) | `
|
|
26
|
-
| [
|
|
27
|
-
| [
|
|
28
|
-
| [
|
|
24
|
+
| [01. ツール概要とアーキテクチャ](docs/01_overview.md) | 本章では、sdd-forge がどのような課題を解決するツールであるか、その全体的なアーキテクチャ、および利用を開始するまでの典型的なフローを説明します。ソースコードの自動解析によるドキュメント生成と、Spec-Driven Development ワークフローの両面からツールの役割を理解できます。 |
|
|
25
|
+
| [02. CLI コマンドリファレンス](docs/02_cli_commands.md) | `sdd-forge` は `sdd-forge <コマンド>` 形式のサブコマンド体系を採用しており、ドキュメント生成・品質チェック・SDD ワークフロー支援など 16 種類のコマンドを提供しています。すべてのコマンドで共通して利用できるグローバルオプションとして `--help` および `--project` が用意されています。 |
|
|
26
|
+
| [02. 技術スタックと運用](docs/02_stack_and_ops.md) | 本章では、sdd-forge が動作するために必要な技術スタックと、日常的な運用・デプロイ手順を説明します。Node.js 18 以上を実行環境とする純粋な ES モジュール CLI ツールであり、外部フレームワークや npm 依存パッケージを持たない軽量な構成です。 |
|
|
27
|
+
| [03. 設定とカスタマイズ](docs/03_configuration.md) | sdd-forge は `.sdd-forge/config.json` を中心とした複数の設定ファイルを読み込み、ドキュメント生成の言語・スタイル・AI プロバイダー・プロジェクト登録などを制御します。テンプレートや AI エージェントのコマンドをカスタマイズすることで、さまざまなプロジェクト環境に合わせた柔軟な運用が可能です。 |
|
|
28
|
+
| [03. プロジェクト構成](docs/03_project_structure.md) | 本章では sdd-forge のソースコード構成を解説します。`src/` 配下は `docs`・`specs`・`lib`・`templates` の 4 つの主要ディレクトリに整理されており、それぞれドキュメント生成・仕様管理・共通処理・テンプレートの役割を担っています。 |
|
|
29
|
+
| [04. 開発ガイド](docs/04_development.md) | 本章では、sdd-forge の開発環境セットアップからローカル開発の手順、テスト実行までを説明します。外部依存パッケージがないため `npm install` と `npm link` のみで開発環境を構築でき、テストは Node.js 標準の `node:test` モジュールと `node --test` コマンドで実行します。 |
|
|
30
|
+
| [04. 内部設計](docs/04_internal_design.md) | 本章では sdd-forge の内部構造を解説します。エントリポイント `sdd-forge.js` からサブシステムディスパッチャ(`docs.js` / `spec.js` / `flow.js`)、さらに `commands/` 配下の個別コマンドへと三層構造で委譲が行われ、`src/lib/` の共有ユーティリティが各層から横断的に利用されます。 |
|
|
31
|
+
| [05. CLI コマンドリファレンス](docs/05_commands.md) | `sdd-forge` が提供する 16 のサブコマンドをリファレンス形式でまとめた章です。すべてのコマンドに共通する `--project` および `--help` グローバルオプションを備え、ドキュメント生成系・SDD ワークフロー系・プロジェクト管理系の 3 つの用途に大別されるサブコマンド体系を構成しています。 |
|
|
32
|
+
| [05. 開発・テスト・配布](docs/05_development.md) | 本章では、`npm link` を用いたビルドレスなローカル開発環境の構築手順から、ブランチ運用・コミット規約・リリースフローまで、sdd-forge の開発に参加するために必要な情報をまとめています。外部依存ライブラリを持たない素の ES Modules 構成により、セットアップは最小限の手順で完了します。 |
|
|
33
|
+
| [06. 設定とカスタマイズ](docs/06_config.md) | sdd-forge は `.sdd-forge/config.json` を中心に動作し、プロジェクトタイプ・出力言語・ドキュメントスタイル・AI エージェントなどを一元管理します。`sdd-forge setup` で初期生成された設定ファイルを直接編集することで、ドキュメント生成の挙動やワークフローのマージ戦略などをカスタマイズできます。 |
|
|
29
34
|
|
|
30
35
|
## 開発ワークフロー(SDD)
|
|
31
36
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdd-forge",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
4
|
-
"description": "Spec-Driven Development tooling for
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
|
+
"description": "Spec-Driven Development tooling for automated documentation generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"sdd-forge": "./src/
|
|
7
|
+
"sdd-forge": "./src/sdd-forge.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"src/"
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
"keywords": [
|
|
16
16
|
"sdd",
|
|
17
17
|
"documentation",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
18
|
+
"spec-driven-development",
|
|
19
|
+
"source-analysis",
|
|
20
|
+
"technical-docs"
|
|
21
21
|
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "find tests -name '*.test.js' | xargs node --test"
|
|
24
|
+
},
|
|
22
25
|
"license": "MIT"
|
|
23
26
|
}
|
package/src/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# sdd-forge — Internal Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
sdd-forge は Spec-Driven Development (SDD) のための CLI ツール。
|
|
6
|
+
対象プロジェクトのソースコードを解析し、テンプレートベースのドキュメントを自動生成する。
|
|
7
|
+
|
|
8
|
+
- **Runtime**: Node.js >= 18
|
|
9
|
+
- **Module system**: ES Modules (`"type": "module"`)
|
|
10
|
+
- **External dependencies**: なし(Node.js 組み込み API のみ)
|
|
11
|
+
|
|
12
|
+
## Directory Structure
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
src/
|
|
16
|
+
├── sdd-forge.js # CLI エントリポイント(トップレベルディスパッチャ)
|
|
17
|
+
├── docs.js # docs ディスパッチャ
|
|
18
|
+
├── spec.js # spec ディスパッチャ
|
|
19
|
+
├── flow.js # SDD フロー自動実行(直接実行コマンド)
|
|
20
|
+
├── help.js # コマンド一覧表示
|
|
21
|
+
│
|
|
22
|
+
├── docs/ # ドキュメント生成ドメイン
|
|
23
|
+
│ ├── commands/ # CLI コマンド(各サブコマンドの実装)
|
|
24
|
+
│ ├── lib/ # 共通ロジック(パーサー、レンダラー、リゾルバー等)
|
|
25
|
+
│ └── presets/ # フレームワーク固有の解析・テンプレート拡張
|
|
26
|
+
│ └── webapp/cakephp2/ # CakePHP 2.x 用プリセット
|
|
27
|
+
│
|
|
28
|
+
├── specs/ # 仕様管理ドメイン
|
|
29
|
+
│ └── commands/ # CLI コマンド(spec 初期化、gate チェック)
|
|
30
|
+
│
|
|
31
|
+
├── lib/ # パッケージ全体の共通ユーティリティ
|
|
32
|
+
│ ├── cli.js # repoRoot(), sourceRoot(), parseArgs()
|
|
33
|
+
│ ├── config.js # loadJsonFile(), 設定読み込み
|
|
34
|
+
│ ├── agent.js # AI エージェント抽象化
|
|
35
|
+
│ ├── process.js # プロセス実行ヘルパー
|
|
36
|
+
│ ├── projects.js # プロジェクト管理(登録、解決、デフォルト)
|
|
37
|
+
│ ├── i18n.js # 国際化(メッセージ・UI テキスト)
|
|
38
|
+
│ └── types.js # 型定義・定数
|
|
39
|
+
│
|
|
40
|
+
└── templates/ # 静的データ(npm publish に含まれる)
|
|
41
|
+
├── config.example.json # .sdd-forge/config.json のサンプル
|
|
42
|
+
├── review-checklist.md # レビュー観点チェックリスト
|
|
43
|
+
└── locale/ # 言語別テンプレート・メッセージ
|
|
44
|
+
├── en/ # English
|
|
45
|
+
└── ja/ # 日本語
|
|
46
|
+
├── base/ # 共通章テンプレート(全プロジェクトタイプ共通)
|
|
47
|
+
├── webapp/ # Web アプリ用章テンプレート
|
|
48
|
+
│ └── cakephp2/ # CakePHP 2.x オーバーライド
|
|
49
|
+
├── cli/ # CLI ツール用章テンプレート
|
|
50
|
+
│ └── node-cli/ # Node.js CLI オーバーライド
|
|
51
|
+
├── library/ # ライブラリ用章テンプレート
|
|
52
|
+
├── messages.json # CLI メッセージ
|
|
53
|
+
├── prompts.json # AI プロンプトテンプレート
|
|
54
|
+
├── sections.json # セクション定義
|
|
55
|
+
└── ui.json # UI テキスト
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Command Routing
|
|
59
|
+
|
|
60
|
+
3 段階のディスパッチで CLI コマンドをルーティングする。
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
sdd-forge <cmd> [args]
|
|
64
|
+
│
|
|
65
|
+
├─ sdd-forge.js # 1. プロジェクトコンテキスト解決 + ディスパッチ
|
|
66
|
+
│ ├─ docs.js # 2. docs サブコマンドのルーティング
|
|
67
|
+
│ │ └─ docs/commands/*.js # 3. 実際のコマンド実装
|
|
68
|
+
│ ├─ spec.js # 2. spec サブコマンドのルーティング
|
|
69
|
+
│ │ └─ specs/commands/*.js # 3. 実際のコマンド実装
|
|
70
|
+
│ ├─ flow.js # 2+3. 直接実行(ディスパッチャなし)
|
|
71
|
+
│ └─ help.js # 2+3. 直接実行
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- **ディスパッチャ** (`docs.js`, `spec.js`): サブコマンド名を受け取り、`commands/` 配下のスクリプトに `import()` で委譲する
|
|
75
|
+
- **直接実行コマンド** (`flow.js`, `help.js`): サブコマンドを持たず、引数をそのまま処理する
|
|
76
|
+
|
|
77
|
+
### プロジェクトコンテキスト
|
|
78
|
+
|
|
79
|
+
`sdd-forge.js` は実行時に以下の環境変数を設定する:
|
|
80
|
+
|
|
81
|
+
| 環境変数 | 意味 | 設定元 |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `SDD_SOURCE_ROOT` | 対象プロジェクトのソースコードルート | `projects.js` で解決 |
|
|
84
|
+
| `SDD_WORK_ROOT` | 作業ディレクトリ(`.sdd-forge/`, `docs/` の親) | `projects.js` で解決 |
|
|
85
|
+
|
|
86
|
+
各コマンドは `lib/cli.js` の `sourceRoot()` / `repoRoot()` 経由でこれらを参照する。
|
|
87
|
+
|
|
88
|
+
## Coding Rules
|
|
89
|
+
|
|
90
|
+
### プロジェクト固有情報の埋め込み禁止
|
|
91
|
+
|
|
92
|
+
`src/` 配下のコードおよび `src/templates/` 配下のテンプレートに、特定プロジェクトの情報を直接書いてはならない。
|
|
93
|
+
|
|
94
|
+
- **禁止**: プロジェクト名、ホスト名、ポート番号、コンテナ名、固有 DB 名
|
|
95
|
+
- **許可**: `presets/` 配下のフレームワーク固有ロジック(汎用的な解析パターン)
|
|
96
|
+
- **設定**: プロジェクト固有の値は `.sdd-forge/config.json` で外部化する
|
|
97
|
+
|
|
98
|
+
### 外部依存の禁止
|
|
99
|
+
|
|
100
|
+
Node.js 組み込み API (`fs`, `path`, `child_process`, `url` 等) のみを使用する。
|
|
101
|
+
npm パッケージへの依存を追加しないこと。
|
|
102
|
+
|
|
103
|
+
### フォールバック値の抑制
|
|
104
|
+
|
|
105
|
+
必須の設定値・環境変数が不足している場合は、黙ってデフォルト値で動作させず、エラーメッセージを出力して停止すること。
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
// NG
|
|
109
|
+
const agent = config.agent ?? "claude";
|
|
110
|
+
|
|
111
|
+
// OK
|
|
112
|
+
if (!config.agent) {
|
|
113
|
+
console.error("Error: 'agent' is not configured in config.json");
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### コマンドファイルの構造
|
|
119
|
+
|
|
120
|
+
`commands/` 配下のファイルは以下のパターンに従う:
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
import { repoRoot, parseArgs } from "../../lib/cli.js";
|
|
124
|
+
|
|
125
|
+
function main() {
|
|
126
|
+
const args = process.argv.slice(2);
|
|
127
|
+
const opts = parseArgs(args, { flags: [...], options: [...] });
|
|
128
|
+
|
|
129
|
+
if (opts.help) {
|
|
130
|
+
console.log("Usage: ...");
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 実装
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
main();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- `parseArgs()` で `--help` を処理する
|
|
141
|
+
- 直接実行ガード (`isDirectRun`) が必要なスクリプトは、`docs.js` の `build` パイプラインで `import()` される場合のみ
|
|
142
|
+
|
|
143
|
+
### presets の追加
|
|
144
|
+
|
|
145
|
+
新しいフレームワークプリセットを追加する場合:
|
|
146
|
+
|
|
147
|
+
1. `docs/presets/<type>/<framework>/` ディレクトリを作成
|
|
148
|
+
2. `scanner.js` — フレームワーク固有のスキャン拡張
|
|
149
|
+
3. `resolver.js` — `@data` ディレクティブのデータ解決ロジック
|
|
150
|
+
4. `analyze-*.js` — 個別カテゴリの解析スクリプト(必要に応じて)
|
|
151
|
+
5. `templates/locale/<lang>/<type>/<framework>/` に章テンプレートのオーバーライドを配置
|
|
152
|
+
|
|
153
|
+
### テンプレート継承
|
|
154
|
+
|
|
155
|
+
テンプレートは `base → type → framework` の順で継承される。
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
locale/ja/base/01_overview.md ← 全タイプ共通
|
|
159
|
+
locale/ja/webapp/05_auth_and_session.md ← webapp タイプ共通
|
|
160
|
+
locale/ja/webapp/cakephp2/05_auth_and_session.md ← CakePHP 2.x 固有オーバーライド
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
より具体的なパスにファイルが存在すれば、そちらが優先される。
|
|
164
|
+
|
|
165
|
+
## File Operations
|
|
166
|
+
|
|
167
|
+
- ファイルの削除・リネーム・移動は `git mv` / `git rm` を使用し、履歴を保持する
|
|
168
|
+
- コミットメッセージは英語。形式: `<type>: <subject>`
|
|
169
|
+
- type: `feat`, `fix`, `docs`, `refactor`, `chore`, `test`
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* src/docs/commands/agents.js
|
|
4
|
+
*
|
|
5
|
+
* AGENTS.md を更新する。
|
|
6
|
+
* デフォルト: AI エージェントで analysis.json を要約し PROJECT セクションを生成
|
|
7
|
+
* --template: AI を使わずテンプレートベースで生成
|
|
8
|
+
* --force: SDD + PROJECT + 空の Guidelines で全体を書き直す
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { execFileSync } from "child_process";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { sourceRoot, repoRoot, parseArgs } from "../../lib/cli.js";
|
|
16
|
+
import { loadJsonFile, loadConfig, resolveProjectContext } from "../../lib/config.js";
|
|
17
|
+
|
|
18
|
+
const PKG_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// SDD テンプレート読み込み
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
function loadSddTemplate(lang) {
|
|
25
|
+
for (const l of [lang, "en"]) {
|
|
26
|
+
const p = path.join(PKG_DIR, "templates", "locale", l, "base", "AGENTS.sdd.md");
|
|
27
|
+
if (fs.existsSync(p)) return fs.readFileSync(p, "utf8");
|
|
28
|
+
}
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// AI エージェント呼び出し
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
function loadAgentConfig(cfg, agentName) {
|
|
37
|
+
const providerKey = agentName || cfg.defaultAgent;
|
|
38
|
+
if (!providerKey) {
|
|
39
|
+
throw new Error("No default agent configured. Set 'defaultAgent' in config.json or run 'sdd-forge setup'.");
|
|
40
|
+
}
|
|
41
|
+
const provider = cfg.providers?.[providerKey];
|
|
42
|
+
if (!provider) {
|
|
43
|
+
throw new Error(`Unknown agent provider: ${providerKey}. Available: ${Object.keys(cfg.providers || {}).join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
return provider;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function callAgent(agent, prompt, timeoutMs) {
|
|
49
|
+
const args = Array.isArray(agent.args) ? [...agent.args] : [];
|
|
50
|
+
const resolvedArgs = args.map((a) =>
|
|
51
|
+
typeof a === "string" ? a.replaceAll("{{PROMPT}}", prompt) : a
|
|
52
|
+
);
|
|
53
|
+
const hasToken = args.some((a) => typeof a === "string" && a.includes("{{PROMPT}}"));
|
|
54
|
+
const finalArgs = hasToken ? resolvedArgs : [...resolvedArgs, prompt];
|
|
55
|
+
|
|
56
|
+
const env = { ...process.env };
|
|
57
|
+
delete env.CLAUDECODE;
|
|
58
|
+
|
|
59
|
+
return execFileSync(agent.command, finalArgs, {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
62
|
+
timeout: timeoutMs,
|
|
63
|
+
env,
|
|
64
|
+
}).trim();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// AI 要約プロンプト構築
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
function buildSummaryPrompt(analysis, config, srcRoot) {
|
|
72
|
+
const parts = [];
|
|
73
|
+
|
|
74
|
+
parts.push("以下のソースコード解析データ (analysis.json) を要約し、AGENTS.md の Project Context セクションを生成してください。");
|
|
75
|
+
parts.push("");
|
|
76
|
+
parts.push("## 出力ルール(厳守)");
|
|
77
|
+
parts.push("- <!-- PROJECT:START --> と <!-- PROJECT:END --> タグで囲むこと");
|
|
78
|
+
parts.push("- 最初の行は `<!-- PROJECT:START — managed by sdd-forge. Do not edit manually. -->` とすること");
|
|
79
|
+
parts.push("- 最後の行は `<!-- PROJECT:END -->` とすること");
|
|
80
|
+
parts.push("- `## Project Context` の見出しで始めること");
|
|
81
|
+
parts.push("- AI エージェントがプロジェクトを理解するのに役立つ情報を構造的にまとめること");
|
|
82
|
+
parts.push("- 技術スタック、プロジェクト構造の概要、主要コンポーネント、DB 構成、利用可能なコマンドを含めること");
|
|
83
|
+
parts.push("- マークダウンのテーブルやリストを活用して読みやすくすること");
|
|
84
|
+
parts.push("- 前置き・メタコメンタリーは含めないこと");
|
|
85
|
+
parts.push("");
|
|
86
|
+
|
|
87
|
+
// config info
|
|
88
|
+
if (config.type) {
|
|
89
|
+
parts.push(`## プロジェクト設定`);
|
|
90
|
+
parts.push(`- type: ${config.type}`);
|
|
91
|
+
const ctx = resolveProjectContext(repoRoot());
|
|
92
|
+
if (ctx) parts.push(`- context: ${ctx}`);
|
|
93
|
+
parts.push("");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// package.json scripts
|
|
97
|
+
const pkgPath = path.join(srcRoot, "package.json");
|
|
98
|
+
if (fs.existsSync(pkgPath)) {
|
|
99
|
+
try {
|
|
100
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
101
|
+
if (pkg.scripts) {
|
|
102
|
+
parts.push("## package.json scripts");
|
|
103
|
+
parts.push(JSON.stringify(pkg.scripts, null, 2));
|
|
104
|
+
parts.push("");
|
|
105
|
+
}
|
|
106
|
+
} catch (_) { /* ignore */ }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// analysis.json (truncated)
|
|
110
|
+
parts.push("## analysis.json");
|
|
111
|
+
const analysisJson = JSON.stringify(analysis, null, 2);
|
|
112
|
+
if (analysisJson.length > 30000) {
|
|
113
|
+
parts.push(analysisJson.slice(0, 30000));
|
|
114
|
+
parts.push("... (truncated)");
|
|
115
|
+
} else {
|
|
116
|
+
parts.push(analysisJson);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return parts.join("\n");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// テンプレートベース PROJECT セクション生成
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
function generateProjectSectionTemplate(analysis, config, srcRoot) {
|
|
127
|
+
const lines = [];
|
|
128
|
+
|
|
129
|
+
lines.push("<!-- PROJECT:START — managed by sdd-forge. Do not edit manually. -->");
|
|
130
|
+
lines.push("## Project Context");
|
|
131
|
+
lines.push("");
|
|
132
|
+
lines.push(`- generated_at: ${new Date().toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}`);
|
|
133
|
+
lines.push("");
|
|
134
|
+
|
|
135
|
+
if (config.type) {
|
|
136
|
+
lines.push("### Technology Stack");
|
|
137
|
+
lines.push("");
|
|
138
|
+
lines.push(`- type: ${config.type}`);
|
|
139
|
+
|
|
140
|
+
if (analysis.extras?.composerDeps?.require) {
|
|
141
|
+
const req = analysis.extras.composerDeps.require;
|
|
142
|
+
if (req.php) lines.push(`- PHP: ${req.php}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const pkgPath = path.join(srcRoot, "package.json");
|
|
146
|
+
if (fs.existsSync(pkgPath)) {
|
|
147
|
+
try {
|
|
148
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
149
|
+
if (pkg.engines?.node) lines.push(`- Node.js: ${pkg.engines.node}`);
|
|
150
|
+
} catch (_) { /* ignore */ }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
lines.push("");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const ctrl = analysis.controllers?.summary;
|
|
157
|
+
const mdl = analysis.models?.summary;
|
|
158
|
+
const sh = analysis.shells?.summary;
|
|
159
|
+
const rt = analysis.routes?.summary;
|
|
160
|
+
|
|
161
|
+
if (ctrl || mdl || sh || rt) {
|
|
162
|
+
lines.push("### Structure Summary");
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push("| category | count | details |");
|
|
165
|
+
lines.push("| --- | --- | --- |");
|
|
166
|
+
if (ctrl) lines.push(`| Controllers | ${ctrl.total} | ${ctrl.totalActions} actions |`);
|
|
167
|
+
if (mdl) lines.push(`| Models | ${mdl.total} | FE: ${mdl.feModels || 0}, Logic: ${mdl.logicModels || 0} |`);
|
|
168
|
+
if (sh) lines.push(`| Shells | ${sh.total} | ${sh.withMain || 0} with main() |`);
|
|
169
|
+
if (rt) lines.push(`| Routes | ${rt.total} | ${(rt.controllers || []).length} controllers |`);
|
|
170
|
+
lines.push("");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (mdl?.dbGroups) {
|
|
174
|
+
const groups = Object.entries(mdl.dbGroups).filter(([, v]) => v.length > 0);
|
|
175
|
+
if (groups.length > 0) {
|
|
176
|
+
lines.push("### Database Groups");
|
|
177
|
+
lines.push("");
|
|
178
|
+
lines.push("| connection | models |");
|
|
179
|
+
lines.push("| --- | --- |");
|
|
180
|
+
for (const [name, models] of groups) {
|
|
181
|
+
lines.push(`| ${name} | ${models.length} |`);
|
|
182
|
+
}
|
|
183
|
+
lines.push("");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const pkgPath2 = path.join(srcRoot, "package.json");
|
|
188
|
+
if (fs.existsSync(pkgPath2)) {
|
|
189
|
+
try {
|
|
190
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath2, "utf8"));
|
|
191
|
+
if (pkg.scripts && Object.keys(pkg.scripts).length > 0) {
|
|
192
|
+
lines.push("### Available Commands");
|
|
193
|
+
lines.push("");
|
|
194
|
+
lines.push("| command | script |");
|
|
195
|
+
lines.push("| --- | --- |");
|
|
196
|
+
for (const [name, script] of Object.entries(pkg.scripts)) {
|
|
197
|
+
lines.push(`| \`npm run ${name}\` | ${script.replace(/\|/g, "\\|")} |`);
|
|
198
|
+
}
|
|
199
|
+
lines.push("");
|
|
200
|
+
}
|
|
201
|
+
} catch (_) { /* ignore */ }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
lines.push("<!-- PROJECT:END -->");
|
|
205
|
+
return lines.join("\n");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// AGENTS.md 更新
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
function updateProjectSection(filePath, projectSection) {
|
|
213
|
+
if (!fs.existsSync(filePath)) {
|
|
214
|
+
console.error(`Error: ${filePath} not found. Run 'sdd-forge setup' first.`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
219
|
+
const projectPattern = /<!-- PROJECT:START[^>]*-->[\s\S]*?<!-- PROJECT:END -->/;
|
|
220
|
+
|
|
221
|
+
let updated;
|
|
222
|
+
if (projectPattern.test(content)) {
|
|
223
|
+
updated = content.replace(projectPattern, projectSection);
|
|
224
|
+
} else {
|
|
225
|
+
const sddEndPattern = /<!-- SDD:END -->/;
|
|
226
|
+
if (sddEndPattern.test(content)) {
|
|
227
|
+
updated = content.replace(sddEndPattern, `<!-- SDD:END -->\n\n${projectSection}`);
|
|
228
|
+
} else {
|
|
229
|
+
updated = content.trimEnd() + "\n\n" + projectSection + "\n";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fs.writeFileSync(filePath, updated, "utf8");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function rewriteAgentsMd(filePath, sddSection, projectSection) {
|
|
237
|
+
const parts = [
|
|
238
|
+
sddSection.trim(),
|
|
239
|
+
"",
|
|
240
|
+
projectSection,
|
|
241
|
+
"",
|
|
242
|
+
"## Project Guidelines",
|
|
243
|
+
"",
|
|
244
|
+
"<!-- Add project-specific guidelines here -->",
|
|
245
|
+
"",
|
|
246
|
+
];
|
|
247
|
+
fs.writeFileSync(filePath, parts.join("\n"), "utf8");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
// Main
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
|
|
254
|
+
function main() {
|
|
255
|
+
const args = process.argv.slice(2);
|
|
256
|
+
const opts = parseArgs(args, {
|
|
257
|
+
flags: ["--force", "--template", "--dry-run"],
|
|
258
|
+
options: [],
|
|
259
|
+
defaults: { force: false, template: false, dryRun: false },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (opts.help) {
|
|
263
|
+
console.log("Usage: sdd-forge agents [--force] [--template]");
|
|
264
|
+
console.log("");
|
|
265
|
+
console.log(" analysis.json から AGENTS.md を更新する。");
|
|
266
|
+
console.log(" デフォルトで AI エージェントを使用して PROJECT セクションを要約生成する。");
|
|
267
|
+
console.log("");
|
|
268
|
+
console.log("Options:");
|
|
269
|
+
console.log(" --force AGENTS.md を全体書き直す(SDD + PROJECT + 空の Guidelines)");
|
|
270
|
+
console.log(" --template AI を使わずテンプレートベースで生成する");
|
|
271
|
+
console.log(" --dry-run ファイル書き込みせず生成内容を stdout に出力する");
|
|
272
|
+
process.exit(0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const workRoot = repoRoot();
|
|
276
|
+
const srcRoot = sourceRoot();
|
|
277
|
+
|
|
278
|
+
// Load analysis.json
|
|
279
|
+
const analysisPath = path.join(workRoot, ".sdd-forge", "output", "analysis.json");
|
|
280
|
+
let analysis;
|
|
281
|
+
try {
|
|
282
|
+
analysis = loadJsonFile(analysisPath);
|
|
283
|
+
} catch (err) {
|
|
284
|
+
console.error(`Error: ${analysisPath} not found.`);
|
|
285
|
+
console.error("Run 'sdd-forge scan' first.");
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Load config.json
|
|
290
|
+
let config = {};
|
|
291
|
+
try {
|
|
292
|
+
config = loadJsonFile(path.join(workRoot, ".sdd-forge", "config.json"));
|
|
293
|
+
} catch (_) {
|
|
294
|
+
// config is optional for template mode
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const lang = config.lang || config.output?.default || "en";
|
|
298
|
+
|
|
299
|
+
// Generate PROJECT section
|
|
300
|
+
let projectSection;
|
|
301
|
+
|
|
302
|
+
if (opts.template) {
|
|
303
|
+
projectSection = generateProjectSectionTemplate(analysis, config, srcRoot);
|
|
304
|
+
console.error("[agents] template mode: generating from analysis.json without AI");
|
|
305
|
+
} else {
|
|
306
|
+
// AI mode (default)
|
|
307
|
+
let agent;
|
|
308
|
+
try {
|
|
309
|
+
agent = loadAgentConfig(config);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error(`Error: ${err.message}`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
console.error("[agents] generating PROJECT section with AI...");
|
|
316
|
+
const prompt = buildSummaryPrompt(analysis, config, srcRoot);
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
const result = callAgent(agent, prompt, 180000);
|
|
320
|
+
|
|
321
|
+
// Extract PROJECT section from AI response
|
|
322
|
+
const projectMatch = result.match(/<!-- PROJECT:START[^>]*-->[\s\S]*?<!-- PROJECT:END -->/);
|
|
323
|
+
if (projectMatch) {
|
|
324
|
+
projectSection = projectMatch[0];
|
|
325
|
+
} else {
|
|
326
|
+
// AI didn't wrap in tags — wrap it
|
|
327
|
+
projectSection = [
|
|
328
|
+
"<!-- PROJECT:START — managed by sdd-forge. Do not edit manually. -->",
|
|
329
|
+
result,
|
|
330
|
+
"<!-- PROJECT:END -->",
|
|
331
|
+
].join("\n");
|
|
332
|
+
}
|
|
333
|
+
} catch (err) {
|
|
334
|
+
console.error(`Error: AI agent call failed: ${err.message}`);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
console.error("[agents] AI summary generated.");
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Update AGENTS.md
|
|
342
|
+
const agentsPath = path.join(srcRoot, "AGENTS.md");
|
|
343
|
+
|
|
344
|
+
if (opts.dryRun) {
|
|
345
|
+
console.error("[agents] DRY-RUN: would update " + agentsPath);
|
|
346
|
+
process.stdout.write(projectSection + "\n");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (opts.force) {
|
|
351
|
+
const sddSection = loadSddTemplate(lang);
|
|
352
|
+
if (!sddSection) {
|
|
353
|
+
console.error("Error: SDD template not found.");
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
rewriteAgentsMd(agentsPath, sddSection, projectSection);
|
|
357
|
+
console.log(`[agents] rewrote ${agentsPath}`);
|
|
358
|
+
} else {
|
|
359
|
+
updateProjectSection(agentsPath, projectSection);
|
|
360
|
+
console.log(`[agents] updated PROJECT section in ${agentsPath}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export { main };
|
|
365
|
+
|
|
366
|
+
const isDirectRun = process.argv[1] &&
|
|
367
|
+
path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
|
|
368
|
+
if (isDirectRun) {
|
|
369
|
+
main();
|
|
370
|
+
}
|