コンテンツにスキップ
↑↓移動 ↵開く esc閉じる

拡張機能を作る

@openchamber/sdk を使うと、OpenChamber に自分のパネルを追加できます。拡張機能とは、OpenChamber が右側のレールに表示する小さなウェブページです。アプリとは connectHost() で話します。現在のプロジェクトとセッションを読む、トーストを出す、チャット欄にテキストを入れる、タスクをセッションに添付する、そしてユーザーの承認があればセッションを開始してプロンプトを送る、といったことができます。

拡張機能は OpenChamber のウェブ版とデスクトップ版で動きます。VS Code とモバイルはまだ読み込みません。

拡張機能とは何か

3 つのファイルが入ったフォルダです。

  • openchamber ブロック(マニフェスト)を持つ package.json
  • panel/index.html、OpenChamber が表示するページ
  • panel/main.js、あなたのスクリプト。単一の classic ファイル(ES モジュールではなく IIFE)にビルドしたもの。ページはサンドボックス化された iframe で読み込まれるためです

OpenChamber はあなたのコードをコンパイルしません。ビルド済みの .js ファイルを同梱してください。SDK にはバンドラーコマンドが含まれています。IIFE を出力できるバンドラーなら何でも使えます。

Terminal window
npm install @openchamber/sdk
bunx openchamber-guest-bundle panel/main.ts panel/main.js

このバンドラーコマンドは Bun で動きます。Bun がない場合は、esbuild など他のバンドラーを --format=iife --platform=browser で使ってください。

3 つのファイルすべてを含む、動作する完全な拡張機能は 例 ページにあります。コピーして、API と一覧を差し替えてください。

index.html からは通常の <script src="main.js"></script> で main.js を読み込みます。

作業中にインストールする

  1. OpenChamber をウェブかデスクトップで起動します。
  2. 設定 → 拡張機能 を開きます。
  3. フォルダの絶対パスを貼り付けて、追加をクリックします。

OpenChamber がマニフェストを読み、拡張機能が求めているものの一覧をダイアログで表示します(権限 を参照)。承認すると、レールにアイコンが現れます。クリックするとページが読み込まれます。

ローカルの .zip や、git リポジトリまたは zip ファイルへの https リンクも追加できます。更新できるのは git からのインストールだけです。package.json の version を上げてプッシュすると、OpenChamber は起動の直後と数時間ごとに確認し、ユーザーに一度だけ知らせて、設定 → 拡張機能 で更新を提案します。任意のページに openchamber://extensions/install?url=<encoded repository URL> へのリンクを置くと、そのリポジトリが追加ダイアログに入った状態でデスクトップアプリが開くので、インストールボタンを用意できます。URL の #tag や #branch で、どれを追従するかを固定できます。これらは OpenChamber のデータフォルダにコピーされ、そのコピーから実行されます。そのため node_modules や TypeScript のソースではなく、ビルド済みファイルを同梱してください。拡張機能を削除するとコピーも消えます。フォルダからのインストールはそのフォルダから直接動くので、編集、再ビルド、再読み込みができます。

マニフェスト

{
"name": "@acme/hello",
"version": "1.0.0",
"openchamber": {
"apiVersion": 1,
"engines": { "openchamber": ">=1.24.0" },
"id": "acme-hello",
"name": "Hello",
"icon": "window",
"contributes": {
"panel": { "entry": "panel/index.html" },
"attach": "dialog",
"page": true,
"capabilities": ["prompt", "sessions"],
"integration": {
"name": "Acme",
"description": "Tasks from Acme",
"token": {
"apiOrigin": "https://api.acme.example",
"account": { "path": "/me", "name": "login" },
"scheme": "bearer"
},
"settings": [{ "id": "list-id", "label": "List ID" }]
}
}
}
}

version は必須で、semver でなければなりません。設定 → 拡張機能 のカードに表示されます。

apiVersion は 1 です。OpenChamber は他の値を拒否します。

