refactor: explicit Opencode Executor (#188)
* use display and fromStr implementations in ExecutorConfig (cherry picked from commit 115a6a447d9195d28b9c29004fa6301fb60b1b89) (cherry picked from commit 25d589d54a3fc89f8868f5c409f25bdb162f1326) * rename opencode to charm/opencode (cherry picked from commit 41fe88a46cc6c7a1cbf5ecbc3599639351c415c8) * rename opencode on the frontend * resuse executor types on the frontend * put back missing types
This commit is contained in:
committed by
GitHub
parent
d994622a99
commit
459f93b751
@@ -9,7 +9,7 @@ export const EXECUTOR_TYPES: string[] = [
|
||||
"claude",
|
||||
"amp",
|
||||
"gemini",
|
||||
"opencode"
|
||||
"charmopencode"
|
||||
];
|
||||
|
||||
export const EDITOR_TYPES: EditorType[] = [
|
||||
@@ -26,7 +26,7 @@ export const EXECUTOR_LABELS: Record<string, string> = {
|
||||
"claude": "Claude",
|
||||
"amp": "Amp",
|
||||
"gemini": "Gemini",
|
||||
"opencode": "OpenCode"
|
||||
"charmopencode": "Charm Opencode"
|
||||
};
|
||||
|
||||
export const EDITOR_LABELS: Record<string, string> = {
|
||||
|
||||
@@ -7,7 +7,7 @@ use ts_rs::TS;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::executors::{
|
||||
AmpExecutor, ClaudeExecutor, EchoExecutor, GeminiExecutor, OpencodeExecutor,
|
||||
AmpExecutor, CharmOpencodeExecutor, ClaudeExecutor, EchoExecutor, GeminiExecutor,
|
||||
SetupScriptExecutor,
|
||||
};
|
||||
|
||||
@@ -345,8 +345,8 @@ pub enum ExecutorConfig {
|
||||
Claude,
|
||||
Amp,
|
||||
Gemini,
|
||||
Opencode,
|
||||
SetupScript { script: String },
|
||||
CharmOpencode,
|
||||
// Future executors can be added here
|
||||
// Shell { command: String },
|
||||
// Docker { image: String, command: String },
|
||||
@@ -369,7 +369,7 @@ impl FromStr for ExecutorConfig {
|
||||
"claude" => Ok(ExecutorConfig::Claude),
|
||||
"amp" => Ok(ExecutorConfig::Amp),
|
||||
"gemini" => Ok(ExecutorConfig::Gemini),
|
||||
"opencode" => Ok(ExecutorConfig::Opencode),
|
||||
"charmopencode" => Ok(ExecutorConfig::CharmOpencode),
|
||||
"setup_script" => Ok(ExecutorConfig::SetupScript {
|
||||
script: "setup script".to_string(),
|
||||
}),
|
||||
@@ -385,7 +385,7 @@ impl ExecutorConfig {
|
||||
ExecutorConfig::Claude => Box::new(ClaudeExecutor),
|
||||
ExecutorConfig::Amp => Box::new(AmpExecutor),
|
||||
ExecutorConfig::Gemini => Box::new(GeminiExecutor),
|
||||
ExecutorConfig::Opencode => Box::new(OpencodeExecutor),
|
||||
ExecutorConfig::CharmOpencode => Box::new(CharmOpencodeExecutor),
|
||||
ExecutorConfig::SetupScript { script } => {
|
||||
Box::new(SetupScriptExecutor::new(script.clone()))
|
||||
}
|
||||
@@ -395,7 +395,9 @@ impl ExecutorConfig {
|
||||
pub fn config_path(&self) -> Option<std::path::PathBuf> {
|
||||
match self {
|
||||
ExecutorConfig::Echo => None,
|
||||
ExecutorConfig::Opencode => dirs::home_dir().map(|home| home.join(".opencode.json")),
|
||||
ExecutorConfig::CharmOpencode => {
|
||||
dirs::home_dir().map(|home| home.join(".opencode.json"))
|
||||
}
|
||||
ExecutorConfig::Claude => dirs::home_dir().map(|home| home.join(".claude.json")),
|
||||
ExecutorConfig::Amp => {
|
||||
dirs::config_dir().map(|config| config.join("amp").join("settings.json"))
|
||||
@@ -411,7 +413,7 @@ impl ExecutorConfig {
|
||||
pub fn mcp_attribute_path(&self) -> Option<Vec<&'static str>> {
|
||||
match self {
|
||||
ExecutorConfig::Echo => None, // Echo doesn't support MCP
|
||||
ExecutorConfig::Opencode => Some(vec!["mcpServers"]),
|
||||
ExecutorConfig::CharmOpencode => Some(vec!["mcpServers"]),
|
||||
ExecutorConfig::Claude => Some(vec!["mcpServers"]),
|
||||
ExecutorConfig::Amp => Some(vec!["amp", "mcpServers"]), // Nested path for Amp
|
||||
ExecutorConfig::Gemini => Some(vec!["mcpServers"]),
|
||||
@@ -431,7 +433,7 @@ impl ExecutorConfig {
|
||||
pub fn display_name(&self) -> &'static str {
|
||||
match self {
|
||||
ExecutorConfig::Echo => "Echo (Test Mode)",
|
||||
ExecutorConfig::Opencode => "Opencode",
|
||||
ExecutorConfig::CharmOpencode => "Charm Opencode",
|
||||
ExecutorConfig::Claude => "Claude",
|
||||
ExecutorConfig::Amp => "Amp",
|
||||
ExecutorConfig::Gemini => "Gemini",
|
||||
@@ -447,7 +449,7 @@ impl std::fmt::Display for ExecutorConfig {
|
||||
ExecutorConfig::Claude => "claude",
|
||||
ExecutorConfig::Amp => "amp",
|
||||
ExecutorConfig::Gemini => "gemini",
|
||||
ExecutorConfig::Opencode => "opencode",
|
||||
ExecutorConfig::CharmOpencode => "charmopencode",
|
||||
ExecutorConfig::SetupScript { .. } => "setup_script",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
|
||||
@@ -9,16 +9,16 @@ use crate::{
|
||||
};
|
||||
|
||||
/// An executor that uses OpenCode to process tasks
|
||||
pub struct OpencodeExecutor;
|
||||
pub struct CharmOpencodeExecutor;
|
||||
|
||||
/// An executor that continues an OpenCode thread
|
||||
pub struct OpencodeFollowupExecutor {
|
||||
pub struct CharmOpencodeFollowupExecutor {
|
||||
pub session_id: String,
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Executor for OpencodeExecutor {
|
||||
impl Executor for CharmOpencodeExecutor {
|
||||
async fn spawn(
|
||||
&self,
|
||||
pool: &sqlx::SqlitePool,
|
||||
@@ -70,9 +70,9 @@ Task title: {}"#,
|
||||
let child = command
|
||||
.group_spawn() // Create new process group so we can kill entire tree
|
||||
.map_err(|e| {
|
||||
crate::executor::SpawnContext::from_command(&command, "OpenCode")
|
||||
crate::executor::SpawnContext::from_command(&command, "CharmOpenCode")
|
||||
.with_task(task_id, Some(task.title.clone()))
|
||||
.with_context("OpenCode CLI execution for new task")
|
||||
.with_context("CharmOpenCode CLI execution for new task")
|
||||
.spawn_error(e)
|
||||
})?;
|
||||
|
||||
@@ -81,7 +81,7 @@ Task title: {}"#,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Executor for OpencodeFollowupExecutor {
|
||||
impl Executor for CharmOpencodeFollowupExecutor {
|
||||
async fn spawn(
|
||||
&self,
|
||||
_pool: &sqlx::SqlitePool,
|
||||
@@ -111,9 +111,9 @@ impl Executor for OpencodeFollowupExecutor {
|
||||
let child = command
|
||||
.group_spawn() // Create new process group so we can kill entire tree
|
||||
.map_err(|e| {
|
||||
crate::executor::SpawnContext::from_command(&command, "OpenCode")
|
||||
crate::executor::SpawnContext::from_command(&command, "CharmOpenCode")
|
||||
.with_context(format!(
|
||||
"OpenCode CLI followup execution for session {}",
|
||||
"CharmOpenCode CLI followup execution for session {}",
|
||||
self.session_id
|
||||
))
|
||||
.spawn_error(e)
|
||||
@@ -1,15 +1,15 @@
|
||||
pub mod amp;
|
||||
pub mod charm_opencode;
|
||||
pub mod claude;
|
||||
pub mod dev_server;
|
||||
pub mod echo;
|
||||
pub mod gemini;
|
||||
pub mod opencode;
|
||||
pub mod setup_script;
|
||||
|
||||
pub use amp::{AmpExecutor, AmpFollowupExecutor};
|
||||
pub use charm_opencode::{CharmOpencodeExecutor, CharmOpencodeFollowupExecutor};
|
||||
pub use claude::{ClaudeExecutor, ClaudeFollowupExecutor};
|
||||
pub use dev_server::DevServerExecutor;
|
||||
pub use echo::EchoExecutor;
|
||||
pub use gemini::{GeminiExecutor, GeminiFollowupExecutor};
|
||||
pub use opencode::{OpencodeExecutor, OpencodeFollowupExecutor};
|
||||
pub use setup_script::SetupScriptExecutor;
|
||||
|
||||
@@ -1217,7 +1217,6 @@ pub async fn get_execution_process_normalized_logs(
|
||||
if !stdout.trim().is_empty() {
|
||||
// Determine executor type and create appropriate executor for normalization
|
||||
let executor_type = process.executor_type.as_deref().unwrap_or("unknown");
|
||||
|
||||
let executor_config = if process.process_type == ExecutionProcessType::SetupScript {
|
||||
// For setup scripts, use the setup script executor
|
||||
ExecutorConfig::SetupScript {
|
||||
@@ -1227,13 +1226,9 @@ pub async fn get_execution_process_normalized_logs(
|
||||
.unwrap_or_else(|| "setup script".to_string()),
|
||||
}
|
||||
} else {
|
||||
match executor_type {
|
||||
"amp" => ExecutorConfig::Amp,
|
||||
"claude" => ExecutorConfig::Claude,
|
||||
"echo" => ExecutorConfig::Echo,
|
||||
"gemini" => ExecutorConfig::Gemini,
|
||||
"opencode" => ExecutorConfig::Opencode,
|
||||
_ => {
|
||||
match executor_type.to_string().parse() {
|
||||
Ok(config) => config,
|
||||
Err(_) => {
|
||||
tracing::warn!(
|
||||
"Unsupported executor type: {}, cannot normalize logs properly",
|
||||
executor_type
|
||||
|
||||
@@ -415,20 +415,18 @@ impl ProcessService {
|
||||
)
|
||||
})?;
|
||||
|
||||
// Determine the executor config from the stored executor_type
|
||||
let executor_config = match most_recent_coding_agent.executor_type.as_deref() {
|
||||
Some("claude") => crate::executor::ExecutorConfig::Claude,
|
||||
Some("amp") => crate::executor::ExecutorConfig::Amp,
|
||||
Some("gemini") => crate::executor::ExecutorConfig::Gemini,
|
||||
Some("echo") => crate::executor::ExecutorConfig::Echo,
|
||||
Some("opencode") => crate::executor::ExecutorConfig::Opencode,
|
||||
let executor_config: crate::executor::ExecutorConfig = match most_recent_coding_agent
|
||||
.executor_type
|
||||
.as_deref()
|
||||
{
|
||||
Some(executor_str) => executor_str.parse().unwrap(),
|
||||
_ => {
|
||||
tracing::error!(
|
||||
"Invalid or missing executor type '{}' for execution process {} (task attempt {})",
|
||||
most_recent_coding_agent.executor_type.as_deref().unwrap_or("None"),
|
||||
most_recent_coding_agent.id,
|
||||
attempt_id
|
||||
);
|
||||
"Invalid or missing executor type '{}' for execution process {} (task attempt {})",
|
||||
most_recent_coding_agent.executor_type.as_deref().unwrap_or("None"),
|
||||
most_recent_coding_agent.id,
|
||||
attempt_id
|
||||
);
|
||||
return Err(TaskAttemptError::ValidationError(format!(
|
||||
"Invalid executor type for follow-up: {}",
|
||||
most_recent_coding_agent
|
||||
@@ -640,7 +638,7 @@ impl ProcessService {
|
||||
Some("claude") => crate::executor::ExecutorConfig::Claude,
|
||||
Some("amp") => crate::executor::ExecutorConfig::Amp,
|
||||
Some("gemini") => crate::executor::ExecutorConfig::Gemini,
|
||||
Some("opencode") => crate::executor::ExecutorConfig::Opencode,
|
||||
Some("charmopencode") => crate::executor::ExecutorConfig::CharmOpencode,
|
||||
_ => crate::executor::ExecutorConfig::Echo, // Default for "echo" or None
|
||||
}
|
||||
}
|
||||
@@ -667,35 +665,13 @@ impl ProcessService {
|
||||
None, // Dev servers don't have an executor type
|
||||
),
|
||||
crate::executor::ExecutorType::CodingAgent(config) => {
|
||||
let executor_type_str = match config {
|
||||
crate::executor::ExecutorConfig::Echo => "echo",
|
||||
crate::executor::ExecutorConfig::Claude => "claude",
|
||||
crate::executor::ExecutorConfig::Amp => "amp",
|
||||
crate::executor::ExecutorConfig::Gemini => "gemini",
|
||||
crate::executor::ExecutorConfig::Opencode => "opencode",
|
||||
crate::executor::ExecutorConfig::SetupScript { .. } => "setup_script",
|
||||
};
|
||||
(
|
||||
"executor".to_string(),
|
||||
None,
|
||||
Some(executor_type_str.to_string()),
|
||||
)
|
||||
}
|
||||
crate::executor::ExecutorType::FollowUpCodingAgent { config, .. } => {
|
||||
let executor_type_str = match config {
|
||||
crate::executor::ExecutorConfig::Echo => "echo",
|
||||
crate::executor::ExecutorConfig::Claude => "claude",
|
||||
crate::executor::ExecutorConfig::Amp => "amp",
|
||||
crate::executor::ExecutorConfig::Gemini => "gemini",
|
||||
crate::executor::ExecutorConfig::Opencode => "opencode",
|
||||
crate::executor::ExecutorConfig::SetupScript { .. } => "setup_script",
|
||||
};
|
||||
(
|
||||
"followup_executor".to_string(),
|
||||
None,
|
||||
Some(executor_type_str.to_string()),
|
||||
)
|
||||
("executor".to_string(), None, Some(format!("{}", config)))
|
||||
}
|
||||
crate::executor::ExecutorType::FollowUpCodingAgent { config, .. } => (
|
||||
"followup_executor".to_string(),
|
||||
None,
|
||||
Some(format!("{}", config)),
|
||||
),
|
||||
};
|
||||
|
||||
let create_process = CreateExecutionProcess {
|
||||
@@ -803,8 +779,8 @@ impl ProcessService {
|
||||
prompt,
|
||||
} => {
|
||||
use crate::executors::{
|
||||
AmpFollowupExecutor, ClaudeFollowupExecutor, GeminiFollowupExecutor,
|
||||
OpencodeFollowupExecutor,
|
||||
AmpFollowupExecutor, CharmOpencodeFollowupExecutor, ClaudeFollowupExecutor,
|
||||
GeminiFollowupExecutor,
|
||||
};
|
||||
|
||||
let executor: Box<dyn crate::executor::Executor> = match config {
|
||||
@@ -839,9 +815,9 @@ impl ProcessService {
|
||||
// Echo doesn't support followup, use regular echo
|
||||
config.create_executor()
|
||||
}
|
||||
crate::executor::ExecutorConfig::Opencode => {
|
||||
crate::executor::ExecutorConfig::CharmOpencode => {
|
||||
if let Some(sid) = session_id {
|
||||
Box::new(OpencodeFollowupExecutor {
|
||||
Box::new(CharmOpencodeFollowupExecutor {
|
||||
session_id: sid.clone(),
|
||||
prompt: prompt.clone(),
|
||||
})
|
||||
|
||||
@@ -81,9 +81,7 @@ export function OnboardingDialog({ open, onComplete }: OnboardingDialogProps) {
|
||||
<Label htmlFor="executor">Default Executor</Label>
|
||||
<Select
|
||||
value={executor.type}
|
||||
onValueChange={(value: 'echo' | 'claude' | 'amp') =>
|
||||
setExecutor({ type: value })
|
||||
}
|
||||
onValueChange={(value) => setExecutor({ type: value as any })}
|
||||
>
|
||||
<SelectTrigger id="executor">
|
||||
<SelectValue placeholder="Select your preferred coding agent" />
|
||||
@@ -100,6 +98,8 @@ export function OnboardingDialog({ open, onComplete }: OnboardingDialogProps) {
|
||||
{executor.type === 'claude' && 'Claude Code from Anthropic'}
|
||||
{executor.type === 'amp' && 'From Sourcegraph'}
|
||||
{executor.type === 'gemini' && 'Google Gemini from Bloop'}
|
||||
{executor.type === 'charmopencode' &&
|
||||
'Charm/Opencode AI assistant'}
|
||||
{executor.type === 'echo' &&
|
||||
'This is just for debugging vibe-kanban itself'}
|
||||
</p>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { useConfig } from '@/components/config-provider';
|
||||
import { attemptsApi, projectsApi } from '@/lib/api';
|
||||
import type { GitBranch, TaskAttempt } from 'shared/types';
|
||||
import { EXECUTOR_TYPES, EXECUTOR_LABELS } from 'shared/types';
|
||||
import {
|
||||
TaskAttemptDataContext,
|
||||
TaskAttemptLoadingContext,
|
||||
@@ -16,13 +17,10 @@ import CreatePRDialog from '@/components/tasks/Toolbar/CreatePRDialog.tsx';
|
||||
import CreateAttempt from '@/components/tasks/Toolbar/CreateAttempt.tsx';
|
||||
import CurrentAttempt from '@/components/tasks/Toolbar/CurrentAttempt.tsx';
|
||||
|
||||
const availableExecutors = [
|
||||
{ id: 'echo', name: 'Echo' },
|
||||
{ id: 'claude', name: 'Claude' },
|
||||
{ id: 'amp', name: 'Amp' },
|
||||
{ id: 'gemini', name: 'Gemini' },
|
||||
{ id: 'opencode', name: 'OpenCode' },
|
||||
];
|
||||
const availableExecutors = EXECUTOR_TYPES.map((id) => ({
|
||||
id,
|
||||
name: EXECUTOR_LABELS[id] || id,
|
||||
}));
|
||||
|
||||
function TaskDetailsToolbar() {
|
||||
const { task, projectId } = useContext(TaskDetailsContext);
|
||||
|
||||
368
shared/types.ts
368
shared/types.ts
@@ -4,90 +4,35 @@
|
||||
|
||||
export type ApiResponse<T> = { success: boolean, data: T | null, message: string | null, };
|
||||
|
||||
export type Config = {
|
||||
theme: ThemeMode,
|
||||
executor: ExecutorConfig,
|
||||
disclaimer_acknowledged: boolean,
|
||||
onboarding_acknowledged: boolean,
|
||||
telemetry_acknowledged: boolean,
|
||||
sound_alerts: boolean,
|
||||
sound_file: SoundFile,
|
||||
push_notifications: boolean,
|
||||
editor: EditorConfig,
|
||||
github: GitHubConfig,
|
||||
analytics_enabled: boolean | null,
|
||||
};
|
||||
export type Config = { theme: ThemeMode, executor: ExecutorConfig, disclaimer_acknowledged: boolean, onboarding_acknowledged: boolean, telemetry_acknowledged: boolean, sound_alerts: boolean, sound_file: SoundFile, push_notifications: boolean, editor: EditorConfig, github: GitHubConfig, analytics_enabled: boolean | null, };
|
||||
|
||||
export type ThemeMode = "light" | "dark" | "system" | "purple" | "green" | "blue" | "orange" | "red";
|
||||
|
||||
export type EditorConfig = { editor_type: EditorType, custom_command: string | null, };
|
||||
|
||||
export type GitHubConfig = {
|
||||
pat: string | null,
|
||||
token: string | null,
|
||||
username: string | null,
|
||||
primary_email: string | null,
|
||||
default_pr_base: string | null,
|
||||
};
|
||||
export type GitHubConfig = { pat: string | null, token: string | null, username: string | null, primary_email: string | null, default_pr_base: string | null, };
|
||||
|
||||
export type EditorType = "vscode" | "cursor" | "windsurf" | "intellij" | "zed" | "custom";
|
||||
|
||||
export type EditorConstants = { editor_types: Array<EditorType>, editor_labels: Array<string>, };
|
||||
|
||||
export type SoundFile =
|
||||
"abstract-sound1"
|
||||
| "abstract-sound2"
|
||||
| "abstract-sound3"
|
||||
| "abstract-sound4"
|
||||
| "cow-mooing"
|
||||
| "phone-vibration"
|
||||
| "rooster";
|
||||
export type SoundFile = "abstract-sound1" | "abstract-sound2" | "abstract-sound3" | "abstract-sound4" | "cow-mooing" | "phone-vibration" | "rooster";
|
||||
|
||||
export type SoundConstants = { sound_files: Array<SoundFile>, sound_labels: Array<string>, };
|
||||
|
||||
export type ConfigConstants = { editor: EditorConstants, sound: SoundConstants, };
|
||||
|
||||
export type ExecutorConfig = { "type": "echo" } | { "type": "claude" } | { "type": "amp" } | { "type": "gemini" } | {
|
||||
"type": "opencode"
|
||||
};
|
||||
export type ExecutorConfig = { "type": "echo" } | { "type": "claude" } | { "type": "amp" } | { "type": "gemini" } | { "type": "setupscript", script: string, } | { "type": "charmopencode" };
|
||||
|
||||
export type ExecutorConstants = { executor_types: Array<ExecutorConfig>, executor_labels: Array<string>, };
|
||||
|
||||
export type CreateProject = {
|
||||
name: string,
|
||||
git_repo_path: string,
|
||||
use_existing_repo: boolean,
|
||||
setup_script: string | null,
|
||||
dev_script: string | null,
|
||||
};
|
||||
export type CreateProject = { name: string, git_repo_path: string, use_existing_repo: boolean, setup_script: string | null, dev_script: string | null, };
|
||||
|
||||
export type Project = {
|
||||
id: string,
|
||||
name: string,
|
||||
git_repo_path: string,
|
||||
setup_script: string | null,
|
||||
dev_script: string | null,
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
};
|
||||
export type Project = { id: string, name: string, git_repo_path: string, setup_script: string | null, dev_script: string | null, created_at: Date, updated_at: Date, };
|
||||
|
||||
export type ProjectWithBranch = {
|
||||
id: string,
|
||||
name: string,
|
||||
git_repo_path: string,
|
||||
setup_script: string | null,
|
||||
dev_script: string | null,
|
||||
current_branch: string | null,
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
};
|
||||
export type ProjectWithBranch = { id: string, name: string, git_repo_path: string, setup_script: string | null, dev_script: string | null, current_branch: string | null, created_at: Date, updated_at: Date, };
|
||||
|
||||
export type UpdateProject = {
|
||||
name: string | null,
|
||||
git_repo_path: string | null,
|
||||
setup_script: string | null,
|
||||
dev_script: string | null,
|
||||
};
|
||||
export type UpdateProject = { name: string | null, git_repo_path: string | null, setup_script: string | null, dev_script: string | null, };
|
||||
|
||||
export type SearchResult = { path: string, is_file: boolean, match_type: SearchMatchType, };
|
||||
|
||||
@@ -99,65 +44,19 @@ export type CreateBranch = { name: string, base_branch: string | null, };
|
||||
|
||||
export type CreateTask = { project_id: string, title: string, description: string | null, };
|
||||
|
||||
export type CreateTaskAndStart = {
|
||||
project_id: string,
|
||||
title: string,
|
||||
description: string | null,
|
||||
executor: ExecutorConfig | null,
|
||||
};
|
||||
export type CreateTaskAndStart = { project_id: string, title: string, description: string | null, executor: ExecutorConfig | null, };
|
||||
|
||||
export type TaskStatus = "todo" | "inprogress" | "inreview" | "done" | "cancelled";
|
||||
|
||||
export type Task = {
|
||||
id: string,
|
||||
project_id: string,
|
||||
title: string,
|
||||
description: string | null,
|
||||
status: TaskStatus,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
};
|
||||
export type Task = { id: string, project_id: string, title: string, description: string | null, status: TaskStatus, created_at: string, updated_at: string, };
|
||||
|
||||
export type TaskWithAttemptStatus = {
|
||||
id: string,
|
||||
project_id: string,
|
||||
title: string,
|
||||
description: string | null,
|
||||
status: TaskStatus,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
has_in_progress_attempt: boolean,
|
||||
has_merged_attempt: boolean,
|
||||
has_failed_attempt: boolean,
|
||||
};
|
||||
export type TaskWithAttemptStatus = { id: string, project_id: string, title: string, description: string | null, status: TaskStatus, created_at: string, updated_at: string, has_in_progress_attempt: boolean, has_merged_attempt: boolean, has_failed_attempt: boolean, };
|
||||
|
||||
export type UpdateTask = { title: string | null, description: string | null, status: TaskStatus | null, };
|
||||
|
||||
export type TaskAttemptStatus =
|
||||
"setuprunning"
|
||||
| "setupcomplete"
|
||||
| "setupfailed"
|
||||
| "executorrunning"
|
||||
| "executorcomplete"
|
||||
| "executorfailed";
|
||||
export type TaskAttemptStatus = "setuprunning" | "setupcomplete" | "setupfailed" | "executorrunning" | "executorcomplete" | "executorfailed";
|
||||
|
||||
export type TaskAttempt = {
|
||||
id: string,
|
||||
task_id: string,
|
||||
worktree_path: string,
|
||||
branch: string,
|
||||
base_branch: string,
|
||||
merge_commit: string | null,
|
||||
executor: string | null,
|
||||
pr_url: string | null,
|
||||
pr_number: bigint | null,
|
||||
pr_status: string | null,
|
||||
pr_merged_at: string | null,
|
||||
worktree_deleted: boolean,
|
||||
setup_completed_at: string | null,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
};
|
||||
export type TaskAttempt = { id: string, task_id: string, worktree_path: string, branch: string, base_branch: string, merge_commit: string | null, executor: string | null, pr_url: string | null, pr_number: bigint | null, pr_status: string | null, pr_merged_at: string | null, worktree_deleted: boolean, setup_completed_at: string | null, created_at: string, updated_at: string, };
|
||||
|
||||
export type CreateTaskAttempt = { executor: string | null, base_branch: string | null, };
|
||||
|
||||
@@ -165,48 +64,31 @@ export type UpdateTaskAttempt = Record<string, never>;
|
||||
|
||||
export type CreateFollowUpAttempt = { prompt: string, };
|
||||
|
||||
export type TaskAttemptActivity = {
|
||||
id: string,
|
||||
execution_process_id: string,
|
||||
status: TaskAttemptStatus,
|
||||
note: string | null,
|
||||
created_at: string,
|
||||
};
|
||||
export type TaskAttemptActivity = { id: string, execution_process_id: string, status: TaskAttemptStatus, note: string | null, created_at: string, };
|
||||
|
||||
export type TaskAttemptActivityWithPrompt = {
|
||||
id: string,
|
||||
execution_process_id: string,
|
||||
status: TaskAttemptStatus,
|
||||
note: string | null,
|
||||
created_at: string,
|
||||
prompt: string | null,
|
||||
};
|
||||
export type TaskAttemptActivityWithPrompt = { id: string, execution_process_id: string, status: TaskAttemptStatus, note: string | null, created_at: string, prompt: string | null, };
|
||||
|
||||
export type CreateTaskAttemptActivity = {
|
||||
execution_process_id: string,
|
||||
status: TaskAttemptStatus | null,
|
||||
note: string | null,
|
||||
};
|
||||
export type CreateTaskAttemptActivity = { execution_process_id: string, status: TaskAttemptStatus | null, note: string | null, };
|
||||
|
||||
export type AttemptData = {
|
||||
activities: TaskAttemptActivityWithPrompt[];
|
||||
processes: ExecutionProcessSummary[];
|
||||
runningProcessDetails: Record<string, ExecutionProcess>;
|
||||
activities: TaskAttemptActivityWithPrompt[];
|
||||
processes: ExecutionProcessSummary[];
|
||||
runningProcessDetails: Record<string, ExecutionProcess>;
|
||||
}
|
||||
|
||||
export interface ProcessedLine {
|
||||
content: string;
|
||||
chunkType: DiffChunkType;
|
||||
oldLineNumber?: number;
|
||||
newLineNumber?: number;
|
||||
content: string;
|
||||
chunkType: DiffChunkType;
|
||||
oldLineNumber?: number;
|
||||
newLineNumber?: number;
|
||||
}
|
||||
|
||||
export interface ProcessedSection {
|
||||
type: 'context' | 'change' | 'expanded';
|
||||
lines: ProcessedLine[];
|
||||
expandKey?: string;
|
||||
expandedAbove?: boolean;
|
||||
expandedBelow?: boolean;
|
||||
type: 'context' | 'change' | 'expanded';
|
||||
lines: ProcessedLine[];
|
||||
expandKey?: string;
|
||||
expandedAbove?: boolean;
|
||||
expandedBelow?: boolean;
|
||||
}
|
||||
|
||||
export type DirectoryEntry = { name: string, path: string, is_directory: boolean, is_git_repo: boolean, };
|
||||
@@ -219,185 +101,97 @@ export type FileDiff = { path: string, chunks: Array<DiffChunk>, };
|
||||
|
||||
export type WorktreeDiff = { files: Array<FileDiff>, };
|
||||
|
||||
export type BranchStatus = {
|
||||
is_behind: boolean,
|
||||
commits_behind: number,
|
||||
commits_ahead: number,
|
||||
up_to_date: boolean,
|
||||
merged: boolean,
|
||||
has_uncommitted_changes: boolean,
|
||||
base_branch_name: string,
|
||||
};
|
||||
export type BranchStatus = { is_behind: boolean, commits_behind: number, commits_ahead: number, up_to_date: boolean, merged: boolean, has_uncommitted_changes: boolean, base_branch_name: string, };
|
||||
|
||||
export type ExecutionState =
|
||||
"NotStarted"
|
||||
| "SetupRunning"
|
||||
| "SetupComplete"
|
||||
| "SetupFailed"
|
||||
| "CodingAgentRunning"
|
||||
| "CodingAgentComplete"
|
||||
| "CodingAgentFailed"
|
||||
| "Complete";
|
||||
export type ExecutionState = "NotStarted" | "SetupRunning" | "SetupComplete" | "SetupFailed" | "CodingAgentRunning" | "CodingAgentComplete" | "CodingAgentFailed" | "Complete";
|
||||
|
||||
export type TaskAttemptState = {
|
||||
execution_state: ExecutionState,
|
||||
has_changes: boolean,
|
||||
has_setup_script: boolean,
|
||||
setup_process_id: string | null,
|
||||
coding_agent_process_id: string | null,
|
||||
};
|
||||
export type TaskAttemptState = { execution_state: ExecutionState, has_changes: boolean, has_setup_script: boolean, setup_process_id: string | null, coding_agent_process_id: string | null, };
|
||||
|
||||
export type ExecutionProcess = {
|
||||
id: string,
|
||||
task_attempt_id: string,
|
||||
process_type: ExecutionProcessType,
|
||||
executor_type: string | null,
|
||||
status: ExecutionProcessStatus,
|
||||
command: string,
|
||||
args: string | null,
|
||||
working_directory: string,
|
||||
stdout: string | null,
|
||||
stderr: string | null,
|
||||
exit_code: bigint | null,
|
||||
started_at: string,
|
||||
completed_at: string | null,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
};
|
||||
export type ExecutionProcess = { id: string, task_attempt_id: string, process_type: ExecutionProcessType, executor_type: string | null, status: ExecutionProcessStatus, command: string, args: string | null, working_directory: string, stdout: string | null, stderr: string | null, exit_code: bigint | null, started_at: string, completed_at: string | null, created_at: string, updated_at: string, };
|
||||
|
||||
export type ExecutionProcessSummary = {
|
||||
id: string,
|
||||
task_attempt_id: string,
|
||||
process_type: ExecutionProcessType,
|
||||
executor_type: string | null,
|
||||
status: ExecutionProcessStatus,
|
||||
command: string,
|
||||
args: string | null,
|
||||
working_directory: string,
|
||||
exit_code: bigint | null,
|
||||
started_at: string,
|
||||
completed_at: string | null,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
};
|
||||
export type ExecutionProcessSummary = { id: string, task_attempt_id: string, process_type: ExecutionProcessType, executor_type: string | null, status: ExecutionProcessStatus, command: string, args: string | null, working_directory: string, exit_code: bigint | null, started_at: string, completed_at: string | null, created_at: string, updated_at: string, };
|
||||
|
||||
export type ExecutionProcessStatus = "running" | "completed" | "failed" | "killed";
|
||||
|
||||
export type ExecutionProcessType = "setupscript" | "codingagent" | "devserver";
|
||||
|
||||
export type CreateExecutionProcess = {
|
||||
task_attempt_id: string,
|
||||
process_type: ExecutionProcessType,
|
||||
executor_type: string | null,
|
||||
command: string,
|
||||
args: string | null,
|
||||
working_directory: string,
|
||||
};
|
||||
export type CreateExecutionProcess = { task_attempt_id: string, process_type: ExecutionProcessType, executor_type: string | null, command: string, args: string | null, working_directory: string, };
|
||||
|
||||
export type UpdateExecutionProcess = {
|
||||
status: ExecutionProcessStatus | null,
|
||||
exit_code: bigint | null,
|
||||
completed_at: string | null,
|
||||
};
|
||||
export type UpdateExecutionProcess = { status: ExecutionProcessStatus | null, exit_code: bigint | null, completed_at: string | null, };
|
||||
|
||||
export type ExecutorSession = {
|
||||
id: string,
|
||||
task_attempt_id: string,
|
||||
execution_process_id: string,
|
||||
session_id: string | null,
|
||||
prompt: string | null,
|
||||
summary: string | null,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
};
|
||||
export type ExecutorSession = { id: string, task_attempt_id: string, execution_process_id: string, session_id: string | null, prompt: string | null, summary: string | null, created_at: string, updated_at: string, };
|
||||
|
||||
export type CreateExecutorSession = { task_attempt_id: string, execution_process_id: string, prompt: string | null, };
|
||||
|
||||
export type UpdateExecutorSession = { session_id: string | null, prompt: string | null, summary: string | null, };
|
||||
|
||||
export type NormalizedConversation = {
|
||||
entries: Array<NormalizedEntry>,
|
||||
session_id: string | null,
|
||||
executor_type: string,
|
||||
prompt: string | null,
|
||||
summary: string | null,
|
||||
};
|
||||
export type NormalizedConversation = { entries: Array<NormalizedEntry>, session_id: string | null, executor_type: string, prompt: string | null, summary: string | null, };
|
||||
|
||||
export type NormalizedEntry = { timestamp: string | null, entry_type: NormalizedEntryType, content: string, };
|
||||
|
||||
export type NormalizedEntryType = { "type": "user_message" } | { "type": "assistant_message" } | {
|
||||
"type": "tool_use",
|
||||
tool_name: string,
|
||||
action_type: ActionType,
|
||||
} | { "type": "system_message" } | { "type": "error_message" } | { "type": "thinking" };
|
||||
export type NormalizedEntryType = { "type": "user_message" } | { "type": "assistant_message" } | { "type": "tool_use", tool_name: string, action_type: ActionType, } | { "type": "system_message" } | { "type": "error_message" } | { "type": "thinking" };
|
||||
|
||||
export type ActionType = { "action": "file_read", path: string, } | { "action": "file_write", path: string, } | {
|
||||
"action": "command_run",
|
||||
command: string,
|
||||
} | { "action": "search", query: string, } | { "action": "web_fetch", url: string, } | {
|
||||
"action": "task_create",
|
||||
description: string,
|
||||
} | { "action": "other", description: string, };
|
||||
export type ActionType = { "action": "file_read", path: string, } | { "action": "file_write", path: string, } | { "action": "command_run", command: string, } | { "action": "search", query: string, } | { "action": "web_fetch", url: string, } | { "action": "task_create", description: string, } | { "action": "other", description: string, };
|
||||
|
||||
export type StartGitHubDeviceFlowType = {
|
||||
device_code: string;
|
||||
user_code: string;
|
||||
verification_uri: string;
|
||||
expires_in: number;
|
||||
interval: number;
|
||||
device_code: string;
|
||||
user_code: string;
|
||||
verification_uri: string;
|
||||
expires_in: number;
|
||||
interval: number;
|
||||
};
|
||||
|
||||
// Generated constants
|
||||
export const EXECUTOR_TYPES: string[] = [
|
||||
"echo",
|
||||
"claude",
|
||||
"amp",
|
||||
"gemini",
|
||||
"opencode"
|
||||
"echo",
|
||||
"claude",
|
||||
"amp",
|
||||
"gemini",
|
||||
"charmopencode"
|
||||
];
|
||||
|
||||
export const EDITOR_TYPES: EditorType[] = [
|
||||
"vscode",
|
||||
"cursor",
|
||||
"windsurf",
|
||||
"intellij",
|
||||
"zed",
|
||||
"custom"
|
||||
"vscode",
|
||||
"cursor",
|
||||
"windsurf",
|
||||
"intellij",
|
||||
"zed",
|
||||
"custom"
|
||||
];
|
||||
|
||||
export const EXECUTOR_LABELS: Record<string, string> = {
|
||||
"echo": "Echo (Test Mode)",
|
||||
"claude": "Claude",
|
||||
"amp": "Amp",
|
||||
"gemini": "Gemini",
|
||||
"opencode": "OpenCode"
|
||||
"echo": "Echo (Test Mode)",
|
||||
"claude": "Claude",
|
||||
"amp": "Amp",
|
||||
"gemini": "Gemini",
|
||||
"charmopencode": "Charm Opencode"
|
||||
};
|
||||
|
||||
export const EDITOR_LABELS: Record<string, string> = {
|
||||
"vscode": "VS Code",
|
||||
"cursor": "Cursor",
|
||||
"windsurf": "Windsurf",
|
||||
"intellij": "IntelliJ IDEA",
|
||||
"zed": "Zed",
|
||||
"custom": "Custom"
|
||||
"vscode": "VS Code",
|
||||
"cursor": "Cursor",
|
||||
"windsurf": "Windsurf",
|
||||
"intellij": "IntelliJ IDEA",
|
||||
"zed": "Zed",
|
||||
"custom": "Custom"
|
||||
};
|
||||
|
||||
export const SOUND_FILES: SoundFile[] = [
|
||||
"abstract-sound1",
|
||||
"abstract-sound2",
|
||||
"abstract-sound3",
|
||||
"abstract-sound4",
|
||||
"cow-mooing",
|
||||
"phone-vibration",
|
||||
"rooster"
|
||||
"abstract-sound1",
|
||||
"abstract-sound2",
|
||||
"abstract-sound3",
|
||||
"abstract-sound4",
|
||||
"cow-mooing",
|
||||
"phone-vibration",
|
||||
"rooster"
|
||||
];
|
||||
|
||||
export const SOUND_LABELS: Record<string, string> = {
|
||||
"abstract-sound1": "Gentle Chime",
|
||||
"abstract-sound2": "Soft Bell",
|
||||
"abstract-sound3": "Digital Tone",
|
||||
"abstract-sound4": "Subtle Alert",
|
||||
"cow-mooing": "Cow Mooing",
|
||||
"phone-vibration": "Phone Vibration",
|
||||
"rooster": "Rooster Call"
|
||||
};
|
||||
"abstract-sound1": "Gentle Chime",
|
||||
"abstract-sound2": "Soft Bell",
|
||||
"abstract-sound3": "Digital Tone",
|
||||
"abstract-sound4": "Subtle Alert",
|
||||
"cow-mooing": "Cow Mooing",
|
||||
"phone-vibration": "Phone Vibration",
|
||||
"rooster": "Rooster Call"
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user