بنقرة واحدة
update-store
// ストア情報の更新自動化 — スクリーンショット撮影(シミュレーター × モック画面 × Marionette MCP)とメタデータテキスト更新。ストア更新、スクショ更新、App Store / Google Play のメタデータ更新、リリースノート作成の際に使用すること。
// ストア情報の更新自動化 — スクリーンショット撮影(シミュレーター × モック画面 × Marionette MCP)とメタデータテキスト更新。ストア更新、スクショ更新、App Store / Google Play のメタデータ更新、リリースノート作成の際に使用すること。
アプリのリリース(バージョンbump + CHANGELOG + タグ → GH Actions で自動ビルド・配布)。iOS / Android / macOS / Linux / Windows の任意の組み合わせでリリースできる。「リリース」「バージョン上げて」「リリースして」と言われたときに使う。
ccpocket の X 向けリリース告知カード画像を作成・更新する。最新の iOS/Android/macOS リリースタグ、App Store release_notes、既存の scripts/release-card/generate.mjs を使って英語・日本語の告知PNGを生成し、画像を目視確認して不備があれば生成スクリプトを修正する。「リリースカード」「X告知画像」「リリース報告用画像」「release-card」と言われたときに使用する。
Codex の使い方、CLI/app/IDE、rules・hooks・AGENTS.md・skills・subagents・config などを案内する。Codex や OpenAI 製品の仕様を答える前に必ず公式ドキュメントを確認し、rules/approval は `codex execpolicy check` で実検証すること。
MCP (dart-mcp + Marionette) を使ったFlutterアプリのE2E自動化・UI検証ガイド。シミュレーターでのUI動作確認、モックプレビュー検証、Bridge経由のE2Eテスト、スクリーンショット撮影など、アプリの動作検証が必要なときに使う。「動作確認して」「UIを検証して」「E2Eテスト」「シミュレーターで確認」「モックで確認」と言われたときや、UI変更後の検証フェーズで使用すること。
GitHub Issue・PRのトリアージ。番号を渡すと、要望の要約・実現難易度・既存機能との重複チェック・対応判断を調査してレポートする。Issue/PRの番号が出てきたとき、トリアージ、優先度判断、対応判断と言われたときに使用する。
Shorebird OTA パッチの作成・staging 配布(stable 昇格はユーザー実施)
| name | update-store |
| description | ストア情報の更新自動化 — スクリーンショット撮影(シミュレーター × モック画面 × Marionette MCP)とメタデータテキスト更新。ストア更新、スクショ更新、App Store / Google Play のメタデータ更新、リリースノート作成の際に使用すること。 |
ストアスクリーンショットの自動撮影・合成と、メタデータテキスト(description, release_notes等)の更新を行う。
ccpocket.navigateToStoreScenario)が登録済みcall_custom_extensionが使用可能compose.shで使用)scripts/sim-tap.swift)。macOSアクセシビリティAPIでSimulatorのネイティブダイアログ(通知許可等)をラベル指定でタップできる# 最新リリースタグ
git tag -l 'ios/v*' --sort=-v:refname | head -1
# 現在のバージョン
grep '^version:' apps/mobile/pubspec.yaml
# 前回リリースからの変更コミット
git log $(git tag -l 'ios/v*' --sort=-v:refname | head -1)..HEAD --oneline -- apps/mobile/
CHANGELOGの最新セクションも確認:
head -80 CHANGELOG.md
変更内容を分析し、UI変更があったかどうかを判断する。
AskUserQuestion(multiSelect)で更新対象を確認する。 変更分析結果に基づいて推奨をdescriptionに含める。
iPhone スクリーンショット(8シナリオ):
| Key | シナリオ名 | 内容 | テーマ |
|---|---|---|---|
01_session_list | Session List (Recent) | ホーム画面(名前付きセッション) | ライト |
02_approval_list | Session List | 承認待ち一覧(3セッション) | ライト |
03_multi_question | Multi-Question Approval | 質問UI(3問) | ライト |
04_markdown_input | Markdown Input | Markdown箇条書き入力 | ライト |
05_image_attach | Image Attach | 画像添付UI | ライト |
06_git_diff | Git Diff | Diff表示画面 | ライト |
07_new_session | New Session | 新規セッションシート | ライト |
08_dark_theme | Session List | 承認待ち一覧(ダークモード訴求) | ダーク |
iPad スクリーンショット(5シナリオ):
| Key | シナリオ名 | 内容 | テーマ |
|---|---|---|---|
01_workspace_overview | Workspace Overview | 左一覧 + 中央チャット + 右Git | ライト |
02_workspace_explorer | Workspace Explorer | 左一覧 + 中央チャット + 右Explorer | ライト |
03_approval_context | Approval In Context | 左一覧 + 中央承認UI | ライト |
04_approval_queue | Approval Queue | 複数の承認待ちセッションを同時に確認 | ライト |
05_dark_workspace | Dark Workspace | 3-pane ワークスペースのダークテーマ訴求 | ダーク |
メタデータテキスト:
| ファイル | 対象 |
|---|---|
fastlane/metadata/en-US/release_notes.txt | iOS リリースノート (EN) |
fastlane/metadata/ja/release_notes.txt | iOS リリースノート (JA) |
fastlane/metadata/en-US/description.txt | App Store 説明文 (EN) |
fastlane/metadata/ja/description.txt | App Store 説明文 (JA) |
fastlane/metadata/en-US/promotional_text.txt | プロモーションテキスト (EN) |
fastlane/metadata/android/en-US/full_description.txt | Play Store 説明文 (EN) |
fastlane/metadata/android/ja-JP/full_description.txt | Play Store 説明文 (JA) |
fastlane/metadata/android/en-US/changelogs/default.txt | Play Store リリースノート (EN) |
fastlane/metadata/android/ja-JP/changelogs/default.txt | Play Store リリースノート (JA) |
上記のファイルパスは apps/mobile/ からの相対パス。
CHANGELOGの内容をベースに:
更新後、AskUserQuestionで内容確認を挟む。
xcrun simctl list devices available | grep -E "iPhone 17|iPad Pro.*13"
ソフトウェアキーボードを無効化(全デバイス共通、セッション冒頭で1回実行):
defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true
これによりソフトウェアキーボードが表示されなくなり、日本語キーボードがスクショに映り込む問題を防止する。
iPhone / iPad ともに 既存シミュレーターを再利用するのがデフォルト。毎回 erase すると通知・音声認識・マイク等のネイティブダイアログが再出現し、スクショフローが不安定になる。通常はアプリの再起動と向き調整だけで十分。
iPhone 17 Proシミュレーターを起動し、ライトモードに設定:
xcrun simctl boot "iPhone 17 Pro" 2>/dev/null || true
xcrun simctl ui booted appearance light
英語ロケール設定(ストアスクショは en-US 基準のため):
# iPhone・iPad の両デバイスIDで実行
for ID in <iPhone_ID> <iPad_ID>; do
xcrun simctl spawn $ID defaults write -g AppleLanguages "(en-US)"
xcrun simctl spawn $ID defaults write -g AppleLocale "en_US"
done
# 反映には再起動が必要
for ID in <iPhone_ID> <iPad_ID>; do
xcrun simctl shutdown $ID
done
sleep 2
for ID in <iPhone_ID> <iPad_ID>; do
xcrun simctl boot $ID
done
これによりアプリ内の標準コンポーネント(DatePicker、システムダイアログ等)も英語化される。
アプリ内文言はカスタムエクステンション ccpocket.setLocale で別途 en に切り替える。
ステータスバーを Apple 純正風に固定(9:41 / WiFi / 100% 充電 / キャリア非表示):
for ID in <iPhone_ID> <iPad_ID>; do
xcrun simctl status_bar $ID override \
--time "9:41" \
--dataNetwork wifi \
--wifiMode active \
--wifiBars 3 \
--cellularMode notSupported \
--batteryState charged \
--batteryLevel 100
done
iPad の日付について(既知の制限):
iPad のステータスバーには時刻に加えて日付(例: Tue Apr 21)が表示されるが、xcrun simctl status_bar --time は 時刻部分のみ反映で日付は変更不可(Xcode 26.1 時点で ISO 日付を渡してもエラーになる)。
Apple 純正アプリのスクショは Apr 1 等になっているが、現状はシミュレーターのシステム日付がそのまま出る。完全一致が必要な場合のみ、シミュレーター内 Settings > General > Date & Time > Set Automatically OFF で手動設定する。通常は許容して進める。
参考:
dart-mcp launch_app でアプリを起動:
root: /Users/k9i-mini/Workspace/ccpocket/apps/mobile
device: <iPhone 17 Pro の device ID>
起動後、dart-mcp list_running_apps でDTD URIを取得し、connect_dart_tooling_daemon で接続。
dart-mcp get_app_logs でVM Service URIを取得し、marionette connect で接続。
テーマ設定: アプリ起動後、カスタムエクステンションでテーマを切り替える(01〜07はライトテーマ):
call_custom_extension: ccpocket.setTheme / { "theme": "light" }light, dark, system言語設定: 必要に応じてカスタムエクステンションで言語を切り替える:
call_custom_extension: ccpocket.setLocale / { "locale": "en" }en, ja, zh, "" (システムデフォルト)選択された各シナリオに対して:
遷移: marionette call_custom_extension
ccpocket.navigateToStoreScenario{ "scenario": "<シナリオ名>" }待機: 2-3秒(描画完了を待つ。New SessionやImage Attachなど複雑なUIは3秒推奨)
撮影:
xcrun simctl io booted screenshot apps/mobile/fastlane/screenshots/en-US/<key>.png
戻る: marionette call_custom_extension
ccpocket.popToRoot待機: 1秒(ルートへの遷移完了)
08_dark_theme の撮影: 01〜07撮影後、ccpocket.setTheme で dark に切り替え、Session List シナリオを撮影する。
dart-mcp stop_app でアプリを停止。
シミュレーターはシャットダウンしない。次のデバイスの起動に進む。
iPad は iPhone とは別セットを撮影する。既存の mobile 専用シナリオを流用せず、 workspace レイアウト前提の 5 シナリオを撮る。
iPadでアプリが互換モード(iPhone用の小さいウィンドウ + 黒帯)で起動する場合がある。
ただし、通常は erase しない。まずは既存シミュレーターをそのまま使い、アプリだけ再起動する:
# シミュレーターを起動(未起動なら)
xcrun simctl boot "iPad Pro 13-inch (M4)" 2>/dev/null || true
重要: erase を実行するとアプリがアンインストールされ、通知・音声認識・マイク等のネイティブダイアログが毎回復活する。これはスクショ取得の妨げになるため、erase は最後の手段に限定する。
erase を使ってよいケース:
その場合のみ、以下を実行してやり直す:
xcrun simctl shutdown "iPad Pro 13-inch (M4)" 2>/dev/null || true
xcrun simctl erase "iPad Pro 13-inch (M4)"
xcrun simctl boot "iPad Pro 13-inch (M4)" 2>/dev/null || true
横向き前提: iPad スクショは landscape で撮る。起動後に sim-tap.swift の準備コマンドを必ず実行する:
swift .claude/skills/update-store/scripts/sim-tap.swift prepare-store ipad
これで以下をまとめて行う:
Device > Orientation > Landscape Left で iPad を明示的に横向き固定撮影中に向きが崩れた場合や許諾ダイアログが再表示された場合も、スクショを撮る前に再度これを実行する。
ネイティブダイアログの自動dismiss: erase を避ければ、これらのダイアログは通常は再発しない。既存シミュレーター再利用時は、まず prepare-store ipad で向きを整え、ダイアログが出ていた場合だけ dismiss する。
事前権限付与: もし erase を実行した場合のみ、アプリ起動前に実行する:
xcrun simctl privacy booted grant notifications com.k9i.ccpocket
xcrun simctl privacy booted grant speech-recognition com.k9i.ccpocket
xcrun simctl privacy booted grant microphone com.k9i.ccpocket
これによりダイアログの表示自体を防止できる。simctl privacy が失敗した場合は以下のフォールバックを使う。
フォールバック: sim-tap.swift の個別コマンド: ダイアログはホーム画面ではなくセッション画面遷移後に表示されることがある。 最初のシナリオ遷移後にdismissし、必要なら撮り直す。
AX API でボタンが見つからない場合(特にiPad)、CGEvent ベースのクリックで自動フォールバックする:
swift .claude/skills/update-store/scripts/sim-tap.swift rotate right
swift .claude/skills/update-store/scripts/sim-tap.swift dismiss-dialogs ipad
swift .claude/skills/update-store/scripts/sim-tap.swift dismiss-dialogs iphone
従来の個別タップも引き続き使用可能:
while swift .claude/skills/update-store/scripts/sim-tap.swift tap "許可" 2>/dev/null; do sleep 1; done
テーマ設定: iPad 側は Dark Workspace 以外をライトテーマで撮る。アプリ起動後に最初に一度:
marionette call_custom_extension
ccpocket.setTheme{ "theme": "light" }Dark Workspace はシナリオ側で一時的にダークへ切り替わるため、個別に setTheme dark する必要はない。
各シナリオに対して:
marionette call_custom_extension
ccpocket.navigateToStoreScenario{ "scenario": "<シナリオ名>" }Workspace OverviewWorkspace ExplorerApproval In ContextApproval QueueDark Workspace2-3秒待機
撮影
swift .claude/skills/update-store/scripts/sim-tap.swift capture-store ipad apps/mobile/fastlane/screenshots/en-US/ipad_<key>.png
marionette call_custom_extension
ccpocket.popToRoot1秒待機
撮影後、スクショの解像度がiPadのネイティブ解像度と一致するか検証する:
swift .claude/skills/update-store/scripts/sim-tap.swift capture-store ipad apps/mobile/fastlane/screenshots/en-US/ipad_<key>.png
# 解像度検証(互換モード検出)
WIDTH=$(sips -g pixelWidth apps/mobile/fastlane/screenshots/en-US/ipad_<key>.png | tail -1 | awk '{print $2}')
HEIGHT=$(sips -g pixelHeight apps/mobile/fastlane/screenshots/en-US/ipad_<key>.png | tail -1 | awk '{print $2}')
echo "Screenshot: ${WIDTH}x${HEIGHT}"
# iPad Pro 13-inch (M4) landscape: 2752x2064 が期待値
# 解像度が大幅に小さい場合のみ、互換モードを疑って erase を検討する
もし解像度が期待値と異なる場合は、まずアプリ再起動で再確認する。それでも解消しない場合のみ erase、必要に応じて flutter clean → flutter build ios --simulator でやり直すこと。
dart-mcp stop_app でアプリを停止。
シミュレーターはシャットダウンしない(compose.sh 実行や確認に支障はない)。
cd apps/mobile && bash fastlane/screenshots/compose.sh
このスクリプトが行うこと:
fastlane/screenshots/store/ へコピー(fastlane deliver用)fastlane/metadata/android/ へコピー(Google Play用)docs/images/screenshots.png を更新(READMEバナー)# 生成画像の確認
ls -la apps/mobile/fastlane/screenshots/store/en-US/
ls -la apps/mobile/fastlane/screenshots/store/ja/
# 変更ファイル一覧
git diff --stat
| シナリオ名(extension引数) | ファイルキー(スクショファイル名) | テーマ |
|---|---|---|
| Session List (Recent) | 01_session_list | ライト |
| Session List | 02_approval_list | ライト |
| Multi-Question Approval | 03_multi_question | ライト |
| Markdown Input | 04_markdown_input | ライト |
| Image Attach | 05_image_attach | ライト |
| Git Diff | 06_git_diff | ライト |
| New Session | 07_new_session | ライト |
| Session List | 08_dark_theme | ダーク |
addPostFrameCallbackで自動表示されるため、3秒待機推奨ConnectHardwareKeyboard を有効化済み)xcrun simctl list devices available で確認convert / magick) が必要。PNGタイムスタンプを除去して不要なgit diffを防止2752x2064 を基準に扱うxcrun simctl status_bar <ID> clear を実行する(override 自体はシミュレーター再起動後も保持される)xcrun simctl spawn <ID> defaults write -g AppleLanguages "(ja-JP)" + defaults write -g AppleLocale "ja_JP" を実行して再起動