engines.openchamber は任意です。拡張機能が動作する最も古い OpenChamber のバージョンを、1.24.0 または >=1.24.0 の形で指定します。古いビルドは、後で失敗する代わりにインストール自体を拒否します。

id、name、icon で拡張機能を識別します。id は kebab-case で、インストール済みの拡張機能の中で一意でなければなりません。icon は Remixicon の名前(RiWindowLine なら window)か、フォルダ内の SVG ファイル(icon.svg など)です。contributes.panel はレールに表示される拡張機能のパネルで、その entry はフォルダ内の HTML ファイルです。レールのパネルがない拡張機能では panel を省略します。古いパッケージでは id、name、icon が panel の中にありますが、引き続き動作します。

contributes.attach は任意です。チャット欄の横にある + メニューに拡張機能を追加し、ユーザーがタスクを選んでセッションに添付できるようにします。

  • "dialog" はページをウィンドウで開く
  • true または "panel" は代わりにレールのパネルを開く
  • { "mode": "dialog", "entry": "panel/attach.html" } はあなたの別ページをウィンドウで開くので、選択画面がレールのパネルとコードを共有する必要がなくなる
  • 省略すると拡張機能はそのメニューに出ない

ctx.surface は panel、dialog、page、status、block のいずれかです。添付項目をクリックすると、そのデータが ctx.item に入り、それ以外は null です。

contributes.page: true を指定すると、セッション一覧の上にある拡張機能のページメニューから全画面で開けます。{ "entry": "panel/page.html", "title": "Board" } で別の HTML と任意のタイトルを指定できます。panel.entry は必須で、サンドボックスと権限は共通です。ページを開くのはユーザーだけです。再読み込み、一時停止、削除、サーバー切り替えで閉じます。

ボードには host.storage と、プロジェクト、worktree、セッションの一覧およびライブ状態を使えます。startSession はボードを閉じずに別のプロジェクトを指定できます。Host API を参照してください。

contributes.integration は任意です。設定 → 連携 にカードを追加し、ユーザーがそこでアカウントを接続します。アカウントとネットワーク を参照してください。

contributes.service は任意です。Docker ソケットのようにウェブページからは届かないもののために、OpenChamber が拡張機能の隣で起動するローカルプロセスを宣言します。そのプロセスはユーザーのフルアクセス権限で、サンドボックスなしに動くため、承認ダイアログはそれについて警告します。ページでは対応できない場合にのみ宣言してください。パッケージ内のファイル GUEST_SERVICES.md を参照してください。 provides: ["browser"] を持つサービスはエージェントのブラウザーの代わりも務められます。サーバー上で browser.* 操作に応答するので、デスクトップアプリを開かなくてもエージェントがブラウズでき、ユーザーは設定 → OpenChamber ツールで選択します。このようなサービスにパネルは不要です。サービスはユーザーのセッションで起きたことを受け取ることもできます。その隣に contributes.sessionEvents を宣言すると、OpenChamber は完了または失敗した各ターンと、エージェントが求めた各許可や質問を、すべてのプロジェクトから、ウィンドウを開いていなくてもサービスに送ります。セッションイベント を参照してください。また、provides: ["notifications"] を持つサービスは、デスクトップとスマートフォンに加えて、Slack、Matrix、または自前のサーバーにユーザーの通知を届けます。ユーザーは設定 → 連携 でアカウントを接続し、トークンは OpenChamber に保持されます。通知チャネル を参照してください。 provides: ["tracker"] を持つサービスは Linear の隣に並ぶ作業アイテムのトラッカーで、そのアカウントカードは拡張機能のアカウントの下に出ます。トラッカー を参照してください。そして provides: ["quota"] を持つサービスは、マニフェストに列挙したプロバイダーについて OpenCode が保持する認証情報を読み、組み込みのプロバイダーの隣で使用量を報告します。使用量プロバイダー を参照してください。

権限

パネルを描くことと現在のセッションを読むことに権限は要りません。ユーザーの代わりに何かを行うものには要ります。それらを contributes.capabilities に列挙します。

権限許可されること
promptユーザーのセッションにメッセージを送る(prompt({ send: true })、text 付きの startSession)
sessionsプロジェクト、worktree、セッション状態を一覧表示し、登録済みプロジェクトでセッションを作成して開く
files開いているプロジェクト内のファイルを読み書きする(相対パス付きの readFile、writeFile、listDir、stat)
modelセッションの外で、ユーザーの Small Model による一回限りのテキスト生成を行う(generate)

さらに 11 個が自動で追加されます。integration を宣言すると network、service を宣言すると service、filesystem パターンを宣言すると filesystem、origins を宣言すると origins、セッションのアクションがメッセージを求めると conversation(アクション、コマンド、バッジ を参照)、sessionEvents または sessionControl が content を求めると transcript(セッションイベント を参照)、サービスがセッションを操作すると sessionControl(OpenChamber の呼び出し を参照)、サービスがユーザーの代わりにエージェントの権限リクエストやフォームに応答すると sessionAnswers(sessionControl: { answers: true })、エージェントが読む内容に追加すると instructions、contributes.skills を宣言すると skills です。contributes.skills はパッケージ内のスキルのフォルダーで、拡張機能がオンの間、すべてのエージェントに届きます。contributes.opencodePlugin を宣言すると opencodePlugin も追加されます(下記参照)。

ユーザーは拡張機能をインストールするときに一覧を一度だけ見て、承認するか拡張機能を削除するかを選びます。新しいバージョンがより多くを求める場合、ダイアログが再び表示されます。ユーザーが承認していない権限を必要とする呼び出しは NOT_GRANTED で失敗します。

パッケージに OpenCode プラグインを同梱する

拡張機能は OpenCode プラグインを同梱できます。利用者は 2 つではなく 1 つをインストールするだけで済みます。"opencodePlugin": "plugin" を宣言してください。これはパッケージ内のフォルダーで、そのルートに index.js または server.js を置きます。OpenCode は main を読まないため、エントリーを別の場所に置く場合はフォルダーの package.json に name と exports を指定してください。エントリーは OpenCode が読み込む形 { id, setup } をデフォルトエクスポートします。OpenCode は何もインストールされていないあなたのフォルダーから素の import() で読み込むため、エントリーは何もインポートしません。ツールの input は素の JSON Schema で、execute は { content } を返します。

{
"contributes": {
"panel": { "id": "teapot-tools", "name": "Teapot Tools", "icon": "cup" },
"opencodePlugin": "plugin"
}
}

承認ダイアログに OpenCode にプラグインを追加 という行が増え、プラグインのコードが利用者の全権限で OpenCode の中で実行されることをはっきり伝えます。許可されると、OpenChamber は自身が管理する OpenCode 設定(contributes.skills を載せるのと同じファイル)にあなたのフォルダーを載せます。OpenChamber が起動した OpenCode はそのファイルを監視し、数秒以内にプラグインを読み込みます。拡張機能を無効にするか削除すると、同じ経路で取り除かれます。利用者自身の opencode.json には何も書き込みません。そのファイルは利用者のものであり、そこにあるプラグインは拡張機能より長く残り、マシン上のすべての OpenCode で動いてしまうからです。

そのファイルが OpenCode に届かない場合、拡張機能の画面がそう伝え、グローバル設定に追加 を提示します。これはあなたのフォルダーを利用者のグローバル OpenCode 設定に、以後は利用者が所有する項目として書き込みます。これに該当するのは、OpenChamber が通信相手の OpenCode を起動していない場合と、サーバーの環境が独自の OPENCODE_CONFIG を設定している場合です(後者ではプラグインは次回の OpenCode 起動時に読み込まれます)。別のマシンの OpenCode はこのマシンのフォルダーを読み込めません。画面はそう伝え、何も提示しません。読み込みに失敗したプラグインは、項目がある場合に設定 → Plugins で OpenCode が報告します。どちらの場合も拡張機能自体は動き続けます。プラグインのフォルダーがない、またはその package.json にエントリーファイルの指定がないパッケージは、インストールが拒否されます。

VS Code とモバイルアプリは拡張機能を読み込まないため、プラグインも届きません。隔離スペース内のセッションは独自の OpenCode を実行し、ホストの設定を読むことはありません。エンタープライズモードではプラグインはローカルサービスと同じ扱いで、管理者が登録したリポジトリからのみインストールできます。SDK には動作する例 examples/opencode-plugin があります。

テキストを生成する

model 権限があると、host.generate はユーザーの Small Model に一回限りの回答を求めます。要約、タイトル、下書きなどです。何もセッションには入らず、履歴も残らず、拡張機能がプロバイダーを選ぶこともありません。OpenChamber は自身のバックグラウンド作業で使うのと同じモデルを使います。設定 → セッション → Small Model で選んだモデル、ユーザーが使っているプロバイダーの small model、またはユーザーの OpenCode 設定の既定モデルです。

const { text } = await host.generate({
prompt: task.description,
system: "Write a one-line summary. Return only the summary.",
maxOutputTokens: 200,
});

利用できるモデルがない場合、呼び出しは NO_MODEL で失敗します。モデルがエラーを返した場合は MODEL_FAILED です。プロンプトは 64,000 文字までに制限され、呼び出しは最大 90 秒待ちます。ユーザーにはこの権限が「Small Model を使う」と表示され、トークンを消費するので、プロンプトは短く保ち、キー入力のたびにではなくクリック時に呼び出してください。

アカウントとネットワーク

ページはサンドボックスで動き、自力ではネットワークに出られません。スクリプト、スタイル、画像、フォント、メディアはパッケージからしか読み込めず、fetch が届くのもパッケージ内のファイルだけです。フォントや画像は CDN から読み込まず、パッケージに同梱してください。

外部のサービスとやり取りするには、integration を宣言します。OpenChamber が host.request を通じて、ユーザーのトークンを付けて代わりに呼び出します。トークンがページに届くことはありません。

CDN のフォントや画像、公開 API など、ページが直接必要とするそれ以外のものには、https のオリジンを最大 8 個まで列挙します。

"origins": ["https://fonts.example.com"]

ユーザーには承認ダイアログで、拡張機能がデータを送受信できるアドレスとして表示されます。更新でオリジンが追加されると、改めて承認が必要です。承認されたオリジンは fetch、画像、フォント、スタイル、メディアには開かれますが、スクリプトには決して開かれません。コードはパッケージに同梱する必要があります。ページのオリジンは null なので、fetch のレスポンスを読むには、サーバーがそのオリジンに対して CORS を許可している必要があります。

エンタープライズモードでは、origins、integration、service のいずれかを持つ拡張機能は、管理者がリストに載せた Git リポジトリからしかインストールできません。これらがなくても動く拡張機能なら、そうしたチームでもインストールできます。そうしたマシンで拡張機能を開発するには、管理者に allowLocalExtensions を依頼してください。これでフォルダーからインストールできます。

  • token: ユーザーが 設定 → 連携 のカードに API トークンを貼り付けます。apiOrigin は request が呼べる唯一のオリジンです。account は任意で、GET のパスとフィールド名を指定すると、カードに誰が接続しているかを表示できます。scheme はトークンの送り方を指定します。下の表を参照してください。どのヘッダーを期待するかはプロバイダーの API ドキュメントで確認してください。
  • oauth: ユーザーがクライアント ID を貼り付け、OpenChamber が認可フローを実行します。authorizeUrl、tokenUrl、apiOrigin が必要です。
  • host: { "provider": "linear" }: OpenChamber にすでに接続済みの Linear アカウントを再利用します。クライアント ID は不要です。

各 scheme が送るもの:

schemeOpenChamber が送るヘッダー使いどころ
省略Authorization: <token>API がヘッダーにプレフィックスなしのトークンを記載している
"bearer"Authorization: Bearer <token>API が bearer トークンまたは personal access token を記載している
"basic"Authorization: Basic base64(username:token)API がユーザー名 (多くはメール) と API トークンによる HTTP Basic 認証を記載している。カードは両方を尋ね、usernameLabel が最初の欄のラベルになる

settings はカードにプレーンテキストの入力欄を追加します。その値は ctx.settings に届きます。"secret": true を指定したフィールドはカード上でマスクされ、ページには届きません。サービスは readSettings() で読み取ります。

ファイル

ページ自体はディスクに触れません。OpenChamber がユーザーの承認した範囲内で、代わりに読み書きします。

  • 相対パス(README.md、src/index.ts、.)は開いているプロジェクトを指します。files 権限が必要です。開いているプロジェクトがない場合は NO_DIRECTORY です。
  • / または ~/ で始まるパスはそれ以外の場所を指します。contributes.filesystem で宣言したパターンのいずれかに一致する必要があり、ユーザーは承認ダイアログでそのパターンをそのまま目にします:
"filesystem": ["~/.config/opencode/opencode.json", "~/notes/**"]

パターンでは * がパスの 1 セグメント、** が任意の深さを表します。パターンの外にあるものは、承認後であっても BAD_PATH です。.. は決して許可されません。

const config = await host.readFile("~/.config/opencode/opencode.json");
await host.writeFile("~/.config/opencode/opencode.json", nextJson);
const { entries } = await host.listDir(".");

書き込みはアトミックです。OpenChamber は一時ファイルに書いてからリネームするので、読み手が書きかけのファイルを見ることはありません。ファイルは UTF-8 テキストとして読み書きされ、上限は 2 MB です。

Work Status のセクション

contributes.statusSection は、チャットの横にある Work Status パネルに独自のセクションを追加します。ユーザーは組み込みのセクションと同じように、そのパネルのセクション一覧でオン・オフや並べ替えができます。

"statusSection": { "entry": "status/index.html", "title": "Recent commits", "height": 160 }
  • true は panel.entry をそのまま使います。
  • entry はフォルダ内の別の HTML ページです。これがあれば panel.entry は不要なので、レールのアイコンなしでこのセクションだけの拡張機能にできます。
  • title はセクション見出しのパネル名を置き換えます。最大 60 文字です。
  • height はピクセル単位の初期の高さで、24〜320 (既定は 120) です。内容のサイズが変わったら host.setHeight() を呼んでください。

ページから見た ctx.surface は status です。OpenChamber は Work Status パネルが表示され、セクションが展開されている間だけページを読み込み、ユーザーがセクションを折りたたむと破棄します。作り直せない状態はそこに置かないでください。セクションだけの拡張機能は権限、サービス、連携、ファイルを使えますが、page、attach、actions、commands は使えません。Web とデスクトップのみです。git-graph-status の例が完成したセクションです。

あなたのファイル形式のエディター

contributes.fileEditors を指定すると、ファイルをテキストエディターではなくあなたのページで開きます。ユーザーが Files で一致するファイルを開くと、OpenChamber はそこにあなたのエディターを表示します。ソース表示の切り替え、全画面ボタン、保存ボタンは組み込みのビューアーと同じものが付きます。

"fileEditors": [
{ "id": "canvas", "title": "Excalidraw", "match": ["*.excalidraw", "*.excalidraw.md"], "entry": "editor/index.html" }
]
  • match はファイル名だけを、大文字と小文字を区別せずに比較します。* は任意の長さの文字列に、? は 1 文字に一致します。パターンに / は含められず、ワイルドカードだけのパターンも使えません。
  • entry はフォルダ内の HTML ページです。panel.entry は不要なので、レールのアイコンなしでエディターだけの拡張機能にできます。
  • content は "text"(既定)または "binary" です。詳しくは後述します。
  • エディターは拡張機能ごとに最大 8 個、それぞれのパターンは最大 16 個です。

