メインコンテンツまでスキップ

組み込みリソース同期プロセス

resources/design-studio-builtin/ 配下の 600 件以上のファイル (Skill / Design System / Craft) は git には含まれていません。これらはコミットピンに基づいて upstream の nexu-io/open-design リポジトリから取得され、初回起動時にマテリアライザーによってユーザーディレクトリへ実体化されます。

この方式を採用している理由: upstream のコンテンツは大規模で、頻繁に更新されます。すべてをコミットすると、elftia の git 履歴に大きなノイズが入り、マージコンフリクトも頻発します。コミットをピン留めすることで再現可能なビルドを保証しつつ、「組み込みアセットのアップグレード」をロックファイルの一度きりの更新にできます。

:::warning キュレーション例外: prompt-templates/ は同期しない (2026-06-04)

prompt-templates/ は、その場で管理される手動キュレーション済みサブセットであり、同期には参加しません。upstream の完全なコレクションには、実在人物の顔(例: Elon Musk の画像を生成するテンプレート)のようなコンテンツリスクのあるエントリが含まれており、これらの JSON はすべてのチャンネルリリースで匿名閲覧可能な「コミュニティテンプレート」としてパッケージ化されてしまうためです。したがって:

  • ロックの subdirs には prompt-templates含まれていません。同期スクリプトには NEVER_SYNC_SUBDIRS セーフガードがあり、これを戻すとハードフェイルします(再同期はまず clearSubdirs でキュレーション済みセットを削除し、その後フィルターされていない upstream の完全セットを注入します)。
  • upstream から新しいテンプレートを導入する場合: JSON を 1 つずつ手動でコピーしてレビューし(実在人物の顔 / ブランド IP / NSFW)、キュレーションログを更新します — resources/design-studio-builtin/prompt-templates/README.md を参照してください。
  • このディレクトリは例外的に git に入ります.gitignoreresources/design-studio-builtin/* に対して !…/prompt-templates/ で反転されています)。新規 clone でもネットワークアクセスなしでキュレーション済みセットをすぐに再現できます。

:::

関連ファイル

パス目的git に含まれるか
resources/design-studio-builtin.lock.jsonピンファイル — { repo, commit, subdirs }✅ git 内の唯一のファイル
resources/design-studio-builtin/ディスク上の同期済みコンテンツ(600 件以上)❌ gitignored
resources/design-studio-builtin/prompt-templates/キュレーション例外 — 手動キュレーション済みサブセット、同期しない(上記警告を参照)、README.md キュレーションログを含む✅ git 内の例外(gitignore 反転)
resources/design-studio-builtin/.synced.jsonマーカー — 最後に成功した同期コミットを記録し、一致時はスキップ❌ (無視対象ディレクトリ内)
resources/design-studio-builtin/NOTICE自動生成されるサードパーティ帰属表示
scripts/sync-design-studio.mjs同期スクリプト(ロックに基づいて取得)
scripts/update-design-studio.mjs自動アップグレードスクリプト — upstream HEAD の取得 + ロック更新 + 同期 + FLAG_FILENAME 更新を 1 コマンドで実行
packages/desktop/app/main/services/content/workspace/design/builtin/index.ts初回起動マテリアライザー + FLAG_FILENAME

トリガータイミング

トリガーコマンド / フックモード
npm installpostinstall フック--soft(ネットワーク失敗はインストールをブロックしない)
npm run setup / setup:native手動初期化--soft
npm run build:electron / build:official / build:steamelectron-vite buildelectron-builder の間厳格モード(失敗するとビルド失敗)
npm run sync:design手動実行厳格モード
npm run sync:design -- --force手動実行(強制再取得)厳格モード + マーカーをスキップ
npm run sync:design:updateupstream HEAD へのワンクリックアップグレード(推奨)下記「upstream 最新コミットへのアップグレード」を参照

マーカーがヒットした場合({repo, commit, subdirs} の 3 フィールドすべてがロックと完全一致)、そのままスキップし、[sync:design] already synced @ <repo>@<sha7> — skipping (use --force) を出力します。これは正常な状態です。エラーと取り違えないでください。

同期スクリプトが行うこと

scripts/sync-design-studio.mjs のメインフロー:

  1. resources/design-studio-builtin.lock.json を読み込み、スキーマを検証(repo / commit / subdirs[] が必須)
  2. ローカルの .synced.json マーカーと比較 — 3 フィールドすべてが一致し、--force がなければスキップして終了
  3. tarball を取得:
    • パブリックリポジトリ → https://codeload.github.com/<repo>/tar.gz/<commit>
    • GITHUB_TOKEN / GH_TOKEN 環境変数を設定した後 → https://api.github.com/repos/<repo>/tarball/<commit>(プライベートリポジトリではこちらを使用)
  4. decompress で展開し、strip: 1 で外側のパッケージ名ディレクトリを削除し、filter でロックに列挙された subdirs のみを残す
  5. 展開前に fs.rm(subdir, { recursive: true, force: true }) で各ターゲットサブディレクトリをクリーンにし、upstream で削除された後の古いファイルが残らないようにする
  6. マーカー .synced.json を書き込む
  7. NOTICE を書き込む — サードパーティ帰属表示を自動生成(Apache-2.0)

decompress 4.x のクロスプラットフォーム注意点(壊さないこと)

stripfilter より前に適用されますが、Windows では filter が受け取るパスはすでにバックスラッシュに正規化されています。スクリプトの filter は file.path.split(/[\\/]/)[0] を使い、両方の区切り文字に対応しています — / だけで分割すると Linux では 600 件以上のファイルがすべて通りますが、Windows では 0 件になり、失敗モードは無音(空のディレクトリだけが出力される)なのでデバッグが厄介です。このセクションを変更する場合は、両方のプラットフォームで検証してください。

upstream 最新コミットへのアップグレード

推奨パス: ワンクリック自動化

npm run sync:design:update

scripts/update-design-studio.mjs は、「アップグレード」プロセスの 3 ステップを 1 つのアクションにまとめます:

  1. GET https://api.github.com/repos/<repo>/commits/HEAD — upstream デフォルトブランチ HEAD の SHA を解析
  2. ロック内の commit と同じ場合 → already up to date — nothing to do をログ出力して exit 0
  3. 異なる場合は、ロックファイルの commit フィールドを正規表現で置換(元のフォーマットを保持)し、sync-design-studio.mjs を spawn して取得・展開します。同期が失敗した場合は自動的にロックをロールバックし、未同期コミットへの汚れたポインターを残しません
  4. upstream の新しいコミットの short-sha(先頭 7 文字)を使い、services/content/workspace/design/builtin/index.tsFLAG_FILENAME 定数を .elftia-builtin-materialized-<short-sha>.json に正規表現で書き換えます — 既存ユーザーの <userData> 内にある古いフラグファイル名とは一致しなくなり、次回起動時に新しいコンテンツが再マテリアライズされます
  5. git diff / git commit のヒントを表示

コミット時に変更されるファイルは lock.jsonbuiltin/index.ts の 2 つだけです。

フラグ命名規則: FLAG_FILENAME には upstream コミットの short-sha(例: .elftia-builtin-materialized-83ddf76.json)を埋め込みます。以前は整数のバージョン番号 v1/v2/... でしたが、short-sha 形式に移行しました — コミットを切り替えると名前も自然に変わるため、手動のバージョン番号を管理する必要はありません。

Dry-run:

npm run sync:design:update -- --dry-run

SHA の差分だけを表示し、ファイルには一切触れません。CI で「新しい upstream バージョンが利用可能かどうか」を検出するために使用できます。

Auth: GITHUB_TOKEN が設定されていない場合、GitHub パブリック API は未認証で 60 req/hr に制限されます。CI では GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} を設定して 5000 req/hr にしてください。

代替パス: 手動 3 ステップ

自動スクリプトが壊れている場合、またはデフォルトブランチ以外 / 過去のコミットにピン留めしたい場合にのみ使用してください:

  1. ロックを変更: resources/design-studio-builtin.lock.jsoncommit フィールドに 40 文字の完全な SHA を書き込む(短縮ハッシュではありません — スクリプトは厳密な文字列比較を行います)

  2. 同期を実行:

    npm run sync:design

    commit がマーカーと一致しない場合は自動的に再取得されるため、--force は不要です。--force は、マーカーとロックが一致しているがローカルディレクトリが破損しており、強制的に再取得したい場合にのみ使います。

  3. FLAG_FILENAME を更新: packages/desktop/app/main/services/content/workspace/design/builtin/index.ts を編集し、定数を新しいコミットの short-sha に変更します:

    const FLAG_FILENAME = '.elftia-builtin-materialized-<new short-sha>.json';

    このステップは重要です — 既存の elftia ユーザーの <userData>/elftia/.elftia-builtin-materialized-<old>.json フラグが一致しなくなり、次回起動時に再マテリアライズがトリガーされます。更新しない場合、新規インストールだけが新しいコンテンツを取得し、既存ユーザーには古いコンテンツが表示され続けます。

検証

# ローカルマーカーを削除して検証を強制再実行
rm resources/design-studio-builtin/.synced.json
npm run sync:design

# NOTICE の新しいファイル数 / 日付を確認
cat resources/design-studio-builtin/.synced.json
cat resources/design-studio-builtin/NOTICE | head -10

よくある操作

シナリオコマンド
upstream 最新コミットへアップグレード(フラグ更新を含む)npm run sync:design:update
新しい upstream バージョンが利用可能か確認(ファイルは変更しない)npm run sync:design:update -- --dry-run
ローカルが同期済みか / どのコミットへ同期済みか確認cat resources/design-studio-builtin/.synced.json
1 回だけ強制再取得(ディレクトリ破損 / 不完全な展開の疑い)npm run sync:design -- --force
upstream main の最新 SHA を問い合わせgh api repos/nexu-io/open-design/commits/main --jq .sha
一時的に同期をスキップ(CI デバッグ)ロックファイルを削除 → スクリプトが "lock file missing, skipping" とログ出力して終了
upstream をプライベートフォークに置き換えロックの repo フィールドを変更し、GITHUB_TOKEN を export してから同期を実行

トラブルシューティング

症状原因 / 解決策
[sync:design] already synced @ ... — skipping (use --force)正常、マーカーがヒットしています。再取得するには -- --force を追加
HTTP 404 ... (private repo? set GITHUB_TOKEN)ロック内のリポジトリがプライベート、またはコミットが存在しません。GITHUB_TOKEN を export するか SHA を確認
no files matched subdirs [...]subdirs のディレクトリがそのコミットに存在しません(upstream でリネーム / リファクタリング済み)。そのコミットのディレクトリ構成を確認
Windows では同期が成功するが製品ディレクトリが空decompress filter のパス区切り文字問題。スクリプトの split(/[\\/]/)split('/')変更しないでください
ユーザーがアップグレードしたが新しい組み込み Skill が見えないFLAG_FILENAME の更新忘れです。古いユーザーの古いフラグが残っている → マテリアライズをスキップ。sync:design:update は自動更新しますが、手動でロックを変更する場合はステップ 3 を忘れないでください
sync:design:updateHTTP 403 ... rate-limited? を報告GitHub 未認証 API は 60 req/hr に制限されています。GITHUB_TOKEN を export して再実行
sync:design:update は同期に成功したがフラグが変わらないservices/content/workspace/design/builtin/index.tsFLAG_FILENAME がリネームされていないか確認してください — スクリプトは正規表現 const FLAG_FILENAME = '\.elftia-builtin-materialized-...\.json'; で位置を特定するため、リネーム後は失敗します
CI の tarball 取得が遅すぎる / 帯域幅を超えるactions/cache を使い、ロックファイルハッシュをキーに resources/design-studio-builtin/ をキャッシュして、ヒット時はダウンロードをスキップ

関連ファイル / モジュール