create-einja-app 0.3.1 → 0.3.3

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 (120) hide show
  1. package/README.md +34 -1
  2. package/dist/cli.js +92 -80
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +1 -1
  5. package/templates/default/.changeset/config.json +11 -0
  6. package/templates/default/.claude/hooks/einja/plan-mode-skill-loader.sh +27 -0
  7. package/templates/default/.claude/settings.json +29 -1
  8. package/templates/default/.claude/skills/cli-package-specs/SKILL.md +247 -0
  9. package/templates/default/.einja-sync.json +1 -1
  10. package/templates/default/.env.personal.example +6 -2
  11. package/templates/default/.envrc +5 -0
  12. package/templates/default/.github/release.yml +10 -0
  13. package/templates/default/.github/workflows/changeset-status.yml +60 -0
  14. package/templates/default/.github/workflows/deploy-pr-preview.yml +23 -24
  15. package/templates/default/.github/workflows/deploy-stable-branches.yml +336 -100
  16. package/templates/default/.mcp.json +2 -12
  17. package/templates/default/.serena/project.yml +7 -0
  18. package/templates/default/CLAUDE.md +61 -10
  19. package/templates/default/README.md +22 -10
  20. package/templates/default/apps/admin/package.json +1 -1
  21. package/templates/default/apps/admin/tsconfig.json +2 -1
  22. package/templates/default/apps/web/package.json +1 -1
  23. package/templates/default/apps/web/tsconfig.json +2 -1
  24. package/templates/default/docs/plans/.gitkeep +0 -0
  25. package/templates/default/docs/plans/agile-munching-knuth.md +161 -0
  26. package/templates/default/docs/plans/agile-riding-nova.md +158 -0
  27. package/templates/default/docs/plans/agile-wibbling-dusk.md +91 -0
  28. package/templates/default/docs/plans/ancient-greeting-flamingo-agent-a87e67c.md +221 -0
  29. package/templates/default/docs/plans/ancient-greeting-flamingo-agent-ab73a1c.md +107 -0
  30. package/templates/default/docs/plans/ancient-greeting-flamingo.md +120 -0
  31. package/templates/default/docs/plans/ancient-watching-otter.md +152 -0
  32. package/templates/default/docs/plans/bright-sauteeing-bumblebee.md +30 -0
  33. package/templates/default/docs/plans/bright-stargazing-dawn.md +87 -0
  34. package/templates/default/docs/plans/calm-stirring-bonbon.md +196 -0
  35. package/templates/default/docs/plans/calm-watching-widget.md +111 -0
  36. package/templates/default/docs/plans/cheerful-wiggling-ullman.md +164 -0
  37. package/templates/default/docs/plans/compiled-humming-cherny.md +94 -0
  38. package/templates/default/docs/plans/composed-doodling-mountain.md +362 -0
  39. package/templates/default/docs/plans/dapper-launching-lynx.md +81 -0
  40. package/templates/default/docs/plans/dazzling-foraging-cascade.md +32 -0
  41. package/templates/default/docs/plans/effervescent-munching-kite-agent-ac08baf.md +672 -0
  42. package/templates/default/docs/plans/effervescent-munching-kite-agent-aecc373.md +442 -0
  43. package/templates/default/docs/plans/effervescent-munching-kite.md +263 -0
  44. package/templates/default/docs/plans/enchanted-wiggling-ember-agent-a5befd57d0ca4c7c7.md +177 -0
  45. package/templates/default/docs/plans/enchanted-wiggling-ember.md +170 -0
  46. package/templates/default/docs/plans/federated-questing-kahan.md +47 -0
  47. package/templates/default/docs/plans/fix-orphan-cleaner-review.md +25 -0
  48. package/templates/default/docs/plans/fix-sync-template-variables.md +162 -0
  49. package/templates/default/docs/plans/flickering-pondering-hearth.md +26 -0
  50. package/templates/default/docs/plans/fluttering-snuggling-sprout.md +172 -0
  51. package/templates/default/docs/plans/generic-sleeping-snowglobe-agent-a41d8da.md +179 -0
  52. package/templates/default/docs/plans/generic-sleeping-snowglobe.md +108 -0
  53. package/templates/default/docs/plans/generic-snuggling-pudding.md +57 -0
  54. package/templates/default/docs/plans/glimmering-giggling-sedgewick.md +126 -0
  55. package/templates/default/docs/plans/glittery-swimming-bachman.md +78 -0
  56. package/templates/default/docs/plans/happy-watching-toast.md +56 -0
  57. package/templates/default/docs/plans/harmonic-strolling-nebula.md +210 -0
  58. package/templates/default/docs/plans/idempotent-wiggling-cherny.md +122 -0
  59. package/templates/default/docs/plans/import-alias-refactor.md +75 -0
  60. package/templates/default/docs/plans/lazy-percolating-sloth-agent-abda679.md +346 -0
  61. package/templates/default/docs/plans/lazy-percolating-sloth.md +151 -0
  62. package/templates/default/docs/plans/linked-greeting-llama-agent-a7a6e5b.md +345 -0
  63. package/templates/default/docs/plans/linked-greeting-llama.md +467 -0
  64. package/templates/default/docs/plans/lovely-bubbling-rose.md +80 -0
  65. package/templates/default/docs/plans/optimized-watching-sprout.md +149 -0
  66. package/templates/default/docs/plans/peaceful-beaming-toast-agent-a292da6.md +288 -0
  67. package/templates/default/docs/plans/peaceful-beaming-toast-agent-a819699.md +366 -0
  68. package/templates/default/docs/plans/peaceful-beaming-toast-agent-ac11de2.md +474 -0
  69. package/templates/default/docs/plans/peaceful-beaming-toast.md +345 -0
  70. package/templates/default/docs/plans/purrfect-spinning-hickey-agent-ae6194c.md +300 -0
  71. package/templates/default/docs/plans/purrfect-spinning-hickey-agent-ae6900e.md +444 -0
  72. package/templates/default/docs/plans/purrfect-spinning-hickey.md +361 -0
  73. package/templates/default/docs/plans/recursive-fluttering-mitten.md +176 -0
  74. package/templates/default/docs/plans/recursive-kindling-lemon-agent-a42199e.md +186 -0
  75. package/templates/default/docs/plans/recursive-kindling-lemon.md +36 -0
  76. package/templates/default/docs/plans/seed-migration-tests.md +47 -0
  77. package/templates/default/docs/plans/sprightly-leaping-manatee.md +224 -0
  78. package/templates/default/docs/plans/stateful-wishing-lerdorf.md +161 -0
  79. package/templates/default/docs/plans/streamed-purring-wreath.md +40 -0
  80. package/templates/default/docs/plans/synthetic-percolating-pearl.md +101 -0
  81. package/templates/default/docs/plans/todo-create-einja-app-ux-fix.md +16 -0
  82. package/templates/default/docs/plans/todo-direnv-hang-fix.md +12 -0
  83. package/templates/default/docs/plans/todo-fix-sync-template-variables.md +21 -0
  84. package/templates/default/docs/plans/todo-github-actions-release-workflow.md +34 -0
  85. package/templates/default/docs/plans/todo-issue-spec-rename.md +24 -0
  86. package/templates/default/docs/plans/todo-phase4-marker-update.md +39 -0
  87. package/templates/default/docs/plans/todo-skill-creator-sync.md +23 -0
  88. package/templates/default/docs/plans/todo-skill-creator-upgrade.md +18 -0
  89. package/templates/default/docs/plans/typed-snuggling-parnas-agent-a6f6391.md +476 -0
  90. package/templates/default/docs/plans/typed-snuggling-parnas-agent-adb678b.md +144 -0
  91. package/templates/default/docs/plans/typed-snuggling-parnas.md +84 -0
  92. package/templates/default/docs/plans/velvety-chasing-spark.md +28 -0
  93. package/templates/default/docs/plans/warm-hopping-lighthouse-agent-a30aa4f.md +534 -0
  94. package/templates/default/docs/plans/warm-hopping-lighthouse-agent-a57a278.md +508 -0
  95. package/templates/default/docs/plans/warm-hopping-lighthouse-agent-a90b809.md +421 -0
  96. package/templates/default/docs/plans/warm-hopping-lighthouse.md +199 -0
  97. package/templates/default/docs/plans/wondrous-strolling-crystal-agent-a0615fc.md +215 -0
  98. package/templates/default/docs/plans/wondrous-strolling-crystal.md +182 -0
  99. package/templates/default/docs/plans/zesty-roaming-steele.md +74 -0
  100. package/templates/default/docs/verification-test.md +2 -0
  101. package/templates/default/gitignore +9 -1
  102. package/templates/default/package.json +6 -2
  103. package/templates/default/packages/admin-ui/package.json +1 -1
  104. package/templates/default/packages/server-core/tsconfig.json +6 -1
  105. package/templates/default/pnpm-lock.yaml +823 -57
  106. package/templates/default/scripts/ensure-serena.sh +75 -0
  107. package/templates/default/scripts/env-rotate-secrets.ts +66 -6
  108. package/templates/default/scripts/init-github.ts +363 -0
  109. package/templates/default/scripts/init.sh +11 -5
  110. package/templates/default/scripts/lib/worktree-config.ts +64 -0
  111. package/templates/default/scripts/setup-dev.ts +16 -1
  112. package/templates/default/scripts/stop-serena.sh +25 -0
  113. package/templates/default/scripts/worktree/dev.ts +2 -2
  114. package/templates/default/.claude/skills/create-einja-app-release/SKILL.md +0 -186
  115. package/templates/default/.claude/skills/dev-cli-release/SKILL.md +0 -173
  116. package/templates/default/.cursor/commands/spec-create.md +0 -227
  117. package/templates/default/.cursor/commands/task-exec.md +0 -287
  118. package/templates/default/.cursor/commands/update-docs-by-task-specs.md +0 -448
  119. /package/templates/default/scripts/{cli-template-update.ts → _cli-template-update.ts} +0 -0
  120. /package/templates/default/scripts/{template-update.ts → _template-update.ts} +0 -0
