g3 console init
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::models::*;
|
||||
use crate::process::{ProcessController, ProcessDetector};
|
||||
use crate::process::ProcessController;
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -82,7 +82,14 @@ pub async fn launch_instance(
|
||||
|
||||
// Validate binary path if provided
|
||||
if let Some(ref binary_path) = request.g3_binary_path {
|
||||
let path = std::path::Path::new(binary_path);
|
||||
// Expand relative paths and resolve to absolute
|
||||
let path = if binary_path.starts_with("./") || binary_path.starts_with("../") {
|
||||
std::env::current_dir()
|
||||
.map(|cwd| cwd.join(binary_path))
|
||||
.unwrap_or_else(|_| std::path::PathBuf::from(binary_path))
|
||||
} else {
|
||||
std::path::PathBuf::from(binary_path)
|
||||
};
|
||||
|
||||
// Check if file exists
|
||||
if !path.exists() {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::logs::{LogParser, StatsAggregator};
|
||||
use crate::models::*;
|
||||
use crate::process::ProcessDetector;
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use axum::{extract::{Query, State}, http::StatusCode, Json};
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{debug, error, warn};
|
||||
@@ -187,3 +188,34 @@ fn read_file_snippet(workspace: &std::path::Path, filename: &str) -> Option<Stri
|
||||
.join("\n")
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FileQuery {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub async fn get_file_content(
|
||||
axum::extract::Path(id): axum::extract::Path<String>,
|
||||
Query(query): Query<FileQuery>,
|
||||
State(detector): State<AppState>,
|
||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let mut detector = detector.lock().await;
|
||||
|
||||
// Find the instance
|
||||
let instances = detector.detect_instances().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let instance = instances.iter().find(|i| i.id == id).ok_or(StatusCode::NOT_FOUND)?;
|
||||
|
||||
// Read the full file
|
||||
let file_path = instance.workspace.join(&query.name);
|
||||
if !file_path.exists() {
|
||||
return Err(StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(&file_path)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(serde_json::json!({
|
||||
"name": query.name,
|
||||
"content": content,
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::logs::LogParser;
|
||||
use crate::models::*;
|
||||
use crate::process::ProcessDetector;
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -2,8 +2,3 @@ pub mod instances;
|
||||
pub mod control;
|
||||
pub mod logs;
|
||||
pub mod state;
|
||||
|
||||
pub use instances::*;
|
||||
pub use control::*;
|
||||
pub use logs::*;
|
||||
pub use state::*;
|
||||
|
||||
@@ -44,7 +44,7 @@ pub struct BrowseResponse {
|
||||
pub struct FileEntry {
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
pub is_directory: bool,
|
||||
pub is_dir: bool,
|
||||
pub is_executable: bool,
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ pub async fn browse_filesystem(
|
||||
entries.push(FileEntry {
|
||||
name: entry.file_name().to_string_lossy().to_string(),
|
||||
path: entry.path().to_string_lossy().to_string(),
|
||||
is_directory: metadata.is_dir(),
|
||||
is_dir: metadata.is_dir(),
|
||||
is_executable: metadata.permissions().mode() & 0o111 != 0,
|
||||
});
|
||||
}
|
||||
@@ -84,7 +84,7 @@ pub async fn browse_filesystem(
|
||||
}
|
||||
|
||||
entries.sort_by(|a, b| {
|
||||
match (a.is_directory, b.is_directory) {
|
||||
match (a.is_dir, b.is_dir) {
|
||||
(true, false) => std::cmp::Ordering::Less,
|
||||
(false, true) => std::cmp::Ordering::Greater,
|
||||
_ => a.name.cmp(&b.name),
|
||||
|
||||
@@ -57,10 +57,10 @@ impl ConsoleState {
|
||||
}
|
||||
|
||||
fn config_path() -> PathBuf {
|
||||
// Use explicit ~/.config/g3/console-state.json path as per requirements
|
||||
// Use explicit ~/.config/g3/console.json path as per requirements
|
||||
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
home.join(".config")
|
||||
.join("g3")
|
||||
.join("console-state.json")
|
||||
.join("console.json")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ mod models;
|
||||
mod process;
|
||||
mod launch;
|
||||
|
||||
use api::control::{kill_instance, launch_instance, restart_instance, ControllerState};
|
||||
use api::instances::{get_instance, list_instances, AppState};
|
||||
use api::control::{kill_instance, launch_instance, restart_instance};
|
||||
use api::instances::{get_instance, get_file_content, list_instances};
|
||||
use api::logs::get_instance_logs;
|
||||
use api::state::{get_state, save_state, browse_filesystem};
|
||||
use axum::{
|
||||
@@ -56,6 +56,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
.route("/instances", get(list_instances))
|
||||
.route("/instances/:id", get(get_instance))
|
||||
.route("/instances/:id/logs", get(get_instance_logs))
|
||||
.route("/instances/:id/file", get(get_file_content))
|
||||
.with_state(detector.clone());
|
||||
|
||||
let control_routes = Router::new()
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
use std::path::PathBuf;
|
||||
use sysinfo::{Pid, Signal, System, Process};
|
||||
use tracing::{debug, error, info};
|
||||
use tracing::{debug, info};
|
||||
use crate::models::LaunchParams;
|
||||
|
||||
pub struct ProcessController {
|
||||
@@ -120,8 +120,8 @@ impl ProcessController {
|
||||
// We need to scan for it by matching workspace and recent start time
|
||||
info!("Scanning for newly launched g3 process in workspace: {}", workspace);
|
||||
|
||||
// Wait a moment for the process to fully start
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
// Wait even longer for the process to fully start and appear in process list
|
||||
std::thread::sleep(std::time::Duration::from_millis(2500));
|
||||
|
||||
// Refresh and scan for the process
|
||||
self.system.refresh_processes();
|
||||
@@ -149,11 +149,11 @@ impl ProcessController {
|
||||
});
|
||||
|
||||
if has_workspace {
|
||||
// Check if it's recent (started within last 5 seconds)
|
||||
// Check if it's recent (started within last 10 seconds)
|
||||
let now = std::time::SystemTime::now();
|
||||
let start_time = std::time::UNIX_EPOCH + std::time::Duration::from_secs(process.start_time());
|
||||
if let Ok(duration) = now.duration_since(start_time) {
|
||||
if duration.as_secs() < 5 {
|
||||
if duration.as_secs() < 10 {
|
||||
found_pid = Some(pid.as_u32());
|
||||
break;
|
||||
}
|
||||
@@ -161,7 +161,42 @@ impl ProcessController {
|
||||
}
|
||||
}
|
||||
|
||||
let pid = found_pid.unwrap_or(intermediate_pid);
|
||||
let pid = if let Some(found) = found_pid {
|
||||
found
|
||||
} else {
|
||||
// If we couldn't find it, try one more refresh after a longer delay
|
||||
info!("Process not found on first scan, trying again...");
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
self.system.refresh_processes();
|
||||
|
||||
// Try the scan again with full logic
|
||||
let mut retry_found = None;
|
||||
for (pid, process) in self.system.processes() {
|
||||
let cmd = process.cmd();
|
||||
let cmd_str = cmd.join(" ");
|
||||
|
||||
let is_g3 = process.name().contains("g3") || cmd_str.contains("g3");
|
||||
if !is_g3 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let has_workspace = cmd.iter().any(|arg| {
|
||||
if let Ok(path) = PathBuf::from(arg).canonicalize() {
|
||||
if let Ok(ws) = workspace_path.canonicalize() {
|
||||
return path == ws;
|
||||
}
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
if has_workspace {
|
||||
retry_found = Some(pid.as_u32());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retry_found.unwrap_or(intermediate_pid)
|
||||
};
|
||||
|
||||
info!("Launched g3 process with PID {}", pid);
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::models::{ExecutionMethod, Instance, InstanceStatus, InstanceType};
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::Result;
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use sysinfo::{System, Process, Pid};
|
||||
use sysinfo::{System, Pid, Process};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
pub struct ProcessDetector {
|
||||
@@ -46,14 +45,26 @@ impl ProcessDetector {
|
||||
) -> Option<Instance> {
|
||||
let cmd_str = cmd.join(" ");
|
||||
|
||||
// Check if this is a g3 binary
|
||||
let is_g3_binary = cmd.get(0).map(|s| s.ends_with("g3")).unwrap_or(false);
|
||||
// Check if this is a g3 binary (more comprehensive check)
|
||||
let is_g3_binary = cmd.get(0).map(|s| {
|
||||
s.ends_with("g3") || s.ends_with("/g3") || s.contains("/target/release/g3") || s.contains("/target/debug/g3")
|
||||
}).unwrap_or(false);
|
||||
|
||||
// Check if this is cargo run with g3
|
||||
let is_cargo_run = cmd.get(0).map(|s| s.contains("cargo")).unwrap_or(false)
|
||||
&& cmd.iter().any(|s| s == "run" || s.contains("g3"));
|
||||
|
||||
if !is_g3_binary && !is_cargo_run {
|
||||
let is_cargo_run = cmd.get(0).map(|s| s.contains("cargo")).unwrap_or(false) && cmd.iter().any(|s| s == "run");
|
||||
|
||||
// Also check if any part of the command line contains g3-related patterns
|
||||
let has_g3_pattern = cmd_str.contains("g3 ")
|
||||
|| cmd_str.contains("/g3 ")
|
||||
|| cmd_str.contains("g3-")
|
||||
|| cmd_str.ends_with("g3")
|
||||
|| cmd_str.contains("--workspace") // g3-specific flag
|
||||
|| cmd_str.contains("--autonomous"); // g3-specific flag
|
||||
|
||||
// Accept if it's a g3 binary, cargo run with g3 patterns, or has g3-specific flags
|
||||
let is_g3_process = is_g3_binary || (is_cargo_run && has_g3_pattern) || has_g3_pattern;
|
||||
|
||||
if !is_g3_process {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -100,7 +111,7 @@ impl ProcessDetector {
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_workspace(&self, pid: Pid, process: &Process, cmd: &[String]) -> Option<PathBuf> {
|
||||
fn extract_workspace(&self, pid: Pid, _process: &Process, cmd: &[String]) -> Option<PathBuf> {
|
||||
// Look for --workspace flag
|
||||
for i in 0..cmd.len() {
|
||||
if cmd[i] == "--workspace" && i + 1 < cmd.len() {
|
||||
|
||||
Reference in New Issue
Block a user