Conversation
Ctrl/⌘+クリックで main / locked / preparing を複数選択でき、選択中のどのエリアから ドラッグしても選択全体がまとめて動く。スナップと中央ぞろえの指示線は個々のエリアでは なく**選択全体の外接矩形**の辺・中央で判定する。リサイズハンドルは単独選択時のみ。 - 移動は「floor した外接矩形の変位」を整数化してから全メンバーへ同量加算する剛体移動。 相対位置が 1px も崩れず、±MAX_DIMENSION のクランプ境界でも移動量側を制限して グループが変形しない。座標系の不変条件(整数のみ)は従来どおり store 側で担保。 - store に moveAreas を追加し、グループ移動は 1 回の set() でまとめて反映 (pointermove ごとに N 回の再レンダリング・永続化が走らないように)。 - Shift はトグルに使わない。従来の「ドラッグ中のスナップ無効」に割当済みで、 両方に割り当てると Shift+ドラッグ開始が不能になるため(レビューで検出し修正)。 - 複数選択のメンバーを移動なしでクリックしたら単独選択へ縮退(開始閾値 3px)。 preparing の選択参照は index ベースのため、削除で別エリアに付け替わらないよう 配列が縮んだら preparing の選択を落とす。 - boundingBox は「座標・スケールは core/coords.ts に集約」の規約に従い core に配置。 - 検証: tsc / eslint 0 エラー。コードレビュー(8 アングル)で 10 件検出し全件修正。 実装関数(boundingBox/snapMove/floorCell)を合成したアルゴリズム検証 5 件通過 (剛体性・bbox 中央への磁着・個別エリア中央では磁着しないこと・境界クランプ・ 広い選択の寸法表示)。ブラウザペイン非表示の制約で実ポインタ操作の目視は未実施。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
起動時に GitHub Releases の最新版を 1 回チェックし、新しいバージョンがあれば タブ上部の横断バナーとトーストで通知する。「ダウンロード」で配布形態に合う アセットを**実行ファイルと同じフォルダ**へ保存する(進捗 % 表示付き)。 自動適用はしない(CLAUDE.md「自動更新なし」の範囲内。適用はユーザー操作)。 - 配布形態を自動判定してアセットを選ぶ。Windows は uninstall.exe の有無 (NSIS)と Program Files 配下か(MSI)で判定し、**それ以外はポータブル exe**。 ポータブルはリネームされ得るためファイル名に依存せず、判別不能時も ポータブルに倒す。macOS は /Applications 配下なら dmg、それ以外は ポータブル zip。アセット命名は release.yml の実物(v3.2.0)で照合。 - ダウンロードは Rust 側(reqwest / rustls)でストリーミング。`.part` に 書いてから rename するので中断で壊れたファイルが残らない。実行フォルダが 書き込み不可(Program Files 等)なら OS のダウンロードフォルダへ フォールバック。macOS は .app の中に埋もれないよう .app を含むフォルダへ。 - URL は Rust 側で自リポジトリの releases/download/ 接頭辞のみ許可 (webview からの任意ダウンロードへの悪用防止)。ファイル名も検証。 - チェック失敗(オフライン・レート制限)は console.warn のみで起動を妨げない。 プレリリースタグは semver 3 要素に解釈できないため通知対象外。 - リリースページのリンクは opener 経由(Tauri webview の target=_blank は 環境依存で無反応のため)。権限追加は不要(opener:default が openUrl / revealItemInDir を含むことをプラグイン実物で確認)。 - 既知の制限: Tauri 実機での表示・ダウンロードの確認は未実施(この環境では tauri dev を起動できない)。package.json のバージョンを一時的に下げて 起動すると通知〜ダウンロードまで再現できる。 - 検証: cargo check / cargo test(semver 比較・アセット選択の 2 件)通過。 tsc / eslint 0 エラー、vite build 成功。Web バンドルへの漏れなし (desktopUpdate は遅延チャンク、index チャンクに tauri/opener 参照 0)。 Web 実機でバナー非表示・GitHub への fetch 0・コンソールエラー 0 を確認。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/simplify レビュー(4 アングル)の指摘の適用(プレビュー側)。
- エリア選択を WallPreview のローカル state から store(ui.selectedAreas)へ移す。
preparing の選択は index 参照のため、削除時に「配列が縮んだら preparing の選択を
全部落とす」という応急処置を入れていたが、removePreparing が削除と同じ set() 内で
index を詰め直す形に変えた(removeBackgroundLayer が selectedBackgroundLayerId を
直すのと同じ流儀)。{#1, #3} 選択中に #1 を消しても #3 の選択が正しく追跡される。
- AreaTarget を store の公用語として export し、AreaMove = AreaTarget & {x,y} に。
WallPreview 側の AreaRef は AreaTarget | layer の合成になり、moveAreas への
変換に使っていた再タグ付け switch(到達不能な layer 分岐込み)が消えた。
- selectedRefs の identity を安定化(何も落ちなければ入力をそのまま返す)。
ドラッグ中は layout.preparing の identity が毎フレーム変わるため、従来は
選択が不変でも Set の再構築とハンドラの再生成が毎イベント走っていた。
- initDragDerived を items 配列を直接受ける形に、二重ネストの if を一本化、
クリック縮退ガードの冗長条件(pressedRef が含意する mode/件数)を削除。
- 検証: tsc / eslint 0 エラー。dev サーバで store を直接呼び、removePreparing の
選択詰め直し({#0,#2} 選択で #0 削除 → 旧 #2 を index 1 として追跡)、
空選択の DEFAULT_AREA_SELECTION への縮退、reset 時の初期化を確認。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/simplify レビュー(4 アングル)の指摘の適用(更新機能側)。 - Rust の更新機能一式(約 380 行、lib.rs の 44%)を src-tauri/src/update.rs へ分離。 lib.rs は自身のヘッダが定義する「ファイル I/O コマンドの最小表面積」に戻る。 併せて #[allow(unreachable_code)] 等 3 つのサプレッションを撤去し、 detect_install_kind / pick_asset / update_dest_dir を OS ごとの cfg 付き関数定義に分割。 - 効率: reqwest::Client を OnceLock で共有(TLS 設定とプールを check/download で再利用)、 ダウンロードを 1MB BufWriter に(8〜16KB チャンク直書きだと 100MB 級で数千 syscall)、 sync_all を削除(.part → rename で完全性は担保済み。再取得可能な成果物に fsync は 不要で、async ワーカーを数百 ms〜数秒ブロックしていた)、書き込み可否プローブを .part 作成自体に統合。 - ExternalLink を ui/ に昇格して adapter の openExternalUrl 経由に。Tauri webview では a[target=_blank] が環境依存で無反応になるため、バナーだけでなく AboutModal の 8 リンク(Desktop でも表示される)が確実に開くようになる。 - バナーの更新トーストを削除(直下に出るバナーと同文の二重通知)。付随する toastShown / dismissedVersion グローバルと update.toastAvailable キー(ja/en)も削除。 サイズ表示は新設の core/format.ts formatBytes に統一。 - release.yml にアセット命名が update.rs の pick_asset と結合している旨を注記 (リネームすると更新通知がアセットを見つけられなくなる契約を両端に明記)。 - 検証: cargo check / cargo test 2 件 / tsc / eslint(error 0)/ vite build 通過。 Web バンドルへの漏れなし(index チャンクに opener/update 参照 0)。Web 実機で AboutModal のリンクが openExternalUrl 経由で開くこと、コンソールエラー 0 を確認。 Tauri 実機での動作確認は引き続き未実施。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
プレビューの複数選択とまとめて移動、Desktop の更新通知+リリースアセットの ダウンロード補助、および /simplify リファクタ 2 件をリリース範囲とする。 - package.json / src-tauri/Cargo.toml を 3.3.0 に更新。tauri.conf.json は package.json 参照なので変更不要。Cargo.lock は cargo check で追随済み。 - 検証: cargo check 通過。vite build の成果物に v3.3.0 が埋め込まれることを確認。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 01e4462741
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| InstallKind::Installed => find_asset(assets, |n| n.ends_with("-setup.exe")) | ||
| .or_else(|| find_asset(assets, |n| n.ends_with(".msi"))), |
There was a problem hiding this comment.
Preserve MSI installs when selecting the update asset
For Windows installations detected through the Program Files check—specifically the MSI case without uninstall.exe—kind is still only Installed, so this branch always selects the NSIS -setup.exe while both formats are published by .github/workflows/release.yml. An MSI user will therefore be directed into a different installer technology, which can create separate installation/uninstall registrations instead of upgrading the existing MSI installation; retain NSIS versus MSI in the detected install kind and select the matching asset.
Useful? React with 👍 / 👎.
| if file_name.is_empty() | ||
| || file_name.chars().any(|c| c == '/' || c == '\\' || c == ':') | ||
| || file_name.contains("..") |
There was a problem hiding this comment.
Bind the destination filename to the release asset URL
The IPC caller supplies file_name independently of url, and this validation only rejects traversal characters. Consequently, a caller can provide a valid repository release URL together with the basename of any existing file in the executable directory (or downloads fallback), after which lines 330–332 delete that file and replace it with the downloaded asset. This is especially risky for a portable executable kept alongside user files; verify that the filename is the decoded final asset component of the approved URL or otherwise derive it server-side.
Useful? React with 👍 / 👎.
| let chunk = resp.chunk().await.map_err(|e| { | ||
| let _ = fs::remove_file(&part); | ||
| format!("ダウンロード中に切断されました: {e}") |
There was a problem hiding this comment.
Close the temporary file before removing it on failure
On Windows, if the connection is interrupted, this cleanup attempts to remove .part while both writer and file still hold the file open. Windows rejects deletion of an open file, the error is discarded, and unwinding closes the handles only after the removal attempt, so every failed download leaves the partial file behind despite the stated cleanup guarantee. Drop the writer/file before removal or use a guard whose cleanup runs after the handles close; the write and flush error paths have the same ordering issue.
Useful? React with 👍 / 👎.
v3.3.0 のリリース範囲。機能 2 件+クリーンアップ 2 件+バージョン更新(5 コミット / 21 ファイル / +1589 −132)。
1. プレビュー: エリアの複数選択とまとめて移動(
1179d2f,9ebfaf8)ui.selectedAreas)が持ち、preparing 削除時は削除と同じ set() 内で選択 index を詰め直します({パフォーマンス / 整合性 / SeedQueue 仕様整合の監査と是正(14ユニット)+ lock 重み対応 #1, v3.3.0 — プレビューの複数選択+まとめて移動 / Desktop の更新通知とアセットダウンロード補助 #3} 選択中に パフォーマンス / 整合性 / SeedQueue 仕様整合の監査と是正(14ユニット)+ lock 重み対応 #1 を消しても v3.3.0 — プレビューの複数選択+まとめて移動 / Desktop の更新通知とアセットダウンロード補助 #3 の選択を正しく追跡)。moveAreasで 1 回の set() にまとめ、pointermove ごとの N 回再レンダリング・永続化を回避。2. Desktop: 起動時の更新通知+リリースアセットのダウンロード補助(
33384b2,d816881)CLAUDE.md「自動更新なし」の範囲内での実装です。自動適用はしません(適用=インストーラ実行や exe 差し替えはユーザー操作)。
uninstall.exeの有無(NSIS)/ Program Files 配下(MSI)で判定し、それ以外はポータブル exe。ポータブルはリネームされ得るためファイル名に依存せず、判別不能時もポータブルに倒します。.app内で動作中はバンドルの外へ保存。.part→ rename なので中断で壊れたファイルが残りません。URL は自リポジトリのreleases/download/接頭辞のみ許可(webview からの悪用防止)。src-tauri/src/update.rsに分離。ExternalLinkをui/に共有化したため、AboutModal の 8 リンクも Tauri webview で確実に開くようになりました(target=_blankは webview で環境依存の無反応になるため opener 経由に)。検証
cargo check/cargo test2 件(semver 比較・アセット選択)/tsc/eslint(error 0、既存 warning 2 件のみ)/vite build通過。ビルド成果物にv3.3.0が埋め込まれることを確認。desktopUpdateは遅延チャンク、index チャンクに opener/update 参照 0)。Web 実機でバナー非表示・GitHub への fetch 0・コンソールエラー 0。boundingBox/snapMove/floorCell)を合成して 5 ケース検証(剛体性・外接矩形中央への磁着・個別エリア中央では磁着しないこと・境界クランプ・広い選択の寸法表示)。store の選択追跡(preparing 削除時の index 詰め直し)も実測確認。レビュー時の注意
package.jsonのバージョンを一時的に 3.2.0 未満へ下げてpnpm tauri devを起動すると、通知〜ダウンロードまで再現できます。update.rsのpick_assetと結合しています(release.yml に注記済み)。ポータブル版のファイル名を変えると更新通知がアセットを見つけられなくなります。🤖 Generated with Claude Code