Pasty v0.9.7-beta
Pasty v0.9.7-beta — 30 件の P1 + 4 件の Audit Follow-up
v0.9.6-beta の P0 安定化に続き、v0.9.5-beta Stability Audit で洗い出された 30 件の P1 と、Wave-2 audit で追加検出された 4 件の follow-up をまとめて落とします。「ホットパスを軽く、失敗を黙らせず、削除済みは本当に消す。」
⚡ パフォーマンス強化
同一テキスト連続コピー時の SHA256 を省略
クリップボード変化検出のたびに SHA256 を計算していましたが、lastTextString キャッシュを追加し、直前と同一文字列なら既存ハッシュをそのまま再利用します。長文を立て続けにコピーする場面で CPU 使用率が目に見えて下がります。
OCR 同時実行を 2 並列に制限
複数の画像を同時にコピーすると Vision OCR が無制限に並走して AIEngine が CPU/メモリを吸い上げる挙動がありました。actor OCRQueue (max=2) で 同時 2 件まで に抑え、3 件目以降はキュー待ちにします。
正規表現の type-load コンパイル
SyntaxHighlighter がプレビュー描画ごとに try! NSRegularExpression(...) を実行していたものを、言語ごとの 静的プロパティに巻き上げ て型ロード時に一度だけコンパイルする方式に変更。コードプレビューが滑らかになります。
Markdown プレビューのメモ化
AttributedString(markdown:) のパース結果を clipID + contentHash をキーに NSCache (容量 256) で記憶します。同じクリップを繰り返し開いてもパースが走らず、長文 Markdown のプレビュー再表示が即座に。
Strip 検索結果の上限明示化
検索結果が大量ヒットした場合に StripPanel が無制限にロードしていた箇所に LIMIT 1000 を明示適用し、上限到達時は「結果が1000件を超えています。検索条件を絞り込んでください」とトーストでガイドします。
🔔 アップデート通知強化
Sparkle 失敗/成功デリゲートの完全実装
これまで Sparkle のダウンロード/インストール失敗はサイレントでした。failedToDownloadUpdate / didFinishUpdateCycleFor / didAbortWithError の 3 デリゲートを実装し、エラーを network / edsa / sandbox / other に分類してそれぞれ専用トーストを出します。インストール成功時も「Pasty を更新しました(バージョン X)」と通知。
起動直後の自動チェックを抑制
launchPad で初回ペーストする前に Sparkle がバックグラウンドチェックに走り、ペースト操作と HTTP リクエストが競合する微細なラグがあった問題を解消。初回ペースト完了 か 起動から 30 秒経過 のいずれか早いほうまで初回チェックを遅延します。
🔐 セキュリティ + TCC
Accessibility 権限の永続アラート
セッション中にユーザーがアクセシビリティ権限を OFF にすると、これまではトーストのみで埋もれがちでした。NSAlert(5 分クールダウン付き)で 「システム設定を開く」 ボタン付きの永続アラートを出し、x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility に 1 クリックで遷移できるようにしました。
ペースト前の権限チェック順序を修正
PasteAutomator.emitCommandV がこれまで「先にクリップボードへ書き込んでから AX チェック」していたため、権限が剥がれた状態で ユーザーのクリップボードを意図せず上書き していました。チェックを 書き込み前 に移動し、未許可なら一切クリップボードを汚さず処理を中断します。
Blob ディレクトリの権限を 0o700 に固定
~/Library/Application Support/io.pasty.app/blobs/ と画像ステージング dir を毎起動 POSIX 0700 に再適用。他ユーザー / 他プロセスからの覗き見を防ぎます。
IntegrationHubs.undoLast() の AX ガード
Integration Hubs (Linear / Notion / GitHub 等の連携) の 取り消し操作 が CGEvent.post を AX チェック無しで叩いていた点を修正。AXIsProcessTrusted() で事前ガードし、未許可なら pastyPasteFailed 通知を出して失敗を可視化します。
🔎 削除済みクリップが完全に非表示に
v0.9.6-beta で読み出しパスに WHERE deleted_at IS NULL を入れましたが、Wave-2 audit で 3 つの抜け穴 が見つかりました。
SearchEngine の両パス
空クエリ (recent) と FTS5 MATCH の 両方 に deleted_at IS NULL を適用。検索で deleted clip が一瞬出るケースを根絶。
Pinboard.items(in:)
ピンボードに登録済みのクリップが ClipStore で soft-delete された場合、Pinboard 側では残骸として表示され続けていた問題を、JOIN に AND clips.deleted_at IS NULL を追加して解消。
InsightsDashboard の全集計
今日 / 週次 / 日次 / カインド別 / アプリ別 / 長期保存などの 全集計クエリ に deleted_at IS NULL を入れました。削除済みクリップが統計のグラフを歪めることはなくなります。
FTS5 ソフトデリート同期 (migration v10)
最大の漏れは、deleted_at が NULL→値 に変わっても FTS5 インデックスからは削除されない ことでした。v10 マイグレーションで AFTER UPDATE OF deleted_at トリガーを追加し、soft-delete 時に FTS から除去 / 復元時に再投入する 完全同期 を実現。これで「アプリ再起動するまで MATCH に残骸が出る」が消えます。
🧩 エッジケース
HoverPreview のアニメーション競合
複数のホバープレビューを高速に行き来すると、古いアニメーション完了ハンドラが新しいパネル状態を破壊するレースがありました。animatingPanelID: UUID のトークン照合で 古い完了ハンドラを無視 するようにし、状態の整合性を確保。
Esc キーでドラッグ中断時のクリーンアップ
ドラッグ中に Esc を押すと panel は閉じるのに macOS 側のドラッグ状態が残ったまま で、次のクリックが drop と誤認される問題を解消。Esc 受信時にドラッグが進行中なら leftMouseUp CGEvent を合成してから clearAll() するようにしました。
NSScreen 構成変更への追従
ディスプレイの抜き差し / 解像度変更時に notch hot-zone と strip panel の座標がずれる問題を、NSApplication.didChangeScreenParametersNotification 購読で 再登録 + 再配置 することで解消。
📦 メモリ整理
StackPill の observer 解放
StackPill が NotificationCenter にぶら下げた screenObserver token を deinit で確実に解除。長時間稼働でも漏れません。
PastyApp の Stage-1 observer 解放
起動時に登録される Stage-1 observer 群を stage1Observers: [NSObjectProtocol] に保管し、applicationWillTerminate で一括解除。
DropDelegate の余計な main dispatch を削除
DropDelegate は AppKit / SwiftUI 仕様で main thread 呼び出しが保証されているのに、DispatchQueue.main.async で再ラップしていた箇所を解消。微小ですがレスポンスが軽くなります。
🛠 追加修正
AI エラーのケース別メッセージ化
AIError を .modelNotAvailable / .osUnsupported / .aiDisabledBySettings / .other に分類し、4 種のローカライズ済みトースト を出すように。Apple Intelligence 未登録 / OS バージョン不足 / 設定 OFF / その他の区別がユーザー側で明確に。
DragDrop 部分失敗の可視化
複数アイテムのドロップで一部が失敗していた場合に、これまでは成功したものだけ静かに登録されていました。「N 件中 M 件のみ追加されました」 トーストで具体的な数を伝えます。
v5 entity\_uuid バックフィルの冪等化
過去の中断起動などで entity_uuid が NULL のまま残っていた行を救うため、UserDefaults フラグに依存せず毎起動 SELECT COUNT で残存を検査してバックフィルする方式に変更。
🧪 テスト
全 41 テスト pass — v0.9.6-beta の 36 件に加え、SoftDeleteFilterTests を 5 件追加:
testSearchEngineExcludesDeleted_emptyQuerytestSearchEngineExcludesDeleted_FTSMatchtestPinboardItemsExcludesDeletedtestInsightsExcludesDeletedtestV10TriggerRemovesFTSRow
リリース詳細: https://github.com/IvyGain/Pasty/releases/tag/v0.9.7-beta
GitHub Releases で詳細を見る ↗