ブログ

RSS

技術やプロダクト開発に関する知見を発信しています

DevOps

Renovateの参照差し替え先の変更をgh apiで楽をする

Renovateプリセットの参照先差し替えで、Org配下のリポジトリ群に同じ修正PRを冪等に投げるBashスクリプトを、`git clone`を一度もせずに`gh api`だけで書きました。GitHub Contents APIとGit Refs APIの組み合わせ、再実行を前提にした冪等性の4箇所、macOSとLinuxで動く`mktemp`テンプレートまでをまとめます。

DevOps

RenovateのOnboarding PRを毎回手作業で書き換えるのをやめた

Renovateが立てる初回Onboarding PRには、`<org>/renovate-config/default.json`を置けば組織プリセットへの`extends`が自動で差し込まれる仕組みがソースコード側にあります。コメントを残せる`default.json5`を選ぶとこの自動検出が空振りするため、Mend-hostedの`org-inherited-config.json`で`onboardingConfig`を明示的に上書きして、Onboarding PRをそのままマージできる状態に揃えました。

Apple

「no drag hooks」と書いた Framis に drag hook を後から入れた

Framis の product vision には「No drag hooks, no edge snapping」と明記していました。それでも Window を drag で動かすたびにホットキーで Arrange Mode に入り直すのが面倒になり、drag 中に修飾キー (既定 Control) を押すと overlay が出る動線を後付けで入れました。"opt-in only" を保つための `DragScrollMonitor` の State machine、Hold/Toggle の使い分け、修飾キー判定で気をつけた点を扱います。

Apple

Chimrの「5分前通知」を秒単位で正確に出すために2段階タイマーにした

Chimr のカレンダー予定の「N分前通知」を秒精度で出すために、30秒おきの periodic scan と直近120秒以内の予定に対する one-shot timer の2段階構成に切り替えました。なぜ periodic だけだと精度が出ないか、なぜ one-shot を全件分仕込まないか、システムスリープ復帰と App Nap への対応までまとめます。

AI

ChimrのMCPセットアップを手で書かせないために --mcp-install と --mcp-config を足した

Chimr を Claude Code や Claude Desktop の MCP サーバーとして使うときの設定を、ユーザーに手で書いてもらう前提から、Chimr 自身が `claude mcp add` コマンドや JSON を吐く前提に切り替えました。`--mcp-install` `--mcp-config` `--mcp` の3つの CLI フラグの実装と、bundle path を `CommandLine.arguments[0]` から取る判断をまとめます。

DevOps

Cloudflare Pages で llms.txt が文字化けしたので _headers で charset を書いた

Cloudflare Pages は配信ファイルの拡張子から `Content-Type` を推測しますが、`text/plain` などには `charset` が付きません。`public/_headers` で `/llms.txt` `/robots.txt` `/sitemap.xml` `/docs/*.md` などに `charset=utf-8` を明示して、日本語の文字化けを直した手順をまとめます。

Apple

Zone → Window 方式のウィンドウマネージャー Framis を作っている

既存の macOS ウィンドウマネージャー (Rectangle / Magnet / Moom / Raycast / AeroSpace / yabai) は、いずれも「Window を選んでから Zone を指定する」方式です。複数のウィンドウを持つアプリで「どの Window か」を狙うのが面倒で、Zone を先に選んで Window を割り当てる「Zone → Window」方式の Framis を作っています。Arrange Mode の作りと、App Store ではなく GitHub Releases で配る前提の話をまとめます。

Apple

Vigilare の macOS と iOS で共有するコアを VigilareKit に切り出した

Vigilare は macOS と iOS の両方を同じ Apple Reminders 連携と同じタスク管理ロジックで動かしています。共通する部分を VigilareKit という Swift Package に切り出して、Models / Stores / Services / UseCases / ViewModels / DesignSystem を共有し、Views だけプラットフォーム別に持つ構造にしました。何を共有して何を別物にしたか、判断の軸を扱います。

Apple

Vigilare の iOS 版を作っている

macOS で動かしている Vigilare の核は「Apple Reminders を常時最前面のフローティングウィンドウで出しっぱなしにする」ことです。iOS にはこの前提が成立しないため、同じ Apple Reminders 連携を別物の体験として組み直しました。検討した代替案、別物として組むと決めた判断の軸、いまどこまで動いているかを扱います。

