sync: update from private repo (dfadcd5f)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-23 06:38:48 +00:00
parent 6a2f2cc736
commit 29ccaf1e92
377 changed files with 31028 additions and 8994 deletions
+1 -1
View File
@@ -47,7 +47,7 @@
| Office ファイル読み込み | ReadPdf / ReadExcel / ReadDocx / ReadPPTX |
| 音声書き起こし | TranscribeAudio |
| データベース | SQLite |
| 検索 | WebSearch / SearchKnowledge |
| 検索 | WebSearch / WebFetch |
## サンドボックス機構 (`safety.bash_sandbox`)
+10
View File
@@ -282,6 +282,16 @@ BrowseWithSession({
ダウンロードを認証付きで行いたい場合は、Browser Sessions 機能で対象サイトのログインセッションを保存し、タスクで bind した状態で BrowseWeb を呼ぶこと。
## ソースライブラリへの蓄積(スペースタスク)
スペースのタスクで BrowseWeb がページ本文(スナップショット / セレクタ抽出 / dumpHtml 等の抽出テキスト)を取得すると、その本文が Markdown として `source/` に保存され、出典メタ(URL・取得日時・サイズ・`tool: "BrowseWeb"`)が `source/index.jsonl` に追記される。WebFetch / DownloadFile と同じソースライブラリに合流するので、「そのスペースのソース(資料)」が自動で溜まり、後から追加調査やグラウンディングに使える。
- 同一 URL は重複保存しない(既に index にあればスキップ)。同じ URL を 2 回閲覧しても 1 件のまま
- スペース文脈でないタスク(ephemeral / gitea issue 等)では従来どおり蓄積しない(`ctx.spaceId` が無いとき)
- 空・エラー結果、`http(s)` 以外(`file://` 等)の URL はソース化しない
- スクリーンショットはソースではないので `output/` に残り、`source/` には入らない(ソースはあくまでテキスト)
- これは純粋な追記サイドライトで、BrowseWeb の戻り値・スクショ・`logs/` 出力は一切変わらない
## SSRF 保護
ローカル/プライベート IP127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, ::1, fc00::/7 等)へのアクセスはデフォルトでブロックされる。社内ホストへアクセスする必要がある場合は、Settings UI の「SSRF Allowed Hosts」に追加する。
+45
View File
@@ -0,0 +1,45 @@
# カレンダーツール(AddCalendarEvent / ListCalendarEvents
スペース別カレンダーに「予定」を読み書きするツール。予定は受動的なエントリで、
cron の定期タスク(`scheduled_tasks`)とは別概念(予定は実行しない)。
予定は実行中タスクが属するスペース(`ctx.spaceId`)のカレンダーに記録される。
スペースに属していないタスク(旧 local タスク)では使えず、明確なエラーを返す。
## AddCalendarEvent
実行中タスクのスペースのカレンダーに予定を1件追加する。
`created_by` は常に `agent``source_task_id` には実行中タスク ID が記録される。
引数:
- `title`(必須): 予定のタイトル
- `date`(必須): 開始日 `YYYY-MM-DD`(ローカル日付)
- `end_date`(任意): 終了日 `YYYY-MM-DD`。複数日にまたがる予定のとき指定。省略すると単日。`date` より前は不可
- `time`(任意): `HH:MM`。省略すると終日扱い
- `description`(任意): 補足説明
例:
```
AddCalendarEvent({ title: "定例MTG", date: "2026-07-01", time: "10:00" })
AddCalendarEvent({ title: "提出締切", date: "2026-07-10" }) // 終日
AddCalendarEvent({ title: "現地出張", date: "2026-07-10", end_date: "2026-07-12" }) // 複数日
```
使いどころ: ユーザーが「○日に△△を予定に入れて」と依頼したとき、調査の結果として
期限や予定日が判明したとき。日付は必ずユーザーのローカル暦日で指定する。
## ListCalendarEvents
スペースの予定を日付範囲で一覧する(読み取り専用)。
引数:
- `from`(任意): 範囲開始 `YYYY-MM-DD`
- `to`(任意): 範囲終了 `YYYY-MM-DD`
範囲を省略すると全期間。結果は日付→時刻順(終日は各日の先頭)で返る。
## gotcha
- `date` / `from` / `to``YYYY-MM-DD``time``HH:MM` 厳守。形式違反はエラー。
- スペース未所属のタスクからは呼べない(`ctx.spaceId` 必須)。
- 予定はスペースの可視性に従う。イベント単独の可視性は持たない。
+12 -2
View File
@@ -16,7 +16,10 @@ DownloadFile({
- `url`: ダウンロード元 URL
- `filename`: 保存先パス(section 配下からの相対パス)
- `section`: `"input"` `"output"` (成果物に使う場合は `"output"`
- `section`: `"input"` / `"output"` / `"source"`
- `"input"`: 後続処理の入力(既定)
- `"output"`: 成果物
- `"source"`: 調べ物・参照資料。スペースのソースライブラリ(`source/`)に蓄積され、出典付きで Files タブに一覧される。research 系のダウンロードはこれを推奨
## ファイル命名規約
@@ -30,6 +33,13 @@ DownloadFile({
`logs/downloads.jsonl` に各ダウンロードのメタ情報(URL, 保存先, サイズ)が記録される。
### ソースライブラリ(section: "source"
スペースのタスクで `section: "source"` を指定すると、ファイルは `source/` に保存され、
出典メタ(ファイル名・URL・取得日時・サイズ・ツール名)が `source/index.jsonl` に 1 行追記される。
これらは「そのスペースのソース(資料)」として蓄積され、後から追加調査やグラウンディングに使える。
WebFetch がスペース文脈でページ本文を取得した場合や、BrowseWeb がブラウザでページを閲覧した場合も、同じ `source/index.jsonl` に自動で記録される。
## 成果物への画像埋め込み
ダウンロードした画像は Markdown レポートから相対パスで埋め込める:
@@ -47,4 +57,4 @@ WebFetch と同じく、ローカル/プライベート IP はデフォルトブ
## 注意
- 大きすぎるファイル(数百MB以上)はタイムアウトしやすい
- バイナリファイル(PDF, 動画等)も保存可能だが、画像以外の用途では IngestDocument / TranscribeAudio 等の専用ツールも検討
- バイナリファイル(PDF, 動画等)も保存可能だが、画像以外の用途では ReadPdf / TranscribeAudio 等の専用ツールも検討
-97
View File
@@ -1,97 +0,0 @@
# SearchNotes / ReadNote / WriteNote
ユーザーの共有 knowledge notes`data/users/{userId}/notes/{folder}/{file}.md`)を扱う 3 ツール。
ファイルは YAML frontmatter + Markdown 本文で構成され、DB の `note_index` (FTS5 対応) に mirror される。
## SearchNotes
購読中(`note_subscriptions``mode=search` または `mode=inject``enabled=1` の行がある)の note を FTS5 全文検索する。
### 引数
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| `query` | string | 必須 | 検索クエリ。ツール内部でフレーズ検索として扱われる |
| `folder` | string | 省略可 | 特定フォルダーのみに絞り込む |
| `limit` | integer | 省略可 | 最大取得件数(デフォルト 10、上限 100) |
### 戻り値
マッチした note のリスト(`owner_id/folder/file_name: title`)。
続いて `ReadNote` で全文を取得できる。
### FTS5 クエリの注意
クエリはフレーズ検索として自動エスケープされる。`kubernetes pod``"kubernetes pod"` に変換。
AND / OR 演算子を使いたい場合は複数回呼び出して結果を手動合算すること。
---
## ReadNote
特定の note の全文(frontmatter + 本文)を取得。可視性チェックあり。
### 引数
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| `owner_id` | string | 必須 | note の所有者 user ID |
| `folder` | string | 必須 | フォルダー名 |
| `file_name` | string | 必須 | ファイル名(例: `foo.md` |
### 可視性ルール
- 自分の noteowner_id が自分): 常に読める
- `visibility: public` の note: 全ユーザーが読める
- `visibility: org` の note: `scope_org_id` が自分の所属 org に含まれる場合のみ読める
- `visibility: private` の他人の note: 読めない(isError: true
---
## WriteNote
自分の `notes/{folder}/{file}.md` を作成または更新する。
### 引数
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| `folder` | string | 必須 | フォルダー名(`[a-zA-Z0-9._-]` のみ) |
| `file_name` | string | 必須 | ファイル名(`.md` で終わる) |
| `content` | string | 必須 | YAML frontmatter を含む完全な Markdown 内容 |
### Frontmatter フィールド
```yaml
---
title: "Note のタイトル(省略可)"
visibility: public # private | org | public
scope_org_id: "org-id" # visibility=org の場合に必須(自分の所属 org の ID)
mode_hint: search # search | inject(省略可)
tags:
- kubernetes
- security
---
```
- `visibility` は必須。省略すると `private` として扱われる
- `visibility: org` の場合、`scope_org_id` は自分の所属 org の ID でなければならない
- `mode_hint: inject` にすると、購読者の system prompt に自動注入される
- フォルダーとファイル名は固定の 2 階層(`notes/<folder>/<file>.md`
### 書き込み後の動作
- DB の `note_index` + FTS5 テーブルを即座に更新
- 同フォルダーへの self subscription がなければ自動作成(`mode=search``enabled=1`
- エラー時は `isError: true` を返す(バリデーションエラーや権限エラー)
---
## 使い分け
| 場面 | ツール |
|---|---|
| 「CVE 対象?」「〜の設定は?」など知識検索 | `SearchNotes("CVE")` |
| 検索結果の 1 件の詳細を読む | `ReadNote` |
| スケジュールタスクで取得した情報をチームと共有 | `WriteNote``visibility: org` |
| 自分用のメモ・ログを残す | `WriteNote``visibility: private` |
-4
View File
@@ -32,7 +32,3 @@ ReadImage({ file_path: "input/screenshot.png" })
- `input/` または `output/` 配下のローカル画像ファイル
- URL 指定は不可(DownloadFile で先にローカル保存する)
- 対応形式: png, jpg, jpeg, gif, webp, bmp
## SearchKnowledge との連携
SearchKnowledge が返したページ画像(`input/knowledge/{ns}/page_xxx.png`)も ReadImage で内容確認できる。
+35
View File
@@ -0,0 +1,35 @@
# RequestTool
この movement で提示されていないツールがどうしても必要なときに、その要求を**記録**するためのメタツール(`allowed_tools` に書かなくても常時利用可能)。
## いつ使うか
- 依頼を達成するのに必要なツールが、現在の movement の `allowed_tools` に無いと気づいたとき。
- まず「本当にそのツールが要るか」を検討すること。多くの作業は既存のツール(`Bash` / `Read` / `WebSearch` 等)で代替できる。
## 引数
| 引数 | 必須 | 説明 |
|------|------|------|
| `name` | はい | 必要なツール名(例: `WebSearch`, `Bash`, `mcp__foo__bar` |
| `reason` | はい | なぜそのツールが必要かを具体的に。これがピース作者への記録に残る |
## 重要: これは「要求の記録」であって「即時付与」ではない
RequestTool を呼んでも、そのツールが**その場で使えるようにはならない**。要求は記録され、タスク詳細とピース集計に表示される。ピース作者が `allowed_tools` / `shared_tools` に追加すれば次回から使える。
要求したあとの進め方:
1. そのツール無しで達成できないか、もう一度考える。
2. どうしても無理なら `complete({status: "needs_user_input", missing_info: "...", why_no_default: "..."})` でユーザーに依頼する。
3. 勝手に諦めて中途半端な結果を返さない。
## 分類(記録される `category`
- **既に利用可能**: そのツールはこの movement で使える → 記録せず「そのまま呼んでください」と返る。
- **`requested`**: カタログに存在するがこの movement では未許可 → 設定漏れ候補として記録。
- **`unknown`**: そんなツールは存在しない(名前の誤り・能力ギャップ)→ 記録するが付与対象外。
## 関連
足りないツールを呼んで弾かれた場合も、同じ記録に「受動捕捉(`blocked`)」として残る。ピース側の `shared_tools`(全 movement 共通ツール)も参照(`pieces/SCHEMA.md`)。
-103
View File
@@ -1,103 +0,0 @@
# SearchKnowledge / ListNamespaces / ListDocuments / IngestDocument / IngestStatus
DKSDocument Knowledge Service)に取り込んだ社内文書をベクトル検索で参照するツール群。
## 利用可能性チェック
```js
ListNamespaces() // 利用可能な namespace 一覧を返す
```
DKS が設定されていなければ "Knowledge service not configured" を返す。
namespace が空なら何も検索できない。
## 文書一覧の確認
```js
ListDocuments({ namespace: "product-a-support" })
```
その namespace に取り込み済みの文書を表示する。
## 検索
```js
SearchKnowledge({ namespace: "product-a-support", query: "返品ポリシーは何日以内?" })
```
レスポンスには:
1. **sections** — マッチしたツリーノード(タイトル + summary + ページ範囲)
2. **page_image_urls** — 関連ページの画像(PNG
### 自動ダウンロード
検索結果に含まれるページ画像は **自動的にワークスペース** `input/knowledge/{namespace}/page_001.png` などに保存される。
LLM はそのローカルパスを `ReadImage` でそのまま閲覧できる。
```js
// SearchKnowledge の出力例:
// ## 返品ポリシー (manual.pdf, pages: 3, 4)
// 購入後30日以内であれば...
//
// ### ページ画像(ReadImage で閲覧可能)
// - input/knowledge/product-a-support/page_003.png
// - input/knowledge/product-a-support/page_004.png
ReadImage({ file_path: "input/knowledge/product-a-support/page_003.png" })
```
### 生 JSON の保存
DKS の生レスポンス JSON は `logs/raw/searchknowledge-{timestamp}.json` に保存される。doc_id 等の詳細フィールドが必要なときはそちらを Read する。
## 文書の取り込み
```js
// 1. 取り込み開始(非同期)
IngestDocument({ namespace: "product-a-support", file_path: "input/manual.pdf" })
// → "取込を開始しました (job: xxx, 45ページ検出)。完了確認は IngestStatus で可能です。"
// 2. 進捗確認
IngestStatus({ namespace: "product-a-support", job_id: "xxx" })
// → "ジョブ xxx: 処理中: VLM 12/45ページ, ツリー構築: 未完了"
// または "完了 (manual.pdf)" / "失敗: ..."
```
DKS は内部で:
1. PDF → ページ画像化
2. VLM でページごとに記述生成
3. ツリー構造(章・節)構築
4. ベクトル化してインデックス登録
を行う。45 ページで数分かかる規模感。
## ワークフロー例
### 質問応答
```
SearchKnowledge → 関連 sections + ページ画像取得
↓ 必要なら ReadImage で図表確認
回答文に sections の要点を引用、根拠ページを示す
```
### 新文書を取り込んで検索
```
IngestDocument → job_id 取得
↓ 待機(数分後 or 別作業)
IngestStatus → completed まで polling
SearchKnowledge で取り込み済みコンテンツを検索
```
## ログ
`logs/knowledge-history.jsonl` に各ツール呼び出し(クエリ・件数・所要時間・エラー)が記録される。
## 注意
- **検索ヒット件数は DKS 側で制御** されるので、件数上限を心配する必要はない
- DKS サーバーがローカル/プライベート IP でも、API キー認証経由なので SSRF 例外不要
- VLM 処理はバックグラウンドで動くので、IngestDocument 後すぐに SearchKnowledge を呼んでもまだヒットしない可能性あり(IngestStatus で完了確認)
+38
View File
@@ -0,0 +1,38 @@
# SkillsInstallSkill / ReadSkill / ListSkills
Skill は「参照知識」(手順書・ガイド・規約)。実行テンプレートの Piece とは別物。
Piece の取得・編集には GetPiece / CreatePiece / UpdatePiece を使う。
利用可能なスキル一覧はシステムプロンプトの **Skills Index** に出る。本文を読むには
`ReadSkill({ name: "..." })` を呼ぶ。
## ツール
- **InstallSkill** — スキルを保存する。通常は `content` に SKILL.md 全文(YAML frontmatter + 本文)を渡す。workspace 内に `SKILL.md``scripts/` 等を含むディレクトリを組み立て済みなら `sourcePath`(workspace 内の絶対パス)を渡す。`scope``user`(個人 or 共有ワークスペース)か `system`(全ユーザー共有・admin のみ)。
- **ReadSkill** — スキル本文を取得する。ディレクトリ型スキルは workspace の `skills/{name}/` に展開され、その相対パスでスクリプトを実行できる。
- **ListSkills** — インストール済みスキルの一覧を返す。
## スコープと可視性(重要)
`scope: 'user'` で保存したスキルの置き場所は、**いま作業しているワークスペースで決まる**。
AGENTS.md・メモリ・Piece と同じ考え方。
| 作業中のワークスペース | 保存先 | 見える人 |
|---|---|---|
| 共有ワークスペース(案件など) | `data/spaces/{spaceId}/skills/` | そのワークスペースのメンバー全員 |
| 個人ワークスペース | `data/users/{userId}/skills/` | 自分だけ |
つまり、共有ワークスペースで作ったスキルはメンバー間で共有され、Skills Index にも
全メンバー分が出る。個人ワークスペースで作ったスキルは自分専用で、他人には見えない。
`scope: 'system'` は作業中のワークスペースに関係なく常に全ユーザー共有(admin 専用)。
この挙動はワークスペーススコープの影響を受けない。
### 共有時の注意
共有ワークスペースのスキルは他メンバーのジョブからも実行され得る(共有 Piece・
共有 AGENTS.md と同じ信頼境界)。秘匿情報や自分専用の手順は、共有ワークスペースでは
保存しないこと。個人ワークスペースで作れば自分だけのものになる。
InstallSkill のセキュリティスキャン(高深刻度をブロック、中深刻度を警告)と
sourcePath の workspace 外参照拒否・サイズ/深さ上限は、スコープに関係なく常に適用される。
-43
View File
@@ -1,43 +0,0 @@
# UpdateDashboardWidget
ユーザーの個人ダッシュボード (Side Info Panel) の Markdown widget を upsert するツール。
## いつ使う
- ユーザーから「ダッシュボードにメモして」「news タブを更新して」などと頼まれたとき
- 長期的に残したい情報 (ニュース要約、TODO、参照リンク) を残すよう指示されたとき
- 1 タスク内の一時メモには使わない (それは task のコメントに書く)
## 引数
| name | required | 説明 |
|---|---|---|
| `slug` | yes | Widget の安定 ID。kebab-case (`memo`, `news`, `todo`)、32 文字以内 |
| `content` | yes | Markdown 本文。64KB まで |
| `title` | 新規 slug では必須 | 表示タイトル。既存 slug を更新するときは省略可(既存タイトル維持) |
| `mode` | optional | `replace` (default) または `append` |
## 挙動
- 同じユーザーの `slug` が既に存在 → 更新
- 存在しない → 新規作成 (title 必須)
- `mode='append'` → 既存 content の末尾に `\n\n` 区切りで追記
## ワークフロー例
「最新のテック関連ニュースを news タブにまとめておいて」:
1. `WebFetch` などでニュースを収集
2. Markdown でまとめて
3. `UpdateDashboardWidget({ slug: "news", title: "ニュース", content: "<markdown>" })` を呼ぶ
4. ユーザーには「ダッシュボードの news タブに反映しました」と返す
## gotcha
- `slug` は user スコープでユニーク。他ユーザーの slug と衝突は起きない
- 書き込み先は実行中タスクの owner の dashboard。共有タスクでも他人の dashboard には書かない
- 1 度書いた slug の title は更新できない (新しいタイトルにしたい場合は UI から行うか、新 slug を切る)
- 64KB を超える content は失敗する → 古いログを切り詰めるか、append ではなく replace でローテーション
## 関連
+34 -1
View File
@@ -8,10 +8,12 @@ URL を HTTP GET してレスポンス本文を取得するツール。静的ペ
WebFetch({ url: "https://example.com/article", timeout: 30 })
```
- HTML はテキスト化されて返る(タグ等は除去
- HTML は **readability 抽出**でクリーンな Markdown に変換されて返る(ナビ・広告・ヘッダー・フッターを除去し、見出し・リスト・テーブル・リンクは保持
- JSON / XML / プレーンテキストもそのまま取得可能
- リダイレクトは自動で追従
返却テキストは context 節約のため約 10,000 文字で切り詰められる。**スペースタスクでは全文(未切り詰め)が `source/` に保存される**ので、切り詰めが起きると末尾に `... (truncated; full version saved to source/<file>)` という案内が付く。全文を読みたいときは保存された `source/` のファイルを `Read` で開けばよい。
## いつ使うか
| 状況 | 使うツール |
@@ -24,6 +26,27 @@ WebFetch({ url: "https://example.com/article", timeout: 30 })
WebFetch は軽量で速い。BrowseWeb はブラウザ起動コストがかかるので、できる限り WebFetch を優先する。
## クリーン本文抽出(readability
取得した生 HTML は、記事本文だけを取り出す readability エンジンで処理してから返す。
内部パイプラインは `HTML → linkedom で DOM 化 → @mozilla/readability で記事抽出 → turndown(+gfm) で Markdown 化`
- **除去されるもの**: ナビゲーション、広告バナー、ヘッダー、フッター、サイドバー等のボイラープレート
- **保持されるもの**: 見出し(`#` 記法)、箇条書き、番号付きリスト、テーブル(GFM 記法)、リンク、コードブロック
- 相対リンクは取得 URL を基準に絶対 URL へ変換される
- `selector` を指定すると、その CSS セレクタにマッチする要素のサブツリーだけをクリーン抽出する(見つからなければページ全体の抽出にフォールバック)
抽出に失敗するページ(記事構造のない LP、JS で本文を生成する SPA、空ページ等)では、
従来の素朴なタグ除去にフォールバックするので WebFetch が失敗扱いになることはない。
本文がほぼ空のときは SPA の可能性が高いので `BrowseWeb` に切り替える。
### 全文は source へ、切り詰め版は agent へ
- agent のコンテキストに返るのは約 10,000 文字に切り詰めた版(context 膨張を防ぐため)
- **スペースタスクでは、切り詰める前の全文クリーン Markdown が `source/` に保存される**
- 切り詰めが起きた場合、返却テキスト末尾に `... (truncated; full version saved to source/<file>)` が付く
- 病的に巨大なページ対策として、`source/` 保存も 2MB で打ち切る(その旨ノートを付す)
## レスポンス履歴
各 WebFetch 呼び出しは `logs/webfetch-history.jsonl` に記録される。後から「どの URL を取得したか」を振り返れる。
@@ -75,3 +98,13 @@ WebFetch は取得 body の先頭 8KB を sniff し(magic byte / NUL / 不正
(例: `.xls``text/plain`)していても実バイトで検出する。バイナリを処理したい場合は
`DownloadFile``input/` に保存し、`ReadExcel` / `ReadPdf` 等を使う。テキスト body は
5MB で打ち切られる(末尾に `[truncated: body exceeded 5MB]`)。
## ソースライブラリへの蓄積(スペースタスク)
スペースのタスクで WebFetch がページ本文を取得すると、**クリーン抽出した全文 Markdown**agent への
返却で切り詰める前のもの)が `source/` に保存され、出典メタ(URL・タイトル・取得日時・サイズ)が
`source/index.jsonl` に追記される。
これにより「そのスペースのソース(資料)」が自動で溜まり、後から追加調査やグラウンディングに使える。
同一 URL は重複保存しない(既に index にあればスキップ)。スペース文脈でないタスク
ephemeral / gitea issue 等)では従来どおり蓄積しない。`logs/raw/` への生データ保存は従来どおり。
BrowseWeb(ブラウザ閲覧)や DownloadFile`section: "source"`)も同じ `source/index.jsonl` に合流する。
+45
View File
@@ -0,0 +1,45 @@
# ワークスペース・アプリの作り方(エージェント向け)
ユーザーから「ワークスペース・アプリを作って」「○○用の 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(要点)
```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`** を参照。
## ひな型をコピーする
動くサンプルが `docs/examples/workspace-apps/file-note/` にある(`index.html` `app.json`)。
`output/` を一覧・閲覧し、メモを `output/note.md` に保存する自己完結アプリ。これを土台に、
依頼に合わせて改変して `apps/{name}/index.html` に Write するのが最短。
`apps/{name}/app.json`(任意)で一覧の表示名・説明・エントリを指定できる(無ければフォルダ名)。
## 仕上げ
- 書き込んだら、ユーザーに「アプリ」タブの「開く」で起動できることを一言伝える。
- アプリ名(フォルダ名)は内容が分かる短い英小文字+ハイフンにする(例: `invoice-gen`)。