# CuePaste 開発ログ

## 2026-06-08

### 詳細記録

この日の開発では、CuePasteを「プロンプトファイルをキーワードコマンドとして呼び出し、前面アプリへ貼り付けるmacOSメニューバーアプリ」として動作するところまで進めた。実装は、ローカルLinux環境ではSwiftを実行できない制約があったため、純粋ロジックを`CuePasteCore`へ分離し、macOS実機とGitHub Actionsで確認する方針にした。

設計上の中心は、OS依存処理とテスト可能な処理の分離である。`PromptResolver`、`PromptReader`、`PromptCompleter`は`Foundation`中心の処理として切り出し、ファイル探索、UTF-8読込、補完候補生成をユニットテスト対象にした。一方、メニューバー、設定画面、グローバルホットキー、アクセシビリティ権限、クリップボード、自動ペースト、キー入力処理は`Sources/CuePaste/`側に置いた。

プロンプト検索は、最終的にプロンプトフォルダ直下の`.md`/`.txt`だけを対象にした。初期仕様ではサブフォルダ対応も想定していたが、実際の利用方針では「フォルダ内のファイル名をシェルのコマンド名のように補完する」ことが重要だったため、サブフォルダ探索と部分一致は除外した。これにより、補完仕様は前方一致だけになり、候補が複数ある場合は共通prefixまで補完し、さらにTabを押すと候補を順に巡回する単純な挙動に整理できた。

入力画面は`NSPanel`とSwiftUIビューの組み合わせで実装した。最初はSwiftUIの`TextField`に近い形で進めたが、TabキーやReturnキーをコマンド入力として扱うには不十分だった。`NSTextField`はfield editorである`NSTextView`へ実際の編集を委譲するため、`NSTextField.keyDown`だけではTabやReturnを安定して捕捉できない。最終的に`NSTextFieldDelegate`の`control(_:textView:doCommandBy:)`で`insertNewline:`、`insertTab:`、`cancelOperation:`を処理し、Returnで実行、Tabで補完、Escでキャンセルする形にした。

入力欄が1文字しか入力できない問題も発生した。原因は、SwiftUIの更新ごとに`makeFirstResponder`や`stringValue`の更新が走り、field editorの状態を壊していたことだった。対策として、フォーカス取得は初回表示時だけにし、補完でモデル側の文字列が変わる時だけfield editorの文字列とカーソル位置を明示的に更新するようにした。

グローバルショートカットは、当初は固定またはプリセット選択で考えていたが、`Command + :` が環境によって安定しないことが分かった。そこでSettingsの`Record`ボタンを押した後に実際に入力されたキーコードと修飾キーを保存し、その内容をCarbonの`RegisterEventHotKey`へ渡す方式に変更した。実機ではこの方式で`Command + :`の登録と起動を確認できた。

ログ機能は、デバッグと実機確認のために追加した。ただし、プロンプト本文やクリップボード内容、個人パスなどの機微情報は記録しない方針にした。ログには、アプリ起動、設定画面表示、入力画面表示、ショートカット登録、実行キーワード、補完候補数、失敗種別だけを記録する。ログはSettingsで明示的に有効化した場合だけ`Application Support/CuePaste/cuepaste.log`へ出力する。

入力ソースについては、コマンド入力が英数字のキーワードを前提にしているため、Settingsで有効にした場合だけコマンド入力画面を英数入力で開く機能を追加した。表示時に現在の入力ソースを保存し、英数入力へ切り替え、閉じる時に保存した入力ソースへ戻す。入力ソース切替はmacOS全体へ影響するため、ユーザーが設定で無効化できるようにした。

配布はGitHub ActionsでIntel macOS向けとApple Silicon macOS向けの未署名DMGを作る方針にした。Swift Packageだけでは`.app`バンドルが生成されないため、`scripts/build-dmg.sh`で`Contents/MacOS`、`Contents/Resources`、`Info.plist`を組み立て、`hdiutil`でDMG化した。DMGには`CuePaste.app`と`Applications`へのリンクを入れ、ドラッグしてインストールできるようにした。アイコンは`images/cuepaste-icon.png`から`.iconset`と`.icns`を生成し、DMG用アプリバンドルへ入れている。Release Assetsには、DMGに加えてソースコードのzip/tar.gzも明示的に添付する。

