Rename binary to agent-orchestrator, add splash screen, fix white flash
- Rename Cargo package from bterminal to agent-orchestrator so WM_CLASS matches desktop entry and taskbar groups correctly - Update lib name (agent_orchestrator_lib) and telemetry service name - Add Pandora's Box splash screen with progress steps during startup - Prevent white window flash with inline CSS and Tauri backgroundColor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
79e13649a1
commit
adde8462ef
9 changed files with 213 additions and 49 deletions
62
v2/Cargo.lock
generated
62
v2/Cargo.lock
generated
|
|
@ -8,6 +8,37 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "agent-orchestrator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bterminal-core",
|
||||
"dirs 5.0.1",
|
||||
"futures-util",
|
||||
"keyring",
|
||||
"log",
|
||||
"notify",
|
||||
"notify-rust",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry_sdk",
|
||||
"rfd",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-updater",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
|
|
@ -363,37 +394,6 @@ dependencies = [
|
|||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bterminal"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bterminal-core",
|
||||
"dirs 5.0.1",
|
||||
"futures-util",
|
||||
"keyring",
|
||||
"log",
|
||||
"notify",
|
||||
"notify-rust",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry_sdk",
|
||||
"rfd",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-updater",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bterminal-core"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Agent Orchestrator</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #1e1e2e; height: 100%; overflow: hidden; }
|
||||
#app { height: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "bterminal"
|
||||
name = "agent-orchestrator"
|
||||
version = "0.1.0"
|
||||
description = "Multi-session Claude agent dashboard"
|
||||
authors = ["DexterFromLab"]
|
||||
|
|
@ -10,7 +10,7 @@ rust-version = "1.77.2"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
name = "bterminal_lib"
|
||||
name = "agent_orchestrator_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
bterminal_lib::run();
|
||||
agent_orchestrator_lib::run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl Drop for TelemetryGuard {
|
|||
/// Call once at app startup, before any tracing macros fire.
|
||||
pub fn init() -> TelemetryGuard {
|
||||
let filter = EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| EnvFilter::new("bterminal=info,bterminal_lib=info,bterminal_core=info"));
|
||||
.unwrap_or_else(|_| EnvFilter::new("agent_orchestrator=info,agent_orchestrator_lib=info,bterminal_core=info"));
|
||||
|
||||
let fmt_layer = tracing_subscriber::fmt::layer()
|
||||
.with_target(true)
|
||||
|
|
@ -42,7 +42,7 @@ pub fn init() -> TelemetryGuard {
|
|||
match build_otlp_provider(&endpoint) {
|
||||
Ok(provider) => {
|
||||
let otel_layer = tracing_opentelemetry::layer()
|
||||
.with_tracer(provider.tracer("bterminal"));
|
||||
.with_tracer(provider.tracer("agent-orchestrator"));
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
|
|
@ -90,7 +90,7 @@ fn build_otlp_provider(endpoint: &str) -> Result<SdkTracerProvider, Box<dyn std:
|
|||
|
||||
let resource = Resource::builder()
|
||||
.with_attributes([
|
||||
KeyValue::new("service.name", "bterminal"),
|
||||
KeyValue::new("service.name", "agent-orchestrator"),
|
||||
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
|
||||
])
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
"height": 1080,
|
||||
"resizable": true,
|
||||
"fullscreen": false,
|
||||
"decorations": true
|
||||
"decorations": true,
|
||||
"backgroundColor": [30, 30, 46, 255]
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
// Shared
|
||||
import StatusBar from './lib/components/StatusBar/StatusBar.svelte';
|
||||
import ToastContainer from './lib/components/Notifications/ToastContainer.svelte';
|
||||
import SplashScreen from './lib/components/SplashScreen.svelte';
|
||||
|
||||
// Detached mode (preserved from v2)
|
||||
import TerminalPane from './lib/components/Terminal/TerminalPane.svelte';
|
||||
|
|
@ -44,6 +45,19 @@
|
|||
let drawerOpen = $state(false);
|
||||
let loaded = $state(false);
|
||||
|
||||
// Splash screen loading steps
|
||||
let splashSteps = $state([
|
||||
{ label: 'Initializing theme...', done: false },
|
||||
{ label: 'Registering providers...', done: false },
|
||||
{ label: 'Starting agent dispatcher...', done: false },
|
||||
{ label: 'Connecting sidecar...', done: false },
|
||||
{ label: 'Loading workspace...', done: false },
|
||||
]);
|
||||
|
||||
function markStep(idx: number) {
|
||||
splashSteps[idx] = { ...splashSteps[idx], done: true };
|
||||
}
|
||||
|
||||
let activeTab = $derived(getActiveTab());
|
||||
let panelContentEl: HTMLElement | undefined = $state();
|
||||
let panelWidth = $state<string | undefined>(undefined);
|
||||
|
|
@ -77,26 +91,42 @@
|
|||
}
|
||||
|
||||
onMount(() => {
|
||||
// Step 0: Theme
|
||||
initTheme();
|
||||
getSetting('project_max_aspect').then(v => {
|
||||
if (v) document.documentElement.style.setProperty('--project-max-aspect', v);
|
||||
});
|
||||
markStep(0);
|
||||
|
||||
// Step 1: Providers
|
||||
registerProvider(CLAUDE_PROVIDER);
|
||||
registerProvider(CODEX_PROVIDER);
|
||||
registerProvider(OLLAMA_PROVIDER);
|
||||
const memora = new MemoraAdapter();
|
||||
registerMemoryAdapter(memora);
|
||||
memora.checkAvailability();
|
||||
markStep(1);
|
||||
|
||||
// Step 2: Agent dispatcher
|
||||
startAgentDispatcher();
|
||||
startHealthTick();
|
||||
markStep(2);
|
||||
|
||||
// Disable wake scheduler in test mode to prevent timer interference
|
||||
invoke<boolean>('is_test_mode').then(isTest => {
|
||||
if (isTest) disableWakeScheduler();
|
||||
});
|
||||
|
||||
// Step 3: Sidecar (small delay to let sidecar report ready)
|
||||
setTimeout(() => markStep(3), 300);
|
||||
|
||||
if (!detached) {
|
||||
loadWorkspace().then(() => { loaded = true; });
|
||||
// Step 4: Workspace
|
||||
loadWorkspace().then(() => {
|
||||
markStep(4);
|
||||
// Brief pause to show completed state before transition
|
||||
setTimeout(() => { loaded = true; }, 400);
|
||||
});
|
||||
}
|
||||
|
||||
/** Check if event target is an editable element (input, textarea, contenteditable) */
|
||||
|
|
@ -299,7 +329,7 @@
|
|||
<CommandPalette open={paletteOpen} onclose={() => paletteOpen = false} />
|
||||
<SearchOverlay open={searchOpen} onclose={() => searchOpen = false} />
|
||||
{:else}
|
||||
<div class="loading">Loading workspace...</div>
|
||||
<SplashScreen steps={splashSteps} />
|
||||
{/if}
|
||||
<ToastContainer />
|
||||
|
||||
|
|
@ -380,13 +410,4 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
color: var(--ctp-overlay0);
|
||||
font-size: 0.9rem;
|
||||
background: var(--ctp-base);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
BIN
v2/src/assets/splash.jpg
Normal file
BIN
v2/src/assets/splash.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
138
v2/src/lib/components/SplashScreen.svelte
Normal file
138
v2/src/lib/components/SplashScreen.svelte
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<script lang="ts">
|
||||
import splashImg from '../../assets/splash.jpg';
|
||||
|
||||
interface Props {
|
||||
steps: { label: string; done: boolean }[];
|
||||
version?: string;
|
||||
}
|
||||
|
||||
let { steps, version = 'v3' }: Props = $props();
|
||||
|
||||
let doneCount = $derived(steps.filter(s => s.done).length);
|
||||
let progress = $derived(steps.length > 0 ? doneCount / steps.length : 0);
|
||||
let currentStep = $derived(steps.find(s => !s.done)?.label ?? 'Ready');
|
||||
</script>
|
||||
|
||||
<div class="splash">
|
||||
<img src={splashImg} alt="" class="splash-bg" />
|
||||
<div class="splash-overlay"></div>
|
||||
|
||||
<div class="splash-content">
|
||||
<div class="splash-title">
|
||||
<h1>Agent Orchestrator</h1>
|
||||
<span class="splash-version">{version}</span>
|
||||
<span class="splash-codename">Pandora's Box</span>
|
||||
</div>
|
||||
|
||||
<div class="splash-progress">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style:width="{progress * 100}%"></div>
|
||||
</div>
|
||||
<div class="progress-label">{currentStep}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.splash {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #1e1e2e;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.splash-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 0.4;
|
||||
filter: blur(2px);
|
||||
}
|
||||
|
||||
.splash-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(30, 30, 46, 0.3) 0%,
|
||||
rgba(30, 30, 46, 0.6) 50%,
|
||||
rgba(30, 30, 46, 0.95) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.splash-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
width: min(480px, 90vw);
|
||||
}
|
||||
|
||||
.splash-title {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.splash-title h1 {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
color: #cdd6f4;
|
||||
margin: 0;
|
||||
letter-spacing: 0.02em;
|
||||
text-shadow: 0 2px 12px rgba(203, 166, 247, 0.3);
|
||||
}
|
||||
|
||||
.splash-version {
|
||||
font-size: 0.75rem;
|
||||
color: #a6adc8;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.splash-codename {
|
||||
font-size: 0.7rem;
|
||||
color: #cba6f7;
|
||||
font-style: italic;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.splash-progress {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: rgba(108, 112, 134, 0.3);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #cba6f7, #89b4fa);
|
||||
border-radius: 2px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: 0.7rem;
|
||||
color: #6c7086;
|
||||
text-align: center;
|
||||
min-height: 1em;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue