feat(orchestrator): rename kvb-hub to Agent Orchestrator with the phase 2 surface
Surface (requirement 001 phase 2): navigation Stream (Inbox, Regeln) / Agents / Artifacts with keys 1-3 and hash routes (#graph and #tree redirect), header with title, command palette and settings only, server-side badges (unsnoozed inbox, beats within 900 s, open jobs), a Mayday banner with "aufheben", four stream chips with agent:/art:/seit: search, Filter and time menus, the inbox in main, an agents toolbar (Funk an alle with Newsletter, Broadcast, Pan-Pan, Security, Mayday; Priorität; Tag/Nacht), Post or Call in the agent panel, Ambiente in the settings and read-aloud over the seven classes with Mayday locked. Rename (decision 9): hub/ is orchestrator/, the package kvb_orchestrator, the unit kvb-orchestrator-runner.service, scripts/orchestrator.sh, environment KVB_ORCHESTRATOR_*, make targets orchestrator-*, the MCP server, image and compose project kvb-orchestrator, the guard header X-Kvb-Orchestrator and the message marker [kvb-orchestrator msg <id>]. install runs migrate first: it stops the old container, removes its image and code, moves state, approvals and pinned keys, swaps the MCP registration, the PermissionRequest hook and the runner unit, and changes nothing on a second run (scratch-HOME test with stub docker, claude and systemctl). Saved views fall back to the old localStorage key once. MEDUSA acceptances carried to the renamed paths: 82 rows whose lines are unchanged (reason prefixed "renamed from <old path>, line unchanged"), and 7 rows whose text changed only in the product name, the package name, a temp prefix or a new class argument, each upheld by one kvb-think-criticize skeptic (approval.py:60, messaging.py:53, server.py:56, tests/hub_support.py:64, passkey.py:205, page-agent.js:75, language.py:46). Cost 101 %: the longer name adds 15 tokens of skill text; the operator approved it with the commit. 🎯 Fix: 92 % 💥 Break: 4 % 💸 Cost: 101 % ⏱️ Time: – 🛡️ Security: 100 % 💰 Value: ? 🏆 Score: 87 🚦 Gate: ⚠️ cost 101 % > 100: ask the operator before the commit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
54f3725aa1
commit
6f940b4415
125 files changed
+1725
-782
No files matched your search
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Args:
|
||||
--bind: address the server listens on.
|
||||
--listen-port: port the server listens on.
|
||||
--public-port: port browsers and agents reach the hub on; the Host and
|
||||
Origin headers must name it.
|
||||
--council: directory holding rasci.json, news.jsonl, queue-history.jsonl,
|
||||
night.json, radio-silence.json and the claims under cluster/*/ and
|
||||
work/*/; a missing file leaves its part of the state empty. The board
|
||||
actions change it through the skill scripts.
|
||||
--pages: directory every review page must lie in.
|
||||
--state: writable directory for reviews.json, asks.json, decisions.json,
|
||||
messages.json, rules.json, jobs.json, marks.json, settings.json,
|
||||
log.jsonl, the page copies and uploads/<id>/<name>.
|
||||
--host-state: the state directory's path on the host, named in the radio
|
||||
rows that carry an upload.
|
||||
--skills: installed skills directory holding the kvb-org-radio,
|
||||
kvb-org-rasci and kvb-org-sunset scripts.
|
||||
--transcripts: directory the Claude Code transcripts (*.jsonl) lie under.
|
||||
--templates: directory holding index.html.j2 and the *.js modules it
|
||||
includes.
|
||||
--repos: directory holding the repositories as <host>/<owner>/<repo>,
|
||||
mounted read-only at its host path.
|
||||
--worktrees: directory holding linked worktrees, mounted read-only at its
|
||||
host path.
|
||||
--timers: directory holding the systemd user units (*.timer).
|
||||
--llm-url: base URL of an OpenAI-compatible chat endpoint; empty turns the
|
||||
natural-language command line off.
|
||||
--llm-model: model name sent to that endpoint; empty turns it off.
|
||||
--llm-key-file: file holding the endpoint's bearer key; empty file or
|
||||
unreadable means no key.
|
||||
--piper: the Piper executable, run as a separate process; missing turns
|
||||
speech output off.
|
||||
--voices: directory holding the Piper voices as <model>.onnx with
|
||||
<model>.onnx.json; every speaker of a model is a voice <model>:<id>.
|
||||
--operator-voice: the voice of the operator and the hub; it must be one of
|
||||
the installed voices when any is installed.
|
||||
--whisper: the whisper.cpp command line executable; missing turns speech
|
||||
input off.
|
||||
--whisper-model: the ggml model whisper.cpp loads.
|
||||
--scratch: writable directory the engines use as HOME and TMPDIR.
|
||||
--approvers: the pinned passkeys, mounted read-only; the hub only lists
|
||||
their ids and algorithms for the page and never verifies or pins.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from kvb_orchestrator import NAME
|
||||
from kvb_orchestrator.engines import Engines
|
||||
from kvb_orchestrator.errors import ToolError
|
||||
from kvb_orchestrator.exchange import HubServer
|
||||
from kvb_orchestrator.handler import Handler
|
||||
from kvb_orchestrator.hub import Places, open_hub
|
||||
from kvb_orchestrator.language import Model, read_key
|
||||
from kvb_orchestrator.skill_scripts import Scripts
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(prog=NAME)
|
||||
parser.add_argument("--bind", required=True)
|
||||
for name in ("--listen-port", "--public-port"):
|
||||
parser.add_argument(name, type=int, required=True)
|
||||
paths = ("--council", "--pages", "--state", "--host-state", "--skills", "--transcripts", "--templates", "--repos", "--worktrees", "--timers", "--llm-key-file", "--approvers")
|
||||
for name in (*paths, "--piper", "--voices", "--whisper", "--whisper-model", "--scratch"):
|
||||
parser.add_argument(name, type=Path, required=True)
|
||||
for name in ("--llm-url", "--llm-model", "--operator-voice"):
|
||||
parser.add_argument(name, required=True)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
hub = open_hub(
|
||||
council=args.council,
|
||||
pages=args.pages,
|
||||
public_port=args.public_port,
|
||||
state=args.state,
|
||||
host_state=args.host_state,
|
||||
transcripts=args.transcripts,
|
||||
scripts=Scripts(skills=args.skills, council=args.council, home=args.state),
|
||||
templates=args.templates,
|
||||
places=Places(repos=args.repos, worktrees=args.worktrees, timers=args.timers),
|
||||
model=Model(url=args.llm_url.strip(), model=args.llm_model.strip(), key=read_key(args.llm_key_file)),
|
||||
engines=Engines(piper=args.piper, voices=args.voices, operator_voice=args.operator_voice, whisper=args.whisper, whisper_model=args.whisper_model, scratch=args.scratch),
|
||||
approvers=args.approvers,
|
||||
)
|
||||
except ToolError as error:
|
||||
parser.error(str(error))
|
||||
server = HubServer((args.bind, args.listen_port), Handler)
|
||||
server.hub = hub
|
||||
print(f"{NAME}: listening on {args.bind}:{args.listen_port}, public port {args.public_port}", flush=True)
|
||||
server.serve_forever()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user