maestro/docs/tools/workspace-apps.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

5.6 KiB
Raw Blame History

ワークスペース・アプリの作り方(エージェント向け)

ユーザーから「ワークスペース・アプリを作って」「○○用の GUI を作って」などと頼まれたときの 手順です。専用ツールは不要 — edit: true の movement で Write/Edit を使って HTML を書く だけで成立します。

何を作るか

ワークスペースの apps/{name}/index.html に置く、自己完結した 1 枚の HTML(インライン JS/CSS、data: 画像のみ)。ユーザーはワークスペースの「アプリ」タブから「開く」で起動します。 アプリはサンドボックス iframeopaque origin、allow-same-origin 無し)で動き、ファイル I/O は 親への postMessage ブリッジ経由のみです。

守るべき制約(重要)

  • 外部ネットワーク禁止: default-src 'none'; connect-src 'none' の CSP が自動注入される。 外部 CDN・外部 API・別ファイルの <script src>・Web フォントは読み込めない。すべてインライン化する。
  • 資格情報は渡らない: I/O は親がユーザーのセッションで代理する。ユーザーの権限を超えられない。
  • パスはワークスペース相対: output/...apps/{name}/data/... への書き込みは確認不要。 それ以外への書き込み・削除はユーザー確認が出る。..・絶対パスは拒否される。

ブリッジ APIこのヘルパーをそのまま使うこと

アプリは window.parent.postMessage({ ...req, id }, '*') で要求を送り、応答は windowmessage イベントで受け取る。応答エンベロープは { id, ok: true, data }{ id, ok: false, error }id を突き合わせ、ok を見て data を取り出す。 次の call() ヘルパーが正典実装。改変せずそのままコピーして使う(自己流で書くと エンベロープを取り違えて動かない)。

<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));
  });
</script>

使い方(call() は成功時に応答の data を返す):

const { entries } = await call({ type: 'listFiles', dir: 'output' });   // 一覧
const { content } = await call({ type: 'readFile', path: 'output/x.md' }); // 読み取り
await call({ type: 'writeFile', path: 'output/note.md', content: '...' }); // 書き込み
await call({ type: 'deleteFile', path: 'output/old.txt' });             // 削除(常に確認)

確認なしで書ける場所は output/ 配下と自分のアプリの apps/{name}/data/ 配下のみ。 それ以外への writeFile・すべての deleteFile はユーザー確認ダイアログが出る。 ..・絶対パスは拒否される。

ひな型をコピーする

ワークスペース内の readonly/app-templates/ に、複数のアーキタイプテンプレートが seed 済みworkspace-app ピース実行時に自動コピーされる。Read できる実ファイルなので、 Glob({ pattern: "readonly/app-templates/*/index.html" }) で一覧を確認できる。

フォルダ 用途
note-editor/ output/note.md を読み書きするテキストエディタ
data-viewer/ CSV・JSONL ファイルをテーブル表示するビューア
form-input/ フォームで入力した内容を output/ に書き出す
dashboard/ 複数ファイルの集計結果をカードで表示するダッシュボード

各フォルダに index.htmlapp.jsone2e.example.json が入っている。 e2e.example.json は後述の E2E テストに直接渡せる入力例。 いちばん近いものを Read readonly/app-templates/{名前}/index.html で読み、 apps/{name}/index.html に Write するのが最短。テンプレには上記の正しいブリッジ実装が 組み込み済みなので、ファイル I/O もそのまま動く。

apps/{name}/app.json(任意)で一覧の表示名・説明・エントリを指定できる(無ければフォルダ名)。

E2E テストverify ステップ)

workspace-app ピースの verify ステップは、作成したアプリを TestWorkspaceApp ツールで自動 E2E テスト する。

  • ヘッドレスブラウザでアプリを実際に起動
  • seed_files で指定した入力データをワークスペースに書き込んでからロード
  • actions に沿ってクリック・入力・スクリーンショット操作を実行
  • expect 条件(テキスト含有・ファイル存在・要素可視)を検証

テストに通過した場合のみ verify ステップを完了とする。失敗した場合はエラー内容と スクリーンショットが返るので、それをもとに HTML を修正して再実行する。

E2E の入力例は各テンプレートの e2e.example.json を参照。詳細な使い方は ReadToolDoc({ name: "TestWorkspaceApp" }) で取得できる。

仕上げ

  • 書き込んだら、ユーザーに「アプリ」タブの「開く」で起動できることを一言伝える。
  • アプリ名(フォルダ名)は内容が分かる短い英小文字+ハイフンにする(例: invoice-gen)。