nandi/oripublic Fork 0
b6cd929
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

🛟 Updated.Unverified

k33g committed 2026-09-18T13:27:10+02:00 Browse files
b6cd929 parent: 3d1f70c
added .memory/handoffs/2026-09-18-desktop-linux-build.md +69 -0
new file mode 100644
@@ -0,0 +1,69 @@
1+# Handoff — 2026-09-18 — ori-desktop built on Linux, MIT LICENSE added
2+
3+## What was asked
4+
5+1. `cd ori-desktop && wails build`.
6+2. Mid-session: "ajoute un fichier de licence MIT".
7+3. Then: how to build the macOS version (answered in chat), and "cree un document expliquant ca
8+ dans ./ori-desktop/how-to-build.md".
9+
10+## State at the end
11+
12+All three done. New tracked files: `LICENSE` (root) and `ori-desktop/how-to-build.md`. The
13+pre-existing modifications to `docs/.assets/ori-architecture.drawio.svg`,
14+`ori-desktop/README.md`, `ori-desktop/README.fr.md` and `template/build.sh` are the user's and
15+were deliberately not touched. Nothing committed, nothing pushed.
16+
17+## The build recipe that works in this sandbox
18+
19+```bash
20+go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0
21+sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
22+export PATH="$PATH:$(go env GOPATH)/bin"
23+cd ori-desktop && wails build -tags webkit2_41 # → build/bin/ori-desktop (ELF aarch64, 9.4 MB)
24+```
25+
26+## Traps found
27+
28+- **`wails build` without `-tags webkit2_41` fails here.** Wails' cgo pkg-config line asks for
29+ `webkit2gtk-4.0`; Ubuntu 26.04 only packages `webkit2gtk-4.1`. Error:
30+ `Package 'webkit2gtk-4.0' not found` ×3.
31+- **`wails doctor` lies about it**: it reports `libwebkit | Unknown | Not Found` and
32+ `Fatal: Required dependencies missing: libwebkit` *after* 4.1 is installed, because it probes
33+ only 4.0. Trust `pkg-config --modversion webkit2gtk-4.1` (→ 2.52.6) instead.
34+- **`make desktop` is still broken on Linux** — it runs bare `wails build`. Left as-is
35+ deliberately (outside the ask). If you fix it, the tag must stay Linux-only: macOS and the
36+ Windows cross-build must not receive `-tags webkit2_41`.
37+- **No macOS build is possible from here.** Wails needs macOS/Xcode for a `.app`. The
38+ `build/bin/ori-desktop.app` that `scripts/launch-ori.applescript` opens is the user's own Mac
39+ build; this session did not touch it. `build/bin/` now holds all three targets side by side.
40+- The apt packages live on the container disk, so a sandbox recreation loses them and the
41+ install step has to be repeated.
42+
43+## The document
44+
45+`ori-desktop/how-to-build.md` — prerequisites, a from-where/to-what cross-build matrix, one
46+section per platform (macOS / Linux / Windows), the `wails build` flags that matter, `wails dev`,
47+the tests, troubleshooting. Written in the repository's Diátaxis how-to style, in English
48+(the `.md` / `.fr.md` pair convention means the unsuffixed name is the English one).
49+
50+Everything in it about Linux was verified in this session. The macOS section reflects the user's
51+own earlier build plus Wails v2.16 CLI behaviour (`wails build -help` was read, not guessed); the
52+`darwin/universal` variant has never been exercised in this project.
53+
54+## Next steps / still open
55+
56+- The window has **never been run** — neither here (no display) nor confirmed on the Mac after
57+ the CSS specificity fix. The summary's "Not yet established" item about the iframe actually
58+ showing ori inside WKWebView is unchanged by this session.
59+- The Linux binary was not executed either; only compiled. `xvfb` + a running ori server would
60+ be the way to smoke-test it in the sandbox.
61+- `LICENSE` is referenced from nowhere: no badge or "Licence" section in `README.md` /
62+ `README.fr.md` / `ori-desktop/README*.md`, no `"license": "MIT"` in `ui/package.json`. Add
63+ those if the user wants the licence discoverable.
64+- `how-to-build.md` has no French counterpart and nothing links to it. Both were left undone on
65+ purpose: the repository pairs every doc with a `.fr.md`, and `ori-desktop/README.md` has a
66+ "Build a redistributable binary" section that is the obvious place for the pointer — but that
67+ file has uncommitted user edits, so it was not touched. Offered to the user.
68+- The overlap between `how-to-build.md` and the build sections of `ori-desktop/README*.md` is now
69+ duplicated content. If the user wants it deduplicated, the README should shrink to a link.
new file mode 100644
@@ -0,0 +1,69 @@
1+# Handoff — 2026-09-18 — ori-desktop built on Linux, MIT LICENSE added
2+
3+## What was asked
4+
5+1. `cd ori-desktop && wails build`.
6+2. Mid-session: "ajoute un fichier de licence MIT".
7+3. Then: how to build the macOS version (answered in chat), and "cree un document expliquant ca
8+ dans ./ori-desktop/how-to-build.md".
9+
10+## State at the end
11+
12+All three done. New tracked files: `LICENSE` (root) and `ori-desktop/how-to-build.md`. The
13+pre-existing modifications to `docs/.assets/ori-architecture.drawio.svg`,
14+`ori-desktop/README.md`, `ori-desktop/README.fr.md` and `template/build.sh` are the user's and
15+were deliberately not touched. Nothing committed, nothing pushed.
16+
17+## The build recipe that works in this sandbox
18+
19+```bash
20+go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0
21+sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
22+export PATH="$PATH:$(go env GOPATH)/bin"
23+cd ori-desktop && wails build -tags webkit2_41 # → build/bin/ori-desktop (ELF aarch64, 9.4 MB)
24+```
25+
26+## Traps found
27+
28+- **`wails build` without `-tags webkit2_41` fails here.** Wails' cgo pkg-config line asks for
29+ `webkit2gtk-4.0`; Ubuntu 26.04 only packages `webkit2gtk-4.1`. Error:
30+ `Package 'webkit2gtk-4.0' not found` ×3.
31+- **`wails doctor` lies about it**: it reports `libwebkit | Unknown | Not Found` and
32+ `Fatal: Required dependencies missing: libwebkit` *after* 4.1 is installed, because it probes
33+ only 4.0. Trust `pkg-config --modversion webkit2gtk-4.1` (→ 2.52.6) instead.
34+- **`make desktop` is still broken on Linux** — it runs bare `wails build`. Left as-is
35+ deliberately (outside the ask). If you fix it, the tag must stay Linux-only: macOS and the
36+ Windows cross-build must not receive `-tags webkit2_41`.
37+- **No macOS build is possible from here.** Wails needs macOS/Xcode for a `.app`. The
38+ `build/bin/ori-desktop.app` that `scripts/launch-ori.applescript` opens is the user's own Mac
39+ build; this session did not touch it. `build/bin/` now holds all three targets side by side.
40+- The apt packages live on the container disk, so a sandbox recreation loses them and the
41+ install step has to be repeated.
42+
43+## The document
44+
45+`ori-desktop/how-to-build.md` — prerequisites, a from-where/to-what cross-build matrix, one
46+section per platform (macOS / Linux / Windows), the `wails build` flags that matter, `wails dev`,
47+the tests, troubleshooting. Written in the repository's Diátaxis how-to style, in English
48+(the `.md` / `.fr.md` pair convention means the unsuffixed name is the English one).
49+
50+Everything in it about Linux was verified in this session. The macOS section reflects the user's
51+own earlier build plus Wails v2.16 CLI behaviour (`wails build -help` was read, not guessed); the
52+`darwin/universal` variant has never been exercised in this project.
53+
54+## Next steps / still open
55+
56+- The window has **never been run** — neither here (no display) nor confirmed on the Mac after
57+ the CSS specificity fix. The summary's "Not yet established" item about the iframe actually
58+ showing ori inside WKWebView is unchanged by this session.
59+- The Linux binary was not executed either; only compiled. `xvfb` + a running ori server would
60+ be the way to smoke-test it in the sandbox.
61+- `LICENSE` is referenced from nowhere: no badge or "Licence" section in `README.md` /
62+ `README.fr.md` / `ori-desktop/README*.md`, no `"license": "MIT"` in `ui/package.json`. Add
63+ those if the user wants the licence discoverable.
64+- `how-to-build.md` has no French counterpart and nothing links to it. Both were left undone on
65+ purpose: the repository pairs every doc with a `.fr.md`, and `ori-desktop/README.md` has a
66+ "Build a redistributable binary" section that is the obvious place for the pointer — but that
67+ file has uncommitted user edits, so it was not touched. Offered to the user.
68+- The overlap between `how-to-build.md` and the build sections of `ori-desktop/README*.md` is now
69+ duplicated content. If the user wants it deduplicated, the README should shrink to a link.
modified .memory/history.md +10 -0
@@ -178,3 +178,13 @@
178178 - **Decisions**: (1) new adapter over "bake `claude update` + `CLAUDE_CODE_EXECUTABLE`": the SDK ships a current CLI per platform, no version chasing. (2) `adapter` stage stays `--platform=$BUILDPLATFORM` (native npm) and targets the CPU explicitly, instead of npm under qemu. (3) Backend default changed too (user: "backend + template") so `make run` gets the same fix. (4) Pre-existing failures fixed along the way with the user's explicit OK: MIME test, Node 25, Markdown.tsx types, ToolCallCard complexity. (5) Left untracked as the user's artefacts/memos: `kits/.backup/`, `demo/` (the three prompt-generated stories the user moved there — their root copies are deleted in `5d476ff`), `kits/ori/publish.kit.md`, `template/publish.template.md`.
179179 - **Verification**: `go vet ./... && go test ./...` green; ui `tsc -b` + 134 vitest green; `docker build --check` clean; arm64 image built locally — `claude-agent-acp` resolves for root and via `su … agent`, native SDK `linux-arm64` with the 230 MB CLI, manifest 2.1.274, ACP `initialize` answered by adapter 0.79.0, Zed adapter gone; amd64 install verified in a `node:24` container (`-linux-x64` present). Test sandbox `ori-acp` (image via `sbx template load`) served ori with CLI 2.1.274; the user pushed `k33g/ori:0.0.2` (multi-arch) and confirmed a real prompt in sandbox `hello-world` after the kit re-push. **Quality**: run #18 PASS (0/0/0, complex 532) after repairing qlty on the Mac (dangling `.qlty/*` symlinks from the sandbox; golangci-lint too old for Go 1.26).
180180 - **Docs**: as listed, EN + FR in sync. `diataxis-doc` skill not invoked: edits to existing pages, done directly.
181+
182+## 2026-09-18 — Linux build of ori-desktop (webkit2gtk-4.1) + MIT LICENSE
183+
184+- **Asked**: `cd ori-desktop && wails build`; then, mid-session, "ajoute un fichier de licence MIT".
185+- **Build**: installed the Wails CLI (`go install …/cmd/wails@v2.16.0`) and the GUI toolchain (`sudo apt-get install libgtk-3-dev libwebkit2gtk-4.1-dev`) in the sandbox — they were absent, which is why the window had never been launched here. Plain `wails build` fails: Wails' cgo pkg-config asks for `webkit2gtk-4.0`, Ubuntu 26.04 only ships 4.1. `wails build -tags webkit2_41``build/bin/ori-desktop`, ELF aarch64, 9.4 MB, 4.8 s. `wails doctor` still says `libwebkit: Not Found` (it only probes 4.0) — a false negative. No source change was needed.
186+- **Not done**: no macOS build — Wails cannot cross-compile to macOS from Linux, and the `.app` the user actually launches (`build/bin/ori-desktop.app`, and the AppleScript launcher) must still be built on the Mac. The Linux binary was added next to the existing `.app` and `.exe`, overwriting neither. The window itself was not run (no display in the sandbox).
187+- **Changes**: `LICENSE` (MIT, `Copyright (c) 2026 k33g`) at the repository root — the only file added to the tree; `build/bin/` and `frontend/wailsjs/` are gitignored. `.memory/summary.md`: the `-tags webkit2_41` requirement and the three build outputs on the `ori-desktop/` bullet, the apt/CLI install recipe under "Environment facts", the licence line.
188+- **Decisions**: holder `k33g` (the name used by every ticket author block and the git identity), not a guessed legal name. Root-only LICENSE, no copy under `ori-desktop/` despite it being a separate Go module. `make desktop` left untouched even though it fails on Linux for want of the tag — a Makefile change was outside what was asked; flagged to the user instead.
189+- **Verification**: `go test ./internal/...` in `ori-desktop` green (health, settings). Quality gate not re-run: no Go/TS source was modified.
190+- **Follow-up (same session)**: `ori-desktop/how-to-build.md` written on request — prerequisites, the from-where/to-what cross-build matrix (macOS only from macOS; Windows from anywhere; Linux from Linux), one section per platform, the `wails build` flags that matter, `wails dev`, the tests, and a troubleshooting list (webkit 4.0 vs 4.1, the `wails doctor` false negative, `make desktop` on Linux, the lost execute bit under cloud sync, Gatekeeper/`xattr -cr`, empty window = no server). English only, house Diátaxis how-to style; `how-to-build.fr.md` NOT written and `README.md` NOT linked to it — the user's own edits to `ori-desktop/README*.md` are uncommitted in the tree and were left alone. All four relative links in the doc were checked to resolve.
@@ -178,3 +178,13 @@
178 - **Decisions**: (1) new adapter over "bake `claude update` + `CLAUDE_CODE_EXECUTABLE`": the SDK ships a current CLI per platform, no version chasing. (2) `adapter` stage stays `--platform=$BUILDPLATFORM` (native npm) and targets the CPU explicitly, instead of npm under qemu. (3) Backend default changed too (user: "backend + template") so `make run` gets the same fix. (4) Pre-existing failures fixed along the way with the user's explicit OK: MIME test, Node 25, Markdown.tsx types, ToolCallCard complexity. (5) Left untracked as the user's artefacts/memos: `kits/.backup/`, `demo/` (the three prompt-generated stories the user moved there — their root copies are deleted in `5d476ff`), `kits/ori/publish.kit.md`, `template/publish.template.md`.178 - **Decisions**: (1) new adapter over "bake `claude update` + `CLAUDE_CODE_EXECUTABLE`": the SDK ships a current CLI per platform, no version chasing. (2) `adapter` stage stays `--platform=$BUILDPLATFORM` (native npm) and targets the CPU explicitly, instead of npm under qemu. (3) Backend default changed too (user: "backend + template") so `make run` gets the same fix. (4) Pre-existing failures fixed along the way with the user's explicit OK: MIME test, Node 25, Markdown.tsx types, ToolCallCard complexity. (5) Left untracked as the user's artefacts/memos: `kits/.backup/`, `demo/` (the three prompt-generated stories the user moved there — their root copies are deleted in `5d476ff`), `kits/ori/publish.kit.md`, `template/publish.template.md`.
179 - **Verification**: `go vet ./... && go test ./...` green; ui `tsc -b` + 134 vitest green; `docker build --check` clean; arm64 image built locally — `claude-agent-acp` resolves for root and via `su … agent`, native SDK `linux-arm64` with the 230 MB CLI, manifest 2.1.274, ACP `initialize` answered by adapter 0.79.0, Zed adapter gone; amd64 install verified in a `node:24` container (`-linux-x64` present). Test sandbox `ori-acp` (image via `sbx template load`) served ori with CLI 2.1.274; the user pushed `k33g/ori:0.0.2` (multi-arch) and confirmed a real prompt in sandbox `hello-world` after the kit re-push. **Quality**: run #18 PASS (0/0/0, complex 532) after repairing qlty on the Mac (dangling `.qlty/*` symlinks from the sandbox; golangci-lint too old for Go 1.26).179 - **Verification**: `go vet ./... && go test ./...` green; ui `tsc -b` + 134 vitest green; `docker build --check` clean; arm64 image built locally — `claude-agent-acp` resolves for root and via `su … agent`, native SDK `linux-arm64` with the 230 MB CLI, manifest 2.1.274, ACP `initialize` answered by adapter 0.79.0, Zed adapter gone; amd64 install verified in a `node:24` container (`-linux-x64` present). Test sandbox `ori-acp` (image via `sbx template load`) served ori with CLI 2.1.274; the user pushed `k33g/ori:0.0.2` (multi-arch) and confirmed a real prompt in sandbox `hello-world` after the kit re-push. **Quality**: run #18 PASS (0/0/0, complex 532) after repairing qlty on the Mac (dangling `.qlty/*` symlinks from the sandbox; golangci-lint too old for Go 1.26).
180 - **Docs**: as listed, EN + FR in sync. `diataxis-doc` skill not invoked: edits to existing pages, done directly.180 - **Docs**: as listed, EN + FR in sync. `diataxis-doc` skill not invoked: edits to existing pages, done directly.
181+
182+## 2026-09-18 — Linux build of ori-desktop (webkit2gtk-4.1) + MIT LICENSE
183+
184+- **Asked**: `cd ori-desktop && wails build`; then, mid-session, "ajoute un fichier de licence MIT".
185+- **Build**: installed the Wails CLI (`go install …/cmd/wails@v2.16.0`) and the GUI toolchain (`sudo apt-get install libgtk-3-dev libwebkit2gtk-4.1-dev`) in the sandbox — they were absent, which is why the window had never been launched here. Plain `wails build` fails: Wails' cgo pkg-config asks for `webkit2gtk-4.0`, Ubuntu 26.04 only ships 4.1. `wails build -tags webkit2_41``build/bin/ori-desktop`, ELF aarch64, 9.4 MB, 4.8 s. `wails doctor` still says `libwebkit: Not Found` (it only probes 4.0) — a false negative. No source change was needed.
186+- **Not done**: no macOS build — Wails cannot cross-compile to macOS from Linux, and the `.app` the user actually launches (`build/bin/ori-desktop.app`, and the AppleScript launcher) must still be built on the Mac. The Linux binary was added next to the existing `.app` and `.exe`, overwriting neither. The window itself was not run (no display in the sandbox).
187+- **Changes**: `LICENSE` (MIT, `Copyright (c) 2026 k33g`) at the repository root — the only file added to the tree; `build/bin/` and `frontend/wailsjs/` are gitignored. `.memory/summary.md`: the `-tags webkit2_41` requirement and the three build outputs on the `ori-desktop/` bullet, the apt/CLI install recipe under "Environment facts", the licence line.
188+- **Decisions**: holder `k33g` (the name used by every ticket author block and the git identity), not a guessed legal name. Root-only LICENSE, no copy under `ori-desktop/` despite it being a separate Go module. `make desktop` left untouched even though it fails on Linux for want of the tag — a Makefile change was outside what was asked; flagged to the user instead.
189+- **Verification**: `go test ./internal/...` in `ori-desktop` green (health, settings). Quality gate not re-run: no Go/TS source was modified.
190+- **Follow-up (same session)**: `ori-desktop/how-to-build.md` written on request — prerequisites, the from-where/to-what cross-build matrix (macOS only from macOS; Windows from anywhere; Linux from Linux), one section per platform, the `wails build` flags that matter, `wails dev`, the tests, and a troubleshooting list (webkit 4.0 vs 4.1, the `wails doctor` false negative, `make desktop` on Linux, the lost execute bit under cloud sync, Gatekeeper/`xattr -cr`, empty window = no server). English only, house Diátaxis how-to style; `how-to-build.fr.md` NOT written and `README.md` NOT linked to it — the user's own edits to `ori-desktop/README*.md` are uncommitted in the tree and were left alone. All four relative links in the doc were checked to resolve.
modified .memory/summary.md +4 -1
@@ -21,7 +21,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
2121 - `internal/skills``GET /api/skills`: discovers `<cwd>/.claude/skills/*/SKILL.md` and `~/.claude/skills/*/SKILL.md` (frontmatter `name`/`description`, directory-name fallback, project shadows user, sorted).
2222 - `internal/bridge` — hub between agent and browsers: JSON protocol (see `docs/*/reference/websocket-protocol.md`), broadcast with per-client buffers (slow client = dropped), append-only history (cap 4096) replayed on every connection, `user_message` echo so the server is the single source of truth, permission routing by requestId (pending requests replayed to late joiners; agent-side ctx cancellation handled). The `prompt` message carries optional `attachments: [{path,name}]`, turned server-side into ACP `resource_link` blocks (`file://<abs>`) next to the text block — `Prompter.Prompt(ctx, []acp.ContentBlock)` replaced `PromptText`; relative paths are joined to the root given by `Bridge.SetWorkspaceRoot` (wired in `cmd/ori/main.go`); `user_message` echoes the attachments. Uses `github.com/coder/websocket` v1.8.15; origins restricted to localhost.
2323 - `ui/` — Vite + React 19 + TS strict; zustand store around a pure reducer (`ui/src/reducer.ts`, handler-table style); WS client with backoff reconnect; thread resets on `hello` so replays are idempotent; unknown ACP update kinds ignored by design. Workspace panel (separate zustand store `ui/src/workspace.ts`): file tree (click=preview, double-click=edit; column resizable via `ResizeHandle` — ARIA separator, pointer drag / arrows / Home-End / double-click reset — width `fileTreeWidth` in the store, bounded 120–800 px, default 224, applied through the `--filetree-width` CSS custom property, persisted in localStorage `ori.fileTreeWidth`). Colour theme (`ui/src/theme.ts`, own zustand store): `light` (default) | `dark`, stamped as `data-theme` on `<html>` at module load and on change, remembered in localStorage `ori.theme`, toggled by the header ☾/☀ button; `app.css` keys the dark palette on `:root[data-theme="dark"]` (the former `prefers-color-scheme` media query is gone — decision: explicit choice, light default), `MonacoViewer` reads the store (`vs-dark`/`light`), the terminal stays dark. Preview tab (Monaco read-only for code — bundled workers, no CDN, lazy chunk ~1MB gzip; rendered Markdown; rendered AsciiDoc via lazily-imported `@asciidoctor/core`, Rendered/Source toggle), Editor tab (Monaco, dirty ●, Save/Ctrl+S via PUT /api/file), Terminal tab (xterm.js on /ws/terminal, starts on first activation); inactive panes are hidden not unmounted so shell/edit state survives tab switches; `execute` tool-call output renders in a monospace `<pre>`, never markdown. Composer completions (`ui/src/mentions.ts` pure helpers, `ui/src/useCompletion.ts`, `CompletionPopup`): `@` opens a workspace file search (→ attachments), `/` opens a merged list of local skills (`/api/skills`) and ACP `available_commands_update` commands (stored as `commands` in the reducer, cleared on `hello`; deduped by name, skill wins) and inserts `/<name> ` as plain text — the text is the invocation mechanism, there is no ACP "run command" method. Preview kinds `image` (`ImageView`, `<img>` over checkerboard via `/api/raw`, natural size shown) and `drawio` (`DrawioView`: iframe on `embed.diagrams.net` fed by postMessage, Rendered/Source toggle, 8 s timeout → Source fallback; `.drawio.svg/.png` are images). The mock agent emits `available_commands_update` (`review`, `compact`) on session start and echoes `[attached: name]`.
24-- `ori-desktop/` — separate Go module `rickub.com/bots-garden/ori-desktop` (Wails v2.16.0, Go ≥ 1.25, "plain" template, `//go:embed all:frontend/src`, no npm; `frontend/src/main.js` is loaded as an ES module — `type="module"` — since the 2026-09-17 lint cleanup): connection screen (URL remembered in `<UserConfigDir>/ori-desktop/settings.json`, key `serverUrl`; auto-connect at startup), `/healthz` probe via bound Go methods (GetConfig, SaveConfig, CheckHealth, Connect, OpenInBrowser, SettingsPath), then the ori SPA loaded in an `<iframe>` (Wails v2 cannot navigate the main webview to an external URL; `runtime.BrowserOpenURL` is the fallback). Ticket 0005. `make desktop` / `make desktop-test`; root `go test ./...` unaffected (nested module).
24+- `ori-desktop/` — separate Go module `rickub.com/bots-garden/ori-desktop` (Wails v2.16.0, Go ≥ 1.25, "plain" template, `//go:embed all:frontend/src`, no npm; `frontend/src/main.js` is loaded as an ES module — `type="module"` — since the 2026-09-17 lint cleanup): connection screen (URL remembered in `<UserConfigDir>/ori-desktop/settings.json`, key `serverUrl`; auto-connect at startup), `/healthz` probe via bound Go methods (GetConfig, SaveConfig, CheckHealth, Connect, OpenInBrowser, SettingsPath), then the ori SPA loaded in an `<iframe>` (Wails v2 cannot navigate the main webview to an external URL; `runtime.BrowserOpenURL` is the fallback). Ticket 0005. `make desktop` / `make desktop-test`; root `go test ./...` unaffected (nested module). **On Linux, `wails build` needs `-tags webkit2_41`** (Ubuntu 26.04 ships only `webkit2gtk-4.1`; the plain command dies on `Package 'webkit2gtk-4.0' not found`). `make desktop` does NOT pass that tag, so it fails in this sandbox — run `cd ori-desktop && wails build -tags webkit2_41` instead. Build outputs coexist in `build/bin/`: `ori-desktop` (Linux ELF), `ori-desktop.app` (macOS, built on the Mac), `ori-desktop.exe` (Windows cross-build); Wails cannot cross-compile to macOS from Linux. Build instructions for the three platforms: `ori-desktop/how-to-build.md` (2026-09-18, EN only — no `.fr.md` counterpart yet, and no README links to it).
2525
2626 ## Key decisions in force
2727
@@ -54,6 +54,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
5454 - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`.
5555 - Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). With the current template/kit (`claude-agent-acp`, bundled CLI 2.1.274) no `CLAUDE_CODE_EXECUTABLE` is needed. It remains the lever if something spawns the old Zed adapter (points it at another `claude` binary) — but the template's own CLI is 2.1.246 (base image 2026-08-26), below the 2.1.251 floor the API enforces for `claude-fable-5-1[1m]` (host `~/.claude/settings.json`), so `claude update` inside the sandbox would come first. Handoffs `2026-09-18-claude-version-too-old.md`, `2026-09-18-claude-agent-acp-adapter.md`.
5656 - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`).
57+- The Wails GUI toolchain is installable here (verified 2026-09-18): `go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0` then `sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev` (~15 GB free on `/`, plenty). `wails doctor` still reports `libwebkit: Not Found` because it only looks for `webkit2gtk-4.0` — ignore it; `pkg-config --modversion webkit2gtk-4.1` → 2.52.6 is what matters. These are apt packages on the container disk, so a sandbox recreation loses them.
5758
5859 ## Known limitations
5960
@@ -63,6 +64,8 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
6364 - `user_message` / thought / message chunks only render text content blocks; images/audio/resources are not rendered yet; `user_message.attachments` are not rendered as chips (only the `@path` text mention).
6465 - Skills list is fetched once per page load; the file search walks whatever sits under `--cwd` (an untracked `sandboxes/` clone at the repo root gets walked).
6566
67+- Licence: MIT, `LICENSE` at the repository root (added 2026-09-18, holder `k33g` — the name used in the tickets and git identity). No per-module licence file; `ori-desktop/` is covered by the root one. Nothing references it yet from the READMEs or `ui/package.json`.
68+
6669 - Git: remote `origin` = `https://git.rickub.com/bots-garden/ori.git` (Gitea-style self-hosted, not GitHub). `main` fast-forwarded to `feat/acp-webapp` at commit `76d62ac` on 2026-09-17; **not pushed** yet. `hello.md` (a story generated during an ori test) and `.claude/settings.local.json` are deliberately left untracked.
6770
6871 ## Not yet established
@@ -21,7 +21,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
21 - `internal/skills``GET /api/skills`: discovers `<cwd>/.claude/skills/*/SKILL.md` and `~/.claude/skills/*/SKILL.md` (frontmatter `name`/`description`, directory-name fallback, project shadows user, sorted).21 - `internal/skills``GET /api/skills`: discovers `<cwd>/.claude/skills/*/SKILL.md` and `~/.claude/skills/*/SKILL.md` (frontmatter `name`/`description`, directory-name fallback, project shadows user, sorted).
22 - `internal/bridge` — hub between agent and browsers: JSON protocol (see `docs/*/reference/websocket-protocol.md`), broadcast with per-client buffers (slow client = dropped), append-only history (cap 4096) replayed on every connection, `user_message` echo so the server is the single source of truth, permission routing by requestId (pending requests replayed to late joiners; agent-side ctx cancellation handled). The `prompt` message carries optional `attachments: [{path,name}]`, turned server-side into ACP `resource_link` blocks (`file://<abs>`) next to the text block — `Prompter.Prompt(ctx, []acp.ContentBlock)` replaced `PromptText`; relative paths are joined to the root given by `Bridge.SetWorkspaceRoot` (wired in `cmd/ori/main.go`); `user_message` echoes the attachments. Uses `github.com/coder/websocket` v1.8.15; origins restricted to localhost.22 - `internal/bridge` — hub between agent and browsers: JSON protocol (see `docs/*/reference/websocket-protocol.md`), broadcast with per-client buffers (slow client = dropped), append-only history (cap 4096) replayed on every connection, `user_message` echo so the server is the single source of truth, permission routing by requestId (pending requests replayed to late joiners; agent-side ctx cancellation handled). The `prompt` message carries optional `attachments: [{path,name}]`, turned server-side into ACP `resource_link` blocks (`file://<abs>`) next to the text block — `Prompter.Prompt(ctx, []acp.ContentBlock)` replaced `PromptText`; relative paths are joined to the root given by `Bridge.SetWorkspaceRoot` (wired in `cmd/ori/main.go`); `user_message` echoes the attachments. Uses `github.com/coder/websocket` v1.8.15; origins restricted to localhost.
23 - `ui/` — Vite + React 19 + TS strict; zustand store around a pure reducer (`ui/src/reducer.ts`, handler-table style); WS client with backoff reconnect; thread resets on `hello` so replays are idempotent; unknown ACP update kinds ignored by design. Workspace panel (separate zustand store `ui/src/workspace.ts`): file tree (click=preview, double-click=edit; column resizable via `ResizeHandle` — ARIA separator, pointer drag / arrows / Home-End / double-click reset — width `fileTreeWidth` in the store, bounded 120–800 px, default 224, applied through the `--filetree-width` CSS custom property, persisted in localStorage `ori.fileTreeWidth`). Colour theme (`ui/src/theme.ts`, own zustand store): `light` (default) | `dark`, stamped as `data-theme` on `<html>` at module load and on change, remembered in localStorage `ori.theme`, toggled by the header ☾/☀ button; `app.css` keys the dark palette on `:root[data-theme="dark"]` (the former `prefers-color-scheme` media query is gone — decision: explicit choice, light default), `MonacoViewer` reads the store (`vs-dark`/`light`), the terminal stays dark. Preview tab (Monaco read-only for code — bundled workers, no CDN, lazy chunk ~1MB gzip; rendered Markdown; rendered AsciiDoc via lazily-imported `@asciidoctor/core`, Rendered/Source toggle), Editor tab (Monaco, dirty ●, Save/Ctrl+S via PUT /api/file), Terminal tab (xterm.js on /ws/terminal, starts on first activation); inactive panes are hidden not unmounted so shell/edit state survives tab switches; `execute` tool-call output renders in a monospace `<pre>`, never markdown. Composer completions (`ui/src/mentions.ts` pure helpers, `ui/src/useCompletion.ts`, `CompletionPopup`): `@` opens a workspace file search (→ attachments), `/` opens a merged list of local skills (`/api/skills`) and ACP `available_commands_update` commands (stored as `commands` in the reducer, cleared on `hello`; deduped by name, skill wins) and inserts `/<name> ` as plain text — the text is the invocation mechanism, there is no ACP "run command" method. Preview kinds `image` (`ImageView`, `<img>` over checkerboard via `/api/raw`, natural size shown) and `drawio` (`DrawioView`: iframe on `embed.diagrams.net` fed by postMessage, Rendered/Source toggle, 8 s timeout → Source fallback; `.drawio.svg/.png` are images). The mock agent emits `available_commands_update` (`review`, `compact`) on session start and echoes `[attached: name]`.23 - `ui/` — Vite + React 19 + TS strict; zustand store around a pure reducer (`ui/src/reducer.ts`, handler-table style); WS client with backoff reconnect; thread resets on `hello` so replays are idempotent; unknown ACP update kinds ignored by design. Workspace panel (separate zustand store `ui/src/workspace.ts`): file tree (click=preview, double-click=edit; column resizable via `ResizeHandle` — ARIA separator, pointer drag / arrows / Home-End / double-click reset — width `fileTreeWidth` in the store, bounded 120–800 px, default 224, applied through the `--filetree-width` CSS custom property, persisted in localStorage `ori.fileTreeWidth`). Colour theme (`ui/src/theme.ts`, own zustand store): `light` (default) | `dark`, stamped as `data-theme` on `<html>` at module load and on change, remembered in localStorage `ori.theme`, toggled by the header ☾/☀ button; `app.css` keys the dark palette on `:root[data-theme="dark"]` (the former `prefers-color-scheme` media query is gone — decision: explicit choice, light default), `MonacoViewer` reads the store (`vs-dark`/`light`), the terminal stays dark. Preview tab (Monaco read-only for code — bundled workers, no CDN, lazy chunk ~1MB gzip; rendered Markdown; rendered AsciiDoc via lazily-imported `@asciidoctor/core`, Rendered/Source toggle), Editor tab (Monaco, dirty ●, Save/Ctrl+S via PUT /api/file), Terminal tab (xterm.js on /ws/terminal, starts on first activation); inactive panes are hidden not unmounted so shell/edit state survives tab switches; `execute` tool-call output renders in a monospace `<pre>`, never markdown. Composer completions (`ui/src/mentions.ts` pure helpers, `ui/src/useCompletion.ts`, `CompletionPopup`): `@` opens a workspace file search (→ attachments), `/` opens a merged list of local skills (`/api/skills`) and ACP `available_commands_update` commands (stored as `commands` in the reducer, cleared on `hello`; deduped by name, skill wins) and inserts `/<name> ` as plain text — the text is the invocation mechanism, there is no ACP "run command" method. Preview kinds `image` (`ImageView`, `<img>` over checkerboard via `/api/raw`, natural size shown) and `drawio` (`DrawioView`: iframe on `embed.diagrams.net` fed by postMessage, Rendered/Source toggle, 8 s timeout → Source fallback; `.drawio.svg/.png` are images). The mock agent emits `available_commands_update` (`review`, `compact`) on session start and echoes `[attached: name]`.
24-- `ori-desktop/` — separate Go module `rickub.com/bots-garden/ori-desktop` (Wails v2.16.0, Go ≥ 1.25, "plain" template, `//go:embed all:frontend/src`, no npm; `frontend/src/main.js` is loaded as an ES module — `type="module"` — since the 2026-09-17 lint cleanup): connection screen (URL remembered in `<UserConfigDir>/ori-desktop/settings.json`, key `serverUrl`; auto-connect at startup), `/healthz` probe via bound Go methods (GetConfig, SaveConfig, CheckHealth, Connect, OpenInBrowser, SettingsPath), then the ori SPA loaded in an `<iframe>` (Wails v2 cannot navigate the main webview to an external URL; `runtime.BrowserOpenURL` is the fallback). Ticket 0005. `make desktop` / `make desktop-test`; root `go test ./...` unaffected (nested module).24+- `ori-desktop/` — separate Go module `rickub.com/bots-garden/ori-desktop` (Wails v2.16.0, Go ≥ 1.25, "plain" template, `//go:embed all:frontend/src`, no npm; `frontend/src/main.js` is loaded as an ES module — `type="module"` — since the 2026-09-17 lint cleanup): connection screen (URL remembered in `<UserConfigDir>/ori-desktop/settings.json`, key `serverUrl`; auto-connect at startup), `/healthz` probe via bound Go methods (GetConfig, SaveConfig, CheckHealth, Connect, OpenInBrowser, SettingsPath), then the ori SPA loaded in an `<iframe>` (Wails v2 cannot navigate the main webview to an external URL; `runtime.BrowserOpenURL` is the fallback). Ticket 0005. `make desktop` / `make desktop-test`; root `go test ./...` unaffected (nested module). **On Linux, `wails build` needs `-tags webkit2_41`** (Ubuntu 26.04 ships only `webkit2gtk-4.1`; the plain command dies on `Package 'webkit2gtk-4.0' not found`). `make desktop` does NOT pass that tag, so it fails in this sandbox — run `cd ori-desktop && wails build -tags webkit2_41` instead. Build outputs coexist in `build/bin/`: `ori-desktop` (Linux ELF), `ori-desktop.app` (macOS, built on the Mac), `ori-desktop.exe` (Windows cross-build); Wails cannot cross-compile to macOS from Linux. Build instructions for the three platforms: `ori-desktop/how-to-build.md` (2026-09-18, EN only — no `.fr.md` counterpart yet, and no README links to it).
25 25
26 ## Key decisions in force26 ## Key decisions in force
27 27
@@ -54,6 +54,7 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
54 - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`.54 - `~/.npm` is the same kind of 488MB dedicated volume and filled up when installing Monaco; the npm cache now lives at `~/.npm-big` via `NPM_CONFIG_CACHE` exported in `/etc/sandbox-persistent.sh`.
55 - Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). With the current template/kit (`claude-agent-acp`, bundled CLI 2.1.274) no `CLAUDE_CODE_EXECUTABLE` is needed. It remains the lever if something spawns the old Zed adapter (points it at another `claude` binary) — but the template's own CLI is 2.1.246 (base image 2026-08-26), below the 2.1.251 floor the API enforces for `claude-fable-5-1[1m]` (host `~/.claude/settings.json`), so `claude update` inside the sandbox would come first. Handoffs `2026-09-18-claude-version-too-old.md`, `2026-09-18-claude-agent-acp-adapter.md`.55 - Running ori inside this Claude-Code-driven sandbox requires `env -u CLAUDECODE ./bin/ori` (Claude refuses nested sessions). With the current template/kit (`claude-agent-acp`, bundled CLI 2.1.274) no `CLAUDE_CODE_EXECUTABLE` is needed. It remains the lever if something spawns the old Zed adapter (points it at another `claude` binary) — but the template's own CLI is 2.1.246 (base image 2026-08-26), below the 2.1.251 floor the API enforces for `claude-fable-5-1[1m]` (host `~/.claude/settings.json`), so `claude update` inside the sandbox would come first. Handoffs `2026-09-18-claude-version-too-old.md`, `2026-09-18-claude-agent-acp-adapter.md`.
56 - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`).56 - npm blocks install scripts by default here; esbuild's postinstall was approved via `npm approve-scripts` (recorded in `ui/package.json` `allowScripts`).
57+- The Wails GUI toolchain is installable here (verified 2026-09-18): `go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0` then `sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev` (~15 GB free on `/`, plenty). `wails doctor` still reports `libwebkit: Not Found` because it only looks for `webkit2gtk-4.0` — ignore it; `pkg-config --modversion webkit2gtk-4.1` → 2.52.6 is what matters. These are apt packages on the container disk, so a sandbox recreation loses them.
57 58
58 ## Known limitations59 ## Known limitations
59 60
@@ -63,6 +64,8 @@ browser ⇆ WebSocket /ws ⇆ Go backend ⇆ stdio (ACP) ⇆ agent subprocess
63 - `user_message` / thought / message chunks only render text content blocks; images/audio/resources are not rendered yet; `user_message.attachments` are not rendered as chips (only the `@path` text mention).64 - `user_message` / thought / message chunks only render text content blocks; images/audio/resources are not rendered yet; `user_message.attachments` are not rendered as chips (only the `@path` text mention).
64 - Skills list is fetched once per page load; the file search walks whatever sits under `--cwd` (an untracked `sandboxes/` clone at the repo root gets walked).65 - Skills list is fetched once per page load; the file search walks whatever sits under `--cwd` (an untracked `sandboxes/` clone at the repo root gets walked).
65 66
67+- Licence: MIT, `LICENSE` at the repository root (added 2026-09-18, holder `k33g` — the name used in the tickets and git identity). No per-module licence file; `ori-desktop/` is covered by the root one. Nothing references it yet from the READMEs or `ui/package.json`.
68+
66 - Git: remote `origin` = `https://git.rickub.com/bots-garden/ori.git` (Gitea-style self-hosted, not GitHub). `main` fast-forwarded to `feat/acp-webapp` at commit `76d62ac` on 2026-09-17; **not pushed** yet. `hello.md` (a story generated during an ori test) and `.claude/settings.local.json` are deliberately left untracked.69 - Git: remote `origin` = `https://git.rickub.com/bots-garden/ori.git` (Gitea-style self-hosted, not GitHub). `main` fast-forwarded to `feat/acp-webapp` at commit `76d62ac` on 2026-09-17; **not pushed** yet. `hello.md` (a story generated during an ori test) and `.claude/settings.local.json` are deliberately left untracked.
67 70
68 ## Not yet established71 ## Not yet established
added LICENSE +21 -0
new file mode 100644
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2026 k33g
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
new file mode 100644
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2026 k33g
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
modified docs/.assets/ori-architecture.drawio.svg +359 -80
@@ -1,80 +1,359 @@
1-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1220" height="640" viewBox="0 0 1220 640" content="&lt;mxfile host=&quot;Electron&quot; agent=&quot;make-diagram.mjs&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Ori Architecture&quot; id=&quot;diagram-1&quot;&gt;&lt;mxGraphModel dx=&quot;1000&quot; dy=&quot;600&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1169&quot; pageHeight=&quot;826&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&lt;root&gt;&lt;mxCell id=&quot;0&quot;/&gt;&lt;mxCell id=&quot;1&quot; parent=&quot;0&quot;/&gt;&lt;mxCell id=&quot;3&quot; value=&quot;Browser&amp;amp;#10;React SPA&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;20&quot; width=&quot;220&quot; height=&quot;110&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;4&quot; value=&quot;UI Components&amp;amp;#10;· Agent Panel&amp;amp;#10;· Workspace Panel&amp;amp;#10;· File Tree&amp;amp;#10;· Monaco Editor&amp;amp;#10;· Terminal (xterm.js)&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;150&quot; width=&quot;220&quot; height=&quot;150&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;5&quot; value=&quot;httpserver&amp;amp;#10;Serves SPA + /ws&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;20&quot; width=&quot;280&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;6&quot; value=&quot;bridge&amp;amp;#10;· WebSocket ⇄ ACP&amp;amp;#10;· Event broadcast&amp;amp;#10;· Permission routing&amp;amp;#10;· History replay&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;140&quot; width=&quot;280&quot; height=&quot;130&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;7&quot; value=&quot;agent&amp;amp;#10;ACP session&amp;amp;#10;lifecycle&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;300&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;8&quot; value=&quot;files&amp;amp;#10;Workspace&amp;amp;#10;file API&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;515&quot; y=&quot;300&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;9&quot; value=&quot;terminal&amp;amp;#10;PTY per&amp;amp;#10;connection&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;410&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;10&quot; value=&quot;mockagent&amp;amp;#10;Demo agent&amp;amp;#10;(testing)&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;515&quot; y=&quot;410&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;11&quot; value=&quot;ACP Agent&amp;amp;#10;(claude-code-acp / Gemini CLI)&amp;amp;#10;&amp;amp;#10;JSON-RPC over stdio&amp;amp;#10;session_update · permission_request&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#0062FF;fontColor=#0062FF;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;800&quot; y=&quot;230&quot; width=&quot;400&quot; height=&quot;130&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;12&quot; value=&quot;Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=15;fontStyle=0;strokeWidth=2;dashed=1;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;560&quot; width=&quot;1180&quot; height=&quot;60&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;13&quot; value=&quot;1. load SPA&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;3&quot; target=&quot;5&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;14&quot; value=&quot;2. WebSocket&amp;amp;#10;/ws&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.7272727272727273;exitDx=0;exitDy=0;entryX=0;entryY=0.3076923076923077;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;3&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;15&quot; value=&quot;3. prompt +&amp;amp;#10;permission&amp;amp;#10;responses&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.6538461538461539;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;16&quot; value=&quot;4. session_update&amp;amp;#10;events (replay)&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;6&quot; target=&quot;4&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;Array as=&quot;points&quot;&gt;&lt;mxPoint x=&quot;310&quot; y=&quot;230&quot;/&gt;&lt;mxPoint x=&quot;280&quot; y=&quot;230&quot;/&gt;&lt;/Array&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;17&quot; value=&quot;5. ACP&amp;amp;#10;lifecycle&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=0.2857142857142857;exitY=1;exitDx=0;exitDy=0;entryX=0.4962962962962963;entryY=0;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;6&quot; target=&quot;7&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;18&quot; value=&quot;6. stdio&amp;amp;#10;JSON-RPC&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;7&quot; target=&quot;11&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;19&quot; value=&quot;7. updates +&amp;amp;#10;permissions&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;11&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;Array as=&quot;points&quot;&gt;&lt;mxPoint x=&quot;720&quot; y=&quot;200&quot;/&gt;&lt;mxPoint x=&quot;650&quot; y=&quot;200&quot;/&gt;&lt;/Array&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;20&quot; value=&quot;file ops&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;exitX=1;exitY=0.8666666666666667;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;8&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;21&quot; value=&quot;shell I/O&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;9&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;/root&gt;&lt;/mxGraphModel&gt;&lt;/diagram&gt;&lt;/mxfile&gt;">
2- <defs><marker id="arrow-dark" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#15202b"/></marker><marker id="arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0062FF"/></marker></defs>
3- <path d="M 242 75 L 364 75" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>
4- <rect x="254.2" y="62.5" width="97.6" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>
5- <text x="303" y="75" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">1. load SPA</text>
6- <path d="M 242 100 L 364 180" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>
7- <rect x="250.4" y="119" width="105.19999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>
8- <text x="303" y="131.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">2. WebSocket</text>
9- <text x="303" y="148.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">/ws</text>
10- <path d="M 242 225 L 364 225" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>
11- <rect x="254.2" y="195.5" width="97.6" height="59" rx="4" fill="#fdfdfb" opacity="0.92"/>
12- <text x="303" y="208" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">3. prompt +</text>
13- <text x="303" y="225" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">permission</text>
14- <text x="303" y="242" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">responses</text>
15- <path d="M 368 205 L 310 230 L 280 230 L 246 225" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>
16- <rect x="267.4" y="196.5" width="143.2" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>
17- <text x="339" y="209" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">4. session_update</text>
18- <text x="339" y="226" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">events (replay)</text>
19- <path d="M 450 272 L 437 294" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>
20- <rect x="402.3" y="262" width="82.39999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>
21- <text x="443.5" y="274.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">5. ACP</text>
22- <text x="443.5" y="291.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">lifecycle</text>
23- <path d="M 507 345 L 794 295" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>
24- <rect x="613.1" y="299" width="74.8" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>
25- <text x="650.5" y="311.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">6. stdio</text>
26- <text x="650.5" y="328.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">JSON-RPC</text>
27- <path d="M 798 295 L 720 200 L 650 200 L 656 205" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>
28- <rect x="706.4" y="226.5" width="105.19999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>
29- <text x="759" y="239" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">7. updates +</text>
30- <text x="759" y="256" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">permissions</text>
31- <path d="M 242 280 L 509 345" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>
32- <rect x="338.1" y="300" width="74.8" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>
33- <text x="375.5" y="312.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">file ops</text>
34- <path d="M 130 302 L 364 455" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>
35- <rect x="205.8" y="366" width="82.39999999999999" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>
36- <text x="247" y="378.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">shell I/O</text>
37- <rect x="20" y="20" width="220" height="110" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/>
38- <text x="130" y="64.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Browser</text>
39- <text x="130" y="85.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">React SPA</text>
40- <rect x="20" y="150" width="220" height="150" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/>
41- <text x="130" y="172.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">UI Components</text>
42- <text x="130" y="193.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Agent Panel</text>
43- <text x="130" y="214.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Workspace Panel</text>
44- <text x="130" y="235.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· File Tree</text>
45- <text x="130" y="256.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Monaco Editor</text>
46- <text x="130" y="277.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Terminal (xterm.js)</text>
47- <rect x="370" y="20" width="280" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>
48- <text x="510" y="54.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">httpserver</text>
49- <text x="510" y="75.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Serves SPA + /ws</text>
50- <rect x="370" y="140" width="280" height="130" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>
51- <text x="510" y="163" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">bridge</text>
52- <text x="510" y="184" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· WebSocket ⇄ ACP</text>
53- <text x="510" y="205" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· Event broadcast</text>
54- <text x="510" y="226" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· Permission routing</text>
55- <text x="510" y="247" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· History replay</text>
56- <rect x="370" y="300" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>
57- <text x="437.5" y="324" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">agent</text>
58- <text x="437.5" y="345" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">ACP session</text>
59- <text x="437.5" y="366" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">lifecycle</text>
60- <rect x="515" y="300" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>
61- <text x="582.5" y="324" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">files</text>
62- <text x="582.5" y="345" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Workspace</text>
63- <text x="582.5" y="366" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">file API</text>
64- <rect x="370" y="410" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>
65- <text x="437.5" y="434" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">terminal</text>
66- <text x="437.5" y="455" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">PTY per</text>
67- <text x="437.5" y="476" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">connection</text>
68- <rect x="515" y="410" width="135" height="90" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/>
69- <text x="582.5" y="434" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">mockagent</text>
70- <text x="582.5" y="455" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Demo agent</text>
71- <text x="582.5" y="476" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">(testing)</text>
72- <rect x="800" y="230" width="400" height="130" rx="10" ry="10" fill="#fdfdfb" stroke="#0062FF" stroke-width="2"/>
73- <text x="1000" y="253" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">ACP Agent</text>
74- <text x="1000" y="274" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">(claude-code-acp / Gemini CLI)</text>
75- <text x="1000" y="295" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF"></text>
76- <text x="1000" y="316" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">JSON-RPC over stdio</text>
77- <text x="1000" y="337" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">session_update · permission_request</text>
78- <rect x="20" y="560" width="1180" height="60" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2" stroke-dasharray="6 5"/>
79- <text x="610" y="590" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.</text>
80-</svg>
1+<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1182px" height="602px" viewBox="-0.5 -0.5 1182 602" content="&lt;mxfile&gt;&lt;diagram name=&quot;Ori Architecture&quot; id=&quot;diagram-1&quot;&gt;7Vpbc9o4FP41nkkfwsh38xgoSbsz3TIlO2mfOsIW4I2xvLIgsL9+JVvyTTYF1pBmJkPGsY6OZUnfp3MDzRyvdw8EJqsvOECRZoBgp5kfNcPQdXfI/nHJPpfYnpcLliQMhFIpmIX/IiEEQroJA5TWFCnGEQ2TutDHcYx8WpNBQvBLXW2Bo/pbE7hEimDmw0iVPoUBXcl1OcOy4xMKlyvxas9w8o41lMpiJekKBvilIjInmjkmGNP8br0bo4hvntyX/Ln7jt5iYgTF9JgHzPyBLYw2Ym0jvj2IaIYD14lmjjTDZNtujr4hyHbSALPpnZg63cv9IHgTB4gPqTNNSHwBmc7WM3pZhRTNEuhzyQsjBJOt6DoS2oswisY4wiQbylwE7DNn8pQS/IwqPbptAIP3LHBMu+Tyxa5si0mCYkQJmJGtrblbYgO3iFC0q4jE7j0gvEaU7JmK6JVA7uvNl5IWhWxVYYQuqQwFFZfFyCVa7EYA1g6epYD312fWHuN1gmO2pFQBURsb2shlOndLvmQDTGHMz2aX2hMmz2kG3S9V78OIaz0ShLqVvuAY+pjdTIKQYpVkheIjIuswhny1NzvKGoO/0w+X5B3y0DyAvfNOvxLvdPtY4tk9EM9WiLeiNGFWY9tiOGZcnErLwd4+yq73zAhfEM8CnaPxLCzPq+BpOcYvDYnXguewBzgdBc45c7vLA+f4Cc1n2H9G3IRoE0PzXM2zuFkZT7sfmmxzmzMnGAY+TGm36pQf/zQNccwajBU0jJfd2p/ClBkTvpkEJRHcv/Oqyiu9biisI4mlmz0wy1WYBXPH04Ay4w1IkYC80RuFC+Tvfe5f3oGVwJpu3QOYjgqsbtqXsRiegivbTaTGG5X4odGzyMOFu+nnd1BLUG3HroMKrgjqUAGVFlFYA73p4w++1BZvL1Ku7Bi/49p1WK1rHlZdV4DN7a1IApyIvWw0J3xAw1nyxo0fwU2Abn2Wut9CP/nQqtUq/GP29c/bb1M2K4CzcJBRIAhxq64w+D83SQApNweFS0+KAOAnQf9sEA8WXiPpBMAx7u9VOtXkV6eTBxpZp6nSyQKXcuq6ofDpged0c8giwjjIIjwePqZ5rJdXE8qQkYsplsGiZMe4Ghhm0R4QoQLI2VE8BrPJCDuDgvIlXIPhnvmVImasMCkVc5QD0RXXfIGh0PTZyIPXodlJOaZ9VG0jgOmqmHYPnGsknHabBdPbAkmnD8qpdSqdQQUiRhitvSaFGAPlDmFCV3iJmSeblNJRHdkKbOpmHgZMAmMdALATgRRviC/mLFZJIVkioSV8Al/NQZQIiiANt/UC5f/acrW6ZAzqqV8zH2vN6X8zHNAupN/F+Pz+Bz9AA9eofUzR+XEnjlfW2MtGzLbye7WRD2IC1xkaxdWVveUoWUsOcy4jnFdjhFr2MTkjEoLXSVYJ4KWdBimSSibf6CIoTZhVRm+UM/ZZJHFs02M5ubwO+yCJdT5JhHG/BQMArHruIU3P0TwSo09xmLltqYIXixRRhWjFJI7jnlqjsgZlyaCIIBsUQ9u8DA5u8sqQWkK+LNVaw8QWqhV6x3ntKviOCr51MvicjXXwwTng3xHCq2+FQsKpkLZwQ6ZFViOOtRvfVp2mz27yGVyUiWpNyx5o7aXP7sLVb2rhwMDwbFe3ymvF5OlHGryBNXSMyp9Zs4B9GLwWzruv5hXVWpgzqGS9dUaU2fHbIEQfLs/uA3JXhVzWNY61c4zcYDisGZBb+ywnd6qdcxv5uilcbZeda+obQ1u7up1Ty4HuoJaNHw73rh3VXcHVSsJdNBo/j2DKzxAOO1LHPqhfJ9gZ5JHTaXxBwCQ4eVvE6N2oVcnjnWrAgFU3X+ZZYZpCB93r+NpBDpGfAvFUG696NT2GWrBmiGQqn9mzX98WgYrQSnrPU2KpC3jSlmxxeKXgiTXLn7blxCh/IGhO/gM=&lt;/diagram&gt;&lt;/mxfile&gt;">
2+ <defs/>
3+ <g>
4+ <rect x="1" y="1" width="220" height="110" rx="13.2" ry="13.2" fill="#fdfdfb" stroke="#15202b" stroke-width="2" pointer-events="all"/>
5+ <g transform="translate(-0.5 -0.5)">
6+ <switch>
7+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
8+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 56px; margin-left: 2px;">
9+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
10+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
11+ Browser
12+React SPA
13+ </div>
14+ </div>
15+ </div>
16+ </foreignObject>
17+ <text x="111" y="61" fill="#15202b" font-family="Helvetica" font-size="17px" text-anchor="middle">
18+ Browser...
19+ </text>
20+ </switch>
21+ </g>
22+ <rect x="1" y="131" width="220" height="150" rx="18" ry="18" fill="#e8ebda" stroke="#15202b" stroke-width="2" pointer-events="all"/>
23+ <g transform="translate(-0.5 -0.5)">
24+ <switch>
25+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
26+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 206px; margin-left: 2px;">
27+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
28+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
29+ UI Components
30+· Agent Panel
31+· Workspace Panel
32+· File Tree
33+· Monaco Editor
34+· Terminal (xterm.js)
35+ </div>
36+ </div>
37+ </div>
38+ </foreignObject>
39+ <text x="111" y="211" fill="#15202b" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
40+ UI Components...
41+ </text>
42+ </switch>
43+ </g>
44+ <rect x="443" y="1" width="280" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
45+ <g transform="translate(-0.5 -0.5)">
46+ <switch>
47+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
48+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 278px; height: 1px; padding-top: 46px; margin-left: 444px;">
49+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
50+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
51+ httpserver
52+Serves SPA + /ws
53+ </div>
54+ </div>
55+ </div>
56+ </foreignObject>
57+ <text x="583" y="51" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
58+ httpserver...
59+ </text>
60+ </switch>
61+ </g>
62+ <rect x="442" y="121" width="280" height="130" rx="15.6" ry="15.6" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
63+ <g transform="translate(-0.5 -0.5)">
64+ <switch>
65+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
66+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 278px; height: 1px; padding-top: 186px; margin-left: 443px;">
67+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
68+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
69+ bridge
70+· WebSocket ⇄ ACP
71+· Event broadcast
72+· Permission routing
73+· History replay
74+ </div>
75+ </div>
76+ </div>
77+ </foreignObject>
78+ <text x="582" y="191" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
79+ bridge...
80+ </text>
81+ </switch>
82+ </g>
83+ <rect x="351" y="341" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
84+ <g transform="translate(-0.5 -0.5)">
85+ <switch>
86+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
87+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 386px; margin-left: 352px;">
88+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
89+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
90+ agent
91+ACP session
92+lifecycle
93+ </div>
94+ </div>
95+ </div>
96+ </foreignObject>
97+ <text x="419" y="391" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
98+ agent...
99+ </text>
100+ </switch>
101+ </g>
102+ <rect x="546" y="281" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
103+ <g transform="translate(-0.5 -0.5)">
104+ <switch>
105+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
106+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 326px; margin-left: 547px;">
107+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
108+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
109+ files
110+Workspace
111+file API
112+ </div>
113+ </div>
114+ </div>
115+ </foreignObject>
116+ <text x="614" y="331" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
117+ files...
118+ </text>
119+ </switch>
120+ </g>
121+ <rect x="351" y="441" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
122+ <g transform="translate(-0.5 -0.5)">
123+ <switch>
124+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
125+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 486px; margin-left: 352px;">
126+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
127+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
128+ terminal
129+PTY per
130+connection
131+ </div>
132+ </div>
133+ </div>
134+ </foreignObject>
135+ <text x="419" y="491" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
136+ terminal...
137+ </text>
138+ </switch>
139+ </g>
140+ <rect x="781" y="211" width="400" height="130" rx="15.6" ry="15.6" fill="#fdfdfb" stroke="#0062ff" stroke-width="2" pointer-events="all"/>
141+ <g transform="translate(-0.5 -0.5)">
142+ <switch>
143+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
144+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 276px; margin-left: 782px;">
145+ <div data-drawio-colors="color: #0062FF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
146+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
147+ ACP Agent
148+ <br/>
149+ (claude-code-acp)
150+ <br/>
151+ <br/>
152+ JSON-RPC over stdio
153+ <br/>
154+ session_update · permission_request
155+ </div>
156+ </div>
157+ </div>
158+ </foreignObject>
159+ <text x="981" y="281" fill="#0062FF" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
160+ ACP Agent...
161+ </text>
162+ </switch>
163+ </g>
164+ <rect x="1" y="541" width="1180" height="60" rx="7.2" ry="7.2" fill="#fdfdfb" stroke="#15202b" stroke-width="2" stroke-dasharray="6 6" pointer-events="all"/>
165+ <g transform="translate(-0.5 -0.5)">
166+ <switch>
167+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
168+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1178px; height: 1px; padding-top: 571px; margin-left: 2px;">
169+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
170+ <div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
171+ Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.
172+ </div>
173+ </div>
174+ </div>
175+ </foreignObject>
176+ <text x="591" y="576" fill="#15202b" font-family="Helvetica" font-size="15px" text-anchor="middle">
177+ Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.
178+ </text>
179+ </switch>
180+ </g>
181+ <path d="M 221 56 L 322 56 Q 332 56 332 51 L 332 48.5 Q 332 46 342 46 L 434.76 46" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
182+ <path d="M 440.76 46 L 432.76 50 L 434.76 46 L 432.76 42 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
183+ <g transform="translate(-0.5 -0.5)">
184+ <switch>
185+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
186+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 51px; margin-left: 332px;">
187+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
188+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
189+ 1. load SPA
190+ </div>
191+ </div>
192+ </div>
193+ </foreignObject>
194+ <text x="332" y="55" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
195+ 1. load SPA
196+ </text>
197+ </switch>
198+ </g>
199+ <path d="M 221 81 L 321.5 81 Q 331.5 81 331.5 91 L 331.5 151 Q 331.5 161 341.5 161 L 433.76 161" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
200+ <path d="M 439.76 161 L 431.76 165 L 433.76 161 L 431.76 157 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
201+ <g transform="translate(-0.5 -0.5)">
202+ <switch>
203+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
204+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 122px; margin-left: 332px;">
205+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
206+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
207+ 2. WebSocket
208+/ws
209+ </div>
210+ </div>
211+ </div>
212+ </foreignObject>
213+ <text x="332" y="126" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
214+ 2. WebSocket...
215+ </text>
216+ </switch>
217+ </g>
218+ <path d="M 221 206 L 433.76 206" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
219+ <path d="M 439.76 206 L 431.76 210 L 433.76 206 L 431.76 202 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
220+ <g transform="translate(-0.5 -0.5)">
221+ <switch>
222+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
223+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 181px; margin-left: 331px;">
224+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
225+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
226+ 3. prompt +
227+permission
228+responses
229+ </div>
230+ </div>
231+ </div>
232+ </foreignObject>
233+ <text x="331" y="185" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
234+ 3. prompt +...
235+ </text>
236+ </switch>
237+ </g>
238+ <path d="M 442 231 L 331 231 Q 321 231 311 231 L 229.24 231" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
239+ <path d="M 223.24 231 L 231.24 227 L 229.24 231 L 231.24 235 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
240+ <g transform="translate(-0.5 -0.5)">
241+ <switch>
242+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
243+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 251px; margin-left: 374px;">
244+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
245+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
246+ 4. session_update
247+events (replay)
248+ </div>
249+ </div>
250+ </div>
251+ </foreignObject>
252+ <text x="374" y="255" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
253+ 4. session_update...
254+ </text>
255+ </switch>
256+ </g>
257+ <path d="M 522 251 L 522 286 Q 522 296 512 296 L 428 296 Q 418 296 418 306 L 418 332.76" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
258+ <path d="M 418 338.76 L 414 330.76 L 418 332.76 L 422 330.76 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
259+ <g transform="translate(-0.5 -0.5)">
260+ <switch>
261+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
262+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 296px; margin-left: 470px;">
263+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
264+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
265+ 5. ACP
266+lifecycle
267+ </div>
268+ </div>
269+ </div>
270+ </foreignObject>
271+ <text x="470" y="300" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
272+ 5. ACP...
273+ </text>
274+ </switch>
275+ </g>
276+ <path d="M 486 386 L 486 336 Q 486 326 496 326 L 671 326 Q 681 326 681 316 L 681 286 Q 681 276 691 276 L 772.76 276" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
277+ <path d="M 778.76 276 L 770.76 280 L 772.76 276 L 770.76 272 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
278+ <g transform="translate(-0.5 -0.5)">
279+ <switch>
280+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
281+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 381px; margin-left: 671px;">
282+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
283+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
284+ 6. stdio
285+JSON-RPC
286+ </div>
287+ </div>
288+ </div>
289+ </foreignObject>
290+ <text x="671" y="385" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
291+ 6. stdio...
292+ </text>
293+ </switch>
294+ </g>
295+ <path d="M 981 211 L 981 191 Q 981 181 971 181 L 730.24 181" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
296+ <path d="M 724.24 181 L 732.24 177 L 730.24 181 L 732.24 185 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
297+ <g transform="translate(-0.5 -0.5)">
298+ <switch>
299+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
300+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 181px; margin-left: 866px;">
301+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
302+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
303+ 7. updates +
304+permissions
305+ </div>
306+ </div>
307+ </div>
308+ </foreignObject>
309+ <text x="866" y="185" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
310+ 7. updates +...
311+ </text>
312+ </switch>
313+ </g>
314+ <path d="M 166 281 L 346 281 Q 356 281 356 291 L 356 316 Q 356 326 366 326 L 537.76 326" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
315+ <path d="M 543.76 326 L 535.76 330 L 537.76 326 L 535.76 322 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
316+ <g transform="translate(-0.5 -0.5)">
317+ <switch>
318+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
319+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 326px;">
320+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
321+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
322+ file ops
323+ </div>
324+ </div>
325+ </div>
326+ </foreignObject>
327+ <text x="326" y="316" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
328+ file ops
329+ </text>
330+ </switch>
331+ </g>
332+ <path d="M 111 281 L 111 476 Q 111 486 121 486 L 342.76 486" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
333+ <path d="M 348.76 486 L 340.76 490 L 342.76 486 L 340.76 482 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
334+ <g transform="translate(-0.5 -0.5)">
335+ <switch>
336+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
337+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 486px; margin-left: 129px;">
338+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
339+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
340+ shell I/O
341+ </div>
342+ </div>
343+ </div>
344+ </foreignObject>
345+ <text x="129" y="490" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
346+ shell I/O
347+ </text>
348+ </switch>
349+ </g>
350+ </g>
351+ <switch>
352+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
353+ <a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
354+ <text text-anchor="middle" font-size="10px" x="50%" y="100%">
355+ Text is not SVG - cannot display
356+ </text>
357+ </a>
358+ </switch>
359+</svg>
\ No newline at end of file
@@ -1,80 +1,359 @@
1-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1220" height="640" viewBox="0 0 1220 640" content="&lt;mxfile host=&quot;Electron&quot; agent=&quot;make-diagram.mjs&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Ori Architecture&quot; id=&quot;diagram-1&quot;&gt;&lt;mxGraphModel dx=&quot;1000&quot; dy=&quot;600&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1169&quot; pageHeight=&quot;826&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&lt;root&gt;&lt;mxCell id=&quot;0&quot;/&gt;&lt;mxCell id=&quot;1&quot; parent=&quot;0&quot;/&gt;&lt;mxCell id=&quot;3&quot; value=&quot;Browser&amp;amp;#10;React SPA&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;20&quot; width=&quot;220&quot; height=&quot;110&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;4&quot; value=&quot;UI Components&amp;amp;#10;· Agent Panel&amp;amp;#10;· Workspace Panel&amp;amp;#10;· File Tree&amp;amp;#10;· Monaco Editor&amp;amp;#10;· Terminal (xterm.js)&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;150&quot; width=&quot;220&quot; height=&quot;150&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;5&quot; value=&quot;httpserver&amp;amp;#10;Serves SPA + /ws&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;20&quot; width=&quot;280&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;6&quot; value=&quot;bridge&amp;amp;#10;· WebSocket ⇄ ACP&amp;amp;#10;· Event broadcast&amp;amp;#10;· Permission routing&amp;amp;#10;· History replay&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;140&quot; width=&quot;280&quot; height=&quot;130&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;7&quot; value=&quot;agent&amp;amp;#10;ACP session&amp;amp;#10;lifecycle&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;300&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;8&quot; value=&quot;files&amp;amp;#10;Workspace&amp;amp;#10;file API&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;515&quot; y=&quot;300&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;9&quot; value=&quot;terminal&amp;amp;#10;PTY per&amp;amp;#10;connection&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;370&quot; y=&quot;410&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;10&quot; value=&quot;mockagent&amp;amp;#10;Demo agent&amp;amp;#10;(testing)&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;515&quot; y=&quot;410&quot; width=&quot;135&quot; height=&quot;90&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;11&quot; value=&quot;ACP Agent&amp;amp;#10;(claude-code-acp / Gemini CLI)&amp;amp;#10;&amp;amp;#10;JSON-RPC over stdio&amp;amp;#10;session_update · permission_request&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#0062FF;fontColor=#0062FF;fontSize=17;fontStyle=1;strokeWidth=2;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;800&quot; y=&quot;230&quot; width=&quot;400&quot; height=&quot;130&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;12&quot; value=&quot;Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.&quot; style=&quot;rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=15;fontStyle=0;strokeWidth=2;dashed=1;&quot; vertex=&quot;1&quot; parent=&quot;1&quot;&gt;&lt;mxGeometry x=&quot;20&quot; y=&quot;560&quot; width=&quot;1180&quot; height=&quot;60&quot; as=&quot;geometry&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;13&quot; value=&quot;1. load SPA&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;3&quot; target=&quot;5&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;14&quot; value=&quot;2. WebSocket&amp;amp;#10;/ws&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.7272727272727273;exitDx=0;exitDy=0;entryX=0;entryY=0.3076923076923077;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;3&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;15&quot; value=&quot;3. prompt +&amp;amp;#10;permission&amp;amp;#10;responses&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.6538461538461539;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;16&quot; value=&quot;4. session_update&amp;amp;#10;events (replay)&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;6&quot; target=&quot;4&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;Array as=&quot;points&quot;&gt;&lt;mxPoint x=&quot;310&quot; y=&quot;230&quot;/&gt;&lt;mxPoint x=&quot;280&quot; y=&quot;230&quot;/&gt;&lt;/Array&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;17&quot; value=&quot;5. ACP&amp;amp;#10;lifecycle&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=0.2857142857142857;exitY=1;exitDx=0;exitDy=0;entryX=0.4962962962962963;entryY=0;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;6&quot; target=&quot;7&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;18&quot; value=&quot;6. stdio&amp;amp;#10;JSON-RPC&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;7&quot; target=&quot;11&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;19&quot; value=&quot;7. updates +&amp;amp;#10;permissions&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;11&quot; target=&quot;6&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;Array as=&quot;points&quot;&gt;&lt;mxPoint x=&quot;720&quot; y=&quot;200&quot;/&gt;&lt;mxPoint x=&quot;650&quot; y=&quot;200&quot;/&gt;&lt;/Array&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;20&quot; value=&quot;file ops&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;exitX=1;exitY=0.8666666666666667;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;8&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;mxCell id=&quot;21&quot; value=&quot;shell I/O&quot; style=&quot;edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;4&quot; target=&quot;9&quot;&gt;&lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot;&gt;&lt;/mxGeometry&gt;&lt;/mxCell&gt;&lt;/root&gt;&lt;/mxGraphModel&gt;&lt;/diagram&gt;&lt;/mxfile&gt;">1+<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1182px" height="602px" viewBox="-0.5 -0.5 1182 602" content="&lt;mxfile&gt;&lt;diagram name=&quot;Ori Architecture&quot; id=&quot;diagram-1&quot;&gt;7Vpbc9o4FP41nkkfwsh38xgoSbsz3TIlO2mfOsIW4I2xvLIgsL9+JVvyTTYF1pBmJkPGsY6OZUnfp3MDzRyvdw8EJqsvOECRZoBgp5kfNcPQdXfI/nHJPpfYnpcLliQMhFIpmIX/IiEEQroJA5TWFCnGEQ2TutDHcYx8WpNBQvBLXW2Bo/pbE7hEimDmw0iVPoUBXcl1OcOy4xMKlyvxas9w8o41lMpiJekKBvilIjInmjkmGNP8br0bo4hvntyX/Ln7jt5iYgTF9JgHzPyBLYw2Ym0jvj2IaIYD14lmjjTDZNtujr4hyHbSALPpnZg63cv9IHgTB4gPqTNNSHwBmc7WM3pZhRTNEuhzyQsjBJOt6DoS2oswisY4wiQbylwE7DNn8pQS/IwqPbptAIP3LHBMu+Tyxa5si0mCYkQJmJGtrblbYgO3iFC0q4jE7j0gvEaU7JmK6JVA7uvNl5IWhWxVYYQuqQwFFZfFyCVa7EYA1g6epYD312fWHuN1gmO2pFQBURsb2shlOndLvmQDTGHMz2aX2hMmz2kG3S9V78OIaz0ShLqVvuAY+pjdTIKQYpVkheIjIuswhny1NzvKGoO/0w+X5B3y0DyAvfNOvxLvdPtY4tk9EM9WiLeiNGFWY9tiOGZcnErLwd4+yq73zAhfEM8CnaPxLCzPq+BpOcYvDYnXguewBzgdBc45c7vLA+f4Cc1n2H9G3IRoE0PzXM2zuFkZT7sfmmxzmzMnGAY+TGm36pQf/zQNccwajBU0jJfd2p/ClBkTvpkEJRHcv/Oqyiu9biisI4mlmz0wy1WYBXPH04Ay4w1IkYC80RuFC+Tvfe5f3oGVwJpu3QOYjgqsbtqXsRiegivbTaTGG5X4odGzyMOFu+nnd1BLUG3HroMKrgjqUAGVFlFYA73p4w++1BZvL1Ku7Bi/49p1WK1rHlZdV4DN7a1IApyIvWw0J3xAw1nyxo0fwU2Abn2Wut9CP/nQqtUq/GP29c/bb1M2K4CzcJBRIAhxq64w+D83SQApNweFS0+KAOAnQf9sEA8WXiPpBMAx7u9VOtXkV6eTBxpZp6nSyQKXcuq6ofDpged0c8giwjjIIjwePqZ5rJdXE8qQkYsplsGiZMe4Ghhm0R4QoQLI2VE8BrPJCDuDgvIlXIPhnvmVImasMCkVc5QD0RXXfIGh0PTZyIPXodlJOaZ9VG0jgOmqmHYPnGsknHabBdPbAkmnD8qpdSqdQQUiRhitvSaFGAPlDmFCV3iJmSeblNJRHdkKbOpmHgZMAmMdALATgRRviC/mLFZJIVkioSV8Al/NQZQIiiANt/UC5f/acrW6ZAzqqV8zH2vN6X8zHNAupN/F+Pz+Bz9AA9eofUzR+XEnjlfW2MtGzLbye7WRD2IC1xkaxdWVveUoWUsOcy4jnFdjhFr2MTkjEoLXSVYJ4KWdBimSSibf6CIoTZhVRm+UM/ZZJHFs02M5ubwO+yCJdT5JhHG/BQMArHruIU3P0TwSo09xmLltqYIXixRRhWjFJI7jnlqjsgZlyaCIIBsUQ9u8DA5u8sqQWkK+LNVaw8QWqhV6x3ntKviOCr51MvicjXXwwTng3xHCq2+FQsKpkLZwQ6ZFViOOtRvfVp2mz27yGVyUiWpNyx5o7aXP7sLVb2rhwMDwbFe3ymvF5OlHGryBNXSMyp9Zs4B9GLwWzruv5hXVWpgzqGS9dUaU2fHbIEQfLs/uA3JXhVzWNY61c4zcYDisGZBb+ywnd6qdcxv5uilcbZeda+obQ1u7up1Ty4HuoJaNHw73rh3VXcHVSsJdNBo/j2DKzxAOO1LHPqhfJ9gZ5JHTaXxBwCQ4eVvE6N2oVcnjnWrAgFU3X+ZZYZpCB93r+NpBDpGfAvFUG696NT2GWrBmiGQqn9mzX98WgYrQSnrPU2KpC3jSlmxxeKXgiTXLn7blxCh/IGhO/gM=&lt;/diagram&gt;&lt;/mxfile&gt;">
2- <defs><marker id="arrow-dark" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#15202b"/></marker><marker id="arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0062FF"/></marker></defs>2+ <defs/>
3- <path d="M 242 75 L 364 75" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>3+ <g>
4- <rect x="254.2" y="62.5" width="97.6" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>4+ <rect x="1" y="1" width="220" height="110" rx="13.2" ry="13.2" fill="#fdfdfb" stroke="#15202b" stroke-width="2" pointer-events="all"/>
5- <text x="303" y="75" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">1. load SPA</text>5+ <g transform="translate(-0.5 -0.5)">
6- <path d="M 242 100 L 364 180" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>6+ <switch>
7- <rect x="250.4" y="119" width="105.19999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>7+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
8- <text x="303" y="131.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">2. WebSocket</text>8+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 56px; margin-left: 2px;">
9- <text x="303" y="148.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">/ws</text>9+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
10- <path d="M 242 225 L 364 225" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>10+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
11- <rect x="254.2" y="195.5" width="97.6" height="59" rx="4" fill="#fdfdfb" opacity="0.92"/>11+ Browser
12- <text x="303" y="208" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">3. prompt +</text>12+React SPA
13- <text x="303" y="225" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">permission</text>13+ </div>
14- <text x="303" y="242" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">responses</text>14+ </div>
15- <path d="M 368 205 L 310 230 L 280 230 L 246 225" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>15+ </div>
16- <rect x="267.4" y="196.5" width="143.2" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>16+ </foreignObject>
17- <text x="339" y="209" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">4. session_update</text>17+ <text x="111" y="61" fill="#15202b" font-family="Helvetica" font-size="17px" text-anchor="middle">
18- <text x="339" y="226" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">events (replay)</text>18+ Browser...
19- <path d="M 450 272 L 437 294" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>19+ </text>
20- <rect x="402.3" y="262" width="82.39999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>20+ </switch>
21- <text x="443.5" y="274.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">5. ACP</text>21+ </g>
22- <text x="443.5" y="291.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">lifecycle</text>22+ <rect x="1" y="131" width="220" height="150" rx="18" ry="18" fill="#e8ebda" stroke="#15202b" stroke-width="2" pointer-events="all"/>
23- <path d="M 507 345 L 794 295" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/>23+ <g transform="translate(-0.5 -0.5)">
24- <rect x="613.1" y="299" width="74.8" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>24+ <switch>
25- <text x="650.5" y="311.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">6. stdio</text>25+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
26- <text x="650.5" y="328.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#15202b">JSON-RPC</text>26+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 206px; margin-left: 2px;">
27- <path d="M 798 295 L 720 200 L 650 200 L 656 205" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>27+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
28- <rect x="706.4" y="226.5" width="105.19999999999999" height="42" rx="4" fill="#fdfdfb" opacity="0.92"/>28+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
29- <text x="759" y="239" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">7. updates +</text>29+ UI Components
30- <text x="759" y="256" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">permissions</text>30+· Agent Panel
31- <path d="M 242 280 L 509 345" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>31+· Workspace Panel
32- <rect x="338.1" y="300" width="74.8" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>32+· File Tree
33- <text x="375.5" y="312.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">file ops</text>33+· Monaco Editor
34- <path d="M 130 302 L 364 455" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/>34+· Terminal (xterm.js)
35- <rect x="205.8" y="366" width="82.39999999999999" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/>35+ </div>
36- <text x="247" y="378.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" fill="#0062FF">shell I/O</text>36+ </div>
37- <rect x="20" y="20" width="220" height="110" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/>37+ </div>
38- <text x="130" y="64.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Browser</text>38+ </foreignObject>
39- <text x="130" y="85.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">React SPA</text>39+ <text x="111" y="211" fill="#15202b" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
40- <rect x="20" y="150" width="220" height="150" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/>40+ UI Components...
41- <text x="130" y="172.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">UI Components</text>41+ </text>
42- <text x="130" y="193.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Agent Panel</text>42+ </switch>
43- <text x="130" y="214.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Workspace Panel</text>43+ </g>
44- <text x="130" y="235.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· File Tree</text>44+ <rect x="443" y="1" width="280" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
45- <text x="130" y="256.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Monaco Editor</text>45+ <g transform="translate(-0.5 -0.5)">
46- <text x="130" y="277.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">· Terminal (xterm.js)</text>46+ <switch>
47- <rect x="370" y="20" width="280" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>47+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
48- <text x="510" y="54.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">httpserver</text>48+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 278px; height: 1px; padding-top: 46px; margin-left: 444px;">
49- <text x="510" y="75.5" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Serves SPA + /ws</text>49+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
50- <rect x="370" y="140" width="280" height="130" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>50+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
51- <text x="510" y="163" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">bridge</text>51+ httpserver
52- <text x="510" y="184" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· WebSocket ⇄ ACP</text>52+Serves SPA + /ws
53- <text x="510" y="205" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· Event broadcast</text>53+ </div>
54- <text x="510" y="226" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· Permission routing</text>54+ </div>
55- <text x="510" y="247" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">· History replay</text>55+ </div>
56- <rect x="370" y="300" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>56+ </foreignObject>
57- <text x="437.5" y="324" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">agent</text>57+ <text x="583" y="51" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
58- <text x="437.5" y="345" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">ACP session</text>58+ httpserver...
59- <text x="437.5" y="366" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">lifecycle</text>59+ </text>
60- <rect x="515" y="300" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>60+ </switch>
61- <text x="582.5" y="324" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">files</text>61+ </g>
62- <text x="582.5" y="345" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Workspace</text>62+ <rect x="442" y="121" width="280" height="130" rx="15.6" ry="15.6" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
63- <text x="582.5" y="366" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">file API</text>63+ <g transform="translate(-0.5 -0.5)">
64- <rect x="370" y="410" width="135" height="90" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/>64+ <switch>
65- <text x="437.5" y="434" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">terminal</text>65+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
66- <text x="437.5" y="455" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">PTY per</text>66+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 278px; height: 1px; padding-top: 186px; margin-left: 443px;">
67- <text x="437.5" y="476" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">connection</text>67+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
68- <rect x="515" y="410" width="135" height="90" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/>68+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
69- <text x="582.5" y="434" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">mockagent</text>69+ bridge
70- <text x="582.5" y="455" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Demo agent</text>70+· WebSocket ⇄ ACP
71- <text x="582.5" y="476" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">(testing)</text>71+· Event broadcast
72- <rect x="800" y="230" width="400" height="130" rx="10" ry="10" fill="#fdfdfb" stroke="#0062FF" stroke-width="2"/>72+· Permission routing
73- <text x="1000" y="253" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">ACP Agent</text>73+· History replay
74- <text x="1000" y="274" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">(claude-code-acp / Gemini CLI)</text>74+ </div>
75- <text x="1000" y="295" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF"></text>75+ </div>
76- <text x="1000" y="316" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">JSON-RPC over stdio</text>76+ </div>
77- <text x="1000" y="337" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#0062FF">session_update · permission_request</text>77+ </foreignObject>
78- <rect x="20" y="560" width="1180" height="60" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2" stroke-dasharray="6 5"/>78+ <text x="582" y="191" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
79- <text x="610" y="590" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.</text>79+ bridge...
80-</svg>80+ </text>
81+ </switch>
82+ </g>
83+ <rect x="351" y="341" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
84+ <g transform="translate(-0.5 -0.5)">
85+ <switch>
86+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
87+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 386px; margin-left: 352px;">
88+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
89+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
90+ agent
91+ACP session
92+lifecycle
93+ </div>
94+ </div>
95+ </div>
96+ </foreignObject>
97+ <text x="419" y="391" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
98+ agent...
99+ </text>
100+ </switch>
101+ </g>
102+ <rect x="546" y="281" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
103+ <g transform="translate(-0.5 -0.5)">
104+ <switch>
105+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
106+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 326px; margin-left: 547px;">
107+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
108+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
109+ files
110+Workspace
111+file API
112+ </div>
113+ </div>
114+ </div>
115+ </foreignObject>
116+ <text x="614" y="331" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
117+ files...
118+ </text>
119+ </switch>
120+ </g>
121+ <rect x="351" y="441" width="135" height="90" rx="10.8" ry="10.8" fill="#15202b" stroke="#15202b" stroke-width="2" pointer-events="all"/>
122+ <g transform="translate(-0.5 -0.5)">
123+ <switch>
124+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
125+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 486px; margin-left: 352px;">
126+ <div data-drawio-colors="color: #fdfdfb; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
127+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(253, 253, 251); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
128+ terminal
129+PTY per
130+connection
131+ </div>
132+ </div>
133+ </div>
134+ </foreignObject>
135+ <text x="419" y="491" fill="#fdfdfb" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
136+ terminal...
137+ </text>
138+ </switch>
139+ </g>
140+ <rect x="781" y="211" width="400" height="130" rx="15.6" ry="15.6" fill="#fdfdfb" stroke="#0062ff" stroke-width="2" pointer-events="all"/>
141+ <g transform="translate(-0.5 -0.5)">
142+ <switch>
143+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
144+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 276px; margin-left: 782px;">
145+ <div data-drawio-colors="color: #0062FF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
146+ <div style="display: inline-block; font-size: 17px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">
147+ ACP Agent
148+ <br/>
149+ (claude-code-acp)
150+ <br/>
151+ <br/>
152+ JSON-RPC over stdio
153+ <br/>
154+ session_update · permission_request
155+ </div>
156+ </div>
157+ </div>
158+ </foreignObject>
159+ <text x="981" y="281" fill="#0062FF" font-family="Helvetica" font-size="17px" text-anchor="middle" font-weight="bold">
160+ ACP Agent...
161+ </text>
162+ </switch>
163+ </g>
164+ <rect x="1" y="541" width="1180" height="60" rx="7.2" ry="7.2" fill="#fdfdfb" stroke="#15202b" stroke-width="2" stroke-dasharray="6 6" pointer-events="all"/>
165+ <g transform="translate(-0.5 -0.5)">
166+ <switch>
167+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
168+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1178px; height: 1px; padding-top: 571px; margin-left: 2px;">
169+ <div data-drawio-colors="color: #15202b; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
170+ <div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
171+ Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.
172+ </div>
173+ </div>
174+ </div>
175+ </foreignObject>
176+ <text x="591" y="576" fill="#15202b" font-family="Helvetica" font-size="15px" text-anchor="middle">
177+ Go backend bridges browser WebSockets to ACP stdio, broadcasting agent updates to all connected browsers while routing permissions back to the waiting call.
178+ </text>
179+ </switch>
180+ </g>
181+ <path d="M 221 56 L 322 56 Q 332 56 332 51 L 332 48.5 Q 332 46 342 46 L 434.76 46" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
182+ <path d="M 440.76 46 L 432.76 50 L 434.76 46 L 432.76 42 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
183+ <g transform="translate(-0.5 -0.5)">
184+ <switch>
185+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
186+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 51px; margin-left: 332px;">
187+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
188+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
189+ 1. load SPA
190+ </div>
191+ </div>
192+ </div>
193+ </foreignObject>
194+ <text x="332" y="55" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
195+ 1. load SPA
196+ </text>
197+ </switch>
198+ </g>
199+ <path d="M 221 81 L 321.5 81 Q 331.5 81 331.5 91 L 331.5 151 Q 331.5 161 341.5 161 L 433.76 161" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
200+ <path d="M 439.76 161 L 431.76 165 L 433.76 161 L 431.76 157 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
201+ <g transform="translate(-0.5 -0.5)">
202+ <switch>
203+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
204+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 122px; margin-left: 332px;">
205+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
206+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
207+ 2. WebSocket
208+/ws
209+ </div>
210+ </div>
211+ </div>
212+ </foreignObject>
213+ <text x="332" y="126" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
214+ 2. WebSocket...
215+ </text>
216+ </switch>
217+ </g>
218+ <path d="M 221 206 L 433.76 206" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
219+ <path d="M 439.76 206 L 431.76 210 L 433.76 206 L 431.76 202 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
220+ <g transform="translate(-0.5 -0.5)">
221+ <switch>
222+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
223+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 181px; margin-left: 331px;">
224+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
225+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
226+ 3. prompt +
227+permission
228+responses
229+ </div>
230+ </div>
231+ </div>
232+ </foreignObject>
233+ <text x="331" y="185" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
234+ 3. prompt +...
235+ </text>
236+ </switch>
237+ </g>
238+ <path d="M 442 231 L 331 231 Q 321 231 311 231 L 229.24 231" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
239+ <path d="M 223.24 231 L 231.24 227 L 229.24 231 L 231.24 235 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
240+ <g transform="translate(-0.5 -0.5)">
241+ <switch>
242+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
243+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 251px; margin-left: 374px;">
244+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
245+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
246+ 4. session_update
247+events (replay)
248+ </div>
249+ </div>
250+ </div>
251+ </foreignObject>
252+ <text x="374" y="255" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
253+ 4. session_update...
254+ </text>
255+ </switch>
256+ </g>
257+ <path d="M 522 251 L 522 286 Q 522 296 512 296 L 428 296 Q 418 296 418 306 L 418 332.76" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
258+ <path d="M 418 338.76 L 414 330.76 L 418 332.76 L 422 330.76 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
259+ <g transform="translate(-0.5 -0.5)">
260+ <switch>
261+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
262+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 296px; margin-left: 470px;">
263+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
264+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
265+ 5. ACP
266+lifecycle
267+ </div>
268+ </div>
269+ </div>
270+ </foreignObject>
271+ <text x="470" y="300" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
272+ 5. ACP...
273+ </text>
274+ </switch>
275+ </g>
276+ <path d="M 486 386 L 486 336 Q 486 326 496 326 L 671 326 Q 681 326 681 316 L 681 286 Q 681 276 691 276 L 772.76 276" fill="none" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/>
277+ <path d="M 778.76 276 L 770.76 280 L 772.76 276 L 770.76 272 Z" fill="#15202b" stroke="#15202b" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
278+ <g transform="translate(-0.5 -0.5)">
279+ <switch>
280+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
281+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 381px; margin-left: 671px;">
282+ <div data-drawio-colors="color: #15202b; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
283+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(21, 32, 43); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
284+ 6. stdio
285+JSON-RPC
286+ </div>
287+ </div>
288+ </div>
289+ </foreignObject>
290+ <text x="671" y="385" fill="#15202b" font-family="Helvetica" font-size="14px" text-anchor="middle">
291+ 6. stdio...
292+ </text>
293+ </switch>
294+ </g>
295+ <path d="M 981 211 L 981 191 Q 981 181 971 181 L 730.24 181" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
296+ <path d="M 724.24 181 L 732.24 177 L 730.24 181 L 732.24 185 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
297+ <g transform="translate(-0.5 -0.5)">
298+ <switch>
299+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
300+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 181px; margin-left: 866px;">
301+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
302+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
303+ 7. updates +
304+permissions
305+ </div>
306+ </div>
307+ </div>
308+ </foreignObject>
309+ <text x="866" y="185" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
310+ 7. updates +...
311+ </text>
312+ </switch>
313+ </g>
314+ <path d="M 166 281 L 346 281 Q 356 281 356 291 L 356 316 Q 356 326 366 326 L 537.76 326" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
315+ <path d="M 543.76 326 L 535.76 330 L 537.76 326 L 535.76 322 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
316+ <g transform="translate(-0.5 -0.5)">
317+ <switch>
318+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
319+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 326px;">
320+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
321+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
322+ file ops
323+ </div>
324+ </div>
325+ </div>
326+ </foreignObject>
327+ <text x="326" y="316" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
328+ file ops
329+ </text>
330+ </switch>
331+ </g>
332+ <path d="M 111 281 L 111 476 Q 111 486 121 486 L 342.76 486" fill="none" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="stroke"/>
333+ <path d="M 348.76 486 L 340.76 490 L 342.76 486 L 340.76 482 Z" fill="#0062ff" stroke="#0062ff" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/>
334+ <g transform="translate(-0.5 -0.5)">
335+ <switch>
336+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
337+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 486px; margin-left: 129px;">
338+ <div data-drawio-colors="color: #0062FF; background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
339+ <div style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(0, 98, 255); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
340+ shell I/O
341+ </div>
342+ </div>
343+ </div>
344+ </foreignObject>
345+ <text x="129" y="490" fill="#0062FF" font-family="Helvetica" font-size="14px" text-anchor="middle">
346+ shell I/O
347+ </text>
348+ </switch>
349+ </g>
350+ </g>
351+ <switch>
352+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
353+ <a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
354+ <text text-anchor="middle" font-size="10px" x="50%" y="100%">
355+ Text is not SVG - cannot display
356+ </text>
357+ </a>
358+ </switch>
359+</svg>
\ No newline at end of file\ No newline at end of file
modified ori-desktop/README.fr.md +1 -1
@@ -70,7 +70,7 @@ premier lancement, les fichiers invalides et la normalisation d'URL ; `internal/
7070 ## Comment il se connecte à ori
7171
7272 ```
73-┌──────────────── ori-desktop (fenêtre Wails) ───────────────┐
73+┌──────────────── ori-desktop (fenêtre Wails) ────────────────┐
7474 │ frontend/src (embarqué, origine wails://) │
7575 │ écran de connexion ──► window.go.main.App.Connect(url) │
7676 │ │ Go : NormalizeURL → GET /healthz → sauvegarde des réglages
@@ -70,7 +70,7 @@ premier lancement, les fichiers invalides et la normalisation d'URL ; `internal/
70 ## Comment il se connecte à ori70 ## Comment il se connecte à ori
71 71
72 ```72 ```
73-┌──────────────── ori-desktop (fenêtre Wails) ───────────────┐73+┌──────────────── ori-desktop (fenêtre Wails) ────────────────┐
74 │ frontend/src (embarqué, origine wails://) │74 │ frontend/src (embarqué, origine wails://) │
75 │ écran de connexion ──► window.go.main.App.Connect(url) │75 │ écran de connexion ──► window.go.main.App.Connect(url) │
76 │ │ Go : NormalizeURL → GET /healthz → sauvegarde des réglages76 │ │ Go : NormalizeURL → GET /healthz → sauvegarde des réglages
modified ori-desktop/README.md +1 -1
@@ -68,7 +68,7 @@ non-ori, unreachable, cancelled).
6868 ## How it connects to ori
6969
7070 ```
71-┌──────────────── ori-desktop (Wails window) ────────────────┐
71+┌──────────────── ori-desktop (Wails window) ─────────────────┐
7272 │ frontend/src (embedded, wails:// origin) │
7373 │ connection screen ──► window.go.main.App.Connect(url) │
7474 │ │ Go: NormalizeURL → GET /healthz → Save settings
@@ -68,7 +68,7 @@ non-ori, unreachable, cancelled).
68 ## How it connects to ori68 ## How it connects to ori
69 69
70 ```70 ```
71-┌──────────────── ori-desktop (Wails window) ────────────────┐71+┌──────────────── ori-desktop (Wails window) ─────────────────┐
72 │ frontend/src (embedded, wails:// origin) │72 │ frontend/src (embedded, wails:// origin) │
73 │ connection screen ──► window.go.main.App.Connect(url) │73 │ connection screen ──► window.go.main.App.Connect(url) │
74 │ │ Go: NormalizeURL → GET /healthz → Save settings74 │ │ Go: NormalizeURL → GET /healthz → Save settings
added ori-desktop/how-to-build.md +218 -0
new file mode 100644
@@ -0,0 +1,218 @@
1+# How to build ori-desktop
2+
3+This guide shows how to build the [ori-desktop](./README.md) Wails shell on each platform, and
4+what to watch out for. See [README.md](./README.md) for what the app does and
5+[README.fr.md](./README.fr.md) for the French version of that overview.
6+
7+## Prerequisites (every platform)
8+
9+- **Go 1.25 or newer** — `go.mod` requires `go 1.25.0`.
10+- **The Wails v2 CLI**, matching the module's Wails version:
11+
12+ ```bash
13+ go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0
14+ export PATH="$PATH:$(go env GOPATH)/bin"
15+ wails version # → v2.16.0
16+ ```
17+
18+- **No Node or npm.** The frontend is plain HTML/CSS/JS embedded as-is; `wails.json` leaves
19+ `frontend:install` and `frontend:build` empty on purpose.
20+
21+Everything below is run from the `ori-desktop/` directory, which is a **separate Go module**
22+(`rickub.com/bots-garden/ori-desktop`). The repository root's `make build` and `go test ./...`
23+never touch it.
24+
25+## What can be built from where
26+
27+Wails compiles the native window through cgo against the platform's webview, so the host decides
28+what is reachable:
29+
30+| Target | From macOS | From Linux | From Windows |
31+| --- | --- | --- | --- |
32+| `darwin/*` (`.app`) | ✅ | ❌ needs the macOS SDK | ❌ |
33+| `linux/*` | ❌ | ✅ | ❌ |
34+| `windows/*` (`.exe`) | ✅ | ✅ | ✅ |
35+
36+Windows is the only free cross-build: WebView2 is loaded at runtime, so no C toolchain is
37+involved. macOS needs Cocoa and WKWebView from Xcode, and Linux needs WebKitGTK — neither is
38+cross-compilable in practice.
39+
40+All outputs land in `build/bin/` and can coexist there, since each target has a distinct name:
41+`ori-desktop` (Linux), `ori-desktop.app` (macOS), `ori-desktop.exe` (Windows).
42+
43+## macOS
44+
45+1. Install the Xcode command line tools, if they are not already there:
46+
47+ ```bash
48+ xcode-select --install
49+ ```
50+
51+2. Build and launch:
52+
53+ ```bash
54+ cd ori-desktop
55+ wails build
56+ xattr -cr build/bin/ori-desktop.app # clear the quarantine attribute
57+ open build/bin/ori-desktop.app
58+ ```
59+
60+ No build tag is needed: `-tags webkit2_41` is a Linux-only concern (see below).
61+
62+3. The app opens on its connection screen and needs an ori server to reach. From the repository
63+ root: `make run` (Claude Code) or `make run-mock` (demo agent, no network). The
64+ `scripts/launch-ori.applescript` launcher does the whole sequence — start the sandbox, wait
65+ for `/healthz`, open the `.app`.
66+
67+### Choosing the architecture
68+
69+`wails build` alone targets the architecture of the machine you build on. To be explicit:
70+
71+```bash
72+wails build -platform darwin/universal # one .app running on Apple Silicon and Intel
73+wails build -platform darwin/arm64 # Apple Silicon only
74+wails build -platform darwin/amd64 # Intel only
75+```
76+
77+A `universal` build runs the Go compiler twice and merges the results with `lipo`, so it takes
78+about twice as long and produces a noticeably larger bundle.
79+
80+### Bundle details
81+
82+`build/darwin/Info.plist` is a Go template filled from the `info` block of `wails.json`
83+(product name `ori`, version `0.1.0`, company `bots-garden`). It sets
84+`NSAppTransportSecurity/NSAllowsLocalNetworking` so App Transport Security allows the app to load
85+ori over plain HTTP on the loopback interface — without it the iframe stays blank.
86+`build/darwin/Info.dev.plist` is the variant `wails dev` uses.
87+
88+## Linux
89+
90+1. Install the GUI toolchain. On Ubuntu 26.04 (and any distribution that has moved past
91+ WebKitGTK 4.0):
92+
93+ ```bash
94+ sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
95+ ```
96+
97+2. Build with the matching build tag:
98+
99+ ```bash
100+ cd ori-desktop
101+ wails build -tags webkit2_41
102+ ```
103+
104+**The build tag is mandatory on any system without WebKitGTK 4.0.** Wails' default cgo
105+`pkg-config` line asks for `webkit2gtk-4.0`; where only 4.1 is packaged, a bare `wails build`
106+stops with:
107+
108+```
109+# [pkg-config --cflags -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 …]
110+Package 'webkit2gtk-4.0' not found
111+```
112+
113+`-tags webkit2_41` switches Wails to the `webkit2gtk-4.1` pkg-config name. On an older
114+distribution that still ships `libwebkit2gtk-4.0-dev`, drop the tag.
115+
116+Two traps:
117+
118+- **`wails doctor` reports a false negative.** It probes `webkit2gtk-4.0` only, so even with 4.1
119+ correctly installed it prints `libwebkit | Unknown | Not Found` and
120+ `Fatal: Required dependencies missing: libwebkit`. Ignore it and check the real thing:
121+
122+ ```bash
123+ pkg-config --modversion gtk+-3.0 webkit2gtk-4.1
124+ ```
125+
126+- **`make desktop` runs a bare `wails build`**, so it fails on those distributions. Build from
127+ `ori-desktop/` with the tag instead. The target is correct on macOS, where it is normally used.
128+
129+## Windows
130+
131+Cross-build from anywhere, no C toolchain required:
132+
133+```bash
134+cd ori-desktop
135+wails build -platform windows/amd64 # → build/bin/ori-desktop.exe
136+wails build -platform windows/arm64
137+```
138+
139+The resulting binary needs the WebView2 runtime, which is preinstalled on Windows 10 and 11. The
140+`-webview2` flag picks the strategy for machines without it (`download`, the default, `embed`,
141+`browser` or `error`), and `-nsis` produces an installer — that one needs NSIS on the build
142+machine (`sudo apt-get install nsis` on Debian-family systems).
143+
144+`build/windows/` holds the manifest, icon and NSIS assets.
145+
146+## Useful flags
147+
148+`wails build -help` lists them all; these are the ones that matter here.
149+
150+| Flag | Use |
151+| --- | --- |
152+| `-clean` | Empties `build/bin/` first. **It removes the other platforms' outputs too** — the `.app`, the `.exe` and the Linux binary all live in that one directory. |
153+| `-platform os/arch` | Target something other than the host; comma-separate several. Defaults to the host. |
154+| `-tags "…"` | Go build tags — this is how `webkit2_41` is passed. |
155+| `-dryrun` | Prints the `go build` command Wails would run, without running it. Handy for diagnosing a cgo or pkg-config failure. |
156+| `-debug` / `-devtools` | Keep the webview devtools available in a production build. |
157+| `-race`, `-trimpath`, `-ldflags`, `-o` | Passed through to the Go compiler / output name. |
158+| `-s` | Skip the frontend step — a no-op here, since there is no frontend build. |
159+
160+`wails build` also regenerates `frontend/wailsjs/` (the typed JS wrappers for the bound Go
161+methods). Nothing imports them and they are gitignored; the frontend calls
162+`window.go.main.App.<Method>()` directly.
163+
164+## Development mode
165+
166+```bash
167+cd ori-desktop
168+wails dev # add -tags webkit2_41 on Linux, as for build
169+```
170+
171+This opens the window and reloads it whenever a file under `frontend/src/` changes (`assetdir` in
172+`wails.json`). It also serves the app on http://localhost:34115, so it can be opened in a normal
173+browser with devtools while still calling the Go methods.
174+
175+## Tests
176+
177+The connection logic is pure Go and needs no GUI dependency at all — it can be run on a machine
178+where the build itself is impossible:
179+
180+```bash
181+cd ori-desktop && go test ./internal/...
182+# or, from the repository root:
183+make desktop-test
184+```
185+
186+## Troubleshooting
187+
188+**`Package 'webkit2gtk-4.0' not found` (Linux)** — add `-tags webkit2_41`; see above.
189+
190+**`wails: command not found`** — `$(go env GOPATH)/bin` is not on `PATH`.
191+
192+**macOS refuses to open the `.app`** — two distinct causes:
193+
194+- *"cannot be opened"* / nothing happens: the executable inside the bundle lost its execute bit.
195+ This happens when `build/bin/` sits in a cloud-synced folder (iCloud Drive, kDrive, Dropbox),
196+ which does not always preserve POSIX modes. Restore it with:
197+
198+ ```bash
199+ chmod +x build/bin/ori-desktop.app/Contents/MacOS/ori-desktop
200+ ```
201+
202+ That invalidates the bundle's signature, so if macOS then calls the app damaged, rebuild with
203+ `wails build -clean`.
204+
205+- *"cannot be opened because it is from an unidentified developer"* / *"damaged"*: Gatekeeper.
206+ `xattr -cr build/bin/ori-desktop.app` clears the quarantine flag on the machine that built it.
207+ Wails only signs the bundle ad hoc, so distributing it to other Macs requires a Developer ID
208+ certificate, `codesign` and notarisation with `notarytool`.
209+
210+**The window opens but stays empty** — that is the connection screen failing to reach ori, not a
211+build problem. Check that an ori server answers on the URL shown (`curl http://localhost:8888/healthz`)
212+and use the "Open in browser" button to confirm.
213+
214+## See also
215+
216+- What the app is and how it talks to ori: [README.md](./README.md) / [README.fr.md](./README.fr.md)
217+- Running the ori server itself: the repository's [quickstart](../quickstart.md)
218+- Running the test suites: [docs/en/how-to/run-the-tests.md](../docs/en/how-to/run-the-tests.md)
new file mode 100644
@@ -0,0 +1,218 @@
1+# How to build ori-desktop
2+
3+This guide shows how to build the [ori-desktop](./README.md) Wails shell on each platform, and
4+what to watch out for. See [README.md](./README.md) for what the app does and
5+[README.fr.md](./README.fr.md) for the French version of that overview.
6+
7+## Prerequisites (every platform)
8+
9+- **Go 1.25 or newer** — `go.mod` requires `go 1.25.0`.
10+- **The Wails v2 CLI**, matching the module's Wails version:
11+
12+ ```bash
13+ go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0
14+ export PATH="$PATH:$(go env GOPATH)/bin"
15+ wails version # → v2.16.0
16+ ```
17+
18+- **No Node or npm.** The frontend is plain HTML/CSS/JS embedded as-is; `wails.json` leaves
19+ `frontend:install` and `frontend:build` empty on purpose.
20+
21+Everything below is run from the `ori-desktop/` directory, which is a **separate Go module**
22+(`rickub.com/bots-garden/ori-desktop`). The repository root's `make build` and `go test ./...`
23+never touch it.
24+
25+## What can be built from where
26+
27+Wails compiles the native window through cgo against the platform's webview, so the host decides
28+what is reachable:
29+
30+| Target | From macOS | From Linux | From Windows |
31+| --- | --- | --- | --- |
32+| `darwin/*` (`.app`) | ✅ | ❌ needs the macOS SDK | ❌ |
33+| `linux/*` | ❌ | ✅ | ❌ |
34+| `windows/*` (`.exe`) | ✅ | ✅ | ✅ |
35+
36+Windows is the only free cross-build: WebView2 is loaded at runtime, so no C toolchain is
37+involved. macOS needs Cocoa and WKWebView from Xcode, and Linux needs WebKitGTK — neither is
38+cross-compilable in practice.
39+
40+All outputs land in `build/bin/` and can coexist there, since each target has a distinct name:
41+`ori-desktop` (Linux), `ori-desktop.app` (macOS), `ori-desktop.exe` (Windows).
42+
43+## macOS
44+
45+1. Install the Xcode command line tools, if they are not already there:
46+
47+ ```bash
48+ xcode-select --install
49+ ```
50+
51+2. Build and launch:
52+
53+ ```bash
54+ cd ori-desktop
55+ wails build
56+ xattr -cr build/bin/ori-desktop.app # clear the quarantine attribute
57+ open build/bin/ori-desktop.app
58+ ```
59+
60+ No build tag is needed: `-tags webkit2_41` is a Linux-only concern (see below).
61+
62+3. The app opens on its connection screen and needs an ori server to reach. From the repository
63+ root: `make run` (Claude Code) or `make run-mock` (demo agent, no network). The
64+ `scripts/launch-ori.applescript` launcher does the whole sequence — start the sandbox, wait
65+ for `/healthz`, open the `.app`.
66+
67+### Choosing the architecture
68+
69+`wails build` alone targets the architecture of the machine you build on. To be explicit:
70+
71+```bash
72+wails build -platform darwin/universal # one .app running on Apple Silicon and Intel
73+wails build -platform darwin/arm64 # Apple Silicon only
74+wails build -platform darwin/amd64 # Intel only
75+```
76+
77+A `universal` build runs the Go compiler twice and merges the results with `lipo`, so it takes
78+about twice as long and produces a noticeably larger bundle.
79+
80+### Bundle details
81+
82+`build/darwin/Info.plist` is a Go template filled from the `info` block of `wails.json`
83+(product name `ori`, version `0.1.0`, company `bots-garden`). It sets
84+`NSAppTransportSecurity/NSAllowsLocalNetworking` so App Transport Security allows the app to load
85+ori over plain HTTP on the loopback interface — without it the iframe stays blank.
86+`build/darwin/Info.dev.plist` is the variant `wails dev` uses.
87+
88+## Linux
89+
90+1. Install the GUI toolchain. On Ubuntu 26.04 (and any distribution that has moved past
91+ WebKitGTK 4.0):
92+
93+ ```bash
94+ sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
95+ ```
96+
97+2. Build with the matching build tag:
98+
99+ ```bash
100+ cd ori-desktop
101+ wails build -tags webkit2_41
102+ ```
103+
104+**The build tag is mandatory on any system without WebKitGTK 4.0.** Wails' default cgo
105+`pkg-config` line asks for `webkit2gtk-4.0`; where only 4.1 is packaged, a bare `wails build`
106+stops with:
107+
108+```
109+# [pkg-config --cflags -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 …]
110+Package 'webkit2gtk-4.0' not found
111+```
112+
113+`-tags webkit2_41` switches Wails to the `webkit2gtk-4.1` pkg-config name. On an older
114+distribution that still ships `libwebkit2gtk-4.0-dev`, drop the tag.
115+
116+Two traps:
117+
118+- **`wails doctor` reports a false negative.** It probes `webkit2gtk-4.0` only, so even with 4.1
119+ correctly installed it prints `libwebkit | Unknown | Not Found` and
120+ `Fatal: Required dependencies missing: libwebkit`. Ignore it and check the real thing:
121+
122+ ```bash
123+ pkg-config --modversion gtk+-3.0 webkit2gtk-4.1
124+ ```
125+
126+- **`make desktop` runs a bare `wails build`**, so it fails on those distributions. Build from
127+ `ori-desktop/` with the tag instead. The target is correct on macOS, where it is normally used.
128+
129+## Windows
130+
131+Cross-build from anywhere, no C toolchain required:
132+
133+```bash
134+cd ori-desktop
135+wails build -platform windows/amd64 # → build/bin/ori-desktop.exe
136+wails build -platform windows/arm64
137+```
138+
139+The resulting binary needs the WebView2 runtime, which is preinstalled on Windows 10 and 11. The
140+`-webview2` flag picks the strategy for machines without it (`download`, the default, `embed`,
141+`browser` or `error`), and `-nsis` produces an installer — that one needs NSIS on the build
142+machine (`sudo apt-get install nsis` on Debian-family systems).
143+
144+`build/windows/` holds the manifest, icon and NSIS assets.
145+
146+## Useful flags
147+
148+`wails build -help` lists them all; these are the ones that matter here.
149+
150+| Flag | Use |
151+| --- | --- |
152+| `-clean` | Empties `build/bin/` first. **It removes the other platforms' outputs too** — the `.app`, the `.exe` and the Linux binary all live in that one directory. |
153+| `-platform os/arch` | Target something other than the host; comma-separate several. Defaults to the host. |
154+| `-tags "…"` | Go build tags — this is how `webkit2_41` is passed. |
155+| `-dryrun` | Prints the `go build` command Wails would run, without running it. Handy for diagnosing a cgo or pkg-config failure. |
156+| `-debug` / `-devtools` | Keep the webview devtools available in a production build. |
157+| `-race`, `-trimpath`, `-ldflags`, `-o` | Passed through to the Go compiler / output name. |
158+| `-s` | Skip the frontend step — a no-op here, since there is no frontend build. |
159+
160+`wails build` also regenerates `frontend/wailsjs/` (the typed JS wrappers for the bound Go
161+methods). Nothing imports them and they are gitignored; the frontend calls
162+`window.go.main.App.<Method>()` directly.
163+
164+## Development mode
165+
166+```bash
167+cd ori-desktop
168+wails dev # add -tags webkit2_41 on Linux, as for build
169+```
170+
171+This opens the window and reloads it whenever a file under `frontend/src/` changes (`assetdir` in
172+`wails.json`). It also serves the app on http://localhost:34115, so it can be opened in a normal
173+browser with devtools while still calling the Go methods.
174+
175+## Tests
176+
177+The connection logic is pure Go and needs no GUI dependency at all — it can be run on a machine
178+where the build itself is impossible:
179+
180+```bash
181+cd ori-desktop && go test ./internal/...
182+# or, from the repository root:
183+make desktop-test
184+```
185+
186+## Troubleshooting
187+
188+**`Package 'webkit2gtk-4.0' not found` (Linux)** — add `-tags webkit2_41`; see above.
189+
190+**`wails: command not found`** — `$(go env GOPATH)/bin` is not on `PATH`.
191+
192+**macOS refuses to open the `.app`** — two distinct causes:
193+
194+- *"cannot be opened"* / nothing happens: the executable inside the bundle lost its execute bit.
195+ This happens when `build/bin/` sits in a cloud-synced folder (iCloud Drive, kDrive, Dropbox),
196+ which does not always preserve POSIX modes. Restore it with:
197+
198+ ```bash
199+ chmod +x build/bin/ori-desktop.app/Contents/MacOS/ori-desktop
200+ ```
201+
202+ That invalidates the bundle's signature, so if macOS then calls the app damaged, rebuild with
203+ `wails build -clean`.
204+
205+- *"cannot be opened because it is from an unidentified developer"* / *"damaged"*: Gatekeeper.
206+ `xattr -cr build/bin/ori-desktop.app` clears the quarantine flag on the machine that built it.
207+ Wails only signs the bundle ad hoc, so distributing it to other Macs requires a Developer ID
208+ certificate, `codesign` and notarisation with `notarytool`.
209+
210+**The window opens but stays empty** — that is the connection screen failing to reach ori, not a
211+build problem. Check that an ori server answers on the URL shown (`curl http://localhost:8888/healthz`)
212+and use the "Open in browser" button to confirm.
213+
214+## See also
215+
216+- What the app is and how it talks to ori: [README.md](./README.md) / [README.fr.md](./README.fr.md)
217+- Running the ori server itself: the repository's [quickstart](../quickstart.md)
218+- Running the test suites: [docs/en/how-to/run-the-tests.md](../docs/en/how-to/run-the-tests.md)
modified template/build.sh +0 -0
old mode 100755
new mode 100644
old mode 100755
new mode 100644