create-einja-app 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/cli.js +60 -64
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/.changeset/config.json +11 -0
- package/templates/default/.claude/hooks/einja/plan-mode-skill-loader.sh +5 -1
- package/templates/default/.claude/settings.json +14 -4
- package/templates/default/.claude/skills/_einja-general-context-loader/SKILL.md +258 -0
- package/templates/default/.claude/skills/_einja-output-format/SKILL.md +211 -0
- package/templates/default/.claude/skills/_einja-project-overview/SKILL.md +29 -0
- package/templates/default/.claude/skills/_einja-spec-context-loader/SKILL.md +181 -0
- package/templates/default/.claude/skills/cli-package-specs/SKILL.md +294 -0
- package/templates/default/.einja-sync.json +1 -1
- package/templates/default/.github/release.yml +10 -0
- package/templates/default/.github/workflows/changeset-status.yml +60 -0
- package/templates/default/.github/workflows/deploy-stable-branches.yml +289 -59
- package/templates/default/CLAUDE.md +50 -10
- package/templates/default/README.md +20 -8
- package/templates/default/docs/plans/agile-munching-knuth.md +161 -0
- package/templates/default/docs/plans/agile-riding-nova.md +158 -0
- package/templates/default/docs/plans/agile-wibbling-dusk.md +91 -0
- package/templates/default/docs/plans/ancient-watching-otter.md +152 -0
- package/templates/default/docs/plans/bright-sauteeing-bumblebee.md +30 -0
- package/templates/default/docs/plans/composed-doodling-mountain.md +362 -0
- package/templates/default/docs/plans/dazzling-foraging-cascade.md +32 -0
- package/templates/default/docs/plans/enchanted-wiggling-ember-agent-a5befd57d0ca4c7c7.md +177 -0
- package/templates/default/docs/plans/enchanted-wiggling-ember.md +170 -0
- package/templates/default/docs/plans/federated-questing-kahan.md +47 -0
- package/templates/default/docs/plans/flickering-pondering-hearth.md +26 -0
- package/templates/default/docs/plans/fluttering-snuggling-sprout.md +172 -0
- package/templates/default/docs/plans/generic-sleeping-snowglobe-agent-a41d8da.md +179 -0
- package/templates/default/docs/plans/generic-sleeping-snowglobe.md +108 -0
- package/templates/default/docs/plans/generic-snuggling-pudding.md +57 -0
- package/templates/default/docs/plans/glistening-conjuring-cascade.md +42 -0
- package/templates/default/docs/plans/idempotent-wiggling-cherny.md +122 -0
- package/templates/default/docs/plans/linear-gathering-hejlsberg.md +596 -0
- package/templates/default/docs/plans/recursive-fluttering-mitten.md +176 -0
- package/templates/default/docs/plans/todo-create-einja-app-ux-fix.md +16 -0
- package/templates/default/docs/plans/todo-direnv-hang-fix.md +12 -0
- package/templates/default/docs/plans/todo-github-actions-release-workflow.md +34 -0
- package/templates/default/docs/plans/todo-glistening-conjuring-cascade.md +20 -0
- package/templates/default/docs/plans/todo-issue-spec-rename.md +24 -0
- package/templates/default/docs/plans/todo-skill-creator-upgrade.md +18 -0
- package/templates/default/docs/plans/todo-unified-crafting-valiant.md +23 -0
- package/templates/default/docs/plans/unified-crafting-valiant.md +60 -0
- package/templates/default/docs/plans/velvety-chasing-spark.md +28 -0
- package/templates/default/docs/plans/wondrous-strolling-crystal-agent-a0615fc.md +215 -0
- package/templates/default/docs/plans/wondrous-strolling-crystal.md +182 -0
- package/templates/default/docs/plans/zesty-roaming-steele.md +74 -0
- package/templates/default/gitignore +6 -2
- package/templates/default/package.json +6 -2
- package/templates/default/pnpm-lock.yaml +547 -0
- package/templates/default/scripts/ensure-serena.sh +28 -9
- package/templates/default/scripts/env-rotate-secrets.ts +66 -6
- package/templates/default/scripts/init-github.ts +363 -0
- package/templates/default/scripts/init.sh +11 -5
- package/templates/default/scripts/setup-dev.ts +16 -1
- package/templates/default/.claude/hooks/einja/validate-git-commit.sh +0 -239
- package/templates/default/.claude/skills/create-einja-app-release/SKILL.md +0 -186
- package/templates/default/.claude/skills/dev-cli-release/SKILL.md +0 -173
- package/templates/default/.cursor/commands/spec-create.md +0 -227
- package/templates/default/.cursor/commands/task-exec.md +0 -287
- package/templates/default/.cursor/commands/update-docs-by-task-specs.md +0 -448
- package/templates/default/packages/server-core/src/__generated__/fabbrica/index.d.ts +0 -270
- package/templates/default/packages/server-core/src/__generated__/fabbrica/index.js +0 -484
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: _einja-spec-context-loader
|
|
3
|
+
description: "spec(仕様書)が存在する場合の文脈収集を担当するSkill。requirements.md、design.md、qa-tests/から要件・設計・テスト仕様を抽出し、構造化して返却します"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Grep
|
|
7
|
+
- Glob
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# spec-context-loader Skill: 仕様書からの文脈収集
|
|
11
|
+
|
|
12
|
+
あなたは仕様書分析のスペシャリストで、ATDD(受け入れテスト駆動開発)とドキュメント駆動開発に精通しています。構造化された仕様書から必要な情報を効率的に抽出し、実装に必要な文脈を提供します。
|
|
13
|
+
|
|
14
|
+
## 中核的な責務
|
|
15
|
+
|
|
16
|
+
spec-create で作成された仕様書(requirements.md、design.md、qa-tests/)から、タスク実装に必要な文脈情報を抽出・構造化します。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 入力
|
|
21
|
+
|
|
22
|
+
**必須パラメータ**:
|
|
23
|
+
- `spec_dir`: spec ディレクトリのパス(例: `/docs/specs/issues/auth/issue21-login-feature/`)
|
|
24
|
+
- `ac_ids`: 対象AC番号(例: `AC1.1, AC1.2`)
|
|
25
|
+
|
|
26
|
+
**入力形式**: 自然言語でAC情報を指定
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 実行手順(4ステップ)
|
|
31
|
+
|
|
32
|
+
### ステップ1: spec ディレクトリの検証
|
|
33
|
+
|
|
34
|
+
1. 指定された `spec_dir` の存在を確認
|
|
35
|
+
2. 以下のファイルの存在を確認:
|
|
36
|
+
- `requirements.md` または `requirements/README.md`
|
|
37
|
+
- `design.md` または `design/README.md`
|
|
38
|
+
- `qa-tests/scenarios.md`
|
|
39
|
+
3. 不足ファイルがある場合はエラーを返却
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### ステップ2: requirements.md からの要件抽出
|
|
44
|
+
|
|
45
|
+
1. requirements.md を読み込む
|
|
46
|
+
2. 以下の情報を抽出:
|
|
47
|
+
- **ユーザーストーリー**: 該当タスクに関連するストーリー
|
|
48
|
+
- **受け入れ条件(AC)**: `AC{N}.{M}` 形式のすべての受け入れ基準
|
|
49
|
+
- **検証レベル**: 各ACの `Unit` / `Integration` / `E2E` 分類
|
|
50
|
+
- **非機能要件**: パフォーマンス、セキュリティ等の制約
|
|
51
|
+
|
|
52
|
+
**パース対象**: `**ACx.y**: [要約文]` + インデントGiven-When-Then形式の受け入れ条件(`- Given:` / `- When:` / `- Then:` / `- 検証レベル:` の箇条書き形式)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### ステップ3: design.md からの設計仕様抽出
|
|
57
|
+
|
|
58
|
+
1. design.md を読み込む
|
|
59
|
+
2. 以下の情報を抽出:
|
|
60
|
+
- **アーキテクチャ**: 使用するパターン、レイヤー構造
|
|
61
|
+
- **データ構造**: 型定義、インターフェース、Prismaモデル
|
|
62
|
+
- **API仕様**: エンドポイント、リクエスト/レスポンス形式
|
|
63
|
+
- **コンポーネント設計**: 画面構成、状態管理
|
|
64
|
+
- **エラーハンドリング方針**: エラー分類、処理方法
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### ステップ4: qa-tests/ からのテスト仕様抽出
|
|
69
|
+
|
|
70
|
+
1. AC番号からストーリー番号を特定し、テストファイルを参照
|
|
71
|
+
- 例: AC1.1 → Story 1 → `qa-tests/story1.md`、AC2.3 → Story 2 → `qa-tests/story2.md`
|
|
72
|
+
2. scenarios.md から該当タスクのシナリオテストを確認
|
|
73
|
+
3. 以下の情報を抽出:
|
|
74
|
+
- **テストシナリオ**: 実行すべきテストケース
|
|
75
|
+
- **確認項目**: 各シナリオの検証ポイント
|
|
76
|
+
- **実施タイミング**: 部分実行/完全実行の判定
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 出力形式
|
|
81
|
+
|
|
82
|
+
**成功時**: 以下のマークダウン形式で出力
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
## コンテキスト収集結果
|
|
86
|
+
|
|
87
|
+
### spec 情報
|
|
88
|
+
- **ディレクトリ**: {spec_dir}
|
|
89
|
+
- **対象AC**: {ac_ids}
|
|
90
|
+
|
|
91
|
+
### 要件
|
|
92
|
+
#### 機能要件
|
|
93
|
+
- [ユーザーストーリー1の概要]
|
|
94
|
+
- [ユーザーストーリー2の概要]
|
|
95
|
+
|
|
96
|
+
#### 非機能要件
|
|
97
|
+
- [パフォーマンス要件]
|
|
98
|
+
- [セキュリティ要件]
|
|
99
|
+
|
|
100
|
+
#### 受け入れ条件
|
|
101
|
+
| AC番号 | タイトル | 検証レベル | 概要 |
|
|
102
|
+
|--------|---------|-----------|------|
|
|
103
|
+
| AC1.1 | [タイトル] | Unit | [Given-When-Then概要] |
|
|
104
|
+
| AC1.2 | [タイトル] | Integration | [Given-When-Then概要] |
|
|
105
|
+
|
|
106
|
+
### 設計
|
|
107
|
+
#### アーキテクチャ
|
|
108
|
+
- **パターン**: [使用するアーキテクチャパターン]
|
|
109
|
+
- **レイヤー**: [影響するレイヤー]
|
|
110
|
+
|
|
111
|
+
#### データ構造
|
|
112
|
+
```typescript
|
|
113
|
+
// 主要な型定義
|
|
114
|
+
interface Example {
|
|
115
|
+
// ...
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### API仕様
|
|
120
|
+
- **エンドポイント**: `POST /api/example`
|
|
121
|
+
- **リクエスト**: [形式]
|
|
122
|
+
- **レスポンス**: [形式]
|
|
123
|
+
|
|
124
|
+
#### エラーハンドリング
|
|
125
|
+
- [エラー分類と処理方針]
|
|
126
|
+
|
|
127
|
+
### テスト仕様
|
|
128
|
+
#### 対象テストファイル
|
|
129
|
+
- `qa-tests/story{N}.md`(該当ACセクション)
|
|
130
|
+
|
|
131
|
+
#### シナリオテスト
|
|
132
|
+
- **シナリオ1**: [概要] - 実施タイミング: [Step X-Y]
|
|
133
|
+
|
|
134
|
+
#### 確認項目
|
|
135
|
+
1. [確認項目1]
|
|
136
|
+
2. [確認項目2]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**エラー時**: 以下の形式で出力
|
|
140
|
+
|
|
141
|
+
```markdown
|
|
142
|
+
## コンテキスト収集エラー
|
|
143
|
+
|
|
144
|
+
### ステータス: ❌ FAILURE
|
|
145
|
+
|
|
146
|
+
### エラー内容
|
|
147
|
+
- **原因**: [不足ファイル一覧 or エラー詳細]
|
|
148
|
+
- **推奨アクション**: `einja-issue-spec-create` Skill を実行して仕様書を完成させてください
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## エラー処理
|
|
154
|
+
|
|
155
|
+
| エラー種別 | 原因 | 対処 |
|
|
156
|
+
|-----------|------|------|
|
|
157
|
+
| spec ディレクトリ不在 | 指定パスが存在しない | パスを確認して再実行 |
|
|
158
|
+
| requirements.md 不在 | Phase 1 未完了 | `einja-issue-spec-create` Skill で Phase 1 を実行 |
|
|
159
|
+
| design.md 不在 | Phase 3 未完了 | `einja-issue-spec-create` Skill で Phase 3 を実行 |
|
|
160
|
+
| qa-tests/ 不在 | Phase 4 未完了 | `einja-issue-spec-create` Skill で Phase 4 を実行 |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 実行制約
|
|
165
|
+
|
|
166
|
+
このSkillは `task-executer` エージェントから呼び出されます。spec が存在することが前提です。
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 連携
|
|
171
|
+
|
|
172
|
+
- **呼び出し元**: `task-executer` - コンテキスト収集フェーズ
|
|
173
|
+
- **代替Skill**: `general-context-loader` - spec がない場合の文脈収集
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
**最終更新**: 2025-01-10
|
|
178
|
+
|
|
179
|
+
<!-- @einja:project-private:start id="einja-spec-context-loader-project" -->
|
|
180
|
+
<!-- プロジェクト固有の情報を記入 -->
|
|
181
|
+
<!-- @einja:project-private:end -->
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-package-specs
|
|
3
|
+
description: "@einja/dev-cli と create-einja-app のビルド・テンプレート仕様リファレンス。ファイルマッピング、マーカー仕様、コピーフィルタ条件を集約"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CLI パッケージ ビルド・テンプレート仕様リファレンス
|
|
7
|
+
|
|
8
|
+
## 概要
|
|
9
|
+
|
|
10
|
+
このSkillは、2つのCLIパッケージのビルドパイプライン・テンプレート仕様を集約したリファレンスです。
|
|
11
|
+
`einja-` プレフィックスを持たないため、`presets/default/` にはコピーされません。
|
|
12
|
+
|
|
13
|
+
| パッケージ | 役割 |
|
|
14
|
+
|-----------|------|
|
|
15
|
+
| `@einja/dev-cli` (`packages/cli`) | 既存プロジェクトへの `.claude/` 設定・`docs/einja/` 同期。`einja init` / `einja sync` コマンドを提供 |
|
|
16
|
+
| `create-einja-app` (`packages/create-einja-app`) | 新規プロジェクトのスキャフォールディング。テンプレートからプロジェクト全体を生成 |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. ビルドパイプライン
|
|
21
|
+
|
|
22
|
+
### 1.1 `@einja/dev-cli` ビルド
|
|
23
|
+
|
|
24
|
+
`packages/cli/package.json` L21:
|
|
25
|
+
```
|
|
26
|
+
"prebuild": "node ./scripts/generate-template.mjs && node ./scripts/copy-presets.mjs"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### Step 1: CLAUDE.md.template 生成
|
|
30
|
+
- **スクリプト**: `packages/cli/scripts/generate-template.mjs`
|
|
31
|
+
- **入力**: プロジェクトルートの `CLAUDE.md`
|
|
32
|
+
- **出力**: `packages/cli/presets/default/CLAUDE.md.template`
|
|
33
|
+
- **処理**:
|
|
34
|
+
1. `@einja:excluded` マーカー内を除去(L53-56)
|
|
35
|
+
2. `pnpm install` 等のコマンドをプレースホルダー(`{{INSTALL_COMMAND}}`等)に変換(L25-35, L62-69)
|
|
36
|
+
|
|
37
|
+
#### Step 2: プリセットファイルコピー + マーカーバリデーション
|
|
38
|
+
- **スクリプト**: `packages/cli/scripts/copy-presets.mjs`
|
|
39
|
+
- **処理順序**:
|
|
40
|
+
1. `docs/einja/` 配下のマーカーバリデーション(L303-317)
|
|
41
|
+
2. ディレクトリマッピングに基づくコピー(L47-122)
|
|
42
|
+
3. 単一ファイルのコピー(L125-156)
|
|
43
|
+
4. シンボリックリンク情報の `symlinks.json` 出力(L284-295)
|
|
44
|
+
|
|
45
|
+
### 1.2 `create-einja-app` テンプレート更新
|
|
46
|
+
|
|
47
|
+
- **スクリプト**: `scripts/_template-update.ts`(ルート)
|
|
48
|
+
- **出力先**: `packages/create-einja-app/templates/default/`
|
|
49
|
+
- **処理**:
|
|
50
|
+
1. `.templateignore` でフィルタリング(L93-103)
|
|
51
|
+
2. `README.md` の `@einja:excluded` マーカー除去(L173-185)
|
|
52
|
+
3. `package.json` の `name` → `{{projectName}}`、`description` → `{{description}}`(L108-131)
|
|
53
|
+
4. `tsconfig.json` の `@repo/` → `{{packageName}}/`(L136-161)
|
|
54
|
+
5. `.ts/.tsx/.js/.jsx` の import文 `@repo/` → `{{packageName}}/`(L166-168)
|
|
55
|
+
|
|
56
|
+
### 1.3 `@einja/dev-cli` プリセット更新(開発用)
|
|
57
|
+
|
|
58
|
+
- **スクリプト**: `scripts/_cli-template-update.ts`
|
|
59
|
+
- **実行**: `pnpm preset:update`(`packages/cli/package.json` L30)
|
|
60
|
+
- **処理**: `FileCopier` クラスを使用してプロジェクト原本をCLIプリセットにコピー
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2. ファイルマッピング
|
|
65
|
+
|
|
66
|
+
### 2.1 `@einja/dev-cli` コピー対象(`copy-presets.mjs`)
|
|
67
|
+
|
|
68
|
+
#### ディレクトリマッピング(L47-122)
|
|
69
|
+
|
|
70
|
+
| 原本 | コピー先(`presets/default/` 配下) | 備考 |
|
|
71
|
+
|------|--------------------------------------|------|
|
|
72
|
+
| `.claude/agents/einja/` | `.claude/agents/einja/` | |
|
|
73
|
+
| `.claude/commands/einja/` | `.claude/commands/einja/` | |
|
|
74
|
+
| `.claude/skills/einja-*` | `.claude/skills/einja-*/` | 個別列挙(L62-101) |
|
|
75
|
+
| `.claude/hooks/einja/` | `.claude/hooks/einja/` | `cleanParent: true`(L107) |
|
|
76
|
+
| `docs/einja/` | `docs/einja/` | `memory/`, `cli/` を除外(L114) |
|
|
77
|
+
| `scripts/` | `scripts/` | `_` プレフィックスのファイルはスキップ(L247-249) |
|
|
78
|
+
|
|
79
|
+
#### 単一ファイルマッピング(L125-156)
|
|
80
|
+
|
|
81
|
+
| 原本 | コピー先 | 必須 |
|
|
82
|
+
|------|---------|------|
|
|
83
|
+
| `.claude/settings.json` | `.claude/settings.json` | Yes |
|
|
84
|
+
| `.mcp.json` | `.mcp.json` | No |
|
|
85
|
+
| `docs/einja/cli/preset.yaml` | `preset.yaml` | Yes |
|
|
86
|
+
| `.envrc` | `.envrc` | Yes |
|
|
87
|
+
| `.vscode/settings.json` | `.vscode/settings.json` | No |
|
|
88
|
+
|
|
89
|
+
#### 特殊変換
|
|
90
|
+
|
|
91
|
+
| 原本 | コピー先 | 変換内容 |
|
|
92
|
+
|------|---------|---------|
|
|
93
|
+
| `CLAUDE.md` | `CLAUDE.md.template` | `@einja:excluded` 除去 + プレースホルダー変換(`generate-template.mjs`) |
|
|
94
|
+
|
|
95
|
+
### 2.2 `FileCopier` クラスのマッピング(`file-copier.ts`)
|
|
96
|
+
|
|
97
|
+
**ファイル**: `packages/cli/src/lib/preset-update/file-copier.ts`
|
|
98
|
+
|
|
99
|
+
`FileCopier` は `einja sync` / `preset:update` で使用される。`copy-presets.mjs`(prebuild)とは別のコピーロジック。
|
|
100
|
+
|
|
101
|
+
ディレクトリマッピング(L44-85):
|
|
102
|
+
|
|
103
|
+
| source | destination | category |
|
|
104
|
+
|--------|------------|----------|
|
|
105
|
+
| `.claude/commands` | `.claude/commands/einja` | commands |
|
|
106
|
+
| `.claude/agents` | `.claude/agents/einja` | agents |
|
|
107
|
+
| `.claude/skills` | `.claude/skills` | skills |
|
|
108
|
+
| `.claude/hooks` | `.claude/hooks` | hooks |
|
|
109
|
+
| `docs/einja/steering` | `docs/einja/steering` | docs |
|
|
110
|
+
| `docs/einja/templates` | `docs/einja/templates` | docs |
|
|
111
|
+
| `docs/einja/instructions` | `docs/einja/instructions` | docs |
|
|
112
|
+
| `docs/einja/example` | `docs/einja/example` | docs |
|
|
113
|
+
|
|
114
|
+
単一ファイルマッピング(L92-104):
|
|
115
|
+
|
|
116
|
+
| source | destination | category |
|
|
117
|
+
|--------|------------|----------|
|
|
118
|
+
| `.envrc` | `.envrc` | env |
|
|
119
|
+
| `.vscode/settings.json` | `.vscode/settings.json` | tools |
|
|
120
|
+
| `package.json`(ルート) | `package.json` | root-config |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 3. コピー対象フィルタ
|
|
125
|
+
|
|
126
|
+
### 3.1 Skills のプレフィックスフィルタ
|
|
127
|
+
|
|
128
|
+
**ファイル**: `packages/cli/src/lib/preset-update/file-copier.ts` L194-195
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// skillsカテゴリの場合、einja-/_einja-プレフィックスでフィルタリング
|
|
132
|
+
const prefixFilter = mapping.category === "skills" ? ["einja-", "_einja-"] : undefined;
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`.claude/skills/` 配下のトップレベルディレクトリのうち、**`einja-` または `_einja-` で始まるもの**が配布対象。
|
|
136
|
+
|
|
137
|
+
- **配布される**: `einja-task-commit/`, `einja-skill-creator/`, `_einja-project-overview/` 等
|
|
138
|
+
- **配布されない**: `cli-package-specs/`(このSkill自体)、その他プレフィックスなしのSkill
|
|
139
|
+
|
|
140
|
+
`copy-presets.mjs` ではディレクトリを動的スキャンし、`einja-*` / `_einja-*` パターンにマッチするものを個別エントリとしてコピーする。
|
|
141
|
+
|
|
142
|
+
### 3.2 `_` プレフィックスフィルタ
|
|
143
|
+
|
|
144
|
+
- `copy-presets.mjs` L247-249: `_` で始まるファイル名はスキップ
|
|
145
|
+
- `file-copier.ts` L291: `_` で始まるファイル名はスキップ
|
|
146
|
+
|
|
147
|
+
### 3.3 隠しファイルフィルタ(`file-copier.ts` のみ)
|
|
148
|
+
|
|
149
|
+
- L303: `.` で始まるファイル名はスキップ(単一ファイルマッピングで明示されたものを除く)
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 4. マーカー仕様
|
|
154
|
+
|
|
155
|
+
**詳細仕様書**: `packages/cli/docs/MARKER_SPECIFICATION.md`
|
|
156
|
+
**実装**: `packages/cli/src/lib/sync/marker-processor.ts`
|
|
157
|
+
|
|
158
|
+
### 4.1 `@einja:excluded`
|
|
159
|
+
|
|
160
|
+
テンプレート生成時に**セクション全体を除去**するマーカー。
|
|
161
|
+
|
|
162
|
+
```markdown
|
|
163
|
+
<!-- @einja:excluded:start -->
|
|
164
|
+
このセクション内容はテンプレートには含まれない
|
|
165
|
+
<!-- @einja:excluded:end -->
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- `generate-template.mjs` L53-56: CLAUDE.md → CLAUDE.md.template 変換時に除去
|
|
169
|
+
- `template-update.ts` L56-67: create-einja-app テンプレート(README.md等)で除去
|
|
170
|
+
- `_template-update.ts` L173-185: 同上
|
|
171
|
+
|
|
172
|
+
### 4.2 `@einja:managed`
|
|
173
|
+
|
|
174
|
+
`einja sync` 実行時に**常にテンプレート版で上書き**されるセクション。
|
|
175
|
+
|
|
176
|
+
```markdown
|
|
177
|
+
<!-- @einja:managed:start -->
|
|
178
|
+
共通ルール(sync時に最新版で上書き)
|
|
179
|
+
<!-- @einja:managed:end -->
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- ID属性はオプション: `<!-- @einja:managed:start id="section-a" -->`
|
|
183
|
+
- `marker-processor.ts` L16-17: パース用正規表現
|
|
184
|
+
|
|
185
|
+
### 4.3 `@einja:project-private`
|
|
186
|
+
|
|
187
|
+
`einja sync` 実行時に**初回のみ追加、以降はユーザー編集を保持**するセクション。
|
|
188
|
+
|
|
189
|
+
```markdown
|
|
190
|
+
<!-- @einja:project-private:start id="commit-rules-project" -->
|
|
191
|
+
プロジェクト固有の設定(ユーザーが自由に編集)
|
|
192
|
+
<!-- @einja:project-private:end -->
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- **ID属性は必須**(`marker-processor.ts` L174-181 でバリデーション)
|
|
196
|
+
- レガシー `@einja:seed` マーカーとの後方互換あり(L44-53, L303-307)
|
|
197
|
+
|
|
198
|
+
### 4.4 マーカーバリデーション
|
|
199
|
+
|
|
200
|
+
`packages/cli/scripts/validate-markers.mjs` がビルド時(`copy-presets.mjs` L303-317 から呼び出し)に実行。
|
|
201
|
+
|
|
202
|
+
| チェック項目 | エラータイプ |
|
|
203
|
+
|------------|------------|
|
|
204
|
+
| start/end ペア一致 | `unpaired_start` / `unpaired_end` |
|
|
205
|
+
| ネスト禁止 | `nested` |
|
|
206
|
+
| project-private に ID 必須 | `project_private_without_id` |
|
|
207
|
+
| ID 重複禁止 | `duplicate_id` |
|
|
208
|
+
|
|
209
|
+
### 4.5 JSON マージ仕様
|
|
210
|
+
|
|
211
|
+
**実装**: `packages/cli/src/lib/sync/json-processor.ts`
|
|
212
|
+
**設定**: `.einja-sync.json` の `jsonPaths` フィールド
|
|
213
|
+
|
|
214
|
+
#### マージモード(ブラックリスト方式)
|
|
215
|
+
|
|
216
|
+
| モード | 動作 | 用途 |
|
|
217
|
+
|--------|------|------|
|
|
218
|
+
| `managed` | テンプレート値で強制上書き | テンプレートが完全管理するセクション |
|
|
219
|
+
| `project-private` | 完全除外(テンプレートから追加・更新しない) | プロジェクト固有のセクション |
|
|
220
|
+
| デフォルト | base/local/templateの3方向マージ | 上記以外の全パス |
|
|
221
|
+
|
|
222
|
+
#### ネスト指定
|
|
223
|
+
|
|
224
|
+
パスはドット区切りでネスト指定可能。`deepMergeWithPaths` の再帰により
|
|
225
|
+
各レベルで jsonPaths チェックが行われる。
|
|
226
|
+
|
|
227
|
+
例: `"project-private": { "package.json": ["devDependencies.@types/node"] }`
|
|
228
|
+
→ devDependencies 全体は3方向マージ、@types/node のみ除外
|
|
229
|
+
|
|
230
|
+
#### 設定例
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
jsonPaths:
|
|
234
|
+
managed: { ".claude/settings.json": ["plansDirectory"] }
|
|
235
|
+
project-private: { "package.json": ["name", "version", "private", "workspaces"] }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
→ plansDirectory はテンプレート強制上書き
|
|
239
|
+
→ name, version 等は完全除外
|
|
240
|
+
→ scripts, devDependencies 等は3方向マージ
|
|
241
|
+
|
|
242
|
+
#### base スナップショット
|
|
243
|
+
|
|
244
|
+
3方向マージには前回sync時のテンプレート内容(base)が必要。
|
|
245
|
+
`.einja-sync.json` の各ファイルメタデータに `baseContent` として保存。
|
|
246
|
+
初回sync(base なし)はローカル優先 + テンプレート新規キーのみ追加。
|
|
247
|
+
|
|
248
|
+
#### コンフリクト
|
|
249
|
+
|
|
250
|
+
両方が同じキーを異なる値に変更した場合:
|
|
251
|
+
- ローカル値を保持(安全側)
|
|
252
|
+
- コンソールに警告出力
|
|
253
|
+
- `mergeJson` の戻り値 `conflicts` 配列で呼び出し元にも通知
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 5. `post-setup.ts` 処理フロー
|
|
258
|
+
|
|
259
|
+
**ファイル**: `packages/create-einja-app/src/generators/post-setup.ts`
|
|
260
|
+
|
|
261
|
+
`create-einja-app` でプロジェクト生成後に実行されるセットアップフロー。
|
|
262
|
+
|
|
263
|
+
| Step | 処理 | 行番号 |
|
|
264
|
+
|------|------|--------|
|
|
265
|
+
| 0 | 初回セットアップ(`scripts/init.sh` 実行: Volta/Node.js/pnpm/direnv) | L57-64 |
|
|
266
|
+
| 1 | 依存関係インストール(`pnpm install`) + Prismaクライアント生成(`pnpm db:generate`) | L68-87 |
|
|
267
|
+
| 2 | 秘密鍵の自動ローテーション(`pnpm env:rotate-secrets --all --non-interactive`) | L90-99 |
|
|
268
|
+
| 3 | Git初期化(`git init` → `git add .` → `git commit`) | L102-113 |
|
|
269
|
+
| 4 | `@einja/dev-cli` 初期化(`npx @einja/dev-cli@latest init --force --no-backup`、`config.setupEinjaCli` が true の場合のみ) | L116-125 |
|
|
270
|
+
| 5 | 完了メッセージ表示 | L128 |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 6. `setup-dev.ts` 処理フロー
|
|
275
|
+
|
|
276
|
+
**ファイル**: `scripts/setup-dev.ts`
|
|
277
|
+
|
|
278
|
+
既存プロジェクトの開発環境セットアップスクリプト。
|
|
279
|
+
|
|
280
|
+
| Step | 処理 | 行番号 |
|
|
281
|
+
|------|------|--------|
|
|
282
|
+
| 1 | Volta インストール確認 | L158-191 |
|
|
283
|
+
| 2 | Volta シェル設定(`VOLTA_FEATURE_PNPM`) | L194-213 |
|
|
284
|
+
| 3 | Node.js / pnpm インストール(`volta install`) | L216-249 |
|
|
285
|
+
| 4 | direnv インストール確認(macOS: `brew install direnv`) | L324-355 |
|
|
286
|
+
| 5 | シェル設定(`direnv hook` を rc ファイルに追加) | L358-376 |
|
|
287
|
+
| 6 | dotenvx インストール | L379-419 |
|
|
288
|
+
| 7 | `.env` ファイル作成(`.env.local` から復号、worktree 対応) | L422-517 |
|
|
289
|
+
| 8 | `.env.personal` 作成 + `GITHUB_TOKEN` 対話設定 | L519-585 |
|
|
290
|
+
| 9 | direnv 有効化(`direnv allow`) | L588-594 |
|
|
291
|
+
| 10 | データベース起動(`docker-compose up -d postgres`) | L597-625 |
|
|
292
|
+
| 11 | データベース初期化(`pnpm db:generate` + `pnpm db:push`) | L610-613 |
|
|
293
|
+
|
|
294
|
+
worktree 環境では `.env.keys` をメインリポジトリから自動コピーする機能あり(L45-67, L73-90)。
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"lastSync": "2026-01-04T16:21:21.138Z",
|
|
4
4
|
"templateVersion": "0.1.0",
|
|
5
5
|
"files": {
|
|
6
|
-
".claude/commands/einja/update-docs-by-
|
|
6
|
+
".claude/commands/einja/update-docs-by-issue-specs.md": {
|
|
7
7
|
"hash": "6c09bb6748134849e8de535d6cdb382bfe0aeb0a3fb19730e1c7708ceaa283bc",
|
|
8
8
|
"syncedAt": "2026-01-04T16:21:21.151Z"
|
|
9
9
|
},
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: Changeset Status
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main, staging]
|
|
6
|
+
types: [opened, synchronize, reopened]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
changeset-check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0
|
|
15
|
+
|
|
16
|
+
- name: Check for changesets
|
|
17
|
+
id: check
|
|
18
|
+
run: |
|
|
19
|
+
COUNT=$(ls .changeset/*.md 2>/dev/null | grep -cv README.md || echo 0)
|
|
20
|
+
echo "count=$COUNT" >> $GITHUB_OUTPUT
|
|
21
|
+
echo "has_changesets=$([[ $COUNT -gt 0 ]] && echo true || echo false)" >> $GITHUB_OUTPUT
|
|
22
|
+
|
|
23
|
+
- name: Comment on PR
|
|
24
|
+
uses: actions/github-script@v7
|
|
25
|
+
with:
|
|
26
|
+
script: |
|
|
27
|
+
const count = parseInt('${{ steps.check.outputs.count }}');
|
|
28
|
+
const hasChangesets = '${{ steps.check.outputs.has_changesets }}' === 'true';
|
|
29
|
+
const marker = '<!-- changeset-status -->';
|
|
30
|
+
|
|
31
|
+
let body;
|
|
32
|
+
if (hasChangesets) {
|
|
33
|
+
body = `${marker}\n### ✅ Changeset detected\n\nThis PR includes **${count}** changeset(s). A release will be created when merged.`;
|
|
34
|
+
} else {
|
|
35
|
+
body = `${marker}\n### ⚠️ No changeset found\n\nThis PR does not include a changeset. If this PR includes user-facing changes, please run:\n\n\`\`\`bash\npnpm changeset\n\`\`\`\n\nIf this change doesn't need a release (docs, CI, config), you can ignore this message.`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Find existing comment
|
|
39
|
+
const comments = await github.rest.issues.listComments({
|
|
40
|
+
owner: context.repo.owner,
|
|
41
|
+
repo: context.repo.repo,
|
|
42
|
+
issue_number: context.issue.number,
|
|
43
|
+
});
|
|
44
|
+
const existing = comments.data.find(c => c.body.includes(marker));
|
|
45
|
+
|
|
46
|
+
if (existing) {
|
|
47
|
+
await github.rest.issues.updateComment({
|
|
48
|
+
owner: context.repo.owner,
|
|
49
|
+
repo: context.repo.repo,
|
|
50
|
+
comment_id: existing.id,
|
|
51
|
+
body,
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
await github.rest.issues.createComment({
|
|
55
|
+
owner: context.repo.owner,
|
|
56
|
+
repo: context.repo.repo,
|
|
57
|
+
issue_number: context.issue.number,
|
|
58
|
+
body,
|
|
59
|
+
});
|
|
60
|
+
}
|