@@ -0,0 +1,345 @@
1
+ # CLI関係性ドキュメント追記 + init/sync ギャップ修正
2
+
3
+ ## Context
4
+
5
+ `create-einja-app` と `@einja/dev-cli` の関係性・利用シーンがわかりにくい。
6
+ `packages/cli/README.md` に既に比較テーブル(L20-31)があるので、ここにmermaidシーケンス図を追記して利用シーンを可視化する。
7
+
8
+ 併せて、`einja init` のファイルデプロイギャップも修正する。現在 init は `.claude/`, `docs/einja/steering/`, `docs/einja/templates/`, `CLAUDE.md`, `.mcp.json`, symlinks のみをコピーしており、`scripts/`, `.envrc`, `.vscode/settings.json`, `docs/einja/instructions/`, `docs/einja/example/` がデプロイされない。
9
+
10
+ ---
11
+
12
+ ## Part 1: ドキュメント追記
13
+
14
+ ### 追記先
15
+
16
+ `packages/cli/README.md` L31 `> **ポイント**: ...` の直後に新しいサブセクション `### 利用シーンのフロー` として追記。
17
+
18
+ ### 追記内容
19
+
20
+ #### シナリオ1: ゼロから新規プロジェクト作成
21
+
22
+ ```mermaid
23
+ sequenceDiagram
24
+ participant U as ユーザー
25
+ participant C as create-einja-app
26
+ participant D as @einja/dev-cli
27
+
28
+ U->>C: npx create-einja-app my-project
29
+ activate C
30
+ C->>C: 対話プロンプト(名前・認証・ツール)
31
+ C->>C: テンプレート展開<br/>apps/, packages/, docker-compose,<br/>package.json, tsconfig, turbo.json...
32
+ C->>C: git init + pnpm install
33
+ C->>D: npx @einja/dev-cli init --force --no-backup
34
+ activate D
35
+ D->>D: .claude/ 生成
36
+ D->>D: docs/einja/ コピー
37
+ D->>D: CLAUDE.md 生成
38
+ D->>D: .mcp.json セットアップ
39
+ D->>D: symlinks 作成
40
+ D->>D: 依存関係インストール
41
+ D-->>C: 完了
42
+ deactivate D
43
+ C-->>U: プロジェクト作成完了
44
+ deactivate C
45
+ ```
46
+
47
+ #### シナリオ2: テンプレート更新の取り込み
48
+
49
+ ```mermaid
50
+ sequenceDiagram
51
+ participant U as ユーザー
52
+ participant C as create-einja-app
53
+ participant D as @einja/dev-cli
54
+
55
+ Note over U: CLIバージョンアップ後
56
+
57
+ U->>C: npx create-einja-app sync
58
+ activate C
59
+ C->>C: アプリ設定を差分マージ<br/>turbo.json, biome.json,<br/>docker-compose, .github/ 等
60
+ C-->>U: アプリ設定が最新に
61
+ deactivate C
62
+
63
+ U->>D: npx @einja/dev-cli sync
64
+ activate D
65
+ D->>D: AI環境を差分マージ<br/>.claude/, docs/einja/,<br/>CLAUDE.md, .mcp.json 等
66
+ D-->>U: AI環境が最新に
67
+ deactivate D
68
+
69
+ Note over C,D: 管轄が分離しているため順不同・独立
70
+ ```
71
+
72
+ #### シナリオ3: 既存プロジェクトに新規導入
73
+
74
+ ```mermaid
75
+ sequenceDiagram
76
+ participant U as ユーザー
77
+ participant D as @einja/dev-cli
78
+ participant C as create-einja-app
79
+
80
+ Note over U: 既にコードがあるプロジェクト
81
+
82
+ U->>D: npx @einja/dev-cli init
83
+ activate D
84
+ D->>D: .claude/ 生成
85
+ D->>D: docs/einja/ コピー
86
+ D->>D: CLAUDE.md 生成
87
+ D->>D: .mcp.json マージ(既存設定を保持)
88
+ D->>D: 依存関係チェック
89
+ D-->>U: AI開発環境セットアップ完了
90
+ deactivate D
91
+
92
+ alt アプリ設定も部分導入したい場合
93
+ U->>C: npx create-einja-app sync<br/>--categories tools,env,git
94
+ activate C
95
+ C->>C: 選択したカテゴリのみマージ<br/>biome.json, .envrc, .gitignore
96
+ C-->>U: 部分導入完了
97
+ deactivate C
98
+ end
99
+ ```
100
+
101
+ #### シナリオ4: 導入済みプロジェクトの更新
102
+
103
+ シナリオ2と同じ。`dev-cli sync` と `create-einja-app sync` を必要に応じて実行。
104
+
105
+ ---
106
+
107
+ ## Part 2: init/sync ギャップ修正
108
+
109
+ ### 2-1. `init.ts` に不足コピーステップを追加
110
+
111
+ 現在の init ステップ(`packages/cli/src/commands/init.ts`):
112
+
113
+ ```
114
+ 4: .claude 生成
115
+ 5: docs/einja/templates/ コピー
116
+ 6: docs/einja/steering/ コピー
117
+ 7: CLAUDE.md 生成
118
+ 8: symlinks 作成
119
+ 9: .mcp.json セットアップ
120
+ 10: 依存関係チェック
121
+ ```
122
+
123
+ 以下をステップ6の直後(ステップ7の前)に追加:
124
+
125
+ | 追加対象 | プリセット内パス | ターゲットパス | 追加位置 |
126
+ |---------|----------------|-------------|---------|
127
+ | instructions/ | `docs/einja/instructions/` | `docs/einja/instructions/` | 6A |
128
+ | example/ | `docs/einja/example/` | `docs/einja/example/` | 6B |
129
+ | scripts/ | `scripts/` | `scripts/` | 6C |
130
+ | .envrc | `.envrc` | `.envrc` | 6D |
131
+ | .vscode/ | `.vscode/settings.json` | `.vscode/settings.json` | 6E |
132
+
133
+ #### `merger.ts` に追加する関数
134
+
135
+ 既存パターン(`copySteeringDocs`)に合わせた設計:
136
+
137
+ ```typescript
138
+ // merger.ts に追加
139
+
140
+ /**
141
+ * プリセットのサブディレクトリをコピー
142
+ * @param targetPath - コピー先のパス
143
+ * @param presetSubPath - プリセット内の相対パス(例: "scripts", "docs/einja/instructions")
144
+ */
145
+ export async function copyPresetDirectory(
146
+ targetPath: string,
147
+ presetSubPath: string
148
+ ): Promise<void> {
149
+ const presetPath = getPresetPath("default");
150
+ const srcPath = path.join(presetPath, presetSubPath);
151
+
152
+ if (!(await fs.pathExists(srcPath))) {
153
+ return;
154
+ }
155
+
156
+ await fs.ensureDir(targetPath);
157
+ await fs.copy(srcPath, targetPath);
158
+ }
159
+
160
+ /**
161
+ * プリセットの単一ファイルをコピー
162
+ * @param targetPath - コピー先のファイルパス
163
+ * @param presetSubPath - プリセット内の相対パス(例: ".envrc")
164
+ */
165
+ export async function copyPresetFile(
166
+ targetPath: string,
167
+ presetSubPath: string
168
+ ): Promise<void> {
169
+ const presetPath = getPresetPath("default");
170
+ const srcPath = path.join(presetPath, presetSubPath);
171
+
172
+ if (!(await fs.pathExists(srcPath))) {
173
+ return;
174
+ }
175
+
176
+ await fs.ensureDir(path.dirname(targetPath));
177
+ await fs.copy(srcPath, targetPath);
178
+ }
179
+ ```
180
+
181
+ `init.ts` 変更箇所:
182
+ - import に `copyPresetDirectory`, `copyPresetFile` を追加
183
+ - L26-28 に変数定義追加: `instructionsDir`, `exampleDir`, `scriptsDir`
184
+ - L125 の直後(ステップ6の後)に5つのコピーステップを追加
185
+ - L229-234(完了メッセージ)に新しいディレクトリを追記
186
+ - L45-58(ドライランメッセージ)にも追記
187
+
188
+ ### 2-2. `file-filter.ts` と `category-validator.ts` に scripts カテゴリ追加
189
+
190
+ **file-filter.ts** L10-18:
191
+ ```typescript
192
+ const CATEGORY_MAPPING: Record<string, string> = {
193
+ commands: ".claude/commands/einja",
194
+ agents: ".claude/agents/einja",
195
+ skills: ".claude/skills",
196
+ hooks: ".claude/hooks",
197
+ docs: "docs/einja",
198
+ scripts: "scripts", // ← 追加
199
+ env: ".",
200
+ tools: ".vscode",
201
+ };
202
+ ```
203
+
204
+ **category-validator.ts** L9:
205
+ ```typescript
206
+ export const VALID_CATEGORIES = ["commands", "agents", "skills", "hooks", "docs", "scripts", "env", "tools"] as const;
207
+ ```
208
+
209
+ **category-validator.ts** L19-27 `CATEGORY_DESCRIPTIONS` にも追加:
210
+ ```typescript
211
+ scripts: "ユーティリティスクリプト (scripts/)",
212
+ ```
213
+
214
+ **安全性**: orphan cleaner はメタデータに記録された(=過去にsyncで配布された)ファイルのみを対象とする。プロジェクト固有スクリプトは `_` プレフィックスで保護でき、かつメタデータに存在しないので orphan cleaner の影響を受けない。
215
+
216
+ ### 2-3. `scripts/worktree/dev.ts` の packages/config 依存除去
217
+
218
+ `scripts/worktree/dev.ts` L14-15 が `../../packages/config/src/` をimportしている。他プロジェクトには packages/config が存在しないため動作しない。
219
+
220
+ **方針**: `scripts/lib/worktree-config.ts` を新規作成し、型定義+ローダーをインライン化(zod非依存)。
221
+
222
+ `loadWorktreeConfig()` の実体はシンプル:
223
+ 1. `worktree.config.json` を読む
224
+ 2. あれば JSON parse して返す
225
+ 3. なければデフォルト値(web:3000, postgres:25432)を返す
226
+
227
+ zodバリデーションは開発ツールとしてはnice-to-have。ロジックが40行程度で、設定変更頻度も極めて低いため二重管理リスクは低い。
228
+
229
+ **新規ファイル**: `scripts/lib/worktree-config.ts`
230
+
231
+ ```typescript
232
+ import fs from "node:fs";
233
+ import path from "node:path";
234
+
235
+ export interface AppConfig {
236
+ id: string;
237
+ portRangeStart: number;
238
+ rangeSize: number;
239
+ }
240
+
241
+ export interface PostgresConfig {
242
+ port: number;
243
+ containerName: string;
244
+ }
245
+
246
+ export interface WorktreeConfig {
247
+ schemaVersion: number;
248
+ postgres: PostgresConfig;
249
+ apps: AppConfig[];
250
+ }
251
+
252
+ const defaultWorktreeConfig: WorktreeConfig = {
253
+ schemaVersion: 1,
254
+ postgres: { port: 25432, containerName: "einja-management-postgres" },
255
+ apps: [{ id: "web", portRangeStart: 3000, rangeSize: 1000 }],
256
+ };
257
+
258
+ function findProjectRoot(startDir: string = process.cwd()): string | null {
259
+ let currentDir = startDir;
260
+ while (currentDir !== path.dirname(currentDir)) {
261
+ if (fs.existsSync(path.join(currentDir, "package.json"))) {
262
+ return currentDir;
263
+ }
264
+ currentDir = path.dirname(currentDir);
265
+ }
266
+ return null;
267
+ }
268
+
269
+ export function loadWorktreeConfig(projectRoot?: string): WorktreeConfig {
270
+ const root = projectRoot ?? findProjectRoot();
271
+ if (!root) return defaultWorktreeConfig;
272
+
273
+ const configPath = path.join(root, "worktree.config.json");
274
+ if (!fs.existsSync(configPath)) return defaultWorktreeConfig;
275
+
276
+ try {
277
+ const raw = JSON.parse(fs.readFileSync(configPath, "utf-8"));
278
+ return {
279
+ schemaVersion: raw.schemaVersion ?? 1,
280
+ postgres: {
281
+ port: typeof raw.postgres?.port === "number" ? raw.postgres.port : 25432,
282
+ containerName: typeof raw.postgres?.containerName === "string"
283
+ ? raw.postgres.containerName : "einja-management-postgres",
284
+ },
285
+ apps: Array.isArray(raw.apps)
286
+ ? raw.apps.filter((a: unknown) =>
287
+ typeof a === "object" && a !== null && "id" in a && "portRangeStart" in a
288
+ )
289
+ : defaultWorktreeConfig.apps,
290
+ };
291
+ } catch {
292
+ console.warn("worktree.config.json の読み込みに失敗。デフォルト設定を使用します。");
293
+ return defaultWorktreeConfig;
294
+ }
295
+ }
296
+ ```
297
+
298
+ **`scripts/worktree/dev.ts` の変更**: L14-15 のimportパスを変更
299
+
300
+ ```typescript
301
+ // Before:
302
+ import type { AppConfig, WorktreeConfig } from "../../packages/config/src/worktree-config.js";
303
+ import { loadWorktreeConfig } from "../../packages/config/src/worktree-config-loader.js";
304
+
305
+ // After:
306
+ import type { AppConfig, WorktreeConfig } from "../lib/worktree-config.js";
307
+ import { loadWorktreeConfig } from "../lib/worktree-config.js";
308
+ ```
309
+
310
+ ### 2-4. README.md・sync ヘルプに scripts カテゴリ追記
311
+
312
+ **packages/cli/README.md** L93-99:
313
+ ```
314
+ - `scripts` - ユーティリティスクリプト ← 追加
315
+ ```
316
+
317
+ **packages/cli/src/commands/sync.ts**: ヘルプテキスト(Commander定義側)に scripts を追記(該当箇所は `cli.ts` のコマンド定義)。
318
+
319
+ ---
320
+
321
+ ## 対象ファイル
322
+
323
+ | ファイル | 変更内容 |
324
+ |---------|---------|
325
+ | `packages/cli/README.md` | シーケンス図追記(L31の後) + scriptsカテゴリ追記(L99) |
326
+ | `packages/cli/src/commands/init.ts` | 不足コピーステップ5つ追加(L125の後) + 完了メッセージ更新 |
327
+ | `packages/cli/src/lib/merger.ts` | `copyPresetDirectory()` + `copyPresetFile()` 追加 |
328
+ | `packages/cli/src/lib/sync/file-filter.ts` | CATEGORY_MAPPING に `scripts: "scripts"` 追加 |
329
+ | `packages/cli/src/lib/sync/category-validator.ts` | VALID_CATEGORIES に `"scripts"` 追加 |
330
+ | `packages/cli/src/cli.ts` | sync コマンドのヘルプにscripts追記 |
331
+ | `scripts/worktree/dev.ts` | import パスを `../lib/worktree-config.js` に変更 |
332
+ | `scripts/lib/worktree-config.ts` | **新規** — 型定義+ローダー(zod非依存、約60行) |
333
+ | `docs/plans/cli-relationship.md` | **削除**(前回プランモード中に誤作成) |
334
+
335
+ ---
336
+
337
+ ## 検証
338
+
339
+ 1. `pnpm --filter @einja/dev-cli build` 成功
340
+ 2. `pnpm --filter @einja/dev-cli test` 通過
341
+ 3. GitHub で README.md の mermaid 図がレンダリングされること(push後にPRで確認)
342
+ 4. 空ディレクトリで `npx @einja/dev-cli init` → scripts/, .envrc, .vscode/, docs/einja/instructions/, docs/einja/example/ が生成されること
343
+ 5. `einja sync --only scripts` が動作すること
344
+ 6. `tsx scripts/worktree/dev.ts --status` が packages/config なしで動作すること
345
+ 7. category-validator のテストが通ること(新カテゴリ追加反映)
@@ -0,0 +1,300 @@
1
+ # SKILL.md 環境変数管理フロー検証レポート
2
+
3
+ ## 調査概要
4
+
5
+ `.claude/skills/einja-infra-maintenance/SKILL.md` の環境変数管理フローが「自動検知→自動修正→やむを得ない場合のみ人間に操作を求める」という設計になっているか検証。
6
+
7
+ ## 調査対象ファイル
8
+
9
+ 1. `.claude/skills/einja-infra-maintenance/SKILL.md` - 全文
10
+ 2. `docs/einja/instructions/environment-setup.md` - 環境変数セットアップ手順
11
+ 3. `docs/einja/instructions/deployment-setup.md` - デプロイセットアップ手順
12
+ 4. `docs/einja/steering/infrastructure/environment-variables.md` - 環境変数設計方針
13
+ 5. `docs/einja/steering/infrastructure/deployment.md` - デプロイメント設計方針
14
+ 6. `scripts/setup-dev.ts` - 自動セットアップスクリプト
15
+ 7. `scripts/env.ts` - 環境変数対話式ウィザード
16
+ 8. `package.json` - dev:setup の定義確認
17
+
18
+ ## 全環境変数・トークンの自動化分類
19
+
20
+ ### 分類基準
21
+
22
+ - **A: 完全自動**: Claude Codeが検知→CLI/APIで自動取得・設定可能(人間操作不要)
23
+ - **B: 半自動**: Claude Codeが検知→一部自動処理可能だが、値の入力や確認で人間が必要
24
+ - **C: 手動のみ**: Claude Codeでは対応不可、人間のGUI操作やブラウザアクセスが必須
25
+ - **D: 未対応**: 現在のSKILL.mdで検知・対処フローが定義されていない
26
+
27
+ ---
28
+
29
+ ## 検証結果一覧
30
+
31
+ ### 1. ローカル環境変数ファイル
32
+
33
+ | ファイル | 検知 | 修正フロー | 分類 | 理由 |
34
+ |---------|------|----------|------|------|
35
+ | `.env.keys` | ✅ Phase 1 | ⚠️ AskUserQuestion | **B** | 検知可能。修正は「メインworktreeからコピー or 手動配置」を人間に選択させる(SKILL.md L143) |
36
+ | `.env.local` | ✅ Phase 1 | ⚠️ 手動編集案内 | **B** | 検知可能。暗号化済みのため復号→編集→再暗号化の手順を案内(カテゴリ2) |
37
+ | `.env` | ✅ Phase 1 | ✅ 自動再生成 | **A** | `pnpm dev:setup` で `.env.local` から自動復号生成(scripts/setup-dev.ts L222-233) |
38
+ | `.env.personal` | ✅ Phase 1 | ⚠️ 値入力必須 | **B** | 検知可能。値は人間がAskUserQuestionで入力(SKILL.md L168-178) |
39
+ | `.env.develop` | ✅ Phase 1 | ⚠️ 手動編集案内 | **B** | 検知可能。暗号化済みのため復号→編集→再暗号化の手順を案内 |
40
+ | `.env.staging` | ✅ Phase 1 | ⚠️ 手動編集案内 | **B** | 同上 |
41
+ | `.env.production` | ✅ Phase 1 | ⚠️ 手動編集案内 | **B** | 同上 |
42
+ | `.env.preview` | ✅ Phase 1 | ⚠️ 手動編集案内 | **B** | 同上 |
43
+
44
+ **問題点**: `.env.keys` 不在時に「メインworktreeから自動コピー」できるのに、わざわざ人間に選択させている(setup-dev.ts L73-90で自動コピー実装済み)
45
+
46
+ ---
47
+
48
+ ### 2. 個人トークン(.env.personal内)
49
+
50
+ | トークン | 検知 | 修正フロー | 分類 | 理由 |
51
+ |---------|------|----------|------|------|
52
+ | `GITHUB_TOKEN` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | 検知可能(SKILL.md L168)。値の有効性検証は `gh auth status` で可能だが、現状は存在確認のみ |
53
+ | `VERCEL_TOKEN` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | 検知可能(SKILL.md L169)。値の有効性検証は `vercel whoami` で可能だが、現状は存在確認のみ |
54
+ | `NEON_API_KEY` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | 検知可能(SKILL.md L170)。値の有効性検証は `neonctl projects list --api-key $NEON_API_KEY` で可能だが、現状は存在確認のみ |
55
+
56
+ **問題点**: Phase 1の検知で「値の正当性」を検証していない。トークンが期限切れ・無効でも検知できない。
57
+
58
+ ---
59
+
60
+ ### 3. GitHub Secrets(全10個)
61
+
62
+ | Secret | 検知 | 修正フロー | 分類 | 理由 |
63
+ |--------|------|----------|------|------|
64
+ | `DOTENV_PRIVATE_KEY_PREVIEW` | ✅ `gh secret list` | ✅ 自動抽出・設定 | **A** | 一括設定(SKILL.md L340-350)で `.env.keys` から自動抽出→設定可能 |
65
+ | `DOTENV_PRIVATE_KEY_PRODUCTION` | ✅ `gh secret list` | ✅ 自動抽出・設定 | **A** | 同上 |
66
+ | `DOTENV_PRIVATE_KEY_DEVELOP` | ✅ `gh secret list` | ✅ 自動抽出・設定 | **A** | 同上 |
67
+ | `DOTENV_PRIVATE_KEY_STAGING` | ✅ `gh secret list` | ✅ 自動抽出・設定 | **A** | 同上 |
68
+ | `VERCEL_TOKEN` | ✅ `gh secret list` | ⚠️ 値入力必須 | **B** | 検知可能。値は人間がAskUserQuestionで入力(SKILL.md L352-365) |
69
+ | `VERCEL_ORG_ID` | ✅ `gh secret list` | ⚠️ 値入力必須 | **B** | 同上 |
70
+ | `VERCEL_PROJECT_ID_WEB` | ✅ `gh secret list` | ⚠️ 値入力必須 | **B** | 同上 |
71
+ | `VERCEL_PROJECT_ID_ADMIN` | ✅ `gh secret list` | ⚠️ 値入力必須 | **B** | 同上 |
72
+ | `TURBO_TOKEN` | ✅ `gh secret list` | ⚠️ 値入力必須 | **B** | 検知可能。値は人間がAskUserQuestionで入力(SKILL.md L367-383) |
73
+ | `TURBO_TEAM` | ✅ `gh secret list` | ✅ 自動取得 | **A** | `.turbo/config.json` から自動取得可能(SKILL.md L373-377) |
74
+
75
+ **検知の限界**: `gh secret list` は存在確認のみで、**値が正しいか**は検証不可(GitHub APIの制限)
76
+
77
+ ---
78
+
79
+ ### 4. Neon環境変数(.env.preview内)
80
+
81
+ | 変数 | 検知 | 修正フロー | 分類 | 理由 |
82
+ |-----|------|----------|------|------|
83
+ | `NEON_PROJECT_ID` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | `.env.preview` 復号で検知可能。値は人間が入力(deployment-setup.md L170-183) |
84
+ | `NEON_API_KEY` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | 同上 |
85
+ | `DATABASE_URL` | ⚠️ 存在確認のみ | ⚠️ 値入力必須 | **B** | 同上(Neonブランチから自動生成可能だが、現状は手動) |
86
+
87
+ **改善可能性**: `DATABASE_URL` は Neon API(connection_uri)から自動取得可能(deployment.md L258, neon-cli-reference.md参照)
88
+
89
+ ---
90
+
91
+ ### 5. その他(CLI・Docker)
92
+
93
+ | 項目 | 検知 | 修正フロー | 分類 | 理由 |
94
+ |-----|------|----------|------|------|
95
+ | Volta | ✅ Phase 1 | ✅ 自動インストール | **A** | setup-dev.ts L134-161 で自動インストール |
96
+ | direnv | ✅ Phase 1 | ✅ 自動インストール | **A** | setup-dev.ts L163-229 で自動インストール・設定 |
97
+ | dotenvx | ✅ Phase 1 | ✅ 自動インストール | **A** | setup-dev.ts L245-268 で自動インストール |
98
+ | Docker | ✅ Phase 1 | ⚠️ 手動案内 | **C** | 検知可能(SKILL.md L64)。インストールはGUI必須(SKILL.md L144) |
99
+ | PostgreSQL | ✅ Phase 1 | ✅ 自動起動 | **A** | `docker compose up -d postgres` で自動起動(SKILL.md L145) |
100
+ | Vercel CLI | ✅ Phase 1 | ✅ 自動インストール | **A** | `npm install -g vercel` 提案可能(SKILL.md L609) |
101
+ | Neon CLI | ✅ Phase 1 | ✅ 自動インストール | **A** | `npm install -g neonctl` 提案可能(SKILL.md L609) |
102
+ | GitHub CLI | ✅ Phase 1 | ✅ 自動インストール | **A** | `brew install gh` 提案可能(SKILL.md L609) |
103
+
104
+ **問題点**: Docker以外は自動インストール可能だが、SKILL.md L609では「AskUserQuestionで自動インストール提案」と曖昧。
105
+
106
+ ---
107
+
108
+ ## フェーズ別分析
109
+
110
+ ### Phase 1: 環境状態の自動検知(SKILL.md L48-70)
111
+
112
+ #### 検知できるもの
113
+ - ✅ ファイル存在(`.env*`, `.env.keys`)
114
+ - ✅ CLI存在(`vercel`, `neonctl`, `gh`, `dotenvx`, `docker`)
115
+ - ✅ Docker/PostgreSQL状態
116
+ - ✅ 開発サーバー状態
117
+ - ✅ GitHub Secrets数(`gh secret list`)
118
+
119
+ #### 検知できないもの
120
+ - ❌ トークンの有効性(期限切れ・無効)
121
+ - ❌ GitHub Secretsの値の正当性(API制限)
122
+ - ❌ 環境変数の値の正当性(暗号化ファイル内)
123
+ - ❌ Vercel/Neonプロジェクトとの接続性
124
+
125
+ **推奨改善**: Phase 1で以下を追加検証
126
+ ```bash
127
+ # トークン有効性検証
128
+ gh auth status 2>/dev/null && echo "✅ GITHUB_TOKEN" || echo "❌ GITHUB_TOKEN"
129
+ vercel whoami 2>/dev/null && echo "✅ VERCEL_TOKEN" || echo "❌ VERCEL_TOKEN"
130
+ neonctl projects list --api-key $NEON_API_KEY 2>/dev/null && echo "✅ NEON_API_KEY" || echo "❌ NEON_API_KEY"
131
+ ```
132
+
133
+ ---
134
+
135
+ ### Phase 2: 修正フロー
136
+
137
+ #### 完全自動(A): 7項目
138
+ 1. `.env` - `pnpm dev:setup` で自動再生成
139
+ 2. `DOTENV_PRIVATE_KEY_*` (4個) - `.env.keys` から自動抽出→GitHub Secrets設定
140
+ 3. `TURBO_TEAM` - `.turbo/config.json` から自動取得
141
+ 4. CLI自動インストール(Volta, direnv, dotenvx, vercel, neonctl, gh)
142
+
143
+ #### 半自動(B): 18項目
144
+ - `.env.keys` - worktreeから自動コピー可能だが、人間に選択させている
145
+ - `.env.local`, `.env.{develop,staging,production,preview}` - 暗号化のため手動編集案内
146
+ - 個人トークン(3個) - 値入力必須、有効性検証なし
147
+ - GitHub Secrets(6個) - 値入力必須
148
+ - Neon環境変数(3個) - 値入力必須(自動取得可能だが未実装)
149
+
150
+ #### 手動のみ(C): 1項目
151
+ - Docker - GUIインストール必須
152
+
153
+ #### 未対応(D): 0項目
154
+ (全ての項目が何らかの形で対処フローあり)
155
+
156
+ ---
157
+
158
+ ## 設計上の問題点と改善案
159
+
160
+ ### 問題1: `.env.keys` の不要な人間選択
161
+
162
+ **現状**: SKILL.md L143で「AskUserQuestion: メインworktreeからコピー or 手動配置」
163
+
164
+ **実装状況**: `setup-dev.ts` L73-90で自動コピー実装済み
165
+
166
+ **改善案**: AskUserQuestionを削除し、自動コピーを優先実行。失敗時のみ手動配置を案内。
167
+
168
+ ```diff
169
+ - AskUserQuestion: 「メインworktreeからコピー or 手動配置」
170
+ + 自動実行: メインworktreeから自動コピー → 失敗時のみ「1Passwordから手動配置してください」案内
171
+ ```
172
+
173
+ ---
174
+
175
+ ### 問題2: トークン有効性の未検証
176
+
177
+ **現状**: Phase 1で存在確認のみ。期限切れ・無効トークンを検知できない。
178
+
179
+ **改善案**: Phase 1に以下の検証を追加
180
+
181
+ ```bash
182
+ # GITHUB_TOKEN検証
183
+ if gh auth status >/dev/null 2>&1; then
184
+ echo "✅ GITHUB_TOKEN (有効)"
185
+ else
186
+ echo "❌ GITHUB_TOKEN (期限切れ or 無効)"
187
+ fi
188
+
189
+ # VERCEL_TOKEN検証
190
+ if vercel whoami >/dev/null 2>&1; then
191
+ echo "✅ VERCEL_TOKEN (有効)"
192
+ else
193
+ echo "❌ VERCEL_TOKEN (期限切れ or 無効)"
194
+ fi
195
+
196
+ # NEON_API_KEY検証
197
+ if neonctl projects list --api-key $NEON_API_KEY >/dev/null 2>&1; then
198
+ echo "✅ NEON_API_KEY (有効)"
199
+ else
200
+ echo "❌ NEON_API_KEY (期限切れ or 無効)"
201
+ fi
202
+ ```
203
+
204
+ ---
205
+
206
+ ### 問題3: Neon DATABASE_URL の手動設定
207
+
208
+ **現状**: deployment-setup.md L170-183で人間が手動設定
209
+
210
+ **実装可能性**: Neon API(connection_uri)から自動取得可能(deployment.md L258, L299-307参照)
211
+
212
+ **改善案**: カテゴリ4(Neon管理)に自動取得フローを追加
213
+
214
+ ```bash
215
+ # Neonブランチから接続文字列を自動取得
216
+ BRANCH_ID=$(neonctl branches list --project-id $NEON_PROJECT_ID --api-key $NEON_API_KEY | grep production | awk '{print $1}')
217
+ DATABASE_URL=$(curl -s "https://console.neon.tech/api/v2/projects/$NEON_PROJECT_ID/connection_uri?branch_id=$BRANCH_ID&database_name=neondb&role_name=$ROLE_NAME&pooled=true" \
218
+ -H "Authorization: Bearer $NEON_API_KEY" | jq -r .uri)
219
+
220
+ # .env.preview に自動設定
221
+ dotenvx set DATABASE_URL="$DATABASE_URL" -f .env.preview
222
+ ```
223
+
224
+ ---
225
+
226
+ ### 問題4: CLI自動インストールの曖昧さ
227
+
228
+ **現状**: SKILL.md L609で「AskUserQuestionで自動インストール提案」と曖昧
229
+
230
+ **実装状況**: `setup-dev.ts` L134-268で自動インストール実装済み
231
+
232
+ **改善案**: SKILL.mdで明示的に自動インストールを優先
233
+
234
+ ```diff
235
+ - AskUserQuestionで自動インストール提案(`npm i -g <cli>`等)
236
+ + 自動実行: `npm install -g <cli>` → 失敗時のみ手動インストール案内
237
+ ```
238
+
239
+ ---
240
+
241
+ ### 問題5: GitHub Secretsの値検証不可
242
+
243
+ **原因**: GitHub APIの制限(Secretsの値は取得不可)
244
+
245
+ **現状**: `gh secret list` で存在確認のみ
246
+
247
+ **改善不可**: API制限のため、値の正当性は検証不可
248
+
249
+ **回避策**: CI/CDワークフローの失敗ログから自動検出→修正フロー提案(カテゴリ7で実装済み、SKILL.md L529-538)
250
+
251
+ ---
252
+
253
+ ## 総合評価
254
+
255
+ ### 自動化レベル
256
+
257
+ | レベル | 項目数 | 割合 |
258
+ |--------|--------|------|
259
+ | **A: 完全自動** | 7 | 27% |
260
+ | **B: 半自動** | 18 | 69% |
261
+ | **C: 手動のみ** | 1 | 4% |
262
+ | **D: 未対応** | 0 | 0% |
263
+
264
+ ### 設計方針との適合性
265
+
266
+ > 「自動検知→自動修正→やむを得ない場合のみ人間に操作を求める」
267
+
268
+ **適合度**: ⭐⭐⭐⭐☆ (4/5)
269
+
270
+ **理由**:
271
+ - ✅ 自動検知は概ね網羅(Phase 1)
272
+ - ✅ 自動修正は一部実現(A分類 27%)
273
+ - ⚠️ 改善可能な手動操作が複数存在(B分類 69%)
274
+ - ✅ 手動のみはDocker 1項目のみ(C分類 4%)
275
+
276
+ ### 主な改善箇所(優先順)
277
+
278
+ 1. **トークン有効性検証** - Phase 1に追加(高優先度)
279
+ 2. **`.env.keys` 自動コピー** - AskUserQuestion削除(高優先度)
280
+ 3. **Neon DATABASE_URL 自動取得** - API連携実装(中優先度)
281
+ 4. **CLI自動インストール明示化** - SKILL.md修正(低優先度)
282
+
283
+ ---
284
+
285
+ ## 結論
286
+
287
+ 現在の設計は「検知→修正」フローを概ね実現しているが、以下の課題がある:
288
+
289
+ 1. **Phase 1の検知が不完全** - トークン有効性を検証していない
290
+ 2. **自動化可能な箇所で人間選択を求めている** - `.env.keys` コピー等
291
+ 3. **API連携で自動化可能な箇所が手動** - Neon DATABASE_URL等
292
+
293
+ これらを改善することで、自動化レベルを **A: 40% → 60%** に引き上げ可能。
294
+
295
+ ただし、以下は技術的制約により自動化不可:
296
+ - GitHub Secretsの値検証(API制限)
297
+ - Docker初回インストール(GUI必須)
298
+ - Vercel/VercelプロジェクトID取得(Dashboard操作必須)
299
+
300
+ **最終評価**: 設計方針に概ね適合しているが、改善の余地あり(⭐⭐⭐⭐☆)