# CuePaste 仕様書

## 1. 概要

CuePasteは、macOS向けの定型文ペーストアプリである。

ユーザーはグローバルショートカットでコマンド入力画面を表示し、キーワードを入力する。アプリは指定フォルダ内から対応するプロンプトファイルを検索し、その内容をクリップボードへコピーしたうえで、現在の入力欄へ自動で貼り付ける。

主な用途は、チャットAIに対するプロンプト入力を、コマンド操作のように素早く行えるようにすることである。

## 2. 想定利用シーン

ユーザーは、あらかじめ次のようなフォルダにプロンプトファイルを保存しておく。

例:

- `~/Documents/prompts/keyword.md`
- `~/Documents/prompts/keyword.txt`

任意のアプリでテキスト入力欄にフォーカスしている状態で、ショートカットキーを押す。

例:

1. `⌘ + :` を押す
2. コマンド入力画面が表示される
3. `keyword` と入力する
4. `~/Documents/prompts/keyword.md` または `keyword.txt` が検索される
5. ファイル内容がクリップボードにコピーされる
6. 現在の入力欄に自動でペーストされる
7. コマンド入力画面が閉じる

## 3. 対象プラットフォーム

- macOS
- Swift / SwiftUI / AppKitによるネイティブアプリを想定する

## 4. 基本機能

### 4.1 グローバルショートカット

初期ショートカットは次の通りとする。

- `⌘ + Option + P`

このショートカットにより、アプリが非アクティブ状態でもコマンド入力画面を表示できるようにする。

ただし、環境や他アプリの設定によってショートカットが衝突する可能性があるため、設定画面から変更できるようにする。

### 4.2 コマンド入力画面

Raycastやターミナルのような小型の入力ウィンドウを表示する。

要件:

- 画面中央付近に表示する
- 入力欄を1つ表示する
- 入力欄の左にプロンプト記号として `> ` を表示する
- `> ` は表示専用であり、入力キーワード、補完、検索には含めない
- 入力後、Enterキーで実行する
- Escキーで閉じる
- `exit` と入力してEnterキーを押すと閉じる
- 実行成功後は自動で閉じる
- エラー時は閉じず、入力内容とエラーメッセージを保持する
- ファイルが見つからない場合はエラーメッセージを表示する

### 4.3 タブ補完

コマンド入力画面では、ターミナルのシェルコマンドのようにTabキーでキーワードを補完できるようにする。

要件:

- 入力中の文字列をもとに、設定されたプロンプトフォルダ配下の `.md` / `.txt` ファイルを候補にする
- 候補は拡張子を除いたキーワードとして扱う
- `.md` と `.txt` が同じキーワードを持つ場合は、`.md` を優先して重複候補を出さない
- 候補が1件だけなら、そのキーワードまで補完する
- 候補が複数ある場合は、共通するprefixまで補完する
- 共通prefixが現在の入力と同じ場合は、候補一覧を入力画面内に表示する
- 候補一覧を表示した状態でさらにTabキーを押すと、候補を1件ずつ順番に入力欄へ反映する
- 候補の末尾まで進んだ状態でさらにTabキーを押すと、先頭候補へ戻る
- 候補がない場合は、入力内容を変更せずメッセージを表示する

例:

```text
~/Documents/prompts/summarize.md
~/Documents/prompts/outline.md
~/Documents/prompts/outreach.txt
```

入力とTab補完:

```text
sum      -> summarize
o        -> out
```

### 4.4 プロンプトファイル検索

ユーザーが入力したキーワードに対応するファイルを、設定されたプロンプトフォルダから検索する。

初期フォルダ:

- `~/Documents/prompts`

検索優先順位:

1. `{keyword}.md`
2. `{keyword}.txt`

例:

入力:

- `keyword`

検索対象:

1. `~/Documents/prompts/keyword.md`
2. `~/Documents/prompts/keyword.txt`

`.md` と `.txt` の両方が存在する場合は、`.md` を優先する。

### 4.5 サブフォルダ

プロンプト検索とTab補完は、設定されたプロンプトフォルダ直下のファイルだけを対象にする。

サブフォルダ内のファイルは対象にしない。

スラッシュを含むキーワードは無効な入力として扱う。

## 5. ペースト処理

