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.
Files changed (132) hide show
  1. package/README.md +14 -9
  2. package/package.json +9 -6
  3. package/src/README.md +169 -0
  4. package/src/docs/commands/agents.js +370 -0
  5. package/src/docs/commands/changelog.js +252 -0
  6. package/src/{engine/populate.js → docs/commands/data.js} +40 -16
  7. package/src/{projects/setdefault.js → docs/commands/default-project.js} +10 -2
  8. package/src/{forge → docs/commands}/forge.js +138 -20
  9. package/src/docs/commands/init.js +590 -0
  10. package/src/{engine → docs/commands}/readme.js +61 -35
  11. package/src/docs/commands/review.js +106 -0
  12. package/src/docs/commands/scan.js +174 -0
  13. package/src/docs/commands/setup.js +664 -0
  14. package/src/{engine/tfill.js → docs/commands/text.js} +178 -61
  15. package/src/docs/lib/directive-parser.js +181 -0
  16. package/src/docs/lib/resolver-base.js +229 -0
  17. package/src/docs/lib/resolver-factory.js +102 -0
  18. package/src/docs/lib/scanner.js +509 -0
  19. package/src/docs/lib/template-merger.js +257 -0
  20. package/src/docs/presets/registry.js +75 -0
  21. package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-controllers.js +1 -1
  22. package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-extras.js +1 -1
  23. package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-models.js +1 -1
  24. package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-routes.js +1 -1
  25. package/src/{analyzers → docs/presets/webapp/cakephp2}/analyze-shells.js +1 -1
  26. package/src/docs/presets/webapp/cakephp2/resolver.js +328 -0
  27. package/src/docs/presets/webapp/cakephp2/scanner.js +74 -0
  28. package/src/docs/presets/webapp/laravel/analyze-config.js +124 -0
  29. package/src/docs/presets/webapp/laravel/analyze-controllers.js +86 -0
  30. package/src/docs/presets/webapp/laravel/analyze-migrations.js +147 -0
  31. package/src/docs/presets/webapp/laravel/analyze-models.js +173 -0
  32. package/src/docs/presets/webapp/laravel/analyze-routes.js +121 -0
  33. package/src/docs/presets/webapp/laravel/resolver.js +234 -0
  34. package/src/docs/presets/webapp/laravel/scanner.js +104 -0
  35. package/src/docs/presets/webapp/symfony/analyze-config.js +136 -0
  36. package/src/docs/presets/webapp/symfony/analyze-controllers.js +105 -0
  37. package/src/docs/presets/webapp/symfony/analyze-entities.js +152 -0
  38. package/src/docs/presets/webapp/symfony/analyze-migrations.js +149 -0
  39. package/src/docs/presets/webapp/symfony/analyze-routes.js +207 -0
  40. package/src/docs/presets/webapp/symfony/resolver.js +223 -0
  41. package/src/docs/presets/webapp/symfony/scanner.js +104 -0
  42. package/src/docs.js +103 -0
  43. package/src/{flow/flow.js → flow.js} +50 -11
  44. package/src/help.js +42 -31
  45. package/src/lib/agent.js +54 -0
  46. package/src/lib/cli.js +35 -0
  47. package/src/lib/config.js +70 -2
  48. package/src/lib/flow-state.js +56 -0
  49. package/src/lib/i18n.js +137 -0
  50. package/src/{projects → lib}/projects.js +46 -10
  51. package/src/lib/types.js +215 -0
  52. package/src/sdd-forge.js +106 -0
  53. package/src/spec.js +31 -0
  54. package/src/{spec → specs/commands}/gate.js +9 -2
  55. package/src/specs/commands/init.js +271 -0
  56. package/src/templates/config.example.json +31 -0
  57. package/src/templates/locale/en/ui.json +103 -0
  58. package/src/templates/locale/ja/base/01_overview.md +33 -0
  59. package/src/templates/locale/ja/base/02_stack_and_ops.md +33 -0
  60. package/src/templates/locale/ja/base/03_project_structure.md +27 -0
  61. package/src/templates/locale/ja/base/04_development.md +40 -0
  62. package/src/templates/locale/ja/base/AGENTS.sdd.md +84 -0
  63. package/src/templates/locale/ja/cli/05_commands.md +33 -0
  64. package/src/templates/locale/ja/cli/06_config.md +33 -0
  65. package/src/templates/locale/ja/cli/README.md +31 -0
  66. package/src/templates/locale/ja/cli/node-cli/01_overview.md +23 -0
  67. package/src/templates/locale/ja/cli/node-cli/02_cli_commands.md +23 -0
  68. package/src/templates/locale/ja/cli/node-cli/03_configuration.md +23 -0
  69. package/src/templates/locale/ja/cli/node-cli/04_internal_design.md +30 -0
  70. package/src/templates/locale/ja/cli/node-cli/05_development.md +49 -0
  71. package/src/templates/locale/ja/library/05_public_api.md +27 -0
  72. package/src/templates/locale/ja/library/06_usage.md +33 -0
  73. package/src/templates/locale/ja/library/README.md +18 -0
  74. package/src/templates/locale/ja/prompts.json +1 -1
  75. package/src/templates/locale/ja/ui.json +103 -0
  76. package/src/templates/locale/ja/webapp/05_auth_and_session.md +37 -0
  77. package/src/templates/locale/ja/webapp/06_database_architecture.md +33 -0
  78. package/src/templates/locale/ja/webapp/07_db_tables.md +27 -0
  79. package/src/templates/locale/ja/webapp/08_controller_routes.md +41 -0
  80. package/src/templates/locale/ja/webapp/09_business_logic.md +37 -0
  81. package/src/templates/locale/ja/webapp/10_batch_and_shell.md +35 -0
  82. package/src/templates/locale/ja/{php-mvc → webapp}/README.md +2 -2
  83. package/src/templates/locale/ja/webapp/cakephp2/02_stack_and_ops.md +41 -0
  84. package/src/templates/locale/ja/webapp/cakephp2/03_project_structure.md +46 -0
  85. package/src/templates/locale/ja/webapp/cakephp2/04_development.md +58 -0
  86. package/src/templates/locale/ja/webapp/cakephp2/05_auth_and_session.md +22 -0
  87. package/src/templates/locale/ja/webapp/cakephp2/07_db_tables.md +19 -0
  88. package/src/templates/locale/ja/webapp/cakephp2/08_controller_routes.md +11 -0
  89. package/src/templates/locale/ja/webapp/chapters.json +4 -0
  90. package/src/templates/locale/ja/webapp/laravel/02_stack_and_ops.md +35 -0
  91. package/src/templates/locale/ja/webapp/laravel/03_project_structure.md +11 -0
  92. package/src/templates/locale/ja/webapp/laravel/05_auth_and_session.md +25 -0
  93. package/src/templates/locale/ja/webapp/laravel/07_db_tables.md +19 -0
  94. package/src/templates/locale/ja/webapp/laravel/08_controller_routes.md +37 -0
  95. package/src/templates/locale/ja/webapp/symfony/02_stack_and_ops.md +35 -0
  96. package/src/templates/locale/ja/webapp/symfony/03_project_structure.md +11 -0
  97. package/src/templates/locale/ja/webapp/symfony/05_auth_and_session.md +25 -0
  98. package/src/templates/locale/ja/webapp/symfony/07_db_tables.md +25 -0
  99. package/src/templates/locale/ja/webapp/symfony/08_controller_routes.md +35 -0
  100. package/src/templates/skills/sdd-flow-close/SKILL.md +53 -0
  101. package/src/templates/skills/sdd-flow-start/SKILL.md +58 -0
  102. package/src/analyzers/scan.js +0 -116
  103. package/src/bin/sdd-forge.js +0 -129
  104. package/src/engine/directive-parser.js +0 -72
  105. package/src/engine/init.js +0 -253
  106. package/src/engine/resolver.js +0 -568
  107. package/src/projects/add.js +0 -73
  108. package/src/spec/spec.js +0 -198
  109. package/src/templates/checks/check-controller-coverage.sh +0 -46
  110. package/src/templates/checks/check-db-coverage.sh +0 -87
  111. package/src/templates/checks/check-node-cli-docs.sh +0 -125
  112. package/src/templates/checks/check-temp-docs.sh +0 -100
  113. package/src/templates/checks/generate-change-log.sh +0 -142
  114. package/src/templates/checks/self-review-temp-docs.sh +0 -18
  115. package/src/templates/locale/ja/node-cli/01_overview.md +0 -23
  116. package/src/templates/locale/ja/node-cli/02_cli_commands.md +0 -23
  117. package/src/templates/locale/ja/node-cli/03_configuration.md +0 -23
  118. package/src/templates/locale/ja/node-cli/04_internal_design.md +0 -30
  119. package/src/templates/locale/ja/node-cli/05_development.md +0 -49
  120. package/src/templates/locale/ja/php-mvc/01_architecture.md +0 -23
  121. package/src/templates/locale/ja/php-mvc/02_stack_and_ops.md +0 -45
  122. package/src/templates/locale/ja/php-mvc/03_project_structure.md +0 -46
  123. package/src/templates/locale/ja/php-mvc/04_development.md +0 -69
  124. package/src/templates/locale/ja/php-mvc/05_auth_and_session.md +0 -48
  125. package/src/templates/locale/ja/php-mvc/06_database_architecture.md +0 -23
  126. package/src/templates/locale/ja/php-mvc/07_db_tables.md +0 -31
  127. package/src/templates/locale/ja/php-mvc/08_controller_routes.md +0 -33
  128. package/src/templates/locale/ja/php-mvc/09_business_logic.md +0 -27
  129. package/src/templates/locale/ja/php-mvc/10_batch_and_shell.md +0 -25
  130. /package/src/{analyzers → docs}/lib/php-array-parser.js +0 -0
  131. /package/src/{engine → docs/lib}/renderers.js +0 -0
  132. /package/src/templates/locale/ja/{node-cli → cli/node-cli}/README.md +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # {{PROJECT_NAME}}