ファイルを管理するのは OpenChamber です。あなたのページがファイルを読み書きすることはなく、そのための権限も要りません。OpenChamber がテキストを渡し、保存時に編集後のテキストを求め、Cmd/Ctrl+S、自動保存、未保存の変更の確認、改行コード、ディスク上での変更を処理します。

import { connectHost, createFileSaveTracker } from "@openchamber/sdk";
const host = connectHost();
let tracker = createFileSaveTracker(null);
host.onFileOpen((file) => {
if (file.encoding !== "text") return; // テキストエディターには常にテキストが届きます
load(file.content); // file.path、file.name、file.readOnly もあります
tracker = createFileSaveTracker(versionOf(currentText()));
});
// 編集のたびに呼び出します。`edited` はユーザーの手が止まるまで自動保存を待たせます。
const changed = () => host.reportFileChange(tracker.observe(versionOf(currentText())));
host.onFileSnapshot(() => ({ content: currentText(), version: versionOf(currentText()) }));
// OpenChamber の書き込み中に行われた編集があれば、ファイルは未保存のままになります。
host.onFileSaved((version) => host.reportFileChange({ dirty: tracker.markSaved(version), edited: false }));

version は、ドキュメントが変わると変わる短い文字列なら何でも構いません(ハッシュなど)。エディターで開けないファイルなら host.reportFileUnsupported() を呼ぶと、OpenChamber が通知付きでソースを表示します。20 MB を超えるファイルはソース表示のままです。

バイナリファイル

"content": "binary" を指定すると、スプレッドシート、ドキュメント、画像など、テキストではないファイルを開けます。エディターはファイルのバイト列を受け取り、バイト列を返します。それ以外はすべて同じように動きます。

host.onFileOpen((file) => {
if (file.encoding !== "binary") return;
open(file.bytes); // ディスク上とまったく同じ内容の Uint8Array
});
host.onFileSnapshot(() => ({ bytes: currentBytes(), version: versionOf(currentBytes()) }));

バイナリエディターは、パターンに一致するファイルならどれでも引き受けられます。画像や PDF など、OpenChamber が自分でプレビューするファイルも含みます。ソース表示はなく、未保存の変更がある状態でユーザーが全画面に切り替えたり全画面から戻したりすると、OpenChamber が先に保存します。形式の読み書きはエディターの役目です。OpenChamber は返されたバイト列をそのまま書き戻します。

ページから見た ctx.surface は file です。ディスク上でファイルが変わったとき、ユーザーが変更を破棄したとき、エディターが全画面に切り替わるときや全画面から戻るとき、OpenChamber はページを再読み込みし、ファイルを渡し直します。パターンが一致する有効な拡張機能のうち最初のものが優先され、OpenChamber 自身のプレビューよりも先に使われます。エディターだけの拡張機能は権限、サービス、連携、ファイルを使えますが、page、attach、actions、commands は使えません。Web とデスクトップのみです。checklist-editor の例が完成したエディターです。

アクション、コマンド、バッジ

レールと + メニュー以外にも、拡張機能はさらに 3 か所に現れることができます。いずれも、チップのクリックと同じ形で拡張機能に item を渡します。

メッセージとセッションのアクション。 メニュー項目を宣言すると、OpenChamber は組み込みの項目の隣にそれを表示します。

"actions": [
{ "id": "create-task", "label": "Create task", "icon": "add-line", "where": "message", "roles": ["assistant"] },
{ "id": "summarize", "label": "Summarize session", "where": "session", "payload": ["messages"] }
]

where には selection (メッセージ内で選択したテキスト)、file (Files の行)、diff (ファイルや diff の選択した行) も指定できます。これらの項目には同じ名前の kind が付きます。selection にはテキスト、file にはパス、diff にはパスと行の範囲が入ります。選択範囲では、display でアクションの表示方法を指定します。label (デフォルト)、ラベルをツールチップにする icon、または both です。