DevOps

RenovateでCloudflare Workers SDKのパッケージをグルーピングする

Cloudflare Workers SDKはモノレポで管理されていますが、Renovateのデフォルト設定ではパッケージごとに個別のPRが作られます。wrangler、@cloudflare/vite-plugin、miniflareを1つのPRにまとめるpackageRulesの設定と、monorepo presetへの提案で浮上したimmortal PRs問題を紹介します。

Web

Cloudflare Workers で @vercel/og が使えなかったので Satori と Resvg WASM で OGP を組んだ

Astroプロジェクトで動的OGP画像を自動生成する方法を解説します。Cloudflare Workers環境の制約から@vercel/ogではなくSatoriと@resvg/resvg-wasmの組み合わせを選び、ビルド時に1200x630pxのPNG画像を静的生成する設計を紹介します。

Web

Astro の Mermaid を rehype-mermaid から動的 import に切り替えた

AstroプロジェクトでMermaidダイアグラムを表示する方法を解説します。rehype-mermaidによるビルド時変換ではなくクライアントサイドレンダリングを選んだ理由、動的インポートでライブラリをページ単位で読み込む設計を紹介します。

Web

100件超の用語を正規表現でマッチングしていたら遅くなったのでAho-Corasickに変えた

Astroのremarkプラグインで実装した用語自動リンク機能を、正規表現ベースからAho-Corasickアルゴリズムに変更した経緯を解説します。なぜ形態素解析を使わなかったのか、日本語と英語の混在テキストでの単語境界の扱いについても紹介します。

Web

ビルドのたびにOGPを取りに行くリンクカード、CIからDoSになりかけた話

Astroのremarkプラグインでリンクカードを自作しました。ビルド時にOGPメタデータを毎回fetchする設計にしたところ、GitHub ActionsからのビルドがDoS的な負荷になりかけたため、キャッシュをリポジトリにコミットする方式に切り替えた経緯を紹介します。

Web

labee.devは48時間で段階移行し、labee.jpは一括でAstroへ移した

ラビー合同会社のコーポレートサイト(labee.jp)と開発者ツールサイト(labee.dev)をNext.jsからAstroへ移行しました。labee.devは48時間で3段階の段階移行、labee.jpはその経験を踏まえた一括移行です。Tailwind CSSの廃止とCSSカスタムプロパティへの移行についても紹介します。

Apple

テストがアプリ本体の設定を書き換えていたので、UserDefaultsとDateを外から渡すようにした

iOS や macOS のアプリで単体テストを書くなら、UserDefaults.standard と Date() を直接呼んでいる箇所を先に外しておきます。そのままだとテストがアプリ本体の設定を書き換えますし、アサーションが1度も実行されないまま通るテストもできてしまいます。

Web

パスワードに大文字と記号、まだ必要?

パスワードに大文字・小文字・数字・記号を混ぜろという要件について、公的なガイドラインの原文を読みました。文字種を混ぜさせるかどうかは、その文書が誰に向けて書かれているかで分かれます。最低文字数は、資料によって8から15まで開きがあります。定期変更を求めるなという点だけは、読んだ資料が一致していました。

Apple

String.countをNSRangeに渡していた箇所を直しても、文字は消えたままだった

自前のテキストエディターで文字が消える問題を追ったところ、行に属性を付けるNSRangeをString.countで作っている箇所が見つかりました。ただしそこを直しても文字は消えたままで、実際に消していたのはNSTextStorageがNSLayoutManagerへ渡すchangeInLengthでした。最小の再現コードを書いて2つを切り分けた記録です。

Apple

Chimrのメニューバーでカレンダーを開かずに予定を把握する

Chimrのメニューバー表示機能を詳しく解説。3つの表示モード、動的表示の4パターン、更新間隔、右クリックメニューなど、限られたスペースで情報を表示する仕組みを紹介します。

Apple

Chimrのフルスクリーン通知を極める - 絶対に会議を見逃さない設定術

Chimrのフルスクリーン通知機能を詳しく解説。通知タイミング、スヌーズ、出席状態フィルタリング、ビデオ会議モードなど、自分好みにカスタマイズする設定方法を紹介します。