GitHub Actionsでは、`main.swift`と`@main`の衝突で一度ビルドに失敗した。SwiftPMでは`main.swift`がトップレベルコード用として扱われるため、`@main`を使う場合は通常のファイル名にする必要がある。`CuePasteApp.swift`へ移したことで解決した。Actions上ではXcode 16.4、Swift 6.1.2で`swift test`が通り、DMGとSHA-256ファイルをGitHub Releasesへアップロードできた。

実機確認では、アプリ起動、アクセシビリティ権限、設定画面、ショートカット記録、`Command + :`による入力画面表示、ログ出力、キーワードコマンド読込、ペースト成功を確認した。Tab補完はログ上ではTabイベントと候補取得が確認できたが、最終的な候補巡回仕様は`v0.1.9`で改めて確認する必要がある。

### MVPアプリ基盤の作成

- 変更内容: 仕様に設定画面、Tab補完、`exit` コマンド、エラー時に入力画面を閉じない挙動を追記した。
- 変更内容: GitHub ActionsのNode.js 20非推奨警告に対応するため、workflowに `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24` を設定した。
- 変更内容: `PromptCompleter` とユニットテストを追加し、Tabキーによるキーワード補完を実装した。
- 変更内容: メニューバーから設定画面を開き、プロンプトフォルダを選択できるようにした。
- 変更内容: Carbonのグローバルホットキー登録を追加し、設定画面で入力したキーを起動ショートカットとして登録できるようにした。
- 変更内容: コマンド入力画面で `exit` を実行すると閉じ、エラー時は画面を保持するようにした。
- 変更内容: 入力欄のフォーカスを毎回取り直さないようにし、入力中の文字列上書きを避けるようにした。
- 変更内容: Tab補完時に、候補が見つからない場合は対象フォルダを、候補がある場合は候補数と候補名を表示するようにした。
- 変更内容: Return、Tab、Escをfield editorのcommand selectorで処理し、コマンド入力中のキー操作を安定させた。
- 変更内容: プロンプト検索とTab補完をプロンプトフォルダ直下のファイルだけに限定し、Tabを繰り返すと候補を順に巡回するようにした。
- 変更内容: SettingsからAbout CuePasteを表示できるようにした。
- 変更内容: Settingsからログの有効化、ログ表示、ログクリアを操作できるようにし、実行・補完・ショートカット登録のイベントを記録するようにした。
- 変更内容: コマンド入力欄の左に表示専用のプロンプト記号 `> ` を追加した。
- 変更内容: SwiftPMで `@main` と `main.swift` が衝突する問題を避けるため、アプリ入口を `CuePasteApp.swift` に移した。
- 変更内容: DMG内に `CuePaste.app` と `Applications` へのリンクを配置し、Releaseには `.dmg` を直接添付する方針を明記した。
- 変更内容: GitHub ActionsのDMG生成をIntel / Apple Siliconのmatrix buildに変更し、Release Assetsへソースコードのzip/tar.gzも添付するようにした。
- 変更内容: Swift Package構成、`CuePasteCore`、最小のmacOSメニューバーアプリ、コマンド入力パネル、クリップボードコピー、アクセシビリティ確認、`Command + V`送信処理を追加した。
- 変更内容: `.md`優先、`.txt`フォールバック、サブフォルダ、未検出、空キーワード、パストラバーサル、UTF-8読込のユニットテストを追加した。
- 変更内容: GitHub ActionsでIntel macOS向け未署名DMGを作るworkflowと、Swift Packageの実行ファイルを`.app`化してDMGへ入れるスクリプトを追加した。
- 変更内容: READMEに目的、実装状況、プロンプトファイル仕様、開発手順、DMG生成手順、設計方針を整理した。
- 変更内容: `images/cuepaste-icon.png` からmacOS用の `Resources/AppIcon.icns` と `Resources/AppIcon.iconset/` を生成し、DMG用アプリバンドルの `CFBundleIconFile` に設定した。
- 理由: MVPのうち、プロンプトファイル検索と読込をUIや権限処理から分離し、先にテスト可能な中核を固めるため。
- 判断: SwiftUIだけで完結させず、メニューバー常駐、グローバルホットキー、キーイベント、フォーカス制御などmacOS固有の処理はAppKit/Carbon側へ寄せた。
- 判断: プロンプト解決、UTF-8読込、補完候補生成は`CuePasteCore`へ分け、GitHub Actions上の`swift test`で検証できるようにした。
- 判断: 自動ペーストと補完の対象は、プロンプトフォルダ直下の`.md`/`.txt`だけに限定した。サブフォルダや部分一致は便利に見えるが、シェル風のコマンド補完としては挙動が曖昧になるためMVPでは採用しない。
- 判断: Tab補完は前方一致だけとし、候補が複数ある場合は共通prefixまで補完する。さらにTabを押した場合は候補を順に巡回する仕様にした。
- 判断: `> ` はキーワード文字列へ含めず、表示専用にした。入力値へ混ぜると補完と検索の責務が曖昧になるため。
- 判断: ショートカット設定はプリセット選択ではなく、Settingsの`Record`後に実際に押したキーを保存する方式にした。`Command + :` は環境依存で不安定だったが、記録方式では実機で登録できた。
- 判断: ログはSettingsで明示的にオンにした場合だけ出力する。プロンプト本文、クリップボード内容、個人パスなどは記録せず、実行イベント、補完候補数、失敗種別だけを記録する。
- デバッグ: SwiftPMでは`main.swift`がトップレベルコード用として扱われるため、同じターゲット内で`@main`を使うと`'main' attribute cannot be used in a module that contains top-level code`で失敗した。アプリ入口を`CuePasteApp.swift`へ移して解決した。
- デバッグ: 入力ソース切替で使うCarbonの`kTIS...`定数は、GitHub Actions上のSwift 6.1.2ではすでに`CFString`として取り込まれた。`takeUnretainedValue()`を呼ぶとコンパイルできないため、`CFString`をそのまま`CFDictionary`へ渡す実装に修正した。
- デバッグ: `NSTextField`は実際の入力をfield editorである`NSTextView`へ委譲するため、`NSTextField.keyDown`だけではReturnやTabを安定して捕捉できなかった。`NSTextFieldDelegate`の`control(_:textView:doCommandBy:)`で`insertNewline:`、`insertTab:`、`cancelOperation:`を処理する形に変更した。
- デバッグ: 入力欄が1文字しか入力できない問題は、SwiftUI更新のたびに`makeFirstResponder`や`stringValue`更新が走り、field editorの状態を壊していたことが原因と判断した。初回表示時だけフォーカスを取り、補完時だけfield editorの文字列を明示更新するようにした。
- デバッグ: Tabキー自体はログで捕捉できていた。補完されない原因は、当初の仕様が前方一致であり、入力文字列が候補名の途中にしか含まれない場合は候補にならないためだった。部分一致は採用せず、前方一致だけとする仕様を明確化した。
- デバッグ: GitHub ActionsのmacOS runnerではXcode 16.4とSwift 6.1.2でビルド・テストできることを確認した。ローカルLinux環境には`swift`がないため、Swiftの実行検証はGitHub Actionsで行う運用にした。
- デバッグ: GitHub ActionsのNode.js 20非推奨警告は、DMG生成失敗の直接原因ではなかった。`FORCE_JAVASCRIPT_ACTIONS_TO_NODE24`を設定しつつ、実際の失敗原因は各stepのログ本文で確認する必要があると分かった。
- デバッグ: Swift Packageの実行ファイルだけでは`.app`バンドルは生成されないため、`scripts/build-dmg.sh`で`Contents/MacOS`、`Contents/Resources`、`Info.plist`を組み立て、`hdiutil`でDMG化した。
- デバッグ: macOS用アイコンは`images/cuepaste-icon.png`から`Resources/AppIcon.icns`と`.iconset`を生成した。GitHub ActionsではmacOS標準の`sips`/`iconutil`、ローカルではPillowを使えるようにした。
- デバッグ: DMGは`CuePaste.app`だけを入れるより、`Applications`へのリンクも入れた方が一般的なドラッグインストール導線になるため、stagingディレクトリに`.app`と`Applications`リンクを並べてDMG化した。
- 検証: GitHub Actionsで`swift test`が12件成功し、Intel macOS向け未署名DMGとSHA-256ファイルがGitHub Releasesへアップロードされたことを確認した。
- 検証: 実機でアプリ起動、アクセシビリティ権限、設定画面、ショートカット記録、`Command + :`での入力画面表示、ログ出力、キーワードコマンド読込、ペースト成功を確認した。
- 未確認: 最新のTab補完巡回仕様は、`v0.1.9`のDMGで実機確認が必要である。

