agent-zero/plugins/_orchestrator/webui/config.html
Alessandro f64b6490c5 Add bundled Orchestrator plugin
Promote the terminal agent work into the built-in plugins tree as _orchestrator with Orchestrator branding and the orchestrator skill.

Include adapter status APIs, settings UI, per-agent skill references, thumbnail asset, tests, and DOX coverage for the bundled plugin.
2026-07-09 13:18:44 +02:00

504 lines
19 KiB
HTML

<html>
<head>
<title>Orchestrator</title>
<script type="module" src="/plugins/_orchestrator/webui/orchestrator-store.js"></script>
<style>
.ta-settings {
display: grid;
gap: 16px;
}
.ta-header {
align-items: flex-start;
display: flex;
gap: 12px;
justify-content: space-between;
}
.ta-refresh.btn-icon-action {
border-radius: 8px;
color: var(--color-text);
height: 34px;
width: 34px;
}
.ta-usage {
color: var(--color-text);
font-size: 0.82rem;
line-height: 1.45;
margin-top: 10px;
max-width: 760px;
opacity: 0.82;
}
.ta-agent {
border: 1px solid var(--color-border, #333);
border-radius: 8px;
background: color-mix(in srgb, var(--color-background) 28%, transparent);
}
.ta-agent {
display: grid;
overflow: hidden;
padding: 0;
}
.ta-panel {
border-top: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
display: grid;
gap: 16px;
padding: 16px;
}
summary.ta-agent-head {
cursor: pointer;
list-style: none;
}
summary.ta-agent-head::-webkit-details-marker {
display: none;
}
.ta-agent-head {
align-items: center;
display: grid;
gap: 12px;
grid-template-columns: minmax(0, 1fr) auto;
padding: 14px;
}
.ta-agent-copy {
display: grid;
gap: 4px;
min-width: 0;
}
.ta-agent-title {
align-items: baseline;
display: flex;
flex-wrap: wrap;
gap: 8px;
min-width: 0;
}
.ta-agent-title strong {
font-size: 0.94rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ta-agent-title code {
color: var(--color-text-secondary, #aaa);
}
.ta-actions {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: flex-end;
}
.ta-action {
align-items: center;
background: #f5f7fa;
border: 0;
border-radius: 8px;
color: #111418;
cursor: pointer;
display: inline-flex;
font: inherit;
font-size: 0.76rem;
font-weight: 750;
gap: 6px;
justify-content: center;
min-height: 34px;
padding: 0 10px;
white-space: nowrap;
}
.ta-action.secondary {
background: color-mix(in srgb, var(--color-border) 44%, transparent);
border: 1px solid color-mix(in srgb, var(--color-border) 76%, transparent);
color: var(--color-text);
}
.ta-action.danger {
background: color-mix(in srgb, #f06464 16%, var(--color-panel, transparent));
border: 1px solid color-mix(in srgb, #f06464 40%, var(--color-border));
color: var(--color-text);
}
.ta-action:disabled {
cursor: default;
opacity: 0.65;
}
.ta-action .material-symbols-outlined {
font-size: 1rem;
}
.ta-form {
display: grid;
align-items: start;
gap: 16px 18px;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.ta-field {
display: grid;
gap: 7px;
min-width: 0;
}
.ta-field-toggle {
align-items: center;
grid-template-columns: minmax(0, 1fr) auto;
}
.ta-field-toggle .field-control {
justify-content: flex-end;
width: auto;
}
.ta-field .field-label {
display: grid;
gap: 3px;
padding-right: 0;
}
.ta-field .field-title {
color: color-mix(in srgb, var(--color-text) 78%, var(--color-primary));
font-size: 0.84rem;
font-weight: 800;
}
.ta-field .field-description {
color: var(--color-text);
font-size: 0.8rem;
line-height: 1.35;
margin: 0;
opacity: 0.78;
}
.ta-field .field-control {
min-width: 0;
width: 100%;
}
.ta-readonly-value {
align-items: center;
color: var(--color-text);
display: flex;
font-size: 0.82rem;
font-weight: 800;
min-height: 36px;
overflow-wrap: anywhere;
}
.ta-field input:not([type="checkbox"]),
.ta-field select {
background: color-mix(in srgb, var(--color-background) 72%, transparent);
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
border-radius: 7px;
color: var(--color-text);
min-height: 36px;
width: 100%;
}
.ta-wide {
grid-column: 1 / -1;
}
.ta-expand {
color: var(--color-text-secondary, #aaa);
transition: transform 140ms ease;
}
.ta-agent[open] .ta-expand {
transform: rotate(180deg);
}
.ta-login {
background: color-mix(in srgb, var(--color-border) 18%, transparent);
border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
border-radius: 8px;
display: grid;
gap: 8px;
padding: 12px;
}
.ta-login code {
font-size: 1.2rem;
letter-spacing: 2px;
}
@media (max-width: 720px) {
.ta-form {
grid-template-columns: 1fr;
}
.ta-header,
.ta-agent-head {
align-items: stretch;
grid-template-columns: 1fr;
}
.ta-actions {
justify-content: flex-start;
}
}
</style>
</head>
<body>
<div x-data>
<template x-if="config && $store.orchestratorStore">
<div
class="ta-settings"
x-init="$store.orchestratorStore.onOpen()"
x-destroy="$store.orchestratorStore.cleanup()"
>
<div class="ta-header">
<div>
<div class="section-title">Orchestrator</div>
<div class="section-description">
Command defaults and advanced settings for the <code>orchestrator</code> skill.
</div>
<div class="ta-usage">
Ask Agent Zero for a coding agent, or describe the session you want to start.
For example: “Consult with Codex CLI on this heavy refactor before writing code.”
Or: “Create a council with Claude Code and Codex using the models and effort levels I specify.”
</div>
</div>
<button
class="btn-icon-action ta-refresh"
type="button"
title="Refresh status"
aria-label="Refresh status"
:disabled="$store.orchestratorStore.loading"
@click="$store.orchestratorStore.refresh()"
>
<span class="material-symbols-outlined" aria-hidden="true" x-text="$store.orchestratorStore.loading ? 'progress_activity' : 'refresh'"></span>
</button>
</div>
<template x-for="agent in $store.orchestratorStore.agents" :key="agent.id">
<details class="ta-agent" x-init="$store.orchestratorStore.ensureConfig(config, agent)">
<summary class="ta-agent-head">
<div class="ta-agent-copy">
<div class="ta-agent-title">
<strong x-text="agent.title"></strong>
<code x-text="agent.id"></code>
</div>
<div class="section-description" x-text="agent.description"></div>
</div>
<div class="ta-actions">
<button
class="ta-action"
type="button"
x-show="agent.installed && !agent.auth?.connected && agent.supports_device_login && (!$store.orchestratorStore.login || $store.orchestratorStore.login.agentId !== agent.id)"
@click.stop="$store.orchestratorStore.startLogin(agent.id)"
>
<span class="material-symbols-outlined" aria-hidden="true">login</span>
<span>Connect</span>
</button>
<button
class="ta-action danger"
type="button"
x-show="agent.auth?.connected && agent.can_disconnect"
:disabled="$store.orchestratorStore.disconnectingAgent === agent.id"
@click.stop="$store.orchestratorStore.disconnect(agent.id)"
>
<span class="material-symbols-outlined" aria-hidden="true" x-text="$store.orchestratorStore.disconnectingAgent === agent.id ? 'progress_activity' : 'link_off'"></span>
<span x-text="$store.orchestratorStore.disconnectingAgent === agent.id ? 'Disconnecting' : 'Disconnect'"></span>
</button>
<span class="material-symbols-outlined ta-expand" aria-hidden="true">expand_more</span>
</div>
</summary>
<div class="ta-panel">
<div class="ta-form">
<div class="ta-field">
<div class="field-label">
<div class="field-title">Binary</div>
<div class="field-description">Command name or absolute path.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].binary" :placeholder="agent.id" spellcheck="false" />
</div>
</div>
<div class="ta-field">
<div class="field-label">
<div class="field-title">Auth</div>
<div class="field-description">Detected connection source.</div>
</div>
<div class="field-control">
<div class="ta-readonly-value" x-text="$store.orchestratorStore.authText(agent)"></div>
</div>
</div>
<div class="ta-field" x-show="agent.id === 'codex' || agent.id === 'claude' || agent.id === 'grok' || agent.id === 'hermes' || agent.id === 'opencode'">
<div class="field-label">
<div class="field-title">Model</div>
<div class="field-description">Optional CLI model override.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].model" placeholder="default" spellcheck="false" />
</div>
</div>
<div class="ta-field" x-show="agent.id === 'hermes'">
<div class="field-label">
<div class="field-title">Provider</div>
<div class="field-description">Optional Hermes provider override.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].provider" placeholder="openrouter" spellcheck="false" />
</div>
</div>
<div class="ta-field" x-show="agent.id === 'opencode'">
<div class="field-label">
<div class="field-title">Agent</div>
<div class="field-description">Optional OpenCode agent name.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].agent" placeholder="build" spellcheck="false" />
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'codex'">
<div class="field-label">
<div class="field-title">Bypass sandbox</div>
<div class="field-description">Needed in this Docker runtime.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].bypass_sandbox" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'hermes'">
<div class="field-label">
<div class="field-title">Skip approvals</div>
<div class="field-description">Pass <code>--yolo</code> for non-interactive runs.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].yolo" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'cursor'">
<div class="field-label">
<div class="field-title">Force changes</div>
<div class="field-description">Pass <code>--force</code> so scripts can modify files.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].force" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'grok'">
<div class="field-label">
<div class="field-title">Always approve</div>
<div class="field-description">Pass <code>--always-approve</code> for headless runs.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].always_approve" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'grok'">
<div class="field-label">
<div class="field-title">No auto update</div>
<div class="field-description">Pass <code>--no-auto-update</code> in automation.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].no_auto_update" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'opencode'">
<div class="field-label">
<div class="field-title">Auto approve</div>
<div class="field-description">Pass <code>--auto</code> for non-interactive runs.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].auto" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field" x-show="agent.id === 'a0'">
<div class="field-label">
<div class="field-title">Host</div>
<div class="field-description">Empty uses the local Agent Zero runtime.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].host" placeholder="http://localhost:80" spellcheck="false" />
</div>
</div>
<div class="ta-field" x-show="agent.id === 'claude'">
<div class="field-label">
<div class="field-title">Permission mode</div>
<div class="field-description">Claude Code permission preset.</div>
</div>
<div class="field-control">
<select x-model="config[agent.id].permission_mode">
<option value="bypassPermissions">Skip permissions</option>
<option value="acceptEdits">Accept edits</option>
<option value="default">Default</option>
<option value="plan">Plan</option>
<option value="auto">Auto</option>
<option value="dontAsk">Do not ask</option>
</select>
</div>
</div>
<div class="ta-field" x-show="agent.id === 'claude'">
<div class="field-label">
<div class="field-title">Allowed tools</div>
<div class="field-description">Passed to <code>--allowedTools</code>.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].allowed_tools" placeholder="Bash,Read,Edit" spellcheck="false" />
</div>
</div>
<div class="ta-field ta-field-toggle" x-show="agent.id === 'claude'">
<div class="field-label">
<div class="field-title">Bare mode</div>
<div class="field-description">Skip local Claude Code project discovery.</div>
</div>
<div class="field-control">
<label class="toggle">
<input type="checkbox" x-model="config[agent.id].bare" />
<span class="toggler"></span>
</label>
</div>
</div>
<div class="ta-field" x-show="agent.id === 'hermes'">
<div class="field-label">
<div class="field-title">Toolsets</div>
<div class="field-description">Comma-separated Hermes toolsets.</div>
</div>
<div class="field-control">
<input type="text" x-model.trim="config[agent.id].toolsets" placeholder="terminal,files" spellcheck="false" />
</div>
</div>
</div>
<template x-if="$store.orchestratorStore.login && $store.orchestratorStore.login.agentId === agent.id">
<div class="ta-login">
<div>
1. Open
<a :href="$store.orchestratorStore.login.verificationUrl" target="_blank"
x-text="$store.orchestratorStore.login.verificationUrl"></a>
</div>
<div>
2. Enter code:
<code x-text="$store.orchestratorStore.login.userCode"></code>
</div>
<div>
Waiting for confirmation…
<button class="ta-action secondary" type="button" @click="$store.orchestratorStore.cancelLogin()">Cancel</button>
</div>
</div>
</template>
</div>
</details>
</template>
<div x-show="!$store.orchestratorStore.loading && $store.orchestratorStore.agents.length === 0" style="opacity: 0.7;">
No agents registered.
</div>
</div>
</template>
</div>
</body>
</html>