### 5.1 クリップボードへのコピー

検索されたファイルの内容を読み込み、macOSのクリップボードにコピーする。

Swift実装では `NSPasteboard` を使用する。

`NSPasteboard` は、macOSのAppKitで提供されるクリップボード操作用APIである。

### 5.2 現在の入力欄への自動ペースト

クリップボードへコピーした後、現在アクティブなアプリに対して `⌘V` のキーイベントを送信する。

これにより、現在フォーカスされている入力欄へプロンプト本文を貼り付ける。

この処理にはmacOSのアクセシビリティ権限が必要になる。

## 6. 権限

### 6.1 アクセシビリティ権限

自動ペーストのために、アプリはアクセシビリティ権限を必要とする。

初回起動時、または初回ペースト実行時に、権限がない場合はユーザーへ案内を表示する。

案内内容:

- 自動ペーストにはアクセシビリティ権限が必要であること
- macOSの「システム設定」から許可する必要があること
- 許可後に再試行できること

Swift実装では `AXIsProcessTrustedWithOptions` などを用いて、権限状態を確認する。

`AXIsProcessTrustedWithOptions` は、アプリがアクセシビリティクライアントとして信頼されているか確認するためのAPIである。

### 6.2 ファイルアクセス権限

初期状態では、ユーザーのホームディレクトリ配下にある `~/Documents/prompts` を参照する。

サンドボックス化する場合は、ユーザーが設定画面でフォルダを選択し、セキュリティスコープ付きブックマークなどで継続アクセスできるようにする必要がある。

## 7. 設定項目

設定画面では、最低限次の項目を変更できるようにする。

| 項目 | 初期値 | 説明 |
| --- | --- | --- |
| プロンプトフォルダ | `~/Documents/prompts` | プロンプトファイルを保存するフォルダ |
| 起動ショートカット | `⌘ + Option + P` | コマンド入力画面を表示するショートカット |
| 対応拡張子 | `.md`, `.txt` | 読み込み対象のファイル形式 |

設定画面の要件:

- メニューバーから開ける
- 現在のプロンプトフォルダを表示する
- macOS標準のフォルダ選択UIでプロンプトフォルダを変更できる
- 現在の起動ショートカットを表示する
- 起動ショートカットは、記録モードにしてから押したキー入力を登録できる
- 記録するショートカットは、Command、Option、Control、Shiftのいずれかを含む
- アクセシビリティ権限の許可状態を表示する
- 権限が未許可の場合は、macOSのシステム設定で許可する必要があることを案内する
- About CuePaste画面を表示できる
- ログ記録のオン・オフを切り替えられる
- ログファイルを開ける
- ログファイルをクリアできる
- コマンド入力画面を英数入力で開くかどうかを切り替えられる

ログ要件:

- ログにはプロンプト本文とクリップボード内容を記録しない
- ログには実行イベント、補完候補数、失敗種別を記録する
- ログは `Application Support/CuePaste/cuepaste.log` に保存する

入力ソース要件:

- 設定が有効な場合、コマンド入力画面を開く時に現在の入力ソースを保存する
- コマンド入力画面の表示中は、英数入力に切り替える
- コマンド入力画面を閉じる時に、保存していた入力ソースへ戻す
- 入力ソースの切り替えに失敗しても、コマンド入力画面の表示と実行は継続する

## 8. エラー処理

### 8.1 ファイルが見つからない場合

表示例:

`No prompt found: keyword`

処理:

- クリップボードは変更しない
- 自動ペーストは実行しない
- コマンド入力画面にエラーを表示する
- コマンド入力画面は閉じない

### 8.2 ファイルが読み込めない場合

表示例:

`Could not read prompt file`

処理:

- クリップボードは変更しない
- 自動ペーストは実行しない
- エラーを表示する
- コマンド入力画面は閉じない

### 8.3 アクセシビリティ権限がない場合

表示例:

`Accessibility permission is required to paste automatically.`

処理:

- ファイル内容をクリップボードへコピーするかどうかは設定で選択可能にする
- 自動ペーストは実行しない
- 権限付与の案内を表示する
- コマンド入力画面は閉じない

## 9. MVP

Minimum Viable Product、つまり最小実用版では、次の機能を実装する。

