maestro/docs/workspace-apps-bridge.md
oss-sync b857c33ef6
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (f6d625db)
2026-06-26 03:35:45 +00:00

7.4 KiB
Raw Permalink Blame History

ワークスペース・アプリ ブリッジ仕様(アプリ作者=エージェント向け)

ワークスペース・アプリは、ワークスペースの apps/{name}/index.html に置く HTML 製の小さな GUI です。ワークスペースの 「アプリ」タブに一覧表示され、「開く」を押すと AppRunner が サンドボックス iframe で実行します(ファイルタブの「アプリとして実行」からも起動できます)。 アプリはワークスペースのファイルを postMessage ブリッジ経由でのみ 読み書きできます。

このドキュメントは、生成する HTMLアプリが従うべきブリッジ API を定めます。

エージェントへ: ユーザーから「ワークスペース・アプリを作って」と頼まれたら、この仕様に 従った自己完結 HTMLapps/{name}/index.html に Write してください(外部リソース禁止・ インライン JS/CSS のみ)。動くひな型は docs/examples/workspace-apps/note-editor/index.html app.json)。この仕様自体は ReadToolDoc({ name: "workspace-apps" }) でいつでも読めます。

実行環境(重要な制約)

  • アプリは <iframe sandbox="allow-scripts"> で動きます。allow-same-origin は付きません。 そのため不透明オリジンopaque originで動作し、親ウィンドウの DOM・Cookie・セッション・ localStorage には一切アクセスできません。
  • 資格情報は渡されません。 ファイル I/O は親が代理します。代理は実行中ユーザーのセッションで 行われるため、アプリはそのユーザーの権限を超えられません(メンバーシップ・編集権限・パス ガードはサーバ側でそのまま効きます)。
  • 外部ネットワークは使えません。 fetch / XMLHttpRequest による外部通信は想定外です (配信はサンドボックス + CSP で絞られます)。データの入出力は必ずブリッジ経由で行ってください。
  • V1 の主対象は 単一の自己完結 index.htmlJS/CSS をインライン化したもの)。複数ファイル 構成(apps/{name}/ 配下の相対参照)はベストエフォートで、相対 src/href は親が raw URL に 書き換えます。確実に動かしたいなら 1 ファイルにまとめてください。

マニフェスト app.json(任意)

アプリフォルダに apps/{name}/app.json を置くと、「アプリ」タブの表示情報を指定できます。 任意で、無ければフォルダ名と index.html がそのまま使われます。形式が壊れていても無視され、 フォールバックされます(アプリ一覧は壊れません)。

{
  "title": "ファイル・ノート",
  "description": "output/ のファイルを閲覧してメモを保存するアプリ",
  "entry": "index.html"
}
キー 必須 説明
title 任意 一覧に出す表示名(無ければフォルダ名)
description 任意 一覧に出す短い説明
entry 任意 アプリフォルダ基準の HTML エントリ(既定 index.html)。必ず apps/{name}/ 配下に収めること(.. や絶対パスは拒否され、index.html にフォールバックされる)

ブリッジ・プロトコル

要求は window.parent.postMessage(req, '*') で送り、応答は windowmessage イベントで 受け取ります。各要求には一意の id を付け、応答の id と突き合わせてください。

要求

// 読み取り
window.parent.postMessage({ id, type: 'readFile', path: 'output/data.json' }, '*');
// 一覧dir 省略でワークスペース直下)
window.parent.postMessage({ id, type: 'listFiles', dir: 'output' }, '*');
// 書き込みcontent は文字列)
window.parent.postMessage({ id, type: 'writeFile', path: 'output/請求書.html', content: '<html>…' }, '*');
// 削除(常に確認ダイアログが出る)
window.parent.postMessage({ id, type: 'deleteFile', path: 'output/old.txt' }, '*');

応答

window.addEventListener('message', (e) => {
  const r = e.data;            // { id, ok, data } または { id, ok:false, error }
  if (r.id !== myRequestId) return;
  if (r.ok) { /* r.data を使う */ } else { /* r.error を表示 */ }
});

応答ペイロード:

type 成功時 data
readFile { path, content }content は UTF-8 テキスト)
listFiles { dir, entries }entries はファイル/フォルダ)
writeFile { path, bytes }
deleteFile { deleted, skipped }

失敗時は { id, ok:false, error }

パスの規則

  • パスは必ず ワークスペース files 直下からの相対パス。先頭 /..・ドライブ文字 (C:)・バックスラッシュは拒否されます(クライアントとサーバの二重ガード)。
  • アプリは自分のワークスペースの外には出られません。

書き込みの確認ポリシー

  • 確認なしで書ける場所: output/ 配下、および自分のアプリの apps/{name}/data/ 配下。
  • それ以外のパスへの writeFile は、親が確認ダイアログ(「アプリ『{name}』が {path} に書き込もう としています。許可しますか?」)を出し、ユーザーが許可したときだけ書き込みます。
  • deleteFile は場所に関わらず常に確認ダイアログが出ます。

データを残すアプリは、原則として output/(ユーザーに見せる成果物)か apps/{name}/data/(アプリ内部の状態)に書いてください。そうすればユーザーを確認で煩わせません。

最小サンプル(自己完結 index.html

<!doctype html><meta charset="utf-8">
<button id="save">保存</button>
<script>
  let seq = 0;
  const pending = new Map();
  function call(req) {
    return new Promise((resolve, reject) => {
      const id = ++seq;
      pending.set(id, { resolve, reject });
      window.parent.postMessage({ ...req, id }, '*');
    });
  }
  window.addEventListener('message', (e) => {
    const r = e.data;
    const p = pending.get(r && r.id);
    if (!p) return;
    pending.delete(r.id);
    r.ok ? p.resolve(r.data) : p.reject(new Error(r.error));
  });
  document.getElementById('save').onclick = async () => {
    await call({ type: 'writeFile', path: 'output/note.txt', content: 'hello' });
    alert('保存しました');
  };
</script>

ネットワーク制約(重要)

アプリ HTML には default-src 'none'; connect-src 'none'; ... の CSP が自動注入され、 外部ネットワークfetch/XHR/WebSocket/sendBeacon/フォーム外部 POSTはすべて遮断される。 アプリのファイル I/O は postMessage ブリッジ(親が代理)だけが経路。これは、ユーザーから 渡されたワークスペースのファイル内容を外部へ持ち出されないための exfil 対策。

V1 のアプリは 自己完結 HTML(インライン JS/CSS、data: 画像)で書くこと。 外部 CDN・外部 API・別ファイルの <script src> は CSP で読み込めない。