Files
vibe-kanban/backend/src/executors/gemini.rs
Gabriel Gordon-Hall 340b094c75 chore: setup CI scripts (#6)
* wip: workflows

* wip: fix up issues in ci scripts and fix frontend lint errors

* wip: fix backend lints

* remove unused deps

* wip: build frontend in test.yml

* wip: attempt to improve Rust caching

* wip: testing release

* wip: linear release flow

* wip: check against both package.json versions

* wip: spurious attempt to get Rust caching

* wip: more cache

* merge release and publish jobs; add more caching to release flow

* decouple github releases and npm publishing

* update pack flow

---------

Co-authored-by: couscous <couscous@runner.com>
2025-06-27 13:32:32 +01:00

85 lines
2.4 KiB
Rust

use async_trait::async_trait;
use tokio::process::{Child, Command};
use uuid::Uuid;
use crate::{
executor::{Executor, ExecutorError},
models::task::Task,
};
/// An executor that uses Gemini CLI to process tasks
pub struct GeminiExecutor;
/// An executor that resumes a Gemini session
pub struct GeminiFollowupExecutor {
pub session_id: String,
pub prompt: String,
}
#[async_trait]
impl Executor for GeminiExecutor {
async fn spawn(
&self,
pool: &sqlx::SqlitePool,
task_id: Uuid,
worktree_path: &str,
) -> Result<Child, ExecutorError> {
// Get the task to fetch its description
let task = Task::find_by_id(pool, task_id)
.await?
.ok_or(ExecutorError::TaskNotFound)?;
let prompt = format!(
"Task title: {}
Task description: {}",
task.title,
task.description
.as_deref()
.unwrap_or("No description provided")
);
// Use Gemini CLI to process the task
let child = Command::new("npx")
.kill_on_drop(true)
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.current_dir(worktree_path)
.arg("@bloopai/gemini-cli-interactive")
.arg("-p")
.arg(&prompt)
.process_group(0) // Create new process group so we can kill entire tree
.spawn()
.map_err(ExecutorError::SpawnFailed)?;
Ok(child)
}
}
#[async_trait]
impl Executor for GeminiFollowupExecutor {
async fn spawn(
&self,
_pool: &sqlx::SqlitePool,
_task_id: Uuid,
worktree_path: &str,
) -> Result<Child, ExecutorError> {
// Use Gemini CLI with session resumption (if supported)
let child = Command::new("npx")
.kill_on_drop(true)
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.current_dir(worktree_path)
.arg("https://github.com/google-gemini/gemini-cli")
.arg("-p")
.arg(&self.prompt)
.arg(format!("--resume={}", self.session_id))
.process_group(0) // Create new process group so we can kill entire tree
.spawn()
.map_err(ExecutorError::SpawnFailed)?;
Ok(child)
}
}