### 配布方針の決定

- 変更内容: MVPの配布物を、GitHub Actionsで作成したIntel macOS向けの未署名DMGとする方針を`docs/promptpaste_spec.md`と`docs/technical-stack-research.md`へ追記した。
- 理由: GitHub ActionsのIntel macOS runnerを使えば、ローカル環境に依存せずIntel Mac向けDMGを作成できるため。
- 判断: コード署名と公証はMVPの対象外とし、将来の改善対象にする。配布物はGitHub Releasesから取得できるようにする。
- 検証: ドキュメント更新のみ。実際のGitHub Actions workflow作成とDMG生成は未実施。

## 2026-06-07

### 開発実機の空き容量確認

- 変更内容: 内蔵ストレージの空きが約10GBであることを踏まえ、Xcode導入に必要な容量と外付けSSD案を`docs/technical-stack-research.md`へ追記した。
- 理由: Xcodeはダウンロード、展開、本体、ビルドデータに10GBを超える容量を必要とし、現在の空き容量では実装を開始できないため。
- 判断: 内蔵ストレージで最低40GB、安定運用には50GB以上の空きを推奨する。代替として外付けSSDを利用できるが、内蔵側にもビルドデータ用の余裕を残す。
- 補足: Command Line Toolsだけでは`xcodebuild`が含まれず、署名やentitlementsを扱うCuePaste開発の代替にはしない。

