mirror of
https://github.com/MrFadiAi/openclaw-manager.git
synced 2026-08-14 00:57:59 +00:00
fix: gateway start on windows, auth flow, and ui enhancements
This commit is contained in:
@@ -30,10 +30,12 @@ Real-time monitoring and full lifecycle management of the OpenClaw service.
|
||||
- Live service status (port, PID, memory usage, uptime)
|
||||
- **Start / Stop / Restart / Kill All** actions
|
||||
- Real-time log viewer with auto-refresh
|
||||
- **Web Control UI**: Direct chat interface with your agents (served at `http://localhost:18789`)
|
||||
|
||||
**How to Use:**
|
||||
- **Start Service:** Click the **Start** button in the dashboard top-right corner.
|
||||
- **View Logs:** Check the "Live Logs" card for immediate output or go to the **Logs** tab for history.
|
||||
- **Control UI:** Once the service is running, open `http://localhost:18789` to chat with your agents directly.
|
||||
- **System Check:** Use the "System Requirements" card to verify your environment health.
|
||||
|
||||
### 🤖 AI Model Configuration
|
||||
|
||||
@@ -1939,7 +1939,8 @@ pub async fn save_telegram_account(account: TelegramAccount) -> Result<String, S
|
||||
if account.primary == Some(true) {
|
||||
manager_config["primaryBotAccount"] = json!(account.id);
|
||||
|
||||
// --- NEW LOGIC: Configure primary agent workspace ---
|
||||
// --- NEW LOGIC DISABLED: Do NOT auto-create main agent or binding ---
|
||||
/*
|
||||
// 1. Ensure "main" agent exists pointing to ~/.openclaw/workspace
|
||||
let openclaw_home = platform::get_config_dir();
|
||||
// Resolve ~/.openclaw/workspace
|
||||
@@ -2041,6 +2042,7 @@ pub async fn save_telegram_account(account: TelegramAccount) -> Result<String, S
|
||||
}));
|
||||
}
|
||||
config["bindings"] = json!(bindings);
|
||||
*/
|
||||
// --- END NEW LOGIC ---
|
||||
|
||||
} else {
|
||||
@@ -2623,7 +2625,13 @@ pub async fn save_agent(agent: AgentInfo) -> Result<String, String> {
|
||||
// Update or add the agent
|
||||
if let Some(idx) = match_index {
|
||||
let existing = &mut list[idx];
|
||||
|
||||
// Merge: only overwrite fields the user explicitly set (non-empty)
|
||||
if let Some(name) = &agent.name {
|
||||
if !name.is_empty() {
|
||||
existing["name"] = json!(name);
|
||||
}
|
||||
}
|
||||
if let Some(model) = &agent.model {
|
||||
if !model.is_empty() {
|
||||
existing["model"] = json!({ "primary": model });
|
||||
@@ -2634,6 +2642,14 @@ pub async fn save_agent(agent: AgentInfo) -> Result<String, String> {
|
||||
existing["default"] = json!(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce "Main" agent properties
|
||||
if agent.id.eq_ignore_ascii_case("main") {
|
||||
// "Main" should always be default unless user explicitly sets another default (which handles itself)
|
||||
// But to ensure fallback behavior, we mark it.
|
||||
existing["default"] = json!(true);
|
||||
}
|
||||
|
||||
if let Some(sub) = &agent.subagents {
|
||||
if let Some(allow) = &sub.allow_agents {
|
||||
if !allow.is_empty() {
|
||||
@@ -2801,19 +2817,29 @@ pub async fn delete_agent(agent_id: String) -> Result<String, String> {
|
||||
|
||||
if let Some(agent_dir) = agent_dir_to_delete {
|
||||
let path = std::path::Path::new(&agent_dir);
|
||||
if path.exists() {
|
||||
info!("[Agents] Removing agent directory: {}", agent_dir);
|
||||
if let Err(e) = std::fs::remove_dir_all(path) {
|
||||
warn!("[Agents] Failed to remove agent directory {}: {}", agent_dir, e);
|
||||
// Check if this is a nested 'agent' directory (standard structure: .../agents/<id>/agent)
|
||||
// If so, we want to delete the PARENT directory (e.g. .../agents/<id>) to clean up everything including sessions.
|
||||
let path_to_remove = if path.ends_with("agent") {
|
||||
path.parent().unwrap_or(path)
|
||||
} else {
|
||||
path
|
||||
};
|
||||
|
||||
if path_to_remove.exists() {
|
||||
info!("[Agents] Removing agent directory tree: {:?}", path_to_remove);
|
||||
if let Err(e) = std::fs::remove_dir_all(path_to_remove) {
|
||||
warn!("[Agents] Failed to remove agent directory {:?}: {}", path_to_remove, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: try default location if not specified in config
|
||||
let openclaw_home = platform::get_config_dir();
|
||||
let default_agent_dir = std::path::Path::new(&openclaw_home).join("agents").join(&agent_id);
|
||||
if default_agent_dir.exists() {
|
||||
info!("[Agents] Removing default agent directory: {:?}", default_agent_dir);
|
||||
if let Err(e) = std::fs::remove_dir_all(&default_agent_dir) {
|
||||
// Default structure is now ~/.openclaw/agents/<id> (which contains agent/, sessions/, etc.)
|
||||
let default_agent_root = std::path::Path::new(&openclaw_home).join("agents").join(&agent_id);
|
||||
|
||||
if default_agent_root.exists() {
|
||||
info!("[Agents] Removing default agent directory tree: {:?}", default_agent_root);
|
||||
if let Err(e) = std::fs::remove_dir_all(&default_agent_root) {
|
||||
warn!("[Agents] Failed to remove default agent directory: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,13 +364,11 @@ pub fn run_openclaw(args: &[&str]) -> Result<String, String> {
|
||||
let extended_path = get_extended_path();
|
||||
debug!("[Shell] Extended PATH: {}", extended_path);
|
||||
|
||||
let output = if openclaw_path.ends_with(".cmd") {
|
||||
// Windows: .cmd files need to be executed via cmd /c
|
||||
let mut cmd_args = vec!["/c", &openclaw_path];
|
||||
cmd_args.extend(args);
|
||||
let mut cmd = Command::new("cmd");
|
||||
let output = if platform::is_windows() && openclaw_path.ends_with(".cmd") {
|
||||
// Windows: .cmd files can be executed directly
|
||||
let mut cmd = Command::new(&openclaw_path);
|
||||
let gw_token = get_gateway_token_from_config();
|
||||
cmd.args(&cmd_args)
|
||||
cmd.args(args)
|
||||
.env("OPENCLAW_GATEWAY_TOKEN", &gw_token)
|
||||
.env("PATH", &extended_path);
|
||||
|
||||
@@ -559,15 +557,15 @@ pub fn spawn_openclaw_gateway() -> io::Result<()> {
|
||||
let extended_path = get_extended_path();
|
||||
info!("[Shell] Extended PATH: {}", extended_path);
|
||||
|
||||
// On Windows, .cmd files need to be executed via cmd /c
|
||||
// On Windows, .cmd files can be executed directly by Command::new
|
||||
// Set environment variable OPENCLAW_GATEWAY_TOKEN so all subcommands can use it automatically
|
||||
let mut cmd = if openclaw_path.ends_with(".cmd") {
|
||||
info!("[Shell] Windows mode: executing via cmd /c");
|
||||
let mut c = Command::new("cmd");
|
||||
c.args(["/c", &openclaw_path, "gateway", "--port", "18789"]);
|
||||
let mut cmd = if platform::is_windows() && openclaw_path.ends_with(".cmd") {
|
||||
info!("[Shell] Windows mode: executing .cmd directly");
|
||||
let mut c = Command::new(&openclaw_path);
|
||||
c.args(["gateway", "--port", "18789"]);
|
||||
c
|
||||
} else {
|
||||
info!("[Shell] Unix mode: executing directly");
|
||||
info!("[Shell] Unix/Direct mode: executing directly");
|
||||
let mut c = Command::new(&openclaw_path);
|
||||
c.args(["gateway", "--port", "18789"]);
|
||||
c
|
||||
|
||||
@@ -742,27 +742,7 @@ export function Agents() {
|
||||
placeholder="e.g. coder"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 pt-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="defaultAgent"
|
||||
checked={agentForm.default || false}
|
||||
onChange={e => {
|
||||
const isDefault = e.target.checked;
|
||||
const id = agentForm.id || 'agent';
|
||||
const base = openclawHomeDir ? openclawHomeDir.replace(/\\/g, '/') : '';
|
||||
setAgentForm({
|
||||
...agentForm,
|
||||
default: isDefault || null,
|
||||
workspace: base ? (isDefault ? `${base}/workspace` : `${base}/workspace-${id}`) : agentForm.workspace,
|
||||
agent_dir: base ? `${base}/agents/${id}/agent` : agentForm.agent_dir,
|
||||
});
|
||||
}}
|
||||
className="w-4 h-4 rounded bg-dark-600 border-dark-500 text-claw-500 focus:ring-claw-500/50"
|
||||
/>
|
||||
<label htmlFor="defaultAgent" className="text-sm text-gray-300 select-none">Default Agent</label>
|
||||
<span className="text-xs text-gray-500 ml-1">(uses main workspace)</span>
|
||||
</div>
|
||||
{/* Default Agent checkbox removed - Main agent is always default */}\n
|
||||
<div>
|
||||
<label className="block text-sm text-gray-400 mb-1">Workspace Path</label>
|
||||
<input
|
||||
@@ -772,7 +752,7 @@ export function Agents() {
|
||||
className="input-base"
|
||||
placeholder={openclawHomeDir ? (agentForm.default ? `${openclawHomeDir.replace(/\\/g, '/')}/workspace` : `${openclawHomeDir.replace(/\\/g, '/')}/workspace-${agentForm.id || 'agent'}`) : '/path/to/workspace'}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">Default: <code className="text-gray-400">{openclawHomeDir ? (agentForm.default ? `${openclawHomeDir.replace(/\\/g, '/')}/workspace` : `${openclawHomeDir.replace(/\\/g, '/')}/workspace-${agentForm.id || '{id}'}`) : '~/.openclaw/workspace-{id}'}</code></p>
|
||||
<p className="text-xs text-gray-500 mt-1">Default: <code className="text-gray-400">{openclawHomeDir ? `${openclawHomeDir.replace(/\\/g, '/')}/workspace-${agentForm.id || '{id}'}` : '~/.openclaw/workspace-{id}'}</code></p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-400 mb-1">Agent Directory</label>
|
||||
@@ -1038,19 +1018,9 @@ export function Agents() {
|
||||
className="input-base"
|
||||
placeholder="e.g. coder"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">Workspace: <code className="text-gray-400">{wizardForm.isDefault ? 'workspace/' : `workspace-${wizardForm.agentId || '{id}'}/`}</code></p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="wizardDefaultAgent"
|
||||
checked={wizardForm.isDefault}
|
||||
onChange={e => setWizardForm({ ...wizardForm, isDefault: e.target.checked })}
|
||||
className="w-4 h-4 rounded bg-dark-600 border-dark-500 text-claw-500 focus:ring-claw-500/50"
|
||||
/>
|
||||
<label htmlFor="wizardDefaultAgent" className="text-sm text-gray-300 select-none">Default Agent</label>
|
||||
<span className="text-xs text-gray-500 ml-1">(uses main workspace)</span>
|
||||
<p className="text-xs text-gray-500 mt-1">Workspace: <code className="text-gray-400">{`workspace-${wizardForm.agentId || '{id}'}/`}</code></p>
|
||||
</div>
|
||||
{/* Default Agent checkbox removed */}\n
|
||||
<div>
|
||||
<label className="block text-sm text-gray-400 mb-1">Model Override (Optional)</label>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user