カテゴリー: tutorial

  • Snap パッケージを開発して学んだこと

    fpocket を題材にした CI/CD と Snapcraft 実践録

    ここでは、私がオープンソースの分子ポケット検出ツール fpocketsnap パッケージ として公開しようと試みた経験をまとめます。
    Snapcraft の基本から GitHub Actions を用いた CI/CD、自動更新チェックの仕組み、そしてつまづいたポイントまで、私が実際に体験した内容を中心に書いています。

    snap パッケージ化に興味がある方や、CI を使った自動ビルド・公開を行いたい方の参考になれば幸いです。


    1. はじめに

    Linux ディストリビューション間で依存関係の差があると、バイナリ配布が難しくなることがあります。
    fpocket は C 言語製で比較的コンパイルしやすいのですが、一般ユーザーにとってはインストールの手順が多く、簡単とは言えません。

    そこで、クリック一つでインストールできる snap パッケージとして提供できれば便利だと考え、開発を始めました。

    しかし、snapcraft は奥が深く、パッケージング・CI/CD・Snap Store 運用など、多くの学びがありました。
    この記事では、そうした経験を整理して紹介します。


    2. Snapcraft の基礎

    まず、Snapcraft の基本を簡単におさらいします。

    ● snap の confinement

    snap にはアプリの権限レベルを示す confinement(制限モード) があり、次の 3 種類があります。

    モード 説明
    strict 最も制限が強く、標準的なモード。Snap Store で公開する場合は基本これ。
    devmode 開発用。strict に必要な許可が足りていない場合でも動くが、公開不可。
    classic 権限制限なし。伝統的ツール向け。使用には審査が必要。

    一般的な CLI ツールは strict で動かすのが基本です。また今回の fpocket-snap では、 interfaceshome のみを使用します。

    ● Snapcraft のビルド方式

    snap のビルドには複数の方法があり、それぞれ環境の隔離強度が異なります。

    ビルド方法 特徴
    Multipass core20の場合、Multipassはすべてのプラットフォームでデフォルトのプロバイダー。
    LXD core22以降では、LinuxではLXDがデフォルトプロバイダーであり、macOSおよびWindowsではMultipassがデフォルトとなる。
    –destructive-mode ホスト環境でビルド。再現性は低いが高速。

    この中で、特に注意が必要なのが --destructive-mode です。後述します。


    3. --destructive-mode とは何か

    Snapcraft には、ビルド時に --destructive-mode という特別なオプションがあります。

    snapcraft --destructive-mode

    ● 何ができるのか

    • Multipass や LXD が不要
    • つまり build container 起動不要
    • ホスト環境上で直接ビルドできる
    • CI での簡易ビルドやデバッグに便利
    • VM が起動できない環境で使える

    ● なぜ用意されているのか

    • 「動くかどうかだけ確認したい」
    • 「依存パッケージが揃っている環境で簡単に試したい」
      といった、開発者向けの簡易ビルド用途が目的です。

    ● 公開用パッケージに使ってはいけない理由

    結論として、このモードでビルドした snap を Snap Store に公開するべきではありません

    理由は次の通りです。

    • ビルド環境の汚染が反映される可能性がある(再現性がない)
    • 必要な依存関係が “たまたま” ホストにあるために成功してしまう
    • ビルド環境とsnap baseが一致するとは限らない
    • 安全性の検証が不完全になる
    • Snapcraft 公式が推奨していない

    core22 指定なのに Ubuntu 24.04 でビルドすればエラーになるでしょう。GitHub でホストされる runner (この場合はUbuntu)がずっと同じバージョンとは限りません。

    つまり、開発や検証のためのモードであり、最終版の公開には使用しないのが正しい使い方です。


    4. fpocket-snap の構成説明

    私が構築したリポジトリは次のような構成にしています。

    fpocket-snap/
    ├── .github/
    │   └── workflows/
    │       ├── release.yml
    │       └── upstream-check.yml
    └── snap/
        └── snapcraft.yaml

    GitHub Actions で自動ビルド・公開し、加えて upstream の fpocket に更新がないか定期的にチェックする仕組みを入れています。


    5. snap/snapcraft.yaml の詳細解説

    Snapcraft の定義ファイルは本来リポジトリ直下に置くことが多いのですが、今回は整理のために snap/ ディレクトリに配置しました。

    snap/ に置く理由

    • プロジェクトルートを汚さない
    • GitHub Actions で複数の設定を扱うときに見通しが良い
    • Snapcraft 側も問題なくサポートしている

    ● 主な構成

    fpocket-snapのsnap.yamlを参照してください。

    内容としては次のポイントが重要です。

    • makefile に書かれているパス等の調査を反映
    • parts でソースコードとビルド手順を指定
    • build-packages はコンパイルに必要なパッケージ
    • stage-packages はランタイム依存
    • strict モードで動作するように設計
    • Snap Store のページ の紹介文になる情報も記載する
    項目 説明
    summary ストアの検索結果などに表示(短文)
    description 詳細ページに表示(複数行OK)
    title 見出しとして表示される(省略可)
    作成者名 snapcraft.yaml 内には不要(ストア登録時にアカウント名が自動的に「publisher」として表示)
    README.md 自動では反映されない。description部分が代わりに使われる。
    スクリーンショット 手動でSnapcraftダッシュボードからアップロード可能。
    フィールド 目的 fpocket の場合の内容
    website Snapパッケージに関する公式ページ(=あなたがメンテナンスしているsnapラッパープロジェクト) 🔗 https://github.com/akuroiwa/fpocket-snap
    source-code ソフトウェア本体(上流プロジェクト)のソースコードURL 🔗 https://github.com/Discngine/fpocket など、fpocketの公式リポジトリ

    Snapcraft の定義は簡潔ですが、Tiny な CLI ツールには十分です。


    6. GitHub Actions のワークフロー構成

    6-1. release.yml

    この workflow は タグを切ったときに snap をビルドして Store へ公開するためのものです。

    主な流れは次のとおりです。

    1. コード checkout
    2. snapcore/action-build@v1 で snap をビルド
    3. snapcore/action-publish@v1 で Store に公開

    snapcraft.yaml が snap/ にある場合

    デフォルトではルートにあると認識されるため、次の指定が必要です。

    with:
      path: snap/

    これがないとビルドが失敗します。

    ● パッケージ名登録と認証トークン

    パッケージ名は事前に調べ、snap store に存在しないことを確認しなければなりません。Ubuntu One のアカウントが必要です。

    snapcraft register fpocket
    snapcraft export-login --snaps fpocket --channels stable,edge snapcraft_token.json
    snapcraft logout

    生成したトークンの中身(ファイル内の文字列)を GitHub Actions の secret にペーストし保存しますが、その際に yml ファイルから呼び出す環境変数名でなければなりません。

    私の場合、トークン生成時にチャンネル指定の不備が原因で公開に失敗し、再登録後に workflow を re-run して修正することがありました。使用するチャンネルが複数ある場合は必ず指定しなければなりません。


    6-2. upstream-check.yml

    fpocket 自体の更新を監視するための workflow です。

    • cron で定期実行
    • GitHub Releases を確認
    • 新しいリリースがあれば issue を自動作成
    • Issue 作成時にメール通知されるため、見逃しにくい

    fpocket の upstream に動きがあった際に素早く対応できるので便利です。


    7. GitHub Actions: Snapcraft Actions の解説

    snapcore/action-build@v1

    Snap をビルドする Action です。この アクション は自動で LXD を使います。


    snapcore/action-publish@v1

    ビルドした snap を Snap Store のチャネルに公開します。

    with:
      release: stable

    チャネルとしては stable, candidate, beta, edge が選べます。
    オプション無しでインストールできるのは stable(安定版)のみです。

    snapcore/action-build@v1 の出力は id: build を付けることで ${{ steps.build.outputs.snap }} として利用可能です。これにより、.snap の明示的なパス指定(snap/*.snap)が不要になります。


    8. 実際のトラブルと解決策(経験ベース)

    ここからは、私が実際に遭遇したトラブルです。

    ● snapcraft コマンドの変更

    snapcraft list-revisions

    は現在、

    snapcraft revisions

    にリネームされています。
    古いコマンドを使うと警告が出ます。

    snapcraft revisions fpocket #Rev.としてrevision番号を出力する
    snapcraft release fpocket 1 stable #Rev.を特定した1で指定しstableに昇格する

    ● トークン無効による公開失敗

    snapcraft export-login で作成したトークンが権限不足で動作せず、
    workflow が失敗することがありました。
    再生成と再登録で解決しました。

    ● 構成順序のミス

    設定順序の問題で snapcraft が正しく読み込まれず、ビルドエラーが発生したこともあります。snapcore/action-build@v1 実行後でなければ動作しません。snapcraft: command not foundと怒られてしまいます。
    workflow ファイルの記述順は意外と重要です。


    9. まとめ

    fpocket の snap 化を通じて、多くの知見を得ました。

    • snapcraft は強力だが慣れが必要
    • strict モードで動かすための調整が大切
    • GitHub Actions での自動ビルド・公開は便利
    • --destructive-mode は開発時に便利だが、本番公開には不向き
    • upstream 更新チェックによる自動監視は役立つ

    snap パッケージの配布は、Linux ユーザーにとってインストール手順を大幅に簡略化できるメリットがあります。
    今後は multi-arch 対応や、自動テストなどを取り入れて改善していきたいと思います。

  • Spec-kitの活用

    mcts-genとpy-chessboardjsにおけるSpec-kitの活用と開発ワークフロー改善の記録

    この記事では、私が最近行った2つのプロジェクトmcts-genpy-chessboardjsでの開発記録を基に、AIを活用したspec-kitツールの使い方、GitHub Actionsを用いたCI/CDワークフローの構築、そしてPyPIのTrusted Publisher設定について解説します。


    1. spec-kitのアップデートと古い設定ファイルの整理

    プロジェクトmcts-genakuroiwa/mcts-gen)において、spec-kitのバージョン更新を行いました。この際、古いファイルの削除に手間取りました。また、仮想環境管理ツールuvxを用いた初期インストール手順が、恒久的なツールの利点を享受できない原因となりました。

    🚨 古いバージョンからの移行時の注意点

    以前のバージョンでspecify initを実行していたため、新しいバージョンのspec-kitを導入する際、古いコマンド定義ファイルが残ってしまいました。

    現在のgemini-cliでspec-kitのコマンドは全て/speckit.から始まりますが、古いバージョンでは異なっていました。

    【新しいspec-kitのインストール】

    仮想環境をアクティベートし、uv tool installで最新版を取得します。因みにこのuv tool install は 「システム全体(またはユーザーローカル)」に独立した環境を作ってツールを入れる、という働きをしますのでvenvと関わりはありません。他のプロジェクトの仮想環境でもspecifyコマンドを使用できます。Ubuntuの場合のコマンドの場所は~/.local/bin/specifyです。

    source .venv/bin/activate
    uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git

    【内部コマンドの更新】

    プロジェクトのルートで以下のコマンドを実行し、gemini-cliの内部コマンドを更新します。

    specify init --here

    これにより、新しいコマンドファイルが.gemini/commands/以下に作成されます。

    【新規ファイルの確認】

    git statusで確認すると、以下のような新しいファイルが追加されていることが分かります。

    ブランチ main
    追跡されていないファイル:
      (use "git add <file>..." to include in what will be committed)
        .gemini/commands/speckit.analyze.toml
        .gemini/commands/speckit.checklist.toml
        ...(中略)...
        .gemini/commands/speckit.tasks.toml
        .specify/

    .specify/ディレクトリにはmemory/, scripts/, templates/といったサブディレクトリが含まれます。

    🧹 古いファイルの削除手順

    新しいコマンドファイルと競合する古いファイルを特定し、手動で削除する必要がありました。

    1. 古いコマンド定義ファイルの削除

      cd .gemini/commands/
      rm plan.toml
      rm specify.toml
      rm tasks.toml
      cd -
    2. 古い.specify関連ファイルの削除

      rm -rf memory/
      rm -rf templates/
      rm -rf scripts/

    💡 ヒント: コマンド定義ファイルが管理対象外になるように、.gitignore.geminiを追加することも検討できます。ただし、その場合はgit statusには表示されなくなります。


    2. 既存プロジェクト(py-chessboardjs)でのspec-kit導入と運用

    既存のプロジェクトpy-chessboardjsakuroiwa/py-chessboardjs)でもspec-kitを導入しました。

    🛠️ 導入手順

    プロジェクトのルートディレクトリで、以下の手順を実行します。

    uv venv
    source .venv/bin/activate
    uv pip install -e . # プロジェクト依存パッケージのインストール
    uv tool install specify-cli --from git+https://github.com/github/spec-kit.git # spec-kitのインストールが未完の場合
    specify init --here # プロジェクト設定ファイルの作成
    specify --help # 動作確認

    spec-kitをgemini-cliで使用し始めると、プロジェクトルートに**GEMINI.md**というファイルが作成され、これがAIとの対話の出発点となります。

    🚀 spec-kitを利用した開発サイクル

    spec-kitのコアな使い方は、事前にGeminiにチャットで相談し、戦略を固めてからスラッシュコマンドを実行していく流れが最も効果的です。

    コマンド 目的
    /speckit.specify <文字列> 要件定義や仕様策定をAIに依頼し、**specs/**にMarkdownファイルを作成させる
    /speckit.plan 実装計画を立てる
    /speckit.tasks タスクリストを作成する
    /speckit.implement 実際にコードの実装を依頼する

    これらの作業を通して、specs/以下にMarkdownファイルが作成されます。原則として、specs/以下のサブディレクトリは作業ごとに作成されたブランチ名と同じになります。

    🔄 作業終了後のブランチマージ

    spec-kitがブランチを作成して作業を進めた後、作業をメインブランチに反映するには、以下の手順が必要です。

    git commit -m "修正内容のメッセージ" # 作業ブランチで必ずコミットする
    git checkout main
    git merge 001-fix-settings-load-error # 作業ブランチをmainにマージ
    git branch -d 001-fix-settings-load-error # 作業ブランチを削除

    3. GitHub ActionsとPyPI Trusted Publisherの設定

    パッケージの自動公開のために、GitHub Actionsのワークフローを.github/workflows/にYAMLファイルで記述します。このYAMLファイルはGeminiに依頼して作成してもらうことが可能ですが、動作確認が不可欠です。

    🚢 パッケージ公開ワークフロー

    py-chessboardjsのワークフロー例

    このYAMLファイルを使用して、PyPIのTrusted Publisherを登録します。登録時には、上記のYAMLファイル名を指定する必要があります。これにより、GitHub ActionsとPyPIが連携し、OIDC(OpenID Connect)を使って安全にパッケージを公開できます。

    🧪 テスト公開と本番公開

    タグ名によって、TestPyPIと本番PyPIへの公開を分けます。

    公開先 タグ名の条件 コマンド例
    TestPyPI -testを含むタグ名 git tag v0.0.3-test1
    本番PyPI -testを含まないタグ名 git tag v0.0.3

    タグを作成したら、git push origin <タグ名>でプッシュすることで、GitHub Actionsが起動します。

    📝 YAMLの構文チェック: Emacsではflycheck-yamllintをインストールすると、flycheck-modeでYAMLの構文エラーをリアルタイムに確認でき、大変便利です。


    4. AIとの協調作業における重要な教訓

    py-chessboardjsの開発中に遭遇した2つの不具合は、AIによる開発支援の限界と可能性を示す良い事例となりました。

    不具合1: ファイルパスの取得問題(C:\fakepath\

    現象: チェスエンジンのパス指定が機能しないエラーが発生し、出力にはFileNotFoundError: [Errno 2] そのようなファイルやディレクトリはありません: 'C:\\fakepath\\stockfish'とありました。

    解決: Google検索の結果、「fakepath」はHTMLのファイル入力フィールドがセキュリティ上の理由から実際のパスを隠蔽するブラウザの挙動であることが判明しました。この情報をGeminiに提供したところ、**「input type="file"をボタンに置き換え、pywebview.apiを介してPythonのネイティブファイルダイアログを呼び出す」**という正確な解決策が提示され、実装に成功しました。

    不具合2: キャスリング時のエラー(concurrent.futures.CancelledError

    現象: キャスリングを行うとエラーが発生しました。

    解決: ログからconcurrent.futures.CancelledErrorが見つかり、並列処理の不具合が疑われました。原因は、プロジェクトが使用しているchessboardjsの古いバージョンにあり、キャスリング時にFEN(盤面情報)が複数回更新され、チェスエンジンが処理しきれなかった可能性が高いと特定しました。

    以下はGeminiによる解説です:

    1. python-chessエンジン呼び出しの問題について

      根本的な問題は、GUIフレームワークであるpywebviewと、asyncioベースのエンジン通信を行うpython-chessライブラリとの間の並行処理の競合でした。

      • pywebviewのAPI呼び出しは同期かつ別スレッドで実行される: JavaScriptからpywebview.api.some_function()を呼び出すと、pywebviewは新しいPythonスレッドでsome_functionを実行し、その関数が戻るまでスレッドをブロックします。

      • python-chessのエンジン通信は非同期 (asyncio):
        chess.engine.popen_uci()関数やengine.play()メソッドは、Pythonのasyncioライブラリを使用して外部のチェスエンジンプロセス(Stockfishなど)と通信します。asyncioはイベントループ上でタスクを実行し、通常は単一のスレッドで行われます。

      • 競合 (レースコンディション):

        1. 以前のApi.uci_engine_move()は、await self.engine.play()を直接呼び出していました。このawait呼び出しは、エンジンが指し手を返すまでpywebviewのAPIスレッドをブロックしていました。
        2. このpywebviewのAPIスレッドがブロックされている間に、ユーザーが別のUI操作(例: 「リセット」ボタンや「戻る」ボタンのクリック)を行うと、その操作もpywebviewのAPI呼び出し(例: Api.on_closed())をトリガーしていました。
        3. 古い設計のApi.on_closed()メソッドはself.engine.quit()を呼び出し、エンジンプロセスを終了させていました。
        4. エンジンプロセスが終了すると、self.engine.play()が待機していたasyncioのFutureがキャンセルされ、concurrent.futures.CancelledErrorが発生しました。エンジンプロセスが予期せず終了した場合はchess.engine.EngineTerminatedErrorが発生しました。
        5. pywebviewのAPIスレッドはself.engine.play()の結果を待ってブロックされていたため、Futureがキャンセルされると、CancelledError(またはEngineTerminatedError)が伝播し、アプリケーションがクラッシュしたり、一貫性のない状態になったりしていました。
      • 解決策 (専用ワーカースレッド):

        • 私たちは、専用のthreading.Threadで実行されるEngineWorkerクラスを導入しました。
        • このEngineWorkerスレッドは独自のasyncioイベントループを持ちます。
        • pywebviewからApi.uci_engine_move()が呼び出されても、もはやブロックされません。代わりに、EngineWorkerが監視するqueue.Queueに「プレイ」タスクを投入します。
        • EngineWorkerはタスクを受け取り、自身の asyncioイベントループ上でawait self.engine.play()を実行します。指し手が準備できると、スレッドセーフなコールバック(_engine_move_callback)を使用して結果をApiクラスに返します。
        • Apiクラスはself.window.evaluate_js()を使用して、指し手をJavaScriptのフロントエンドにプッシュします。
        • なぜこれで解決したのか: pywebviewのAPIスレッドはasyncio操作によってブロックされなくなりました。asyncioイベントループは独自の安定したスレッドで継続的に実行されます。エンジンを終了させる可能性のあるUI操作は、EngineWorkerのキューに「終了」タスクを送信するようになり、ワーカースレッドはエンジンとそのループを安全にシャットダウンできます。計算中に「終了」が受信されても、ワーカースレッド内でasyncioタスクがキャンセルされるだけで、pywebviewのAPIスレッドには伝播せず、クラッシュを防ぎます。Engine move discardedというメッセージは、この正常な処理を示しています。
    2. specs/002-fix-castling-errorの削除について

      削除したのは良い判断でした。002-fix-castling-errorブランチとその関連する仕様ファイルは、バグ修正の失敗した試みを表していました。それらを残しておくと、誤った情報や置き換えられた情報でリポジトリが煩雑になります。

      フィーチャーの試みが失敗したり、新しいアプローチに置き換えられたりした場合は、古いブランチとその成果物をクリーンアップするのがベストプラクティスです。これにより、プロジェクトの履歴がクリーンに保たれ、成功した作業や関連する作業のみが反映されます。

      新しい003-fix-engine-concurrencyブランチとその仕様は、根本的な並行処理の問題を解決するための現在の成功したアプローチを正確に反映しています。

    💡 教訓: ユーザーの根気強さが成功の鍵

    これらの事例から学んだのは、Geminiでも不具合の特定は難しく、ユーザーとの共同作業であるということです。特に、エラー出力や挙動を注意深く観察し、根気強くAIにフィードバックすることが、適切な解決策を導き出すために不可欠となります。AIは強力な助けとなりますが、最終的なデバッグと検証は人間の役割です。

  • mcts-gen

    mcts-gen:AIエージェント統合型 次世代MCTSフレームワーク

    先日開発した mcts-gen は、標準的なUCT(Upper Confidence Bound 1 applied to Trees)アルゴリズムにAIエージェントを統合した、汎用的なMCTS(モンテカルロ木探索)フレームワークです。

    従来の chess-ant がGenetic Programming(GP)ベースであったのに対し、mcts-genは設計を根本から見直しました。Policy(方策)やValue(価値)の予測を外部AIエージェント(例えばgemini-cli)と連携させることで、探索効率と応用範囲を大幅に拡張しています。

    FastMCPによるAIエージェント連携

    このプロジェクトの核となるのは、FastMCP を介したAIエージェントとの通信です。mcts-genの探索エンジンは、MCP (Model Context Protocol) を通じて外部のAIエージェントと通信し、局面に応じたポリシー予測や価値評価を受け取ります。

    特に spec-kitgemini-cli を組み合わせ、AIをバックエンドとしたMCTSサーバーを生成・構築できる点が大きな特徴です。これにより、高速で柔軟な探索環境が実現します。

    未知領域探索への応用とPolicy Pruning

    MCPサーバーの導入により、このフレームワークは学習済みデータに基づく既存の知識空間だけでなく、未経験・未知の局面への探索も可能としました。

    AIエージェントによるPolicy Pruning(有望手の絞り込み)機能により、広大で非効率になりがちな探索空間の中から、効率的に有益な手だけを選び出して深く探索できます。これは、複雑な問題や新しいゲームへの応用において非常に強力なアドバンテージとなります。

    spec-kitワークフローの注意点(教訓)

    spec-kitのような高度な開発ツールを使用する際は、ワークフローの順守が不可欠です。

    spec-kitでは、/speckit.specify, /speckit.plan, /speckit.tasks といったスラッシュから始まるコマンドを実行すると、作業内容がMarkdownファイルに自動で記録され、新しいGitブランチも作成されます。その後、メインストリームへのマージ作業を行うのが基本の流れです。

    私の場合、コマンドを実行せずに直接GeminiにMarkdownファイルの更新を依頼したため、過去の作業記録が上書きされて失われてしまいました。これはGeminiの動作によるものではなく、規定の手順を踏まなかった私の操作ミスが原因です。ツールが意図するワークフローを守ることの重要性を改めて痛感しました。

    uvによるgemini-cliとFastMCP管理

    gemini-cliおよびFastMCPの公式推奨設定例 Gemini CLI 🤝 FastMCP では、uvコマンド による環境管理が原則とされています。

    uvはPythonパッケージの仮想環境管理ツールで、極めて高速かつクリーンな依存関係管理を可能にします。Rustで書かれており、従来のパッケージ管理ツールが抱えていたパフォーマンスの問題を解決します。

    Ubuntuでのuvインストールと使用法

    mcts-genプロジェクトでuvを利用するための基本的な手順は以下の通りです。

    pipxのインストール:

    sudo apt install pipx

    uvのインストール:

    pipx install uv

    基本的な利用方法。プロジェクトディレクトリで以下のコマンドを実行します:

    uv venv
    source .venv/bin/activate
    uv pip install mcts-gen[shogi]
    fastmcp install gemini-cli .venv/lib/python3.12/site-packages/mcts_gen/fastmcp_server.py:mcp

    コマンドを実行すると .gemini/settings.json が生成されます。
    因みに末尾の :mcpfastmcp_server.py にあるオブジェクト名です。オブジェクトが2つあるためか、自動でFastMCPサーバーのオブジェクトが認識されないので指定しなければなりません。run() メソッドで実行されます。
    仮想環境を終了するには deactivate コマンドを使います。

    マニュアルにある AGENTS.mdv0.0.2 で廃止しコード化しました。AIに指示を追加する場合のみcontextの設定を .gemini/settings.json に追記してください。


    mcts-genは、探索手法にAIの力を統合したいと考えるすべての開発者にとって、有力な選択肢となるはずです。詳細やセットアップ手順は、ぜひ公式ドキュメントも参考にしてください。

  • Gemini-JSCAD-Tool: GeminiとチャットしながらCAD開発する新しい体験

    概要

    gemini-jscad-tool は、Gemini CLI の拡張として開発されたツールで、JSCADを用いた3Dモデル生成を対話的に実現します。Geminiとチャットしながら、3Dモデルを作成し、リアルタイムにプレビュー&STLファイルに変換できます。

    特徴

    • 🔄 Geminiと自然言語でやり取りしながら設計できる
    • 🧊 JSCADモデルを作成し、STLへ変換
    • 🌐 ローカルのライブプレビューサーバーで即座にSTLの形状を確認可能
    • ⚙️ Gemini向け拡張機能の実装例としても活用可能

    インストール方法

    npm install -g gemini-jscad-tool

    インストール後、自動的に以下が行われます:

    • gemini-jscad-server コマンドがグローバルに配置される
    • gemini-extension.jsonGEMINI.md~/.gemini/extensions/jscad/ にコピーされる

    使用方法

    以下のように、Geminiとの会話ベースで操作を進めます。

    1. プレビューサーバーを起動

    あなた: Start the preview server.

    http://localhost:3000 にアクセスしてプレビュー。

    2. モデルを作成

    あなた: Create a 20mm cube.

    Geminiが自動的に .jscad ファイルを生成しSTLに変換後、プレビューサーバーに反映。

    3. サーバーを停止

    あなた: Stop the preview server.

    不要なプロセスの残留を防ぎます。

    STL変換について

    生成されたJSCADモデルは、ツール内部の処理を通じて STL形式に変換され、3Dプリント等にそのまま利用可能です。

    Gemini CLI拡張機能の開発に関して

    当パッケージは、Gemini CLI Extension 開発ガイドに則って作成されています。

    gemini-extension.json の基本構造とMCPサーバー登録

    拡張子 .json のこのファイルは、拡張(extension)ごとに最低1つ必要です。
    MCPサーバーの設定例は以下のようになります。
    因みにgemini-jscad-toolにはMCPサーバーは使用していません。後述の GEMINI.md で呼び出しを定義しています。

    マニュアルからの引用:

    {
      "name": "my-extension",
      "version": "1.0.0",
      "mcpServers": {
        "my-server": {
          "command": "node my-server.js"
        }
      },
      "contextFileName": "GEMINI.md",
      "excludeTools": ["run_shell_command"]
    }

    各項目の説明

    項目 必須 内容・役割
    name 拡張ディレクトリ名と同じにします。拡張の一意名識別子です。
    version 拡張のバージョン。任意の文字列(例 "1.0.0")。省略不可。
    mcpServers この拡張が使うMCPサーバーの "名前: 設定" マップ。各サーバーは必ずcommandプロパティが必要です。
    contextFileName 拡張についてAIへ与える文書ファイル名(通常はGEMINI.md)。省略可能。
    excludeTools Geminiに読み込ませたくないツール名列挙。(例 ["run_shell_command"]/["run_shell_command(rm -rf)"])省略可能。

    mcpServers の詳細

    MCP(Model Context Protocol) に準拠したサーバーの登録ができます。
    これにより、Geminiはサーバーを正しく起動・停止し、会話の中で状態管理することができます。

    mcpServers はオブジェクト形式で記述し、
    「サーバー識別名: 設定」 の形式でサーバーを複数登録できます。

    最小構成例:

    "mcpServers": {
      "my-server": {
        "command": "node my-server.js"
      }
    }
    • my-server:好きな識別名(ユニーク推奨)。
    • command:起動方法。実行ファイルやNodeスクリプト等を記述。

    コマンドにオプションや環境変数を指定したい場合

    因みに、 settings.jsonにもMCPサーバーを登録できます。
    非推奨パッケージになった @modelcontextprotocol/server-github
    設定例が書かれた記事も参照してください。

    マニュアルからの引用:

    "mcpServers": {
      "myPythonServer": {
        "command": "python",
        "args": ["mcp_server.py", "--port", "8080"],
        "cwd": "./mcp_tools/python",
        "timeout": 5000
      },
      "myNodeServer": {
        "command": "node",
        "args": ["mcp_server.js"],
        "cwd": "./mcp_tools/node"
      },
      "myDockerServer": {
        "command": "docker",
        "args": ["run", "-i", "--rm", "-e", "API_KEY", "ghcr.io/foo/bar"],
        "env": {
          "API_KEY": "$MY_API_TOKEN"
        }
      }
    }
    • args → コマンドライン引数
    • env → サーバープロセスの環境変数
    • cwd → サーバを起動する作業ディレクトリ
    • timeout → このMCPサーバーへのリクエストのタイムアウトをミリ秒単位で行います

    contextFileName について

    gemini-extension.json の説明に戻ります。
    この拡張のガイドやAI連携ガイダンスを含むMarkdownファイル名です。
    省略時は拡張ディレクトリ内の GEMINI.md が自動検出されます。

    excludeTools について

    Gemini CLIが利用可能なツールで、本拡張では“除外”したいものを配列で指定します。

    例:

    • すべてのシェルコマンド実行を除外
      "excludeTools": ["run_shell_command"]
    • 特定の危険コマンドのみ除外
      "excludeTools": ["run_shell_command(rm -rf)"]

    設定の優先順位と適用範囲

    • 個人設定(~/.gemini/extensions/)よりワークスペース直下(/.gemini/extensions/)の拡張が優先されます。
    • MCPサーバー設定はsettings.jsonの内容が同名の場合はそちらが上書きします。

    よくある誤り

    • mcpServersは必ずマッピング形式(オブジェクト)で書く。[マニュアル例と食い違う原因の多く]
    • サーバーごとに必ずcommandプロパティが必要

    GEMINI.md の役割

    GEMINI.md には、Geminiが拡張機能と対話する際のワークフローやコマンド定義がMarkdown形式で記述されています。例として下記のように構成します:

    # jscad Extension
    
    ## Commands
    
    ### Start Server
    User: Start the preview server.
    Gemini runs: gemini-jscad-server
    
    ### Create Model
    User: Create a 20mm cube.
    Gemini writes: cube({size: 20})
    
    ### Stop Server
    User: Stop the preview server.
    Gemini stops: jscad_preview

    これにより、Geminiは自動的に動作フローを把握し、ユーザーの自然言語要求をコード生成やファイル操作にマッピングします。

    コード・リソース

    おわりに

    gemini-jscad-tool は、AIとの自然な対話3D設計と即時プレビューの連携を実現した次世代のCLI拡張です。Gemini CLI拡張の実践例としても最適なので、カスタム開発の参考にもご活用ください。

    3D設計をもっと気軽に、もっと賢く―
    Geminiと一緒なら、それが可能です。

  • Ubuntuで2要素認証(2FA)を導入する方法【OTPClient活用ガイド】

    2FA(二要素認証)とは?

    2FA(Two-Factor Authentication、二要素認証)は、アカウントやサービスへのログイン時に「2つの異なる要素」で本人確認を行うセキュリティ手法です。
    一般的には「パスワード(知識情報)」+「ワンタイムパスワードやスマートフォン(所持情報)」の組み合わせが用いられます。これにより、万が一パスワードが漏れても、不正ログインを防ぐことができます123

    2FAを採用している主なウェブサービス

    サービス名 2FA設定ガイドへのリンク
    GitHub GitHub 2FA設定方法4
    PyPI PyPI 2FA設定方法5
    Google Google 2段階認証設定6
    ChatGPT ChatGPT 2FA設定方法7

    Ubuntuで使える2FA用ソフトウェア「OTPClient」

    OTPClientとは?

    • OTPClientは、TOTP(時刻ベース)・HOTP(カウンターベース)両対応のワンタイムパスワード生成アプリです。
    • ローカルデータベースはAES256-GCMで暗号化され、Argon2idによる鍵導出を採用しており高いセキュリティを誇ります8
    • 主要な2FAサービス(Google、GitHub、PyPIなど)に対応。

    Ubuntuへのインストール方法

    1. パッケージリストを更新
      sudo apt update
    2. OTPClientをインストール
      sudo apt -y install otpclient

      apt-getaptitudeでもインストール可能です9

    サイトのQRコード画像の保存と変換

    1. QRコード画像の保存
      2FA設定画面で表示されるQRコード画像を右クリック→「名前を付けて画像を保存」で保存します。

    2. SVG形式の場合のPNG変換
      SVG形式で保存された場合は、Inkscapeを使ってPNG形式にエクスポートできます。

      • InkscapeでSVGファイルを開く
      • 「ファイル」→「エクスポート」→「PNG画像としてエクスポート」

    OTPClientでの2FAトークン追加手順

    1. OTPClientを起動
    2. 「+」ボタンをクリックし「Add token」を選択
    3. 「Using a QR Code」→「From File」を選び、保存したQRコード画像を指定
    4. 登録後は、ワンタイムパスワードの項目をクリックするだけでクリップボードにコピーされます

    リカバリーコード(バックアップコード)の重要性

    • 2FAを有効化すると、万が一スマホやOTPClientにアクセスできなくなった場合に備えてリカバリーコード(バックアップコード)が発行されます。
    • 必ず安全な場所に保存し、第三者に見られないよう管理してください。
    • ログイン時に認証アプリが使えない場合、このリカバリーコードでアクセス回復が可能です1011

    まとめ

    Ubuntu環境でもOTPClientを使えば、主要なウェブサービスの2FAを簡単かつ安全に管理できます。リカバリーコードの保管も忘れずに、セキュリティを強化しましょう。

  • Doom Emacsのキーバインドと管理コマンド:標準Emacsとの違い

    Doom EmacsはEmacsの機能を拡張し、Vimライクな操作性を取り入れた強力なエディタです。本記事では、標準Emacsとの主要な違いを中心に、キーバインドと管理コマンドについて解説します。

    主要なキーバインドの違い

    1. 基本操作

    操作 標準Emacs Doom Emacs
    コマンド実行 M-x SPC : または M-x
    ファイルを開く C-x C-f SPC .
    ファイルを保存 C-x C-s SPC f s または :w (Evilモード)
    バッファ切り替え C-x b SPC b b
    バッファ削除 C-x k SPC b d

    2. ウィンドウ操作

    操作 標準Emacs Doom Emacs
    ウィンドウ分割(垂直) C-x 3 SPC w v
    ウィンドウ分割(水平) C-x 2 SPC w s

    3. 検索と置換

    操作 標準Emacs Doom Emacs
    インクリメンタル検索 C-s / (Evilモード) または C-s
    プロジェクト内検索 なし(追加パッケージが必要) SPC s p

    4. その他

    操作 標準Emacs Doom Emacs
    キーバインドのヘルプ C-h k SPC h k
    プロジェクト切り替え なし(追加パッケージが必要) SPC p p
    設定ファイル編集 手動でファイルを開く SPC f p

    スクロールのキーバインド

    Doom EmacsはVimライクなスクロール操作を採用しています:

    • 1ページ分下にスクロール: Ctrl-f または <PageDown>
    • 1ページ分上にスクロール: Ctrl-b または <PageUp>
    • 半ページ分下にスクロール: Ctrl-d
    • 半ページ分上にスクロール: Ctrl-u

    コメントアウトとアンコメント

    Doom Emacsでは以下のキーバインドでコメント操作を行います:

    • 選択した行をコメントアウト/アンコメント: gcc
    • 選択範囲をコメントアウト/アンコメント: gc(ビジュアルモードで範囲選択後)

    テキスト選択(Visual Mode)

    標準EmacsではCtrl+SPCでマーク開始しますが、Doom Emacsではvimのようにvisual modeで選択します:

    • 文字単位の選択: v
    • 行単位の選択: V(Shift + v)
    • 矩形選択: Ctrl-v
    • 単語選択: viw
    • 選択モードの終了: ESCまたはCtrl-[

    選択後の操作:

    • コピー: y
    • 切り取り: d
    • 削除: x
    • 置換: c
    • コメントアウト/アンコメント: gc

    Doomコマンドの基本

    Doom Emacsの管理にはdoomコマンドを使用します。主要なコマンドは以下の通りです:

    1. doom sync: 設定の変更を反映し、パッケージを更新
    2. doom upgrade: Doom Emacsとそのパッケージを最新版にアップグレード
    3. doom doctor: Doom Emacsの環境に問題がないかチェック
    4. doom env: Doomの環境変数を更新
    5. doom purge: 不要なパッケージや古いビルドファイルを削除

    設定ファイルを変更した後は、必ずdoom syncを実行して変更を反映させましょう(init.elpackages.elconfig.elは不要)。Doom Emacsにインストールされているパッケージによってはaptでインストールしなければならないソフトウェアを呼び出すことがあるので注意が必要です。doom doctorで確認しましょう。1

    sudo apt install ripgrep fd-find shellcheck

    以下はREADMEからの機械翻訳です。マニュアルには更に詳しい説明があります:

    • doom sync は、不足しているパッケージをインストールし、孤立したパッケージを削除し、キャッシュを再生成することで、プライベート設定を Doom と同期します。プライベート init.el または packages.el を変更するとき、または OS パッケージ マネージャーを介して Emacs パッケージ (mu4e や agda など) をインストール/削除するときは、必ずこれを実行します。
    • doom upgrade は、Doom を最新リリースおよびインストールされているすべてのパッケージに更新します。
    • doom doctor は、システムと設定の一般的な問題を診断します。
    • doom env は、起動時に Doom が読み込むファイルにシェル環境のスナップショットをダンプします。これにより、Emacs は PATH などを継承できます。

    まとめ

    Doom Emacsは標準Emacsとは異なるキーバインドを採用していますが、これにより直感的で効率的な操作が可能になっています。ただし、従来のEmacsユーザーにとっては学習曲線がある点に注意が必要です。doomコマンドを効果的に使用することで、環境を最適な状態に保ち、スムーズな編集体験を維持することができます。

  • Doom Emacsのインストールと設定

    インストール手順

    1. Doom Emacsのリポジトリをクローンする

      git clone --depth 1 https://github.com/doomemacs/doomemacs ~/.config/emacs
    2. Doom Emacsをインストールする

      ~/.config/emacs/bin/doom install

      これにより、設定ファイルは~/.config/doom/に、Doom Emacs用のユーザーディレクトリuser-emacs-directory~/.config/emacs/にインストールされます。従来のEmacsのユーザーディレクトリは~/.emacs.d/のままですので、影響を受けることはありませんが、バックアップを取ることをお勧めします。

    3. パスの設定
      Doomコマンドのパスは~/.config/emacs/bin/doomです。システム全体で利用できるようにパスを通すには、以下の方法があります。

      • .bashrcや.zshrcに追加

        echo 'export PATH=$PATH:$HOME/.config/emacs/bin' >> ~/.bashrc
        source ~/.bashrc

        または

        echo 'export PATH=$PATH:$HOME/.config/emacs/bin' >> ~/.zshrc
        source ~/.zshrc

        .bashrc以外のファイルでもパスを設定できますが、使用するシェルやログイン方法によって読み込まれるタイミングが異なります。

        • .bashrc: 通常、ターミナルを新しく開くたびに読み込まれます。
        • .profile: ログインシェル時に読み込まれます。ターミナルを新しく開くたびに読み込まれないため、反映するにはターミナル内でsource ~/.profileを実行する必要があります。
        • .bash_aliases: 通常、.bashrc内で読み込まれるように設定されています。.bashrcが読み込まれるたびに自動的に読み込まれます。

    Doom Emacsの起動

    Doom Emacsを起動するには、以下のコマンドを使用します(Emacs 29以降)。Emacsの変数user-emacs-directoryを指定して起動するためです。1 2

    emacs --maximized --init-directory ~/.config/emacs/

    --maximizedオプションは画面を最大化するためのもので、省略可能です。ショートカットキーに登録すると便利です。
    Ubuntuの場合は以下の通りです:

    1. 設定
    2. キーボード
    3. ショートカットの表示と設定
    4. 独自のショートカット
    5. +をクリック

    ~/.bash_aliasesにエイリアスを登録しても良いでしょう。

    alias emacs.doom='emacs --maximized --init-directory ~/.config/emacs/'

    基本的な使い方

    Doom EmacsはVimユーザーにも親しみやすい設定が整っています。基本的な操作はVimと似ていますが、Emacs独自の機能も多く利用できます。
    All-the-icons fontsの文字化けはM-x nerd-icons-install-fontsを実行すれば解消されます。3

    Doomコマンドの基礎

    Doomコマンドは、Doom Emacsの設定やパッケージ管理に利用されます。例えば、パッケージをインストールする際には、Doom Emacs内で特定のコマンドを実行します。

    予めインストールされるパッケージ

    Doom Emacsには、多くの便利なパッケージがデフォルトでインストールされています。これにより、すぐにでも効率的な開発環境を構築できます。
    多くは~/.config/doom/init.elの各行をアンコメントし、doom syncすることですぐに有効化出来ます。4

    Doom Emacsでパッケージをインストールする方法

    Doom Emacsでは、straight.elがデフォルトのパッケージマネージャーとして使用されています。新しいパッケージをインストールするには、設定ファイルを編集してからdoom syncコマンドを実行する必要があります。

    Codeium.elのインストールと設定

    1. Codeium.elのインストール
      Doom Emacsでは、codeium.elを直接インストールする方法は通常のEmacsと異なります。まず、~/.config/doom/packages.elに以下のコードを追加します:

      (package! codeium :recipe (:host github :repo "Exafunction/codeium.el"))

      編集後は、以下のコマンドで設定を反映させます:

      ~/.config/emacs/bin/doom sync

      次にDoom Emacs内で以下のコマンドを実行します:

      M-x codeium-install

      APIキーを自動取得するオプションが表示されます。autoを選択すると、Webブラウザでログイン画面が表示され、ログイン後にAPIキーが自動取得されます。
      ~/.config/doom/custom.elに保存されます。

    2. 設定
      codeium.elの設定は、customize-variableコマンドではなく、~/.config/doom/config.elを直接編集する必要があります。編集後は、doom syncは不要です。

      以下のコードは、codeium-completion-at-pointcompletion-at-point-functionsに追加するものです:

      (add-to-list 'completion-at-point-functions #'codeium-completion-at-point)

      このコードにより、Codeiumの補完機能が有効になります。また、codeium.elの設定をコピーしても良いでしょう。ただし、codeium.elが正しくインストールされ、他の設定が競合していないことを確認する必要があります。

  • VimとNeovimの基本とパッケージマネージャ、そしてCodeiumについて

    Vimtutorについて

    Vimは非常に強力なテキストエディタであり、特にプログラマーやシステム管理者に人気があります。しかし、初めてVimを使う人にとっては、その操作方法が少し難解に感じられるかもしれません。そこで登場するのがVimtutorです。

    Vimtutorは、Vimの基本的な操作方法を学ぶためのチュートリアルです。多くのUnix系オペレーティングシステムには、Vimtutorが標準でインストールされています。ターミナルでvimtutor jaと入力するだけで、インタラクティブな学習環境が提供されます。このチュートリアルを通じて、基本的な移動、編集、保存、そしてVimのモード(ノーマルモード、インサートモード、ビジュアルモードなど)について学ぶことができます。

    Tagファイルの併用

    Emacsで定義元へ移動するためにetagsを使用しtagファイルを作成していれば、Vimと併用できます。例えば:set tags=~/.venv3.12/TAGSのように選択できます。Tabキーで入力補完できます。Ctrl-]で定義元へ移動し、Ctrl-tで戻ります。頻繁に使用するならば~/.vimrcに書いておきましょう。因みにコロンは不要です。1

    Vimの標準装備のパッケージマネージャについて

    Vim自体には標準でパッケージマネージャが含まれています。Vim 8.0以降では、ネイティブのパッケージ管理機能が導入されています。これにより、プラグインのインストールや管理が非常に簡単になりました。

    使い方

    1. パッケージのインストール:

      • パッケージをインストールするには、~/.vim/pack/<namespace>/start/ディレクトリにプラグインを配置します。
      • 例えば、~/.vim/pack/plugins/start/にプラグインをダウンロードして配置すると、Vimが自動的にそのプラグインを読み込みます。
    2. パッケージのアップデート:

      • パッケージのアップデートは、プラグインのリポジトリから最新のバージョンをダウンロードして、同じディレクトリに置き換えるだけです。

    人気のあるパッケージマネージャ

    Vimの標準パッケージマネージャ以外にも、いくつかの人気のあるパッケージマネージャがあります。

    • Vundle: Vundleは、Vim用のプラグインマネージャで、簡単にプラグインをインストール、アップデート、削除することができます。
    • Pathogen: Pathogenは、プラグインを簡単に管理するためのツールで、プラグインを特定のディレクトリに配置するだけで自動的に読み込まれます。
    • Plug: Plugは、Vim用の軽量なプラグインマネージャで、Vundleと同様に簡単にプラグインを管理できます。

    Neovimについて

    Neovimは、Vimのフォークであり、Vimの機能を拡張し、よりモダンなエディタとしての機能を提供します。Neovimは、Vimと互換性があり、Vimのプラグインや設定ファイルをそのまま使用することができます。

    Neovimの特徴

    • 非同期ジョブ: Neovimは非同期ジョブをサポートしており、バックグラウンドでの処理が可能です。
    • リモートプラグイン: Neovimはリモートプラグインをサポートしており、PythonやLuaなどの言語でプラグインを作成することができます。
    • パフォーマンス: NeovimはVimよりも高速で、メモリ使用量も少ないです。

    Codeiumについて

    Codeiumは、AIを活用したコード補完ツールで、開発者の生産性を大幅に向上させることができます。Codeiumは、VimやNeovimだけでなく、他の多くのエディタやIDEでも利用可能です。

    Codeiumの特徴

    • AIによるコード補完: Codeiumは、AIを使用してコードの補完を行います。これにより、コーディングの速度が向上し、エラーの発生を減少させることができます。
    • 多言語対応: Codeiumは、JavaScript、Python、Java、C++など、多くのプログラミング言語に対応しています。
    • インテグレーション: Codeiumは、VimやNeovimだけでなく、VSCode、IntelliJ、Sublime TextなどのエディタやIDEとも統合されています。

    Codeiumのマニュアルインストール

    Ubuntuでのインストールを想定しています。

    Vimの場合:

    git clone https://github.com/Exafunction/codeium.vim ~/.vim/pack/Exafunction/start/codeium.vim

    Neovimの場合:

    git clone https://github.com/Exafunction/codeium.vim ~/.config/nvim/pack/Exafunction/start/codeium.vim

    インストール後に:Codeium Authを実行するとProvide Authentication Tokenページへ飛びますのでログインし、あなたに与えられたトークンをVim / Neovimにコピー&ペーストして下さい。

    まとめ

    VimとNeovimは、非常に強力なテキストエディタであり、その機能を最大限に引き出すためには、Vimtutorやパッケージマネージャを活用することが重要です。また、CodeiumのようなAIツールを組み合わせることで、さらに効率的な開発環境を構築することができます。これらのツールを駆使して、あなたの開発生産性を最大限に引き出しましょう!

  • PywebviewでPythonとJavaScriptを連携:Promiseの役割と具体例

    Pywebviewは、PythonとJavaScriptを連携させたデスクトップアプリケーション開発に役立つフレームワークです。しかし、Pythonプログラマーにとって慣れない「非同期処理」や「Promise」に直面することもあります。本記事では、py-chessboardjsを例に、以下を詳しく解説します:

    1. Promiseとは何か、なぜ必要か
    2. Pythonのメソッド戻り値をJavaScriptの関数に活用する方法
    3. 具体例:PGNファイルの読み込み

    Promiseとは?

    Promiseは、非同期処理の結果を待つためのオブジェクトであり、成功(resolved)または失敗(rejected)の状態を持ちます。

    • Pythonでは、関数は通常即座に戻り値を返します(同期処理)。
    • 一方、JavaScriptでは処理が非同期になることが多く、処理完了後に値を受け取る必要があります。

    Pythonでは処理が終わるのを待って変数等に代入してくれますが、JavaScriptでは待ってくれません。
    これを解決するために、PywebviewはPythonのメソッド呼び出し結果をPromiseでラップします。これにより、JavaScript側でthenを使って結果を受け取れるようになります。


    Pythonメソッドの戻り値をJavaScriptで利用する

    以下は、py-chessboardjsのPGNファイル読み込み機能を使い、Pythonのメソッド結果をJavaScriptで処理する例です。

    Python側のコード

    PythonでPGNファイルを読み込み、その状態(FEN文字列)を返すメソッドを定義します:

    class Api:
        def open_pgn_dialog(self):
            """
            ユーザーにファイルダイアログを表示し、選択したPGNファイルを読み込み、
            そのゲーム状態をFEN文字列で返す。
            """
            file_types = ('PGN File (*.pgn)', 'All files (*.*)')
            file_path = self.window.create_file_dialog(webview.OPEN_DIALOG, file_types=file_types)[0]
            if os.path.exists(file_path):
                self.pgn = open(file_path)
                self.load_games_from_file()
                return self.board.fen()  # 現在のFEN文字列を返す
            return None

    JavaScript側のコード

    JavaScriptで、このPythonメソッドを呼び出し、結果(FEN文字列)を利用します:

    function openPgnDialog() {
        // Python API を呼び出し
        pywebview.api.open_pgn_dialog().then(fen => {
            if (fen) {
                console.log('FEN文字列:', fen);
                // 必要に応じてフロントエンドで処理
                updateBoardWithFen(fen);
            } else {
                console.error('PGNファイルの読み込みに失敗しました。');
            }
        }).catch(error => {
            console.error('エラーが発生しました:', error);
        });
    }
    
    // FEN文字列でボードを更新する例(仮)
    function updateBoardWithFen(fen) {
        alert('新しいFEN: ' + fen);
    }

    ポイント:
    pywebview.api.open_pgn_dialog()はPromiseを返し、thenで結果を受け取り処理しています。


    Promiseの基本的な使い方(Pythonプログラマー向け)

    PromiseはPythonの「関数の戻り値」をJavaScriptの非同期処理に適応するための仕組みです。

    • Pythonの戻り値はPromiseの成功状態(resolved value)として扱われます。
    • JavaScriptでは、thenを使って成功時の値を受け取ります。

    Promiseの流れ

    1. Pythonメソッドが値を返す。
    2. PywebviewがPromiseに変換。
    3. JavaScriptでthenを使い値を処理。

    フロントエンドのUIデザイン:Bootstrapを活用

    PywebviewはHTML/CSS/JavaScriptフレームワークを使用できるため、py-chessboardjsではBootstrapを活用し、ユーザーにとって使いやすいUIを構築しています。

    実装例

    以下は、index.htmlのナビゲーションバー部分です(省略のために一部改変):

    <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">Py-Chessboardjs</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDarkDropdown" aria-controls="navbarNavDarkDropdown" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNavDarkDropdown">
                <ul class="navbar-nav">
                    <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
                    <li class="nav-item"><a class="nav-link" href="#">Settings</a></li>
                </ul>
            </div>
        </div>
    </nav>

    結果、レスポンシブなナビゲーションバーが表示され、簡単にカスタマイズできます。


    まとめ

    Promiseは、PythonとJavaScriptの動作の違いを吸収するために必要な仕組みです。今回の例では、py-chessboardjsを使いながら以下を学びました:

    1. PythonメソッドをJavaScriptから呼び出し、戻り値をPromiseで扱う方法。
    2. Bootstrapを利用したスタイリッシュなフロントエンドデザイン。

    これらを応用すれば、直感的で高性能なアプリケーションを構築できます。


    アロー関数を使う理由

    今回、ChatGPTとClaudeに記事を書いてもらう際にpy-chessboardjsのコードを標準の書き方に修正してもらい、その理由を解説してもらいました。以下はその内容です。
    JavaScriptの=>アロー関数(arrow function)を意味し、関数を簡潔に書くための記法です。従来のfunctionキーワードを使った関数定義と同じ動作をしますが、以下のような利点があります。

    1. 簡潔な記法:

      • 従来のfunctionキーワードを省略できます。
      • 例えば、以下のようなコードが簡略化されます:

        // 通常の関数
        function add(a, b) {
         return a + b;
        }
        
        // アロー関数
        const add = (a, b) => a + b;
    2. thisの挙動が直感的:

      • アロー関数は親スコープのthisをそのまま使用します。一方、従来のfunctionは呼び出し方によってthisが変わるため、意図しない挙動を防げます。

        例:

        function Example() {
         this.value = 42;
        
         // 通常の関数(意図したthisではない可能性あり)
         setTimeout(function() {
             console.log(this.value); // undefined(thisはグローバルを指す)
         }, 1000);
        
         // アロー関数(意図したthisを保持)
         setTimeout(() => {
             console.log(this.value); // 42
         }, 1000);
        }
        new Example();
    3. Promiseチェーンでの一般的な書き方:

      • Promiseチェーン(thencatch)内で、アロー関数を使うのが一般的です。
      • シンプルなコールバック処理に適しています:

        // 通常の関数
        pywebview.api.get_data().then(function(result) {
         console.log(result);
        });
        
        // アロー関数
        pywebview.api.get_data().then(result => {
         console.log(result);
        });

    アロー関数が好まれるケース

    • 短い関数(関数リテラル): アロー関数は、数行で完結する関数リテラルに適しています。
    • コールバック関数: 非同期処理(setTimeoutPromiseなど)で使うと直感的です。

    アロー関数を避けるべきケース

    アロー関数はthisの挙動が予測しにくいケースがあります。

    • thisを明示的に保持する必要がある場合: メソッド内やイベントリスナーなど、thisの挙動が重要な場合は、従来の関数式を使用する方が安全です。
    • thisの再定義が必要な場合: アロー関数ではthisを新たに定義できません。そのため、例えばイベントリスナーの削除が必要な場合は避けるべきです。

      // イベントリスナーの登録
      button.addEventListener('click', () => console.log('clicked'));
      
      // イベントリスナーの削除(動作しない)
      button.removeEventListener('click', () => console.log('clicked')); // 別の関数として扱われる

    アロー関数は実際にはthisを明示的に保持するのに適していません。むしろ、アロー関数はthisを現在のスコープから継承するため、メソッドやイベントリスナーでは注意が必要です。

    アロー関数はthisの挙動が独特で、以下のような特徴があります:

    1. アロー関数は、定義された場所のthisコンテキストを継承します。
    2. 自身のthisを持たず、外側のスコープのthisをそのまま使用します。
    3. メソッドやイベントリスナーでは、通常の関数式の方がthisの参照が明確です。

    結論

    =>(アロー関数)を使った理由:
    本記事ではPromiseチェーンでの一般的な記法を重視し、可読性と簡潔さのためにアロー関数を使用しました。特に短いコールバック関数を記述する場合、アロー関数が現代的で簡潔な書き方として推奨されるケースが多いです。
    ただし、もし従来のfunctionキーワードに慣れている場合、どちらを使うかは個人のスタイルやプロジェクトのコーディング規約に依存します。

  • Self-Debuggingの先駆け:bolt.new

    bolt.newは、AIを活用した革新的なWeb開発プラットフォームです。自然言語での指示だけで、フルスタックのWebアプリケーションを簡単に作成できる画期的なツールとして注目を集めています。

    AIが生み出す驚異のシミュレーション:bolt.newの実力

    最新のAI駆動型Web開発プラットフォーム、bolt.newの驚くべき能力をご紹介します。私自身がbolt.newを使って作成したシミュレーション「Kinzhal Busters」をご覧ください。このプロジェクトは、現代の軍事技術と防衛システムを模したインタラクティブな3Dシミュレーションです。

    Kinzhal Busters: https://github.com/akuroiwa/kinzhal-busters

    このシミュレーションでは、発電所に飛来するKinzhal(キンジャール)ミサイルと、それを迎撃しようとする複数のドローンによる防衛システムの動きを再現しています。Three.jsを駆使した立体的な表現により、複雑な軌道や迎撃のプロセスを視覚的に理解しやすい形で表現しています。

    bolt.newの驚異的な点は、このような高度な3Dシミュレーションを、プログラミングの詳細な知識がなくても、自然言語での指示だけで作成できることです。AIが要求を理解し、適切なライブラリやフレームワークを選択し、必要なコードを生成してくれるのです。

    Self-Debugging: エラー解決の新たなアプローチ

    bolt.newの特筆すべき機能の一つが、Self-Debuggingです。開発中に発生したエラーを、AIが自動的に解析し修正案を提示します。「Fix problem」ボタンをクリックするだけで、AIがエラーを修正し、アプリケーションを正常に動作させることができます。

    Self-Debuggingについては、論文Teaching Large Language Models to Self-Debugを参照してください。これは、これからのコード生成サービスで主流になる可能性が高い機能です。

    Viteとパッケージのインストール

    bolt.newでプロジェクトを作成すると、デフォルトでViteが選択されます。Viteは高速な開発サーバーと最適化されたビルドツールを提供する次世代のフロントエンドツールです。

    ノーコードで全てが完結する訳ではありません。Stackblitzならば自前でインストールせずともWebブラウザで確認できますが、お気に入りのエディタでコードを手直しし、気軽に動作確認したいでしょう。ここでは、その方法を説明します。

    Ubuntuでの必要なパッケージのインストール

    1. Node.jsとnpm:
    sudo apt update
    sudo apt install nodejs npm
    1. 必要に応じてNode.jsのバージョンを更新:
    sudo npm install -g n
    sudo n stable
    hash -r
    npm -v
    node -v

    npmでインストールする必要があるもの

    プロジェクトのルートディレクトリで以下のコマンドを実行します:

    npm install

    これにより、package.jsonに記載されている全ての依存関係がインストールされます。

    また、bolt.newで生成されるプロジェクトの.gitignoreファイルには、通常components/ディレクトリが含まれ、バージョン管理から除外されます。

    Viteプロジェクトの起動

    1. 開発サーバーの起動:
    npm run dev

    これにより、開発用のサーバーが起動し、通常はhttp://localhost:5173でアプリケーションにアクセスできます。
    hを入力しenterを押せば、使い方を表示してくれます。

    1. プロダクションビルド:
    npm run build

    これにより、プロダクション用のビルドが作成されます。

    1. プロダクションビルドのプレビュー:
    npm run preview

    ビルドされたプロダクションバージョンをローカルでプレビューできます。

    StackBlitzとGitHub連携

    StackBlitzは、GitHubリポジトリとの連携機能を提供しています。
    bolt.newに作成してもらったプロジェクトをGitHubリポジトリとして登録できます。
    プロジェクトの動作確認も出来るので、Webブラウザさえあれば、いつでも作業できます。

    StackblitzもNetlifyも、bolt.newと同じくGitHubアカウントでアカウント登録したりサインインしたりできます。

    bolt.newからNetlifyへのデプロイとユーザー権限移譲

    bolt.newで作成したプロジェクトをNetlifyにデプロイした直後に表示される「claim URL」をクリックすることで、
    アプリケーションの所有権があなたのNetlifyアカウントに移行されます。
    この過程で、デプロイ時に表示されたURLを控えておくことが重要です。新しい所有者がプロジェクトにアクセスする際に必要となります。

    また、GitHubで更新し、Netlifyのアプリも更新したい場合にはリポジトリの登録が必要です。

    bolt.newは、AIの力を借りてWeb開発のプロセスを大幅に簡素化し、効率化する革新的なツールです。プログラミングの経験が浅い方でも、複雑なWebアプリケーションを作成できる可能性を秘めています。