- メニューバー常駐
- `⌘ + :` によるコマンド入力画面の表示
- `exit` コマンドによるコマンド入力画面の終了
- Tabキーによるキーワード補完
- `.md` / `.txt` ファイルの読み込み
- `~/Documents/prompts` からのキーワード検索
- クリップボードへのコピー
- `⌘V` による自動ペースト
- アクセシビリティ権限の確認と案内
- プロンプトフォルダの設定

## 10. 配布形式

MVPの配布物は、GitHub Actionsで作成したIntel macOS向けDMG、Apple Silicon macOS向けDMG、ソースコードアーカイブとする。

要件:

- GitHub ActionsのIntel macOS runnerでIntel Mac向けアプリをビルドする
- GitHub ActionsのApple Silicon macOS runnerでApple Silicon Mac向けアプリをビルドする
- DMGは未署名とし、コード署名と公証はMVPの対象外とする
- 配布物はGitHub Releasesから取得できるようにする
- GitHub Releasesには `.dmg` を直接添付する
- GitHub Releasesにはソースコードの `.zip` と `.tar.gz` も添付する
- DMG内には `CuePaste.app` と `Applications` へのリンクを配置し、ドラッグしてインストールできるようにする

未署名DMGでは、初回起動時にmacOSのGatekeeperによる警告が表示される可能性がある。

## 11. 将来的な拡張案

MVP後に、次の機能を追加できる。

- 入力中の候補表示
- ファイル名のあいまい検索
- 最近使ったプロンプト履歴
- お気に入り登録
- サブフォルダの一覧表示
- YAML Front Matterによるメタ情報対応
- プレースホルダー入力対応
- 例: `{{topic}}` を実行時に入力させる
- Markdownプレビュー
- プロンプトの編集画面
- iCloud Drive上のフォルダ対応
- Raycast拡張版の提供
- Developer ID署名と公証による直接配布

## 12. ファイル形式

対応する基本形式はプレーンテキストとする。

対応拡張子:

- `.md`
- `.txt`

ファイル内容はそのままクリップボードへコピーする。

例:

ファイル名:

`~/Documents/prompts/summarize.md`

内容:

```md
以下の文章を要約してください。

条件:
- 重要な論点を3つに整理してください
- 箇条書きで出力してください
- 専門用語には簡単な説明を添えてください

対象文章:
```

入力コマンド:

`summarize`

結果:

上記ファイル内容が現在の入力欄へ貼り付けられる。

## 13. 実装メモ

### 13.1 想定技術

- Swift
- SwiftUI
- AppKit
- NSPasteboard
- Accessibility API
- KeyboardShortcutsなどのグローバルショートカット用ライブラリ

### 13.2 基本処理の疑似コード

```swift
func pastePrompt(keyword: String) {
    let folder = FileManager.default.homeDirectoryForCurrentUser
        .appendingPathComponent("Documents/prompts")

    let md = folder.appendingPathComponent("\(keyword).md")
    let txt = folder.appendingPathComponent("\(keyword).txt")

    let fileURL: URL

    if FileManager.default.fileExists(atPath: md.path) {
        fileURL = md
    } else if FileManager.default.fileExists(atPath: txt.path) {
        fileURL = txt
    } else {
        showError("Prompt not found")
        return
    }

    guard let content = try? String(contentsOf: fileURL, encoding: .utf8) else {
        showError("Could not read prompt")
        return
    }

    let pasteboard = NSPasteboard.general
    pasteboard.clearContents()
    pasteboard.setString(content, forType: .string)

    sendCommandV()
}
```

## 14. 非目標

初期版では、次の機能は対象外とする。

- クラウド同期機能
- プロンプトマーケットプレイス
- AIによるプロンプト自動生成
- 複数端末間のリアルタイム同期
- Windows / Linux対応
- モバイル対応

## 15. アプリ名候補

- CuePaste
- PromptCmd
- ClipPrompt
- CmdPrompt
- PromptLauncher

## 16. まとめ

CuePasteは、ローカルに保存したプロンプトファイルをキーワードで呼び出し、現在の入力欄へ即座に貼り付けるmacOSアプリである。

チャットAIの利用時に、長いプロンプトや定型的な指示文を毎回手入力する手間を減らし、プロンプト運用をファイルベースで管理できるようにする。