メッセージのアクションは、kind: "message" の ctx.item を付けて拡張機能を開きます。中身はセッションの id とタイトル、プロジェクトのフォルダ、メッセージの id、そのロールとテキストです。セッションのアクションは kind: "session" と、セッションの id、タイトル、フォルダを付けて開きます。"payload": ["messages"] を加えると、項目には会話全体も古い順で含まれます。Markdown エクスポートが出力するのと同じテキストです。これには conversation 権限が必要で、ユーザーには承認ダイアログで別の行として表示されます。item.action でどの項目がクリックされたかが分かります。

添付するスラッシュコマンド。 コマンドを宣言し、ページ側で処理します。

"commands": [{ "name": "task", "description": "Attach a task by id" }]
host.onResolve(async ({ command, args }) => {
const task = await findTask(args.trim());
return task ? { providerId: "acme-tasks", id: task.id, title: task.title, url: task.url } : null;
});

ユーザーがチャット欄に /task ABC-12 と入力すると、OpenChamber は拡張機能に解決を依頼し、返された内容を何も開かずにチップとして添付します。何も見つからなければ null を返してください。パネルが閉じていれば、OpenChamber はこの呼び出しのためにバックグラウンドで読み込みます。OpenChamber や OpenCode がすでに使っている名前は無視されます。

レールのアイコン上のバッジ。 host.setBadge(3) はアイコンにドットを付け、数字(たとえば未処理のタスク数)をツールチップに表示し、host.setBadge(null) はそれを消します。パネルを開いても消えます。

チャットに表示されるあなたのツール

あなたの OpenCode プラグインや MCP サーバーがツールを追加すると、チャットはその呼び出しを汎用アイコンと生の出力で表示します。代わりに、コードなしでどう見せるかを宣言します。

"tools": [
{
"match": "mcp.jira.*",
"name": "Jira",
"icon": "task-line",
"title": "{input.key}",
"subtitle": "{output.status}",
"output": "table",
"columns": ["key", "summary", "status"]
}
]

match は OpenCode が報告するツール名で、末尾の * は前方一致です。icon は Remixicon の名前か、パッケージ内の .svg ファイルで、panel.icon と同じです。title と subtitle は呼び出しの input、output、metadata を使うテンプレートです。output は本文の描画方法を選びます。text、json(ツリー)、markdown、language 付きの code、columns 付きの table(行は出力の配列か output.items から取られます)、または既定の auto です。完全一致の match はワイルドカードより優先され、同点なら先にインストールされた拡張機能が勝ちます。権限は要りません。これはすでにチャットにあるデータの描き方を変えるだけです。

ツールの見た目を整えるだけの拡張機能にはページはまったく不要です。panel.entry を省略すると、レールにアイコンは出ず、設定 → 拡張機能 にカードが表示されるだけになります。ページがない場合は tools だけを宣言して他は何も宣言しなくて構いません。もう一つの例外は、独自の entry を持つ Work Status セクションまたはファイルエディターです(上記参照)。

パネルの最初の数行

import { connectHost } from "@openchamber/sdk";
const host = connectHost();
host.onReady((ctx) => {
document.body.dataset.theme = ctx.theme.mode;
document.body.dataset.surface = ctx.surface;
});

connectHost は OpenChamber の中でのみ動きます。ただのファイルとして開くと、すべての呼び出しが HOST_UNAVAILABLE で reject されます。

パネルはまず @openchamber/sdk/ui の部品で組んでください。ボタン、入力欄、ドロップダウン、タブ、リストなどが、アプリの色とフォントでスタイルされているので、パネルが OpenChamber の一部のように感じられます。自分で HTML と CSS を書くのは、キットにないものだけにしてください。UI キット を参照してください。

関連

  • 拡張機能で SSH インストールとサーバーの Git ID 選択を確認
  • Host API: connectHost の全メソッド、上限、エラーコード
  • UI キット: 部品
  • 例: コピーして使える 3 ファイルの完全な拡張機能