# MindExec Local Bridge Server

??Blazor ?깆뿉??濡쒖뺄 ?뚯씪 ?쒖뒪?쒖뿉 ?묎렐?섍린 ?꾪븳 Node.js 釉뚮━吏 ?쒕쾭?낅땲??

## npm quick start

```bash
npx mindexec-ai
```

The npm CLI now starts both pieces of the local product:

- MindCanvas app: `http://localhost:5167/mindcanvas`
- Public share viewer shell: `http://localhost:5167/share/<share-id>`
- LocalBridge API: `http://127.0.0.1:5167/api/status`
- Workspace assets: `http://127.0.0.1:5167/assets/...`

By default the CLI opens the MindCanvas app in your default browser after the
bridge is ready. Use `mindexec --no-open` or `MINDEXEC_NO_OPEN=1` when you only
want to start the listener.

For npx and global installs, the default workspace is the directory where you
run the command. Run it from the folder that contains your `.mindexec` data, or
pass the workspace explicitly:

```bash
npx mindexec-ai --workspace /path/to/workspace
```

When testing multiple MindExec versions on one machine, keep each `npx` run on
its own app port, RemoteHub port, and npm cache. This avoids Windows `EBUSY`
locks in npm's shared `_npx` cache while another LocalBridge is still running:

```powershell
$env:BRIDGE_PORT="5177"
$env:REMOTE_HUB_PORT="5209"
$env:REMOTE_HUB_HOST="127.0.0.1"
$env:npm_config_cache="$PWD\.tmp\mindexec-ai-npx-cache-5177"
npx -y mindexec-ai@latest --workspace "$PWD\.tmp\mindexec-ai-workspace-5177" --no-open
```

For local frontend development, keep LocalBridge running and refresh the
packaged app bundle after code changes:

```powershell
.\scripts\publish-mindexec-cli.ps1 -AppOnly
```

Then hard-refresh `http://localhost:5167/mindcanvas` in the browser.
The packaged React shell also serves read-only canvas share links under
`/share/<share-id>`; actual public share data is loaded from the configured
Supabase `canvas_shares` snapshot table.

The app and bridge are packaged together. Run `scripts/publish-mindexec-cli.ps1`
from the repository root before publishing so the latest
`MindExecution.Web` WASM `wwwroot` is copied into `LocalBridge/wwwroot`.
The packaged app is configured with `Bridge:Url=app-origin`, so custom
`BRIDGE_PORT` values keep the WASM app and LocalBridge API on the same origin.
The publish helper trims hosted/demo-only gallery images and unused
precompressed static files from the npm bundle by default. Use
`-KeepPackagedGalleryImages` or `-KeepPackagedPrecompressedAssets` only when
testing a full untrimmed local package.

## Remote Direct quick start

LocalBridge also starts a separate RemoteHub listener for direct remote-agent
experiments. By default it binds to loopback only:

```bash
npx mindexec-ai
npx @mindexec/remote connect --manager 127.0.0.1:5199 --pair <pair-token>
```

Read the pair token from the protected local endpoint:

```bash
curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/status
```

LAN/direct mode must be enabled explicitly by changing the RemoteHub bind host:

```powershell
$env:REMOTE_HUB_HOST="0.0.0.0"
$env:REMOTE_HUB_PORT="5199"
$env:REMOTE_HUB_PAIR_TOKEN="<strong-token>"
npx mindexec-ai
```

Device inventory is intentionally not paginated:

```bash
curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/devices
```

Request and read the latest view-only thumbnail for a connected device:

```bash
curl -X POST -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/devices/<device-id>/thumbnail/request
curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/devices/<device-id>/thumbnail
```

Start, read, and stop the focused view-only RemoteFast live stream:

```bash
curl -X POST -H "X-Bridge-Token: <bridge-token>" -H "Content-Type: application/json" \
  -d "{\"fps\":12,\"maxWidth\":960,\"maxHeight\":540,\"quality\":60}" \
  http://127.0.0.1:5167/api/remote/devices/<device-id>/live/start

curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/devices/<device-id>/live/frame

curl -X POST -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5167/api/remote/devices/<device-id>/live/stop
```

Queue a safe task-only instruction for one device or all connected devices:

