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

104 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ワークスペース・アプリの作り方(エージェント向け)
ユーザーから「ワークスペース・アプリを作って」「○○用の 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 }, '*')` で要求を送り、応答は `window`
`message` イベントで受け取る。応答エンベロープは **`{ id, ok: true, data }`** か
**`{ id, ok: false, error }`**。`id` を突き合わせ、`ok` を見て `data` を取り出す。
次の `call()` ヘルパーが正典実装。**改変せずそのままコピーして使う**(自己流で書くと
エンベロープを取り違えて動かない)。
```html
<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` を返す):
```js
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.html``app.json``e2e.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`)。