Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: desktop

on:
push:
branches: [main]
paths:
- "src-tauri/**"
- "console/**"
- "crates/**"
- ".github/workflows/desktop.yml"
pull_request:
paths:
- "src-tauri/**"
- "console/**"
- "crates/**"
- ".github/workflows/desktop.yml"
workflow_dispatch:

env:
CARGO_TERM_COLOR: always

jobs:
# Stage 1: cheap Linux compile-validation of the Tauri app (the Rust bridge +
# wiring must build). macOS/Windows bundling is a follow-on once this is green.
compile-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Tauri Linux system deps
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libgtk-3-dev librsvg2-dev \
libayatana-appindicator3-dev patchelf
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Build the web skin
run: |
npm --prefix console ci
npm --prefix console run build
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "src-tauri -> target"
- name: cargo build (studio-desktop)
working-directory: src-tauri
run: cargo build

# Stage 2: bundle a macOS app on GitHub's free macOS runner (public repo).
# Native arm64, UNSIGNED for now (Gatekeeper: right-click → Open, or
# `xattr -dr com.apple.quarantine`). Universal + code-signing + updater are
# follow-ons (ADR-4). Artifact = the .dmg to download and run.
bundle-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Build the web skin
run: |
npm --prefix console ci
npm --prefix console run build
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "src-tauri -> target"
- name: Install Tauri CLI
run: npm install -g @tauri-apps/cli@^2
- name: Bundle (.app + .dmg)
run: tauri build
- name: Upload macOS bundle
uses: actions/upload-artifact@v4
with:
name: studio-macos-arm64
path: |
src-tauri/target/release/bundle/dmg/*.dmg
src-tauri/target/release/bundle/macos/*.app
if-no-files-found: error
retention-days: 7
3 changes: 3 additions & 0 deletions console/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
dist/
*.local
50 changes: 50 additions & 0 deletions console/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# studio-console (ADR-3 slice-1)

The Studio director's console — **web skin**. A thin front-end over the control
plane's read-model: it renders the deployment **roster** with each instance's
canonical **6-state** and `ready/desired/current` counters, refreshed by
**polling**.

Per [ADR-3](../docs/adr/desktop-console.md), the skin is a client of the
`oab-mcp` / studio-cp read-model — it does not re-implement observation. The
same web build is both the Tauri desktop front-end (slice-2) and a standalone
browser console.

## Run

```sh
cd console
npm install
npm run dev # http://localhost:5173 — renders from MockSource fixtures
```

No core is required: outside the Tauri shell the console uses `MockSource`
(fixtures). A static preview is produced by `npm run build` → open
`dist/index.html` directly (file://).

## Verify

```sh
npm run typecheck # tsc --noEmit, strict
npm test # vitest — rosterHtml rendering logic
npm run build # tsc + vite build → dist/
```

## Structure

| File | Role |
|------|------|
| `src/types.ts` | view-model contract — mirrors studio-cp `Deployment`/`InstancePhase` + `AgentState` |
| `src/source.ts` | `Source` interface + `MockSource` (fixtures) / `TauriSource` (desktop) |
| `src/render.ts` | pure `rosterHtml(deployments)` → table; `renderRoster` sets it on the DOM |
| `src/main.ts` | polls `Source` every 5s and re-renders |
| `src/fixtures.ts` | stand-in roster data |

## Wiring to the core (slice-2)

`TauriSource` calls the Tauri `deploy_list` command via the global bridge
(`window.__TAURI__.core.invoke`), so slice-1 carries no `@tauri-apps/api`
dependency. Slice-2 adds `src-tauri/` whose Rust `deploy_list` command bridges
to `studio-cp::observe_services` / `observe_deployment`. Because the boundary is
the read-model shape (and, later, MCP), swapping `MockSource` → `TauriSource` is
the only change the UI sees.
20 changes: 20 additions & 0 deletions console/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OAB Studio — Console</title>
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<header class="topbar">
<div class="brand">OAB <span>Studio</span></div>
<div class="meta">
<span class="cluster" id="cluster-label"></span>
<span class="status" id="poll-status"></span>
</div>
</header>
<main id="roster" class="roster-wrap"></main>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Loading
Loading