1
+ # sdd-forge
2
2
 
3
- {{PROJECT_DESCRIPTION}}
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 {{PACKAGE_NAME}}
17
- {{PACKAGE_NAME}} help
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) | `sdd-forge` は、PHP-MVC プロジェクト(CakePHP 等)における「仕様と実装の乖離」および「技術ドキュメントの作成・維持コスト」という課題を解決するための Node.js CLI ツールである。ソースコード静的解析(`scan`)・テンプレート駆動のドキュメント生成(`init` / `populate` / `tfill`)・仕様ゲート管理(`spec` / `gate`)・反復改善ループ(`forge`)を単一パッケージに統合し、Spec-Driven Development(SDD)ワークフローをコマンドラインから一貫して実行できる。 |
25
- | [02. CLI コマンドリファレンス](docs/02_cli_commands.md) | `SCRIPTS` オブジェクトから `scan:all` を含めると 19 コマンド(エントリは 18 だが `scan:all` は別処理)が確認できます。正確な数を数えます。 |
26
- | [03. 設定とカスタマイズ](docs/03_configuration.md) | sdd-forge の動作は `.sdd-forge/config.json` を中心とした複数の JSON 設定ファイルによって制御され、言語・テンプレートタイプ・AIプロバイダー・タイムアウト・テキスト生成挙動など幅広い項目をカスタマイズできる。プロジェクトごとのテンプレート差し替えは `project-overrides.json`、解析結果の表現上書きは `overrides.json` で行い、関心ごとに設定を分離できる構成になっている。 |
27
- | [04. 内部設計](docs/04_internal_design.md) | `src/bin/sdd-forge.js` がサブコマンドを各モジュール(`analyzers/`・`engine/`・`spec/`・`forge/`・`flow/`)へディスパッチし、共通ユーティリティ `lib/` を底辺として解析→生成→改善の方向で一方向に依存が流れる設計になっている。PHPソースを `analyzers/` が `analysis.json` へ変換し、`engine/populate` `engine/tfill` がそのデータをテンプレートと組み合わせて `docs/` へ展開するパイプラインが中心的な処理フローである。 |
28
- | [05. 開発・テスト・配布](docs/05_development.md) | `npm link` を使ったビルド不要のローカル開発環境、外部依存ゼロの Node.js 実装、および `npm version` `npm publish` による npm レジストリへのリリースフローを中心に構成された章である。テストフレームワークは現時点では導入されておらず、動作確認はコマンド直接実行による手動テストで行う。 |
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.2",
4
- "description": "Spec-Driven Development tooling for PHP-MVC documentation generation",
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/bin/sdd-forge.js"
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
- "php",
19
- "cakephp",
20
- "spec-driven-development"
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
+ }