feat: add /deploy-plugins webhook route + deploy-plugins script
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

This commit is contained in:
2026-08-17 00:05:55 +02:00
parent eca81ae9af
commit 22fe1526ca
42 changed files with 342 additions and 8156 deletions

View File

@@ -158,52 +158,130 @@ This is the permanent solution — not a workaround. The dsh layer provides the
- [x] Phase 1-3 complete
- [x] dsh running at http://127.0.0.1:3080 with all oikos MCP tools
- [x] Consent/approval flow working end-to-end
- [ ] Commit dsh-harness plugin changes (packages/oikos/ untracked)
- [x] dsh-gate: oikos auto-runs non-destructive when no session
- [x] dsh-harness plugin changes committed
- [x] Post-execute auto-approve removed (dead code)
1. **dsh Web UI basics**
- dsh ships its own Web UI: session list, chat window with tool cards, assistant chunks, turn/step boundaries
- No changes needed for basic agent chat — it works out of the box
#### 4.0 Architecture mapping
2. **Custom ConversationNodes for oikos pages**
- **Entity Graph page** — reimplement sigma.js graph as a dsh Web Client plugin
- ConversationNode listens for tool/call events, renders entity graph
- Health/Type color mode toggle, filter presets (All, Problems, Infra)
- Port `EntityGraph.svelte`'s logic to a dsh conversation node
- **Operations page** — execution list, approval management
- Use dsh's existing `interaction` UI for approvals
- Custom node for execution history + systemctl status
- **Knowledge page** — wiki browser, search, quick-open
- dsh already has `search_knowledge` tool; add a Knowledge conversation node
- Port `WikiTree`, `WikiReader`, `WikiOverview` from oikos-web
- **Signals page** — signal list, ack/mute/resolve
- Custom node reading from oikos REST API (via dsh `agent.inject` or API call)
- **Overview/Dashboard** — fleet summary, health counts
- dsh `get_health_summary` already exists; render as dashboard cards
- **Config page** — API token, server URL, theme settings
- dsh has `settings` and `credentials` seams; hook into them
- **Desktop shell / mascot** — app launcher, dock, taskbar, Cluck mascot
- dsh has no desktop paradigm — either skip the shell or implement as a ConversationNode
- Mascot can be ported as a persistent UI element
oikos-web is a Svelte 5 desktop-windowing SPA (wmkit) with 10 apps in a floating
window manager. dsh's Web Client is a React three-column layout (sidebar |
conversation | details) with a slot-based extension system — no router, no
windowing paradigm.
3. **Route mapping**
| oikos-web page | dsh equivalent |
|---|---|
| Overview.svelte | Custom dashboard ConversationNode |
| EntityGraph.svelte | Custom entity-graph ConversationNode |
| Ops.svelte | Custom operations ConversationNode |
| Signals.svelte | Custom signals ConversationNode |
| Knowledge.svelte / KnowledgeBase.svelte | Custom knowledge ConversationNode |
| Config.svelte | dsh settings/credentials |
| Chat session | Built-in dsh chat window |
| Learning.svelte | Custom learning ConversationNode |
| AppStore.svelte | Custom app-store ConversationNode |
**Key dsh extension surfaces:**
4. **CSS theme migration**
- oikos uses dark terminal aesthetic (cyberspace theme, amber/green, dithered images)
- dsh has its own light/dark theme — customize via CSS overrides in the profile
- Port the GlyphIndicator, MascotLayer, and other visual signatures
| dsh surface | Type | Scope | Use for |
|---|---|---|---|
| `conversation.view` | list | session | View tabs replacing chat (like Trajectory) |
| `settings.section` | list | root | Full settings pages |
| `conversation.chat.node` | keyed | session | Inline chat rows (ConversationNodes) |
| `sidebar.footer.action` | list | root | Sidebar footer actions |
| `shell.overlay` | list | root | Floating overlay badges |
| `conversation.composer` | chain | session | Composer takeover (approvals) |
| `conversation.details.tool` | single | session | Right panel tool details |
| `conversation.session.header.actions` | list | session | Per-session header action buttons |
**Check:** All major oikos-web pages have a functional equivalent in dsh UI. Entity graph renders with force layout and health coloring.
**What dsh provides out of the box (no migration needed):**
- Chat window with tool cards, streaming, turn/step boundaries
- Session list (workspace browser in sidebar)
- Approval dialog (`tools/pre-execute` `ask` → built-in approval UI)
- Settings panel (theme, credentials, model selection)
- Dark/light theme with `--dsw-*` CSS token overrides
#### 4.1 Page migration plan (priority order)
**Tier 1 — Daily operations (week 1-2):**
| oikos-web page | Complexity | dsh approach | Notes |
|---|---|---|---|
| **Ops.svelte** | Medium | `settings.section` → "Operations" page | Approvals list + recent activity. Call `/api/v1/approvals`, `/api/v1/activity/recent` via `fetch()`. Approve/deny via `decide_approval` MCP tool or direct HTTP. This is the most-used page after chat. |
| **Signals.svelte** | Medium | `settings.section` → "Signals" page | Signal list with ack/mute/resolve. Call `/api/v1/signals`. Direct HTTP POSTs for actions. |
| **Config.svelte** | None | dsh built-in | Already handled by dsh settings/credentials. Token stored in dsh credentials seam. |
**Tier 2 — Navigation & fleet awareness (week 2-3):**
| oikos-web page | Complexity | dsh approach | Notes |
|---|---|---|---|
| **Overview.svelte** (Tasks) | Low | dsh built-in + `sidebar.footer.action` badge | dsh already has session list in sidebar. Add a pending-approvals count badge to `shell.overlay` via polling `/api/v1/dashboard/summary`. |
| **KnowledgeBase.svelte** (Fleet) | High | `conversation.view` → "Fleet" tab | Entity table + health status. Call `/api/v1/entities?limit=200`, `/api/v1/ontology`. Live updates via SSE `/api/v1/events/stream`. |
**Tier 3 — Complex visualizations (week 3-4):**
| oikos-web page | Complexity | dsh approach | Notes |
|---|---|---|---|
| **EntityGraph.svelte** | Very High | `conversation.view` → "Graph" tab | sigma.js + graphology force layout. Port the graph rendering to a React component registered as a view tab. Health/Type color modes, filter presets, blast radius on click. This is the hardest port (~711 LOC of Svelte → React). |
| **Knowledge.svelte** (Wiki) | High | `conversation.view` → "Knowledge" tab | Three-pane split (tree + reader + context rail). Full CRUD via `/api/v1/knowledge/*`. Markdown rendering via dsh's built-in `MarkdownText`. Wiki tree and search are the main lift. |
| **EntityDetailContent.svelte** | Very High | `conversation.details.tool` or modal | ~1188 LOC. Dynamic sections per entity type (health, checks, metrics, relations, events, signals, executions, knowledge). Consider deferring to Phase 5 or implementing incrementally (health + relations first). |
**Tier 4 — Nice to have (deferred):**
| oikos-web page | Complexity | dsh approach | Notes |
|---|---|---|---|
| **Learning.svelte** | Medium | `conversation.view` → "Learning" tab | uPlot trend chart + patterns + skills. Lower priority. |
| **AppStore.svelte** | Low | Skip | No real catalog — just "Notes" app. Not needed in dsh. |
| **Desktop shell** (wmkit) | N/A | Skip entirely | dsh uses a standard web layout, not a windowing desktop. The window manager paradigm doesn't map. |
| **Mascot (Cluck)** | Medium | `shell.overlay` or skip | Persistent animated mascot. Low priority — pure visual flair. |
| **GlyphIndicator** | Low | `shell.overlay` or sidebar footer | Canvas-rendered procedural glyph. Low priority. |
#### 4.2 CSS theme
oikos-web uses a **Gruvbox-inspired theme** (amber primary `#d79921`, dark bg `#1d2021`,
JetBrains Mono + VT323 fonts). dsh uses `--dsw-*` CSS tokens with light/dark palettes.
Migration approach:
1. Register a custom dsh theme via `ctx.theme.register()` that overrides
alias-layer tokens to match Gruvbox
2. Key token mappings:
- `--dsw-alias-brand-primary``#d79921` (amber)
- `--dsw-alias-bg-base``#1d2021` (dark bg)
- `--dsw-alias-label-primary``#ebdbb2` (warm white)
3. Fonts: dsh uses its own font system. Override via CSS `font-family` on body
if JetBrains Mono/VT323 are desired. Optional — dsh's default fonts are fine.
#### 4.3 Plugin structure
New package: `packages/oikos/ui-plugin/`
```
packages/oikos/ui-plugin/
src/
index.ts — apply(): registers all slots + theme
theme.ts — Gruvbox token overrides
ops-page.tsx — Operations settings section
signals-page.tsx — Signals settings section
fleet-view.tsx — Fleet conversation view tab
graph-view.tsx — Entity graph conversation view tab
knowledge-view.tsx — Knowledge conversation view tab
api.ts — fetch wrapper for oikos REST endpoints
package.json
tsconfig.json
```
The ui-plugin is composed into the oikos bundle (cordis.patch.yml) alongside
mcp-client, scope, and session-summary. It only runs in the Web Client bundle
(browser-side), not in the Node.js host.
#### 4.4 REST API access
dsh has no generic HTTP client for external APIs. The oikos ui-plugin will:
1. Use native `fetch()` with the oikos API base URL (from plugin config or
dsh credentials seam)
2. Wrap in a typed `OikosApi` class (`api.ts`) with methods for each endpoint
3. Handle auth via the same bearer token stored in dsh credentials
The oikos REST API remains unchanged — all existing `/api/v1/*` endpoints
continue to serve the dsh Web Client the same data they served oikos-web.
#### 4.5 SSE live updates
oikos-web uses SSE (`/api/v1/events/stream`) for real-time updates across all
pages. The ui-plugin will:
1. Open a single `EventSource` connection to `/api/v1/events/stream` on plugin init
2. Dispatch events to registered listeners (signals, approvals, entity health)
3. Auto-reconnect on disconnect (same pattern as oikos-web's `events.ts` store)
**Check:** All Tier 1 and Tier 2 pages have a functional equivalent in dsh UI.
Operator can manage approvals, signals, and view fleet health without oikos-web.
### Phase 5: Experiences as plugins (ongoing)
@@ -223,24 +301,47 @@ Each plugin:
- Listens on `agent/*` or `session/event` for reactive behavior
- Is independently versioned and hot-loadable via Cordis
## 5. Deleted code
## 5. Deleted code ~~— on completion of Phases 1-3~~ DONE (2026-08-16)
On completion of Phases 1-3, the following oikos code is decommissioned:
- `cmd/nomos/` — entire directory (~5,500 LOC): agent.go, server.go, mcp.go, store.go (the old flat store), assent.go, continue.go, tasks.go, turngate.go, messagequeue.go, retrycap.go, plus tests
**Deleted:**
- `cmd/nomos/` — entire directory: agent.go, server.go (the :8092 chat gateway
with `/query`, `/chat`, `/sessions` routes), mcp.go, tasks.go, continue.go,
workers.go, eval/ runner, plus tests
- `nomos/` — SOUL.md, config.yaml, skills/
- `internal/nomos/session/`moved to dsh plugin, but the domain types and some logic may be extracted into a shared `oikos-dsh` npm package
- `internal/httpapi/` chat-related endpoints — replaced by dsh's own agent session endpoints
- `compose/web/` — web service in docker-compose (served oikos-web SPA)
- `desktop/` — Wails desktop wrapper (dsh Web UI is a PWA, no native wrapper needed)
- `internal/nomos/session/`the flat store (mirrored by the dsh
session-summary plugin writing straight to Postgres)
- `internal/nomos/messagequeue/`, `internal/nomos/retrycap/`,
`internal/nomos/turngate/` — nomos-only machinery, no remaining importers
- `compose/nomos/` Dockerfile + the `nomos` service in docker-compose.yml
(profiles now: dev = postgres+api+scheduler, full adds worker+Infisical)
- httpapi's `/agent` reverse-proxy mount (`NOMOS_PROXY_URL`) — the only
chat-related surface in `internal/httpapi/`; the generated REST API was
already chat-free
- `evals/*.yaml` — nomos golden-conversation manifests (their only runner was
`cmd/nomos/eval`; dsh evals live at `packages/oikos/evals` in the harness
workspace)
- Script/doc cleanup: deploy.sh image list, verify-phase6.sh gateway checks,
seed-secrets.sh OpenRouter key source (host env now), README/CONTRIBUTING/
AGENTS.md/operator-facing comments
The following oikos code stays:
- `internal/httpapi/` — REST API for entities, executions, knowledge, signals, health
- `internal/mcp/` — the 67+ MCP tools (now serving dsh instead of nomos)
- `internal/policy/` — risk classification engine
- `internal/scheduler/` — health checks, metrics, probes
- `internal/secrets/` — Infisical/SOPS integration
- `internal/nomos/assent/`, `internal/nomos/session/` domain types (may be extracted to shared package)
**Already gone before this pass:** `compose/web/` (SPA extracted to
dtoro/oikos-web), `desktop/` (Wails wrapper, deleted with the SPA split).
**Kept (per the stays list):**
- `internal/nomos/assent/` — chat-assent/typed-confirmation parsing; the
assent *window* logic lives in `internal/adapters/postgres`
(governance.go/approvals.go) behind the governance port and is shared by
the dsh consent flow
- `internal/httpapi/` REST API, `internal/mcp/` (67+ tools),
`internal/policy/`, `internal/scheduler/`, `internal/secrets/`
- `OIKOS_NOMOS_AGENT_SLUG` config + compose env — resolves the seeded
`agent:nomos` entity the MCP handler attributes activity to (dsh sends no
agent identity of its own)
**Open data item:** `seeds/inventory.yaml` still carries the `agent:nomos`
entity and the `nomos_gateway: 8092` port mapping. Left as-is — the DB is
the source of truth; retire or rename the entity at runtime (set_entity_state
→ retired) when dsh gets its own agent entity.
## 6. Migration path
@@ -249,7 +350,7 @@ The cutover is a rolling deployment:
1. **Deploy dsh alongside nomos** — both agent runtimes run in parallel during development. `compose/dsh/` joins the docker-compose stack.
2. **Port the UI incrementally** — dsh UI and oikos-web coexist on different ports: dsh on `:3080`, oikos-web on `:3000`. The Caddy reverse proxy routes `/chat/*` and `/` to dsh during testing.
3. **Switch the default route** — once dsh passes all golden evals and the UI covers the main pages, Caddy routes all traffic to dsh. oikos-web becomes available at `/legacy` during the transition.
4. **Cleanup** — remove `cmd/nomos/`, `compose/web/`, `oikos-web` repo (or archive).
4. **Cleanup**~~remove `cmd/nomos/`, `compose/web/`~~ done (section 5). The `oikos-web` repo stays until Phase 4 Tier 1-2 land in the dsh UI, then archive.
## 7. Risks