use thiserror::Error;
#[derive(Error, Debug)]
pub enum TrackError {
#[error("Database error: {0}")]
Database(#[from] rusqlite::Error),
#[error("No active task. Run 'track new' or 'track switch' first.")]
NoActiveTask,
#[error("Task #{0} not found")]
TaskNotFound(i64),
#[error("Task #{0} is archived")]
TaskArchived(i64),
#[error("Task name cannot be empty")]
EmptyTaskName,
#[error(
"track sync is deprecated in JJ mode. Use `jj-task start {slug}` instead (or `track sync --legacy` for old per-TODO worktrees)."
)]
SyncUseJjTask { slug: String },
#[error("--worktree was removed. Use one jj-task workspace per task (`jj-task start <slug>`). See `track llm-help`.")]
WorktreeFlagRemoved,
#[error("TODO content cannot be empty")]
EmptyTodoContent,
#[error("Scrap content cannot be empty")]
EmptyScrapContent,
#[error("Workspaces have uncommitted changes: {0:?}")]
UncommittedWorkspaces(Vec<String>),
#[error(
"jj-task workspace '{slug}' is not complete — run `jj-task done {slug}` after merging your PR. Active workspaces: {workspaces:?}"
)]
JjTaskNotCompleted {
slug: String,
workspaces: Vec<String>,
},
#[error("Ticket '{0}' is already linked to task #{1}")]
DuplicateTicket(String, i64),
#[error("Invalid ticket ID format: {0}")]
InvalidTicketFormat(String),
#[error("TODO #{0} not found")]
TodoNotFound(i64),
#[error("Worktree #{0} not found")]
WorktreeNotFound(i64),
#[error("Invalid status: {0}")]
InvalidStatus(String),
#[error("Cannot transition from '{from}' to '{to}'")]
InvalidStatusTransition { from: String, to: String },
#[error("TODO cannot be reopened from '{from}'. Add a new TODO instead.")]
TodoReopenForbidden { from: String },
#[error("Use 'track todo done <id>' to complete a TODO (merges JJ workspace if present).")]
TodoCompleteRequiresDoneCommand,
#[error(
"Workspace was merged (bookmark: {bookmark}) but failed to mark TODO #{todo_index} as done: {detail}"
)]
TodoCompletionDbFailed {
todo_index: i64,
bookmark: String,
detail: String,
},
#[error("JJ error: {0}")]
Jj(String),
#[error("Path '{0}' is not a JJ repository")]
NotJjRepository(String),
#[error("Bookmark '{0}' already exists")]
BookmarkExists(String),
#[error("Invalid URL format: {0}")]
InvalidUrl(String),
#[error("No repositories registered for this task")]
NoRepositoriesRegistered,
#[error("Failed to check status for {0}")]
FailedRepoStatusCheck(String),
#[error("Repository {0} has pending changes in the base workspace. Please clean before sync.")]
RepoHasPendingChanges(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Operation cancelled by user")]
#[allow(dead_code)]
Cancelled,
#[error("Failed to resolve path: {0}")]
PathResolutionFailed(String),
#[error("Current directory is not a registered repository for this task")]
CurrentDirectoryNotRegistered,
#[error("Workspace {path} has uncommitted changes. Use --force to recreate.")]
WorkspaceHasUncommittedChanges { path: String },
#[error("Bookmark '{bookmark}' not found in {repo_path}")]
BookmarkNotFound { bookmark: String, repo_path: String },
#[error("No workspace paths available for this TODO")]
NoWorkspacePathsAvailable,
#[error("Workspace cleanup failed: {0:?}")]
WorkspaceRemovalFailed(Vec<String>),
#[error("Failed to check workspace status for {path}: {detail}")]
WorkspaceStatusCheckFailed { path: String, detail: String },
#[error("JSON serialization failed: {0}")]
SerializationFailed(String),
#[error("TODO #{0} not found in current task")]
TodoIndexNotFound(i64),
#[error("No pending TODOs to reorder")]
NoPendingTodos,
#[error("TODO #{0} is not among pending TODOs")]
TodoNotPending(i64),
#[error("Link #{0} not found")]
LinkNotFound(i64),
#[error("No task found with reference '{0}'")]
TaskReferenceNotFound(String),
#[error("Alias '{alias}' is already in use by task #{task_id}")]
AliasInUse { alias: String, task_id: i64 },
#[error("Invalid alias: {0}")]
InvalidAlias(String),
#[error("Repository already registered for this task")]
RepoAlreadyRegistered,
#[error("Repository #{0} not found")]
TaskRepoNotFound(i64),
#[error("Repository #{0} not found in current task")]
TaskRepoIndexNotFound(i64),
#[error("Link #{0} not found in current task")]
LinkIndexNotFound(i64),
#[error("Path '{0}' is not a git repository")]
NotGitRepository(String),
#[error("Git error: {0}")]
Git(String),
#[error("Invalid jj-task workspace map at {path}: {detail}")]
JjTaskMapInvalid { path: String, detail: String },
#[error("Template '{name}' render failed: {detail}")]
TemplateRenderFailed { name: String, detail: String },
#[error("Failed to determine data directory")]
DataDirectoryUnavailable,
#[error("Invalid VCS mode: {0}")]
InvalidVcsMode(String),
#[error("Invalid app_state value for '{key}': {detail}")]
InvalidAppStateValue { key: String, detail: String },
#[error("Migration blocked: {detail}")]
MigrationBlocked { detail: String },
#[error("Unknown config key '{0}' (supported: vcs-mode)")]
UnknownConfigKey(String),
#[error("{0}")]
Other(String),
}
pub type Result<T> = std::result::Result<T, TrackError>;