### 開発実機とXcodeの確認

- 変更内容: MacBook Air 2018、Intel Core i5、macOS Sonoma 14.8.7での開発可否を確認し、推奨開発環境を`docs/technical-stack-research.md`へ追記した。
- 理由: 現在の最新XcodeはSonomaに対応しないため、実機へ導入できるバージョンを明確にする必要があった。
- 判断: Xcode 16.2、Swift 5言語モード、macOS 13のDeployment Targetを推奨する。小規模なmacOSアプリであるためIntel MacでもMVP開発は可能と判断した。
- 検証: Apple公式のXcode対応表で、Xcode 16.2がmacOS Sonoma 14.5以降に対応することを確認した。

### 技術スタックの調査

- 変更内容: 類似するランチャー・テキスト展開アプリ、macOS公式API、主要な実装候補を調査し、`docs/technical-stack-research.md` に比較と推奨構成を記録した。
- 理由: CuePasteのMVP実装前に、UI、グローバルショートカット、ファイルアクセス、自動ペースト、配布方式の技術的な前提を明確にするため。
- 判断: Swift + SwiftUI + AppKitを基本とし、中央表示のコマンド画面には`NSPanel`、ショートカットには`KeyboardShortcuts`、自動ペーストには`NSPasteboard`と`CGEvent`を使う案を推奨した。
- 配布: 自動ペーストとApp Sandboxの制約から、MVPはDeveloper ID署名・notarizationによる直接配布を推奨した。
- 検証: Apple公式ドキュメント、各製品・ライブラリの公式ドキュメントを参照し、仕様との対応関係を確認した。コード変更とテスト実行は行っていない。

### 開発ガイドラインの作成

- 変更内容: `docs/agents-references/` の資料から、このプロジェクトで有効な作業ルールを抽出して `AGENTS.md` を作成した。
- 理由: CuePaste の仕様、実装、検証を一貫した手順で進め、不要な複雑化や原因未特定の修正を防ぐため。
- 補足: 実装・仕様変更ごとに本ファイルを更新するルールを `AGENTS.md` に追加した。
- 検証: `docs/promptpaste_spec.md` との主要な仕様整合性を確認し、`git diff --check` で形式上の問題がないことを確認した。