```bash
curl -X POST -H "X-Bridge-Token: <bridge-token>" -H "Content-Type: application/json" \
  -d "{\"instruction\":\"Check the desktop and report status.\"}" \
  http://127.0.0.1:5167/api/remote/devices/<device-id>/tasks

curl -X POST -H "X-Bridge-Token: <bridge-token>" -H "Content-Type: application/json" \
  -d "{\"instruction\":\"Prepare a short status report.\",\"allConnected\":true}" \
  http://127.0.0.1:5167/api/remote/tasks
```

Queue an opt-in text-only AI assist task for agents started with `--ai`:

```bash
curl -X POST -H "X-Bridge-Token: <bridge-token>" -H "Content-Type: application/json" \
  -d "{\"instruction\":\"Summarize what this computer should do next.\",\"allConnected\":true,\"approvalLevel\":\"ai-assist\"}" \
  http://127.0.0.1:5167/api/remote/tasks
```

?먮뒗 ?꾩뿭 ?ㅼ튂 ???ㅽ뻾?⑸땲??

```bash
npm install -g mindexec-ai
mindexec
```

湲곕낯 ?ㅽ뻾 二쇱냼??`http://127.0.0.1:5167`?낅땲?? `WORKSPACE_PATH`媛 鍮꾩뼱 ?덉쑝硫??ㅼ튂???⑦궎吏??遺紐??대뜑瑜?湲곕낯 ?묒뾽 怨듦컙?쇰줈 ?ъ슜?⑸땲??

```bash
mindexec --workspace /custom/path
BRIDGE_PORT=8080 WORKSPACE_PATH=/custom/path mindexec
```

?꾩?留먭낵 踰꾩쟾 ?뺤씤:

```bash
mindexec --help
mindexec --version
```

## ?ㅼ튂

```bash
cd LocalBridge
npm install
```

## ?ㅽ뻾

### ?쇰컲 ?ㅽ뻾
```bash
cd LocalBridge
npm start
```

`npm start`??`WORKSPACE_PATH`媛 鍮꾩뼱 ?덉쑝硫?`LocalBridge`??遺紐??대뜑(蹂댄넻 ??μ냼 猷⑦듃)瑜?湲곕낯 ?묒뾽 怨듦컙?쇰줈 ?ъ슜?⑸땲??

### macOS / Linux?먯꽌 ?명븯寃??ㅽ뻾
```bash
cd LocalBridge
chmod +x start-bridge.sh
./start-bridge.sh
```

`start-bridge.sh`???ㅼ쓬???먮룞?쇰줈 泥섎━?⑸땲??
- `WORKSPACE_PATH`媛 ?놁쑝硫???μ냼 猷⑦듃瑜??묒뾽 怨듦컙?쇰줈 ?ъ슜
- `BRIDGE_PORT`媛 ?놁쑝硫?`5167` ?ъ슜
- 媛숈? ?ы듃???대? 釉뚮━吏媛 ???덉쑝硫?以묐났 ?ㅽ뻾 諛⑹?
- ?ㅻⅨ OS?먯꽌 蹂듭궗????`node_modules`媛 媛먯??섎㈃ ?꾩옱 ?뚮옯?쇱슜?쇰줈 ?ㅼ떆 `npm install`

### 媛쒕컻 紐⑤뱶 (?먮룞 ?ъ떆??
```bash
npm run dev
```

### ?섍꼍 蹂??

| 蹂??| ?ㅻ챸 | 湲곕낯媛?|
|------|------|--------|
| `BRIDGE_PORT` | ?쒕쾭 ?ы듃 | 5167 |
| `WORKSPACE_PATH` | ?묒뾽 怨듦컙 寃쎈줈 | `LocalBridge` ?먮뒗 ?ㅼ튂 ?⑦궎吏??遺紐??대뜑 (?놁쑝硫?`~/Documents/MindExecution`) |
| `BRIDGE_TOKEN` | ?꾪뿕 REST API???ъ슜??怨좎젙 ?좏겙. 鍮꾩슦硫??ㅽ뻾 ???쒕뜡 ?앹꽦 | ?쒕뜡 |
| `BRIDGE_REQUIRE_TOKEN` | `false`/`0`/`off`濡??ㅼ젙?섎㈃ REST ?좏겙 寃??鍮꾪솢?깊솕 | true |
| `COMPANY_CORE_URL` | CompanyCore 濡쒖뺄 API 二쇱냼. `/api/company-core/*` ?꾨줉?????| http://127.0.0.1:5077 |
| `BRIDGE_SKIP_PORT_REAP` | ?쒖옉 ???숈씪 ?ы듃??湲곗〈 MindExec bridge ?뺣━瑜?嫄대꼫?? | false |
| `BRIDGE_FORCE_KILL_PORT_OWNER` | `BRIDGE_PORT`瑜??≪쓣 ?꾩쓽 ?꾨줈?몄뒪瑜??뺣━ | false |

