spec-runner 1.1.7 → 1.1.9

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 (92) hide show
  1. package/README.md +51 -80
  2. package/bin/spec-runner-installer.js +411 -0
  3. package/install.sh +1 -1
  4. package/package.json +7 -6
  5. package/spec-runner/templates/.claude/agents/code-reviewer.md +69 -0
  6. package/spec-runner/templates/.claude/agents/design-reviewer.md +65 -0
  7. package/spec-runner/templates/.claude/agents/test-runner.md +34 -0
  8. package/spec-runner/templates/.claude/rules/coding.md +106 -0
  9. package/spec-runner/templates/.claude/rules/design-docs.md +63 -0
  10. package/spec-runner/templates/.claude/skills/architecture-definition/SKILL.md +60 -0
  11. package/spec-runner/templates/.claude/skills/architecture-skill-development/SKILL.md +126 -0
  12. package/spec-runner/templates/.claude/skills/commit/SKILL.md +83 -0
  13. package/spec-runner/templates/.claude/skills/design-change/SKILL.md +94 -0
  14. package/spec-runner/templates/.claude/skills/design-change/references//345/275/261/351/237/277/347/257/204/345/233/262/343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +66 -0
  15. package/spec-runner/templates/.claude/skills/design-change/templates/90_ADR/ADR/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +81 -0
  16. package/spec-runner/templates/.claude/skills/existing-project-to-docs/SKILL.md +57 -0
  17. package/spec-runner/templates/.claude/skills/harness-engineering/SKILL.md +100 -0
  18. package/spec-runner/templates/.claude/skills/plugin-development/SKILL.md +173 -0
  19. package/spec-runner/templates/.claude/skills/plugin-development/templates/01_/350/246/201/344/273/266/345/256/232/347/276/251//346/246/202/350/246/201/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +88 -0
  20. package/spec-runner/templates/.claude/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210/90_ADR/ADR/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +81 -0
  21. package/spec-runner/templates/.claude/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210//343/202/267/343/202/271/343/203/206/343/203/240/345/205/250/344/275/223/344/277/257/347/236/260/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +80 -0
  22. package/spec-runner/templates/.claude/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/270/200/350/246/247/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +57 -0
  23. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/aws.md +53 -0
  24. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/database.md +54 -0
  25. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/schema.dbml +25 -0
  26. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/sequence//343/202/267/343/203/274/343/202/261/343/203/263/343/202/271/345/233/263/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +28 -0
  27. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/agent.md +56 -0
  28. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/config.md +47 -0
  29. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/domain.md +67 -0
  30. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/prompts.md +72 -0
  31. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/plugins/skills/{skill_name}/skill.md +53 -0
  32. package/spec-runner/templates/.claude/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/plugins/tools/{tool_name}/tool.md +51 -0
  33. package/spec-runner/templates/.claude/skills/test-driven-development/SKILL.md +211 -0
  34. package/spec-runner/templates/.github/agents/code-reviewer.agent.md +69 -0
  35. package/spec-runner/templates/.github/agents/design-reviewer.agent.md +65 -0
  36. package/spec-runner/templates/.github/agents/test-runner.agent.md +34 -0
  37. package/spec-runner/templates/.github/instructions/coding.instructions.md +105 -0
  38. package/spec-runner/templates/.github/instructions/design-docs.instructions.md +62 -0
  39. package/spec-runner/templates/.github/skills/architecture-definition/SKILL.md +60 -0
  40. package/spec-runner/templates/.github/skills/architecture-skill-development/SKILL.md +126 -0
  41. package/spec-runner/templates/.github/skills/commit/SKILL.md +83 -0
  42. package/spec-runner/templates/.github/skills/design-change/SKILL.md +94 -0
  43. package/spec-runner/templates/.github/skills/design-change/references//345/275/261/351/237/277/347/257/204/345/233/262/343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +66 -0
  44. package/spec-runner/templates/.github/skills/design-change/templates/90_ADR/ADR/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +81 -0
  45. package/spec-runner/templates/.github/skills/existing-project-to-docs/SKILL.md +57 -0
  46. package/spec-runner/templates/.github/skills/harness-engineering/SKILL.md +100 -0
  47. package/spec-runner/templates/.github/skills/plugin-development/SKILL.md +173 -0
  48. package/spec-runner/templates/.github/skills/plugin-development/templates/01_/350/246/201/344/273/266/345/256/232/347/276/251//346/246/202/350/246/201/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +88 -0
  49. package/spec-runner/templates/.github/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210/90_ADR/ADR/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +81 -0
  50. package/spec-runner/templates/.github/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210//343/202/267/343/202/271/343/203/206/343/203/240/345/205/250/344/275/223/344/277/257/347/236/260/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +80 -0
  51. package/spec-runner/templates/.github/skills/plugin-development/templates/02_/346/246/202/350/246/201/350/250/255/350/250/210//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/270/200/350/246/247/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +57 -0
  52. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/aws.md +53 -0
  53. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/database.md +54 -0
  54. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/schema.dbml +25 -0
  55. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/infrastructure/sequence//343/202/267/343/203/274/343/202/261/343/203/263/343/202/271/345/233/263/343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210.md +28 -0
  56. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/agent.md +56 -0
  57. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/config.md +47 -0
  58. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/domain.md +67 -0
  59. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/agents/{agent_name}/prompts.md +72 -0
  60. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/plugins/skills/{skill_name}/skill.md +53 -0
  61. package/spec-runner/templates/.github/skills/plugin-development/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210/src/plugins/tools/{tool_name}/tool.md +51 -0
  62. package/spec-runner/templates/.github/skills/test-driven-development/SKILL.md +211 -0
  63. package/bin/spec-runner.js +0 -270
  64. package/docs/flow.md +0 -72
  65. package/templates/.spec-runner/project.json.example +0 -27
  66. package/templates/.spec-runner/scripts/check.sh +0 -390
  67. package/templates/.spec-runner/scripts/spec-runner-core.sh +0 -289
  68. package/templates/.spec-runner/scripts/uc-next-start.sh +0 -161
  69. package/templates/.spec-runner/spec-runner.sh +0 -29
  70. package/templates/.spec-runner/steps/steps.json +0 -96
  71. package/templates/.spec-runner/steps//343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +0 -58
  72. package/templates/.spec-runner/steps//343/203/211/343/203/241/343/202/244/343/203/263/350/250/255/350/250/210.md +0 -52
  73. package/templates/.spec-runner/steps//344/273/225/346/247/230/347/255/226/345/256/232.md +0 -210
  74. package/templates/.spec-runner/steps//345/210/206/346/236/220.md +0 -106
  75. package/templates/.spec-runner/steps//345/256/237/350/243/205.md +0 -80
  76. package/templates/.spec-runner/steps//345/256/237/350/243/205/350/250/210/347/224/273.md +0 -96
  77. package/templates/.spec-runner/steps//346/206/262/347/253/240.md +0 -95
  78. package/templates/.spec-runner/steps//346/233/226/346/230/247/343/201/225/350/247/243/346/266/210.md +0 -110
  79. package/templates/.spec-runner/templates/UC-N-MMDD-/345/210/244/346/226/255/350/250/230/351/214/262/343/203/206/343/203/263/343/203/227/343/203/254.md +0 -33
  80. package/templates/.spec-runner/templates/UC-N-/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/345/220/215.md +0 -26
  81. package/templates/.spec-runner/templates/phase-locks.json +0 -49
  82. package/templates/.spec-runner/templates//343/203/211/343/203/241/343/202/244/343/203/263/343/203/242/343/203/207/343/203/253.md +0 -21
  83. package/templates/.spec-runner/templates//343/203/246/343/203/223/343/202/255/343/202/277/343/202/271/350/250/200/350/252/236/350/276/236/346/233/270.md +0 -16
  84. package/templates/.spec-runner/templates//346/206/262/347/253/240.md +0 -51
  85. package/templates/.spec-runner/templates//351/233/206/347/264/204.md +0 -46
  86. package/templates/mkdocs-scaffold/docs/index.md +0 -32
  87. package/templates/mkdocs-scaffold/mkdocs.yml +0 -16
  88. package/templates/mkdocs-scaffold/requirements-docs.txt +0 -2
  89. package/templates/skills/uc-k1-work-card-init/SKILL.md +0 -76
  90. package/templates/skills/uc-k2-pre-commit-check/SKILL.md +0 -57
  91. package/templates/skills/uc-k3-spec-impl-diff-review/SKILL.md +0 -57
  92. package/templates/spec-runner-command.md +0 -51
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # spec-runner
2
2
 
