name: cli-package-specs description: "@einja-inc/dev-cli と @einja-inc/create-app のビルド・テンプレート仕様リファレンス。ファイルマッピング、マーカー仕様、コピーフィルタ条件を集約"
CLI パッケージ ビルド・テンプレート仕様リファレンス
概要
このSkillは、2つのCLIパッケージのビルドパイプライン・テンプレート仕様を集約したリファレンスです。
einja- プレフィックスを持たないため、presets/default/ にはコピーされません。
| パッケージ | 役割 |
|---|---|
@einja-inc/dev-cli (packages/cli) | 既存プロジェクトへの .claude/ 設定・docs/einja/ 同期。einja init / einja sync コマンドを提供 |
@einja-inc/create-app (packages/create-app) | 新規プロジェクトのスキャフォールディング。テンプレートからプロジェクト全体を生成 |
1. ビルドパイプライン
1.1 @einja-inc/dev-cli ビルド
packages/cli/package.json L21:
"prebuild": "node ./scripts/generate-template.mjs && node ./scripts/copy-presets.mjs"
Step 1: CLAUDE.md.template 生成
- スクリプト:
packages/cli/scripts/generate-template.mjs - 入力: プロジェクトルートの
CLAUDE.md - 出力:
packages/cli/presets/default/CLAUDE.md.template - 処理:
@einja:excludedマーカー内を除去(L53-56)pnpm install等のコマンドをプレースホルダー({{INSTALL_COMMAND}}等)に変換(L25-35, L62-69)
Step 2: プリセットファイルコピー + マーカーバリデーション
- スクリプト:
packages/cli/scripts/copy-presets.mjs - 処理順序:
docs/einja/配下のマーカーバリデーション(L303-317)- ディレクトリマッピングに基づくコピー(L47-122)
- 単一ファイルのコピー(L125-156)
- シンボリックリンク情報の
symlinks.json出力(L284-295)
1.2 @einja-inc/create-app テンプレート更新
- スクリプト:
scripts/_template-update.ts(ルート) - 出力先:
packages/create-app/templates/default/ - 処理:
.templateignoreでフィルタリング(L93-103)README.mdの@einja:excludedマーカー除去(L173-185)package.jsonのname→{{projectName}}、description→{{description}}(L108-131)tsconfig.jsonの@repo/→{{packageName}}/(L136-161).ts/.tsx/.js/.jsxの import文@repo/→{{packageName}}/(L166-168)
1.3 @einja-inc/dev-cli プリセット更新(開発用)
- スクリプト:
scripts/_cli-template-update.ts - 実行:
pnpm preset:update(packages/cli/package.jsonL30) - 処理:
FileCopierクラスを使用してプロジェクト原本をCLIプリセットにコピー
2. ファイルマッピング
2.1 @einja-inc/dev-cli コピー対象(copy-presets.mjs)
ディレクトリマッピング(L47-122)
| 原本 | コピー先(presets/default/ 配下) | 備考 |
|---|---|---|
.claude/agents/einja/ | .claude/agents/einja/ | |
.claude/skills/einja-* | .claude/skills/einja-*/ | 個別列挙(L62-101) |
.claude/hooks/einja/ | .claude/hooks/einja/ | cleanParent: true(L107) |
docs/einja/ | docs/einja/ | memory/, cli/ を除外(L114) |
scripts/ | scripts/ | _ プレフィックスのファイルはスキップ(L247-249) |
単一ファイルマッピング(L125-156)
| 原本 | コピー先 | 必須 |
|---|---|---|
.claude/settings.json | .claude/settings.json | Yes |
.mcp.json | .mcp.json | No |
docs/einja/cli/preset.yaml | preset.yaml | Yes |
.envrc | .envrc | Yes |
.vscode/settings.json | .vscode/settings.json | No |
特殊変換
| 原本 | コピー先 | 変換内容 |
|---|---|---|
CLAUDE.md | CLAUDE.md.template | @einja:excluded 除去 + プレースホルダー変換(generate-template.mjs) |
2.2 FileCopier クラスのマッピング(file-copier.ts)
ファイル: packages/cli/src/lib/preset-update/file-copier.ts
FileCopier は einja sync / preset:update で使用される。copy-presets.mjs(prebuild)とは別のコピーロジック。
ディレクトリマッピング(L44-85):
| source | destination | category |
|---|---|---|
.claude/agents | .claude/agents/einja | agents |
.claude/skills | .claude/skills | skills |
.claude/hooks | .claude/hooks | hooks |
docs/einja/steering | docs/einja/steering | docs |
docs/einja/templates | docs/einja/templates | docs |
docs/einja/instructions | docs/einja/instructions | docs |
docs/einja/example | docs/einja/example | docs |
単一ファイルマッピング(L92-104):
| source | destination | category |
|---|---|---|
.envrc | .envrc | env |
.vscode/settings.json | .vscode/settings.json | tools |
package.json(ルート) | package.json | root-config |
3. コピー対象フィルタ
3.1 Skills のプレフィックスフィルタ
ファイル: packages/cli/src/lib/preset-update/file-copier.ts L194-195
// skillsカテゴリの場合、einja-/_einja-プレフィックスでフィルタリング
const prefixFilter = mapping.category === "skills" ? ["einja-", "_einja-"] : undefined;
.claude/skills/ 配下のトップレベルディレクトリのうち、einja- または _einja- で始まるものが配布対象。
- 配布される:
einja-task-commit/,einja-skill-creator/,_einja-project-overview/等 - 配布されない:
cli-package-specs/(このSkill自体)、その他プレフィックスなしのSkill
copy-presets.mjs ではディレクトリを動的スキャンし、einja-* / _einja-* パターンにマッチするものを個別エントリとしてコピーする。
3.2 _ プレフィックスフィルタ
copy-presets.mjsL247-249:_で始まるファイル名はスキップfile-copier.tsL291:_で始まるファイル名はスキップ
3.3 隠しファイルフィルタ(file-copier.ts のみ)
- L303:
.で始まるファイル名はスキップ(単一ファイルマッピングで明示されたものを除く)
4. マーカー仕様
詳細仕様書: packages/cli/docs/MARKER_SPECIFICATION.md
実装: packages/cli/src/lib/sync/marker-processor.ts
4.1 @einja:excluded
テンプレート生成時にセクション全体を除去するマーカー。
<!-- @einja:excluded:start -->
このセクション内容はテンプレートには含まれない
<!-- @einja:excluded:end -->
generate-template.mjsL53-56: CLAUDE.md → CLAUDE.md.template 変換時に除去template-update.tsL56-67: @einja-inc/create-app テンプレート(README.md等)で除去_template-update.tsL173-185: 同上
4.2 @einja:managed
einja sync 実行時に常にテンプレート版で上書きされるセクション。
<!-- @einja:managed:start -->
共通ルール(sync時に最新版で上書き)
<!-- @einja:managed:end -->
- ID属性はオプション:
<!-- @einja:managed:start id="section-a" --> marker-processor.tsL16-17: パース用正規表現
4.3 @einja:project-private
einja sync 実行時に初回のみ追加、以降はユーザー編集を保持するセクション。
<!-- @einja:project-private:start id="commit-rules-project" -->
プロジェクト固有の設定(ユーザーが自由に編集)
<!-- @einja:project-private:end -->
- ID属性は必須(
marker-processor.tsL174-181 でバリデーション) - レガシー
@einja:seedマーカーとの後方互換あり(L44-53, L303-307)
4.4 マーカーバリデーション
packages/cli/scripts/validate-markers.mjs がビルド時(copy-presets.mjs L303-317 から呼び出し)に実行。
| チェック項目 | エラータイプ |
|---|---|
| start/end ペア一致 | unpaired_start / unpaired_end |
| ネスト禁止 | nested |
| project-private に ID 必須 | project_private_without_id |
| ID 重複禁止 | duplicate_id |
4.5 JSON マージ仕様
実装: packages/cli/src/lib/sync/json-processor.ts
設定: .einja-sync.json の jsonPaths フィールド
マージモード(ブラックリスト方式)
| モード | 動作 | 用途 |
|---|---|---|
managed | テンプレート値で強制上書き | テンプレートが完全管理するセクション |
project-private | 完全除外(テンプレートから追加・更新しない) | プロジェクト固有のセクション |
| デフォルト | base/local/templateの3方向マージ | 上記以外の全パス |
ネスト指定
パスはドット区切りでネスト指定可能。deepMergeWithPaths の再帰により
各レベルで jsonPaths チェックが行われる。
例: "project-private": { "package.json": ["devDependencies.@types/node"] }
→ devDependencies 全体は3方向マージ、@types/node のみ除外
設定例
jsonPaths:
managed: { ".claude/settings.json": ["plansDirectory"] }
project-private: { "package.json": ["name", "version", "private", "workspaces"] }
→ plansDirectory はテンプレート強制上書き → name, version 等は完全除外 → scripts, devDependencies 等は3方向マージ
base スナップショット
3方向マージには前回sync時のテンプレート内容(base)が必要。
.einja-sync.json の各ファイルメタデータに baseContent として保存。
初回sync(base なし)はローカル優先 + テンプレート新規キーのみ追加。
コンフリクト
両方が同じキーを異なる値に変更した場合:
- ローカル値を保持(安全側)
- コンソールに警告出力
mergeJsonの戻り値conflicts配列で呼び出し元にも通知
5. post-setup.ts 処理フロー
ファイル: packages/create-app/src/generators/post-setup.ts
@einja-inc/create-app でプロジェクト生成後に実行されるセットアップフロー。
| Step | 処理 | 行番号 |
|---|---|---|
| 0 | 初回セットアップ(scripts/init.sh 実行: mise/Node.js/pnpm/direnv) | L57-64 |
| 1 | 依存関係インストール(pnpm install) + Prismaクライアント生成(pnpm db:generate) | L68-87 |
| 2 | 秘密鍵の自動ローテーション(pnpm env:rotate-secrets --all --non-interactive) | L90-99 |
| 3 | Git初期化(git init → git add . → git commit) | L102-113 |
| 4 | @einja-inc/dev-cli 初期化(npx @einja-inc/dev-cli@latest init --force --no-backup、config.setupEinjaCli が true の場合のみ) | L116-125 |
| 5 | 完了メッセージ表示 | L128 |
6. setup-dev.ts 処理フロー
ファイル: scripts/setup-dev.ts
既存プロジェクトの開発環境セットアップスクリプト。
| Step | 処理 | 行番号 |
|---|---|---|
| 1 | mise インストール確認 | L158-191 |
| 2 | mise シェル設定(eval "$(mise activate zsh)") | L194-213 |
| 3 | Node.js / pnpm インストール(mise install) | L216-249 |
| 4 | direnv インストール確認(macOS: brew install direnv) | L324-355 |
| 5 | シェル設定(direnv hook を rc ファイルに追加) | L358-376 |
| 6 | dotenvx インストール | L379-419 |
| 7 | .env ファイル作成(.env.local から復号、worktree 対応) | L422-517 |
| 8 | .env.personal 作成 + GITHUB_TOKEN 対話設定 | L519-585 |
| 9 | direnv 有効化(direnv allow) | L588-594 |
| 10 | データベース起動(docker-compose up -d postgres) | L597-625 |
| 11 | データベース初期化(pnpm db:generate + pnpm db:push) | L610-613 |
worktree 環境では .env.keys をメインリポジトリから自動コピーする機能あり(L45-67, L73-90)。
7. sync カテゴリ仕様
7.1 dev-cli sync カテゴリ
実装: packages/cli/src/lib/sync/file-filter.ts
| カテゴリ | 対象ファイル | 特別処理 |
|---|---|---|
agents | .claude/agents/einja/** | - |
skills | .claude/skills/{einja-,_einja-}*/** | プレフィックスフィルタ |
hooks | .claude/hooks/** | - |
docs | docs/einja/** | - |
scripts | scripts/** | - |
env | .envrc | 単一ファイル |
tools | .vscode/settings.json | 単一ファイル |
claude-md | CLAUDE.md, AGENTS.md | CLAUDE.md.templateからプレースホルダー展開 |
root-config | package.json, .mcp.json | JSONマージ |
claude-config | .claude/settings.json | JSONマージ |
バリデーション: packages/cli/src/lib/sync/category-validator.ts
7.2 @einja-inc/create-app sync カテゴリ
実装: packages/create-app/src/generators/sync.ts
| カテゴリ | 対象パターン |
|---|---|
env | .env*, .envrc, mise.toml, .node-version |
tools | biome.json, .biomeignore, .vibe-kanban.json, .prettierrc*, .editorconfig |
git | .gitignore, .gitattributes |
git-hooks | .husky/**, .lintstagedrc.js |
github | .github/workflows/**, .github/actions/**, .github/dependabot.yml |
docker | Dockerfile*, docker-compose*.yml, .dockerignore |
monorepo | turbo.json, pnpm-workspace.yaml |
root-config | package.json, tsconfig.json, vitest.config.ts, postcss.config.cjs, next.config.ts, components.json, worktree.config.json |
scripts | scripts/** |
apps | apps/** |
packages | packages/** |
docs | README.md, docs/** |
プロンプト: packages/create-app/src/prompts/sync.ts
8. 管轄境界(dev-cli vs @einja-inc/create-app)
8.1 ファイル管轄テーブル
| ファイル/ディレクトリ | 管轄CLI | sync カテゴリ |
|---|---|---|
.claude/agents/einja/ | dev-cli | agents |
.claude/skills/einja-*/ | dev-cli | skills |
.claude/hooks/einja/ | dev-cli | hooks |
.claude/settings.json | dev-cli | claude-config |
docs/einja/ | dev-cli | docs |
scripts/ | dev-cli | scripts |
CLAUDE.md | dev-cli | claude-md |
AGENTS.md | dev-cli | claude-md |
.envrc | dev-cli | env |
.vscode/settings.json | dev-cli | tools |
package.json | 両方(管理パスが異なる) | dev-cli: root-config / @einja-inc/create-app: root-config |
.mcp.json | dev-cli | root-config |
biome.json, .biomeignore | @einja-inc/create-app | tools |
.gitignore, .gitattributes | @einja-inc/create-app | git |
.husky/, .lintstagedrc.js | @einja-inc/create-app | git-hooks |
turbo.json, pnpm-workspace.yaml | @einja-inc/create-app | monorepo |
tsconfig.json, vitest.config.ts 等 | @einja-inc/create-app | root-config |
Dockerfile*, docker-compose*.yml | @einja-inc/create-app | docker |
.github/workflows/ | @einja-inc/create-app | github |
apps/**, packages/** | @einja-inc/create-app | apps / packages |
8.2 新規ファイル追加時の判断基準
- Claude Code関連(.claude/, CLAUDE.md, AGENTS.md, docs/einja/)→ dev-cli
- プロジェクト基盤(ビルドツール、CI/CD、Docker、lint、テスト設定)→ @einja-inc/create-app
- 両方が関わる(package.json)→ 管理パス(jsonPaths)で分離