This commit is contained in:
@@ -19,26 +19,84 @@ JS/CSS、`data:` 画像のみ)。ユーザーはワークスペースの「ア
|
||||
- **パスはワークスペース相対**: `output/...`・`apps/{name}/data/...` への書き込みは確認不要。
|
||||
それ以外への書き込み・削除はユーザー確認が出る。`..`・絶対パスは拒否される。
|
||||
|
||||
## ブリッジ API(要点)
|
||||
## ブリッジ 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
|
||||
// 一意 id を付けて postMessage、message イベントで応答を id 突き合わせ。
|
||||
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' }); // 削除(常に確認)
|
||||
```
|
||||
|
||||
完全なプロトコル・最小ヘルパー実装・応答形式は **`docs/workspace-apps-bridge.md`** を参照。
|
||||
確認なしで書ける場所は `output/` 配下と自分のアプリの `apps/{name}/data/` 配下のみ。
|
||||
それ以外への `writeFile`・すべての `deleteFile` はユーザー確認ダイアログが出る。
|
||||
`..`・絶対パスは拒否される。
|
||||
|
||||
## ひな型をコピーする
|
||||
|
||||
動くサンプルが `docs/examples/workspace-apps/file-note/` にある(`index.html` + `app.json`)。
|
||||
`output/` を一覧・閲覧し、メモを `output/note.md` に保存する自己完結アプリ。これを土台に、
|
||||
依頼に合わせて改変して `apps/{name}/index.html` に Write するのが最短。
|
||||
ワークスペース内の `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" })` で取得できる。
|
||||
|
||||
## 仕上げ
|
||||
|
||||
- 書き込んだら、ユーザーに「アプリ」タブの「開く」で起動できることを一言伝える。
|
||||
|
||||
Reference in New Issue
Block a user