3
- フェーズ駆動で設計を飛ばさないようにする仕組み。`npx spec-runner` でプロジェクトに `.spec-runner/` を入れ、**次のステップ** 1 本だけ返すコマンドに従って進める。
3
+ `spec-runner` は、`docs/` を正本にして開発を進める運用ハーネスを、**Claude Code(`.claude/`)** **GitHub Copilot(`.github/`)** に導入するインストーラ。
4
4
 
5
- ---
5
+ 主線は `要件定義 -> 概要設計 -> 詳細設計 -> TDD -> 実装`。rules / agents / skills はその流れを安定運用するために配る。
6
6
 
7
7
  ## インストール
8
8
 
@@ -16,114 +16,85 @@ npx spec-runner
16
16
  curl -sSL https://raw.githubusercontent.com/TEEE88/spec-runner/main/install.sh | bash
17
17
  ```
18
18
 
19
- いずれも、プロジェクト直下に `.spec-runner/` ができる。
19
+ 実行時に **Claude / Copilot / 両方** を選ぶ。既存ファイルは原則上書きしない。
20
20
 
21
- あわせて、**未有効時のみ**プロジェクトルートに次が配置される(Material for MkDocs で `docs/` 配下の設計書をプレビューするため)。
21
+ ## 導入されるもの
22
22
 
23
- - `mkdocs.yml` / `requirements-docs.txt`
24
- - `docs/index.md`(サイトのホーム)
23
+ ### Claude を選んだ場合
25
24
 
26
- `.spec-runner/` がすでにあり **2 回目以降はエラーで止まる** 場合も、**その手前**で上記 MkDocs 用ファイルの不足分だけ補完される(初回導入以前のリポジトリで MkDocs だけ足したいときに便利)。
27
-
28
- ---
29
-
30
- ## 使い方
31
-
32
- 1. プロジェクトルートで次を実行する。
33
-
34
- ```bash
35
- ./.spec-runner/spec-runner.sh 次のステップ --json
36
- ```
37
-
38
- 2. 出力の `command_file` に書いてある `.spec-runner/steps/*.md` を開き、その指示に従って作業する。
39
-
40
- 3. 作業が終わったら、再度 1 を実行する。次のステップが返る。
41
-
42
- AI から使う場合は、`/spec-runner` のように「spec-runner を実行する」と伝えればよい。フェーズやコマンド名を覚える必要はない。
43
-
44
- **Git**: フェーズごとにブランチを切る必要はない。**コミットしたくなったとき**に、AI と `project.json` の命名に沿ってブランチ名・メッセージを相談し、一緒にコミットする運用でよい(詳細は同梱の `docs/flow.md` と `.spec-runner/steps/仕様策定.md`)。
25
+ ```text
26
+ <project-root>/
27
+ └── .claude/
28
+ ├── agents/
29
+ ├── rules/
30
+ └── skills/
31
+ ```
45
32
 
46
- ---
33
+ ### Copilot を選んだ場合
47
34
 
48
- ## フロー(全体像)
35
+ ```text
36
+ <project-root>/
37
+ └── .github/
38
+ ├── instructions/
39
+ ├── agents/
40
+ └── skills/
41
+ ```
49
42
 
50
- 設計書(`docs/01..06`)と UC 仕様(`docs/02_ユースケース仕様/`)をどんな順で作っていくかは `docs/flow.md` にまとめています。
43
+ ### 同梱するベース skill
51
44
 
52
- ## Skills テンプレート(任意)
45
+ - `architecture-definition`: 新規プロジェクトで docs と architecture contract を起こす
46
+ - `existing-project-to-docs`: 既存コードから docs の draft と構造化情報を起こす
47
+ - `architecture-skill-development`: architecture contract から project 専用 skill を育てる
48
+ - `plugin-development`: プラグイン型アーキテクチャ向けの reference workflow
49
+ - `design-change`: 変更要求に対して影響調査 -> ADR -> 設計修正 -> TDD で進める
50
+ - `test-driven-development`: アプリケーションコード向けの TDD を徹底する
51
+ - `harness-engineering`: rules / agents / skills / templates 自体を改善する
53
52
 
54
- - `templates/skills/uc-k1-work-card-init/SKILL.md`(`docs/work.md` 初期化)
55
- - `templates/skills/uc-k2-pre-commit-check/SKILL.md`(コミット前チェック案内)
56
- - `templates/skills/uc-k3-spec-impl-diff-review/SKILL.md`(仕様-実装差分レビュー)
57
- - `npx spec-runner` 実行時に、不足分のみ `.claude/skills/` へ自動コピーされます(既存ファイルは上書きしない)。
53
+ `docs/` や `.spec-runner/` の中身は、導入後にこれらの skill を使ってプロジェクトごとに作る。
58
54
 
59
- ---
55
+ ## 推奨フロー
60
56
 
61
- ## ドキュメントサイト(MkDocs + Material)
57
+ ### 新規プロジェクト
62
58
 
63
- ### `npx spec-runner` したプロジェクト側
59
+ 1. `architecture-definition`
60
+ 2. `architecture-skill-development`
61
+ 3. 生成された project 専用 skill
62
+ 4. `test-driven-development`
64
63
 
65
- 憲章・設計書は `steps.json` どおり `docs/01_憲章/` 〜 `docs/06_API仕様/` に置かれる。`mkdocs.yml` の `docs/` がそのままサイトの文書ルートになるので、**追加コピーなしで**これらの Markdown をナビに載せられる(`nav` で先頭に固定した `index.md` の後ろへ、残りのページが自動で続く)。
64
+ ### 既存プロジェクト
66
65
 
67
- プレビュー起動(Python 3 必須・仮想環境 `.venv-docs/` を使用):
66
+ 1. `existing-project-to-docs`
67
+ 2. `architecture-skill-development`
68
+ 3. `design-change`
69
+ 4. `test-driven-development`
68
70
 
69
- ```bash
70
- python3 -m venv .venv-docs && ./.venv-docs/bin/pip install -q -r requirements-docs.txt && ./.venv-docs/bin/mkdocs serve --dev-addr 127.0.0.1:8000
71
- ```
71
+ ## 上書きインストール
72
72
 
73
- `8000` が使用中のとき:
73
+ 差分がある既存ファイルも置換したい場合:
74
74
 
75
75
  ```bash
76
- python3 -m venv .venv-docs && ./.venv-docs/bin/pip install -q -r requirements-docs.txt && ./.venv-docs/bin/mkdocs serve --dev-addr 127.0.0.1:8001
77
- ```
78
-
79
- ## 導入後にできるもの
80
-
81
- ```
82
- <プロジェクトルート>/
83
- ├── .spec-runner/
84
- │ ├── spec-runner.sh # 入口(次のステップ --json)
85
- │ ├── project.json # 設定(ブランチ命名・必須ドキュメント・テストコマンド等)
86
- │ ├── phase-locks.json # フェーズの通過状態
87
- │ ├── scripts/ # spec-runner-core.sh, check, branch 等
88
- │ ├── steps/ # 憲章・ドメイン設計・仕様策定・曖昧さ解消・テスト設計・実装 等の .md
89
- │ └── templates/ # UC 仕様書ひな形
90
- ├── .claude/commands/spec-runner.md # Claude 用コマンド定義(/spec-runner)
91
- ├── .claude/skills/ # Skills テンプレート(不足分のみ自動配置)
92
- ├── mkdocs.yml # MkDocs(未有効時のみ配置)
93
- ├── requirements-docs.txt # mkdocs / mkdocs-material(未有効時のみ配置)
94
- ├── docs/ # 設計書(01..06)+ work.md + index.md 等。MkDocs の文書ルート
95
- └── (AI は Claude Code 前提)
76
+ SPEC_RUNNER_FORCE=1 npx spec-runner
96
77
  ```
97
78
 
98
- ---
79
+ この場合、差分がある既存ファイルは `.spec-runner/archive/<timestamp>/...` に退避してから置換される。
99
80
 
100
81
  ## 必要環境
101
82
 
102
83
  - Node.js 16+
103
- - jq
104
- - git
105
- - bash 4.0+
106
- - 設計書の MkDocs プレビュー: Python 3(venv + mkdocs コマンドを直接実行)
107
84
 
108
- ---
85
+ ## テンプレートの場所
109
86
 
110
- ## 上書きインストール
111
-
112
- すでに `.spec-runner/` があるときは上書きしない。上書きしたい場合:
87
+ - `spec-runner/templates/.claude/`
88
+ - `spec-runner/templates/.github/`
113
89
 
114
- ```bash
115
- SPEC_RUNNER_FORCE=1 npx spec-runner
116
- ```
90
+ ### 構想メモ
117
91
 
118
- ---
92
+ - `docs/ハーネスエンジニアリング構想.md`
119
93
 
120
94
  ## バージョン運用ルール
121
95
 
122
- - このリポジトリでは、今後 **コミットごとに `package.json` の `version` を更新**する。
123
- - バージョンは原則として SemVer に従い、迷う場合はパッチ(`x.y.Z`)を 1 つ上げる。
124
- - 1コミット内で複数の変更をまとめた場合も、コミット単位で 1 回だけ更新する。
125
-
126
- ---
96
+ - このリポジトリでは **コミットごとに `package.json` の `version` を更新**する
97
+ - バージョンは原則 SemVer に従い、迷う場合はパッチを 1 つ上げる
127
98
 
128
99
  ## ライセンス
129
100
 
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * spec-runner インストーラ(Claude / GitHub Copilot 選択式)
6
+ *
7
+ * docs を正本にした開発運用ハーネスをプロジェクトへ導入する。
8
+ * 現在の配布物は原則次のとおり:
9
+ * - Claude: `./.claude/**`
10
+ * - Copilot: `./.github/**`
11
+ *
12
+ * ポリシー:
13
+ * - 通常実行では「既存があるものは上書きしない」(差分バックアップは FORCE 時のみ)
14
+ * - FORCE 時のみ、差分のある既存を `.spec-runner/archive/<timestamp>/...` に退避して上書き
15
+ */
16
+
17
+ const fs = require("fs");
18
+ const path = require("path");
19
+
20
+ const CWD = process.cwd();
21
+ const PKG_DIR = path.resolve(__dirname, "..");
22
+
23
+ const DEST_CLAUDE_DIR = path.join(CWD, ".claude");
24
+ const DEST_GITHUB_DIR = path.join(CWD, ".github");
25
+
26
+ const FORCE = process.env.SPEC_RUNNER_FORCE === "1";
27
+ const TARGET = (process.env.SPEC_RUNNER_TARGET || "").trim().toLowerCase();
28
+ const MODE = (process.env.SPEC_RUNNER_MODE || "").trim().toLowerCase();
29
+ const ARCH_STATUS = (process.env.SPEC_RUNNER_ARCH_STATUS || "").trim().toLowerCase();
30
+
31
+ const TEMPLATE_ROOT = path.join(PKG_DIR, "spec-runner", "templates");
32
+ const CLAUDE_TEMPLATE_DIR = path.join(TEMPLATE_ROOT, ".claude");
33
+ const COPILOT_TEMPLATE_DIR = path.join(TEMPLATE_ROOT, ".github");
34
+
35
+ function parseArgs(argv) {
36
+ const out = { target: "", mode: "", archStatus: "" };
37
+ for (let i = 0; i < argv.length; i += 1) {
38
+ const a = argv[i];
39
+ if (a === "--target" && i + 1 < argv.length) {
40
+ out.target = String(argv[i + 1] || "").trim().toLowerCase();
41
+ i += 1;
42
+ continue;
43
+ }
44
+ if (a.startsWith("--target=")) {
45
+ out.target = a.slice("--target=".length).trim().toLowerCase();
46
+ continue;
47
+ }
48
+ if (a === "--mode" && i + 1 < argv.length) {
49
+ out.mode = String(argv[i + 1] || "").trim().toLowerCase();
50
+ i += 1;
51
+ continue;
52
+ }
53
+ if (a.startsWith("--mode=")) {
54
+ out.mode = a.slice("--mode=".length).trim().toLowerCase();
55
+ continue;
56
+ }
57
+ if (a === "--arch-status" && i + 1 < argv.length) {
58
+ out.archStatus = String(argv[i + 1] || "").trim().toLowerCase();
59
+ i += 1;
60
+ continue;
61
+ }
62
+ if (a.startsWith("--arch-status=")) {
63
+ out.archStatus = a.slice("--arch-status=".length).trim().toLowerCase();
64
+ continue;
65
+ }
66
+ }
67
+ return out;
68
+ }
69
+
70
+ function exists(p) {
71
+ try {
72
+ fs.accessSync(p);
73
+ return true;
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+
79
+ function ensureDir(p) {
80
+ fs.mkdirSync(p, { recursive: true });
81
+ }
82
+
83
+ function isoTimestampSafe() {
84
+ // 例: 2026-04-02T12:34:56.789Z -> 2026-04-02T12-34-56-789Z
85
+ return new Date().toISOString().replace(/[:.]/g, "-");
86
+ }
87
+
88
+ function readFileText(p) {
89
+ return fs.readFileSync(p, "utf8");
90
+ }
91
+
92
+ function writeFileText(p, content) {
93
+ ensureDir(path.dirname(p));
94
+ fs.writeFileSync(p, content, "utf8");
95
+ }
96
+
97
+ function filesEqual(a, b) {
98
+ const bufA = fs.readFileSync(a);
99
+ const bufB = fs.readFileSync(b);
100
+ return bufA.equals(bufB);
101
+ }
102
+
103
+ function normalizeTarget(t) {
104
+ if (!t) return "";
105
+ const x = String(t).trim().toLowerCase();
106
+ if (x === "claude" || x === "c") return "claude";
107
+ if (x === "copilot" || x === "github" || x === "gh" || x === "g") return "copilot";
108
+ if (x === "both" || x === "all") return "both";
109
+ return "";
110
+ }
111
+
112
+ function isTTY() {
113
+ try {
114
+ return !!process.stdin.isTTY;
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ function promptLine(question) {
121
+ process.stdout.write(question);
122
+ // stdin (fd 0) may be in non-blocking mode (EAGAIN); read from /dev/tty directly
123
+ try {
124
+ const { execSync } = require("child_process");
125
+ const result = execSync('IFS= read -r REPLY < /dev/tty && printf "%s" "$REPLY"', {
126
+ shell: "/bin/sh",
127
+ stdio: ["ignore", "pipe", "inherit"],
128
+ });
129
+ return String(result || "").trim();
130
+ } catch {
131
+ return String(fs.readFileSync(0, "utf8") || "").trim();
132
+ }
133
+ }
134
+
135
+ function promptTargetInteractive() {
136
+ if (!isTTY()) return "claude";
137
+
138
+ const ans = promptLine(
139
+ "インストール先を選んでください:\n" +
140
+ " 1) Claude Code(.claude)\n" +
141
+ " 2) GitHub Copilot(.github)\n" +
142
+ " 3) 両方\n" +
143
+ "選択 [1/2/3] : "
144
+ );
145
+ if (ans === "2") return "copilot";
146
+ if (ans === "3") return "both";
147
+ return "claude";
148
+ }
149
+
150
+ function normalizeMode(t) {
151
+ if (!t) return "";
152
+ const x = String(t).trim().toLowerCase();
153
+ if (x === "new" || x === "n") return "new";
154
+ if (x === "existing" || x === "exist" || x === "e") return "existing";
155
+ return "";
156
+ }
157
+
158
+ function promptModeInteractive() {
159
+ if (!isTTY()) return "new";
160
+
161
+ const ans = promptLine(
162
+ "\nプロジェクトの状態を選んでください:\n" +
163
+ " 1) 新規プロジェクト\n" +
164
+ " 2) 既存プロジェクト\n" +
165
+ "選択 [1/2] : "
166
+ );
167
+ if (ans === "2") return "existing";
168
+ return "new";
169
+ }
170
+
171
+ function normalizeArchStatus(t) {
172
+ if (!t) return "";
173
+ const x = String(t).trim().toLowerCase();
174
+ if (x === "undecided" || x === "u") return "undecided";
175
+ if (x === "decided" || x === "d") return "decided";
176
+ return "";
177
+ }
178
+
179
+ function promptArchStatusInteractive() {
180
+ if (!isTTY()) return "undecided";
181
+
182
+ const ans = promptLine(
183
+ "\nアーキテクチャの状態を選んでください:\n" +
184
+ " 1) 未決定(これから決める)\n" +
185
+ " 2) 既に決まっている\n" +
186
+ "選択 [1/2] : "
187
+ );
188
+ if (ans === "2") return "decided";
189
+ return "undecided";
190
+ }
191
+
192
+ function archivePathFor(destPath, archiveRoot) {
193
+ // destPath は CWD の配下を想定
194
+ const rel = path.relative(CWD, destPath);
195
+ return path.join(archiveRoot, rel);
196
+ }
197
+
198
+ function copyFileWithPolicy(src, dest, archiveRoot) {
199
+ if (!exists(dest)) {
200
+ writeFileText(dest, readFileText(src));
201
+ return { changed: true, overwritten: false, archived: false, destWasMissing: true };
202
+ }
203
+
204
+ if (!FORCE) {
205
+ return { changed: false, overwritten: false, archived: false, destWasMissing: false };
206
+ }
207
+
208
+ if (filesEqual(src, dest)) {
209
+ return { changed: false, overwritten: false, archived: false, destWasMissing: false };
210
+ }
211
+
212
+ // FORCE: 差分がある場合は既存を退避して上書き
213
+ if (archiveRoot) {
214
+ const ap = archivePathFor(dest, archiveRoot);
215
+ ensureDir(path.dirname(ap));
216
+ fs.copyFileSync(dest, ap);
217
+ }
218
+ writeFileText(dest, readFileText(src));
219
+ return { changed: true, overwritten: true, archived: !!archiveRoot, destWasMissing: false };
220
+ }
221
+
222
+ function walkFiles(dir, onFile) {
223
+ if (!exists(dir)) return;
224
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
225
+ const full = path.join(dir, entry.name);
226
+ if (entry.isDirectory()) {
227
+ walkFiles(full, onFile);
228
+ } else if (entry.isFile()) {
229
+ onFile(full);
230
+ }
231
+ }
232
+ }
233
+
234
+ function dirHasFiles(dir) {
235
+ let found = false;
236
+ walkFiles(dir, () => {
237
+ found = true;
238
+ });
239
+ return found;
240
+ }
241
+
242
+ function mirrorTreeTo(destRootDir, templateDir, archiveRoot) {
243
+ if (!exists(templateDir)) {
244
+ throw new Error(`テンプレートが見つかりません: ${templateDir}`);
245
+ }
246
+
247
+ walkFiles(templateDir, (srcFile) => {
248
+ const rel = path.relative(templateDir, srcFile);
249
+ const destFile = path.join(destRootDir, rel);
250
+ copyFileWithPolicy(srcFile, destFile, archiveRoot);
251
+ });
252
+ }
253
+
254
+ function copySkillTree(skillsRoot, destRootDir, archiveRoot) {
255
+ if (!exists(skillsRoot)) return;
256
+
257
+ walkFiles(skillsRoot, (skillFile) => {
258
+ const rel = path.relative(skillsRoot, skillFile);
259
+ const destFile = path.join(destRootDir, "skills", rel);
260
+ copyFileWithPolicy(skillFile, destFile, archiveRoot);
261
+ });
262
+ }
263
+
264
+ function parseYamlPathsFromFrontmatter(yamlText) {
265
+ // 仕様簡易: paths: ["a","b"] のような1行配列を優先抽出
266
+ const m = yamlText.match(/paths:\s*\[(.*?)\]/s);
267
+ if (!m) return null;
268
+ const inner = m[1];
269
+ const strMatches = Array.from(inner.matchAll(/"([^"]+)"|'([^']+)'/g)).map((mm) => mm[1]);
270
+ if (!strMatches.length) return null;
271
+ return strMatches.join(",");
272
+ }
273
+
274
+ function convertRuleToCopilotInstructionMarkdown(ruleMarkdown) {
275
+ // `.claude/rules/*.md` の YAML を `.github/instructions/*.instructions.md` の applyTo に変換
276
+ if (!ruleMarkdown.startsWith("---")) {
277
+ return `---\napplyTo: "**"\n---\n\n${ruleMarkdown}`;
278
+ }
279
+ const parts = ruleMarkdown.split(/^---\s*$/m);
280
+ if (parts.length < 3) {
281
+ return `---\napplyTo: "**"\n---\n\n${ruleMarkdown}`;
282
+ }
283
+ const yamlText = parts[1] ?? "";
284
+ const bodyText = parts.slice(2).join("---").replace(/^\n/, "");
285
+ const applyTo = parseYamlPathsFromFrontmatter(yamlText) ?? "**";
286
+ return `---\napplyTo: "${applyTo}"\n---\n\n${bodyText}`;
287
+ }
288
+
289
+ function installCopilotFromClaudeTemplate(archiveRoot) {
290
+ const rulesRoot = path.join(CLAUDE_TEMPLATE_DIR, "rules");
291
+ const agentsRoot = path.join(CLAUDE_TEMPLATE_DIR, "agents");
292
+
293
+ // rules -> .github/instructions/*.instructions.md
294
+ if (exists(rulesRoot)) {
295
+ walkFiles(rulesRoot, (ruleFile) => {
296
+ if (!ruleFile.endsWith(".md")) return;
297
+ const rel = path.relative(rulesRoot, ruleFile);
298
+ const relDir = path.dirname(rel);
299
+ const base = path.basename(rel, ".md");
300
+ const destDir = path.join(DEST_GITHUB_DIR, "instructions", relDir === "." ? "" : relDir);
301
+ const destFile = path.join(destDir, `${base}.instructions.md`);
302
+ if (exists(destFile) && !FORCE) return;
303
+ if (exists(destFile) && FORCE && archiveRoot) {
304
+ const ap = archivePathFor(destFile, archiveRoot);
305
+ ensureDir(path.dirname(ap));
306
+ fs.copyFileSync(destFile, ap);
307
+ }
308
+ const converted = convertRuleToCopilotInstructionMarkdown(readFileText(ruleFile));
309
+ writeFileText(destFile, converted);
310
+ });
311
+ }
312
+
313
+ // agents -> .github/agents/*.agent.md(中身はそのまま)
314
+ if (exists(agentsRoot)) {
315
+ walkFiles(agentsRoot, (agentFile) => {
316
+ if (!agentFile.endsWith(".md")) return;
317
+ const rel = path.relative(agentsRoot, agentFile);
318
+ const relDir = path.dirname(rel);
319
+ const base = path.basename(rel, ".md");
320
+ const destDir = path.join(DEST_GITHUB_DIR, "agents", relDir === "." ? "" : relDir);
321
+ const destFile = path.join(destDir, `${base}.agent.md`);
322
+ copyFileWithPolicy(agentFile, destFile, archiveRoot);
323
+ });
324
+ }
325
+
326
+ // skills -> .github/skills/**(templates / references を含めて同構造コピー)
327
+ copySkillTree(path.join(CLAUDE_TEMPLATE_DIR, "skills"), DEST_GITHUB_DIR, archiveRoot);
328
+ }
329
+
330
+ function printBanner() {
331
+ console.log("");
332
+ console.log("╔════════════════════════════════════════╗");
333
+ console.log("║ spec-runner インストーラ ║");
334
+ console.log("║ docs正本ハーネスをプロジェクトへ導入 ║");
335
+ console.log("╚════════════════════════════════════════╝");
336
+ console.log("");
337
+ }
338
+
339
+ function printNextSteps(mode, archStatus) {
340
+ console.log("─────────────────────────────────────────");
341
+ console.log("次のステップ:");
342
+ console.log("");
343
+ if (mode === "existing") {
344
+ console.log(" 1. /existing-project-to-docs");
345
+ console.log(" 既存コードから docs の draft と architecture contract を生成してください。");
346
+ console.log("");
347
+ console.log(" 2. /architecture-skill-development");
348
+ console.log(" architecture contract を元に、プロジェクト専用の skill を作成してください。");
349
+ } else if (archStatus === "decided") {
350
+ console.log(" 1. .spec-runner/architecture/architecture.yaml を用意してください。");
351
+ console.log(" (既に決まっているアーキテクチャを記述)");
352
+ console.log("");
353
+ console.log(" 2. /architecture-skill-development");
354
+ console.log(" architecture contract を元に、プロジェクト専用の skill を作成してください。");
355
+ } else {
356
+ console.log(" 1. /architecture-definition");
357
+ console.log(" 対話形式でアーキテクチャを決め、docs と architecture contract を生成してください。");
358
+ console.log("");
359
+ console.log(" 2. /architecture-skill-development");
360
+ console.log(" architecture contract を元に、プロジェクト専用の skill を作成してください。");
361
+ }
362
+ console.log("─────────────────────────────────────────");
363
+ }
364
+
365
+ function main() {
366
+ printBanner();
367
+
368
+ const args = parseArgs(process.argv.slice(2));
369
+ let target = normalizeTarget(args.target) || normalizeTarget(TARGET);
370
+ if (!target) target = promptTargetInteractive();
371
+
372
+ let mode = normalizeMode(args.mode) || normalizeMode(MODE);
373
+ if (!mode) mode = promptModeInteractive();
374
+
375
+ let archStatus = normalizeArchStatus(args.archStatus) || normalizeArchStatus(ARCH_STATUS);
376
+ if (!archStatus && mode === "new") archStatus = promptArchStatusInteractive();
377
+ if (!archStatus) archStatus = "undecided";
378
+
379
+ const ts = FORCE ? isoTimestampSafe() : null;
380
+ const archiveRoot = ts ? path.join(CWD, ".spec-runner", "archive", ts) : null;
381
+
382
+ if (!exists(CLAUDE_TEMPLATE_DIR)) {
383
+ throw new Error(`Claude テンプレートが見つかりません: ${CLAUDE_TEMPLATE_DIR}`);
384
+ }
385
+
386
+ console.log("");
387
+ if (target === "claude" || target === "both") {
388
+ mirrorTreeTo(DEST_CLAUDE_DIR, CLAUDE_TEMPLATE_DIR, archiveRoot);
389
+ }
390
+ if (target === "copilot" || target === "both") {
391
+ ensureDir(DEST_GITHUB_DIR);
392
+ if (dirHasFiles(COPILOT_TEMPLATE_DIR)) {
393
+ mirrorTreeTo(DEST_GITHUB_DIR, COPILOT_TEMPLATE_DIR, archiveRoot);
394
+ const copilotSkillsRoot = path.join(COPILOT_TEMPLATE_DIR, "skills");
395
+ if (!dirHasFiles(copilotSkillsRoot)) {
396
+ copySkillTree(path.join(CLAUDE_TEMPLATE_DIR, "skills"), DEST_GITHUB_DIR, archiveRoot);
397
+ }
398
+ } else {
399
+ installCopilotFromClaudeTemplate(archiveRoot);
400
+ }
401
+ }
402
+
403
+ console.log("");
404
+ if (target === "claude") console.log("完了: .claude/ を導入しました。");
405
+ else if (target === "copilot") console.log("完了: .github/ を導入しました。");
406
+ else console.log("完了: .claude/ と .github/ を導入しました。");
407
+ console.log("");
408
+ printNextSteps(mode, archStatus);
409
+ }
410
+
411
+ main();
package/install.sh CHANGED
@@ -24,7 +24,7 @@ die() { echo -e "${RED}ERROR:${NC} $*" >&2; exit 1; }
24
24
  echo ""
25
25
  echo -e "${BOLD}╔════════════════════════════════════════╗${NC}"
26
26
  echo -e "${BOLD}║ spec-runner インストーラ ║${NC}"
27
- echo -e "${BOLD}║ フェーズ駆動 / 次のステップ方式 ║${NC}"
27
+ echo -e "${BOLD}║ docs正本 / 設計駆動ハーネス導入 ║${NC}"
28
28
  echo -e "${BOLD}╚════════════════════════════════════════╝${NC}"
29
29
  echo ""
30
30
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "spec-runner",
3
- "version": "1.1.7",
4
- "description": "フェーズ駆動で設計先行を強制。npx .spec-runner を展開し、次のステップ .md に従って進める",
3
+ "version": "1.1.9",
4
+ "description": "docs を正本にした開発運用ハーネスを Claude / Copilot に導入する",
5
5
  "license": "MIT",
6
6
  "bin": {
7
- "spec-runner": "bin/spec-runner.js"
7
+ "spec-runner": "bin/spec-runner-installer.js"
8
8
  },
9
9
  "engines": {
10
10
  "node": ">=16.0.0"
@@ -20,13 +20,14 @@
20
20
  "rails",
21
21
  "django",
22
22
  "nextjs",
23
- "spec-kit"
23
+ "spec-kit",
24
+ "docs-as-code",
25
+ "architecture-driven"
24
26
  ],
25
27
  "scripts": {},
26
28
  "files": [
29
+ "spec-runner/",
27
30
  "bin/",
28
- "templates/",
29
- "docs/flow.md",
30
31
  "install.sh",
31
32
  "README.md",
32
33
  "LICENSE"