?덉떆:
```bash
BRIDGE_PORT=8080 WORKSPACE_PATH=/custom/path npm start
```

macOS / Linux?먯꽌 ?ㅽ겕由쏀듃? ?④퍡 ?ㅽ뻾???뚮룄 ?숈씪?⑸땲??
```bash
BRIDGE_PORT=8080 WORKSPACE_PATH=/custom/path ./start-bridge.sh
```

## API ?붾뱶?ъ씤??

### ?곹깭 ?뺤씤
- `GET /api/status` - ?쒕쾭 ?곹깭 ?뺤씤, `/events`??`wsToken`怨??꾪뿕 REST API??`bridgeToken` 諛섑솚

### ?묒뾽 怨듦컙
- `GET /api/workspace` - ?꾩옱 ?묒뾽 怨듦컙 ?뺣낫
- `POST /api/workspace/set` - ?묒뾽 怨듦컙 寃쎈줈 ?ㅼ젙

### ?뚯씪 ?묒뾽
- `POST /api/file/read` - ?뚯씪 ?쎄린
- `POST /api/file/write` - ?뚯씪 ?곌린
- `POST /api/file/delete` - ?뚯씪 ??젣
- `POST /api/file/exists` - ?뚯씪 議댁옱 ?뺤씤
- `POST /api/file/copy` - ?뚯씪 蹂듭궗
- `POST /api/file/move` - ?뚯씪 ?대룞/?대쫫 蹂寃?
- `POST /api/file/info` - ?뚯씪 ?뺣낫

### ?붾젆?좊━ ?묒뾽
- `POST /api/dir/create` - ?붾젆?좊━ ?앹꽦
- `POST /api/dir/list` - ?붾젆?좊━ 紐⑸줉
- `POST /api/dir/delete` - ?붾젆?좊━ ??젣

### ???ㅽ뻾
- `POST /api/shell/execute` - ??紐낅졊 ?ㅽ뻾. 湲곗〈 ?명솚?⑹씠硫??대??곸쑝濡?job ?대깽?몃? `/events`濡??꾩넚
- `POST /api/shell/jobs` - ??紐낅졊??諛깃렇?쇱슫??job?쇰줈 ?쒖옉?섍퀬 `jobId` 諛섑솚
- `GET /api/shell/jobs/:jobId` - job ?곹깭/異쒕젰 議고쉶
- `POST /api/shell/jobs/:jobId/cancel` - ?ㅽ뻾 以묒씤 job 痍⑥냼

### ?대깽???ㅽ듃由?- `WebSocket /events?token=<wsToken>` - ?꾨줈?앺듃 蹂寃쎄낵 shell/Codex job ?대깽?몃? push

Shell/Codex job ?대깽??
- `ShellQueued`
- `ShellStarted`
- `ShellStdout`
- `ShellStderr`
- `ShellCompleted`
- `ShellFailed`
- `ShellCancelRequested`

### OpenAI Codex runtime
- `GET /api/codex/capabilities` - TypeScript SDK / App Server scaffold / Legacy Exec provider availability
- `POST /api/codex/thread/start` - start a local Codex thread
- `POST /api/codex/thread/run` - run a Codex turn. Uses `@openai/codex-sdk` first and falls back to legacy `codex exec`
- `POST /api/codex/thread/resume` - resume a stored SDK thread by id
- `POST /api/codex/thread/cancel` - cancel an active turn
- `GET /api/codex/thread/:threadId/status` - inspect local thread status and compact run metadata

The TypeScript SDK runs only inside LocalBridge. Browser/WASM clients should call these bridge endpoints and must not import or execute Codex SDK packages directly.

### Port ownership

On startup, LocalBridge checks `BRIDGE_PORT` and stops an existing MindExec/LocalBridge listener on that same port before binding. If the port is owned by an unrelated process, startup fails with a clear message instead of silently killing it. Set `BRIDGE_FORCE_KILL_PORT_OWNER=1` only when the launcher owns that port policy and should terminate any listener.

The `start-bridge.bat` and `start-bridge.sh` wrappers always delegate startup to `launch-bridge.cjs`, so port cleanup is handled by the same guard path on every launch.
### CompanyCore ?꾨줉??- `GET /api/company-core/health` -> `CompanyCore /health`
- `GET /api/company-core/companies` -> `CompanyCore /api/companies`
- `POST /api/company-core/companies/create-and-run` -> `CompanyCore /api/companies/create-and-run`

MindExec Web? CompanyCore ?ы듃瑜?吏곸젒 ???꾩슂 ?놁씠 LocalBridge `5167`留??몄텧?섎㈃ ?⑸땲?? ???꾨줉?쒕룄 Bridge Token 蹂댄샇瑜?諛쏆뒿?덈떎.

## 蹂댁븞 二쇱쓽?ы빆

- ???쒕쾭??**濡쒖뺄?몄뒪??127.0.0.1)?먯꽌留?* ?묎렐 媛?ν빀?덈떎.
- ?묒뾽 怨듦컙 ?몃????뚯씪?먮뒗 ?묎렐?????놁뒿?덈떎.
- ?꾪뿕????紐낅졊(rm -rf, format ??? 李⑤떒?⑸땲??
- ?뚯씪 ?곌린/??젣, ?붾젆?좊━ ?앹꽦/??젣, asset ?낅줈?? shell, project open/close 媛숈? ?꾪뿕 REST API??湲곕낯?곸쑝濡?`X-Bridge-Token` ?먮뒗 `Authorization: Bearer <token>`???꾩슂?⑸땲??
- ?좏겙? `GET /api/status`??`bridgeToken`?쇰줈 ?뺤씤?⑸땲?? 怨좎젙 ?좏겙???꾩슂?섎㈃ `BRIDGE_TOKEN` ?섍꼍 蹂?섎? ?ъ슜?섏꽭??

## ?ъ슜 ?덉떆

### ?뚯씪 ?쎄린
```javascript
const response = await fetch('http://127.0.0.1:5167/api/file/read', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ path: 'test.txt' })
});
const data = await response.json();
console.log(data.content);
```

### ?뚯씪 ?곌린
```javascript
const status = await fetch('http://127.0.0.1:5167/api/status').then(r => r.json());

await fetch('http://127.0.0.1:5167/api/file/write', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        [status.bridgeTokenHeader || 'X-Bridge-Token']: status.bridgeToken
    },
    body: JSON.stringify({ 
        path: 'test.txt', 
        content: 'Hello, World!' 
    })
});
```

### ??紐낅졊 ?ㅽ뻾
```javascript
const status = await fetch('http://127.0.0.1:5167/api/status').then(r => r.json());

const response = await fetch('http://127.0.0.1:5167/api/shell/execute', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        [status.bridgeTokenHeader || 'X-Bridge-Token']: status.bridgeToken
    },
    body: JSON.stringify({ 
        command: 'dir',
        timeout: 30000 
    })
});
const result = await response.json();
console.log(result.stdout);
```

### ??job ?ㅽ듃由щ컢
```javascript
const status = await fetch('http://127.0.0.1:5167/api/status').then(r => r.json());
const ws = new WebSocket(`ws://127.0.0.1:5167/events?token=${encodeURIComponent(status.wsToken)}`);

ws.onmessage = (message) => {
    const event = JSON.parse(message.data);
    if (event.type === 'ShellStdout') console.log(event.payload.chunk);
    if (event.type === 'ShellCompleted') console.log('done', event.payload.jobId);
};

await fetch('http://127.0.0.1:5167/api/shell/jobs', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        [status.bridgeTokenHeader || 'X-Bridge-Token']: status.bridgeToken
    },
    body: JSON.stringify({
        command: 'codex exec \"Summarize this repository\"',
        timeout: 300000
    })
});
```

## CORS

湲곕낯?곸쑝濡??ㅼ쓬 origin?ㅼ씠 ?덉슜?⑸땲??
- http://localhost:5000
- http://localhost:5001
- https://localhost:5001
- http://127.0.0.1:5000
- http://127.0.0.1:5001

異붽? origin???꾩슂?섎㈃ `server.js`??CORS ?ㅼ젙???섏젙?섏꽭??

## Web怨?MAUI ?숈떆 ?ъ슜

1. 釉뚮━吏 ?쒕쾭瑜??ㅽ뻾?⑸땲??(`npm start`)
2. Web Blazor ?깆쓣 ?ㅽ뻾?⑸땲??
3. MAUI ?깆? 釉뚮━吏 ?쒕쾭 ?놁씠???묐룞?⑸땲??(吏곸젒 ?뚯씪 ?쒖뒪???묎렐)

