use crate::domain::{MemoryScope, OutputFormat, TargetTool, WakeupProfile};
use clap::{Args, Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Debug, Parser)]
#[command(
name = "spool",
version,
about = "Obsidian knowledge-based context extractor"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Get(GetArgs),
Explain(ExplainArgs),
Wakeup(WakeupArgs),
Memory(MemoryArgs),
Mcp(McpArgs),
Hook(HookArgs),
Init(InitArgs),
Status(StatusArgs),
#[cfg(feature = "embedding")]
Embedding(EmbeddingArgs),
Knowledge(KnowledgeArgs),
}
#[derive(Debug, Clone, Args)]
pub struct InitArgs {
#[arg(long)]
pub vault: Option<PathBuf>,
#[arg(long)]
pub project_id: Option<String>,
#[arg(long)]
pub repo: Option<PathBuf>,
}
#[derive(Debug, Clone, Args)]
pub struct StatusArgs {
#[arg(long)]
pub config: Option<PathBuf>,
}
#[derive(Debug, Clone, Args)]
pub struct CommonRouteArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub task: String,
#[arg(long)]
pub cwd: PathBuf,
#[arg(long, value_delimiter = ',')]
pub files: Vec<String>,
#[arg(long, value_enum, default_value_t = TargetValue::Claude)]
pub target: TargetValue,
}
#[derive(Debug, Clone, Args)]
pub struct GetArgs {
#[command(flatten)]
pub common: CommonRouteArgs,
#[arg(long, value_enum)]
pub format: Option<FormatValue>,
}
#[derive(Debug, Clone, Args)]
pub struct ExplainArgs {
#[command(flatten)]
pub common: CommonRouteArgs,
}
#[derive(Debug, Clone, Args)]
pub struct WakeupArgs {
#[command(flatten)]
pub common: CommonRouteArgs,
#[arg(long, value_enum)]
pub profile: WakeupProfileValue,
#[arg(long, value_enum)]
pub format: Option<FormatValue>,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryArgs {
#[command(subcommand)]
pub command: MemoryCommand,
}
#[derive(Debug, Clone, Subcommand)]
pub enum MemoryCommand {
List(MemoryListArgs),
Show(MemoryShowArgs),
History(MemoryShowArgs),
RecordManual(MemoryRecordArgs),
Propose(MemoryRecordArgs),
Accept(MemoryActionArgs),
Promote(MemoryActionArgs),
Archive(MemoryActionArgs),
Import(MemoryImportArgs),
ImportGit(MemoryImportGitArgs),
SyncVault(MemorySyncVaultArgs),
Dedup(MemoryDedupArgs),
Consolidate(MemoryConsolidateArgs),
Prune(MemoryPruneArgs),
Lint(MemoryLintArgs),
SyncIndex(MemorySyncIndexArgs),
Stats(MemoryStatsArgs),
}
#[derive(Debug, Clone, Args)]
pub struct MemoryListArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, value_enum)]
pub view: MemoryListViewValue,
#[arg(long, value_enum)]
pub format: Option<MemoryFormatValue>,
#[arg(long)]
pub daemon_bin: Option<PathBuf>,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryShowArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub record_id: String,
#[arg(long, value_enum)]
pub format: Option<MemoryFormatValue>,
#[arg(long)]
pub daemon_bin: Option<PathBuf>,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryActionArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub record_id: String,
#[arg(long)]
pub actor: Option<String>,
#[arg(long)]
pub reason: Option<String>,
#[arg(long, value_delimiter = ',')]
pub evidence_refs: Vec<String>,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryRecordArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub title: String,
#[arg(long)]
pub summary: String,
#[arg(long)]
pub memory_type: String,
#[arg(long, value_enum)]
pub scope: MemoryScopeValue,
#[arg(long)]
pub source_ref: String,
#[arg(long)]
pub project_id: Option<String>,
#[arg(long)]
pub user_id: Option<String>,
#[arg(long)]
pub sensitivity: Option<String>,
#[arg(long)]
pub actor: Option<String>,
#[arg(long)]
pub reason: Option<String>,
#[arg(long, value_delimiter = ',')]
pub evidence_refs: Vec<String>,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryImportArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, value_enum)]
pub provider: SessionProviderValue,
#[arg(long)]
pub session_id: String,
#[arg(long, default_value_t = false)]
pub apply: bool,
#[arg(long, default_value = "spool-importer")]
pub actor: String,
#[arg(long, value_enum, default_value_t = MemoryFormatValue::Markdown)]
pub format: MemoryFormatValue,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryImportGitArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub repo: Option<PathBuf>,
#[arg(long, default_value_t = 30)]
pub limit: usize,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemorySyncVaultArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
pub enrich: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryDedupArgs {
#[arg(long)]
pub config: PathBuf,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryConsolidateArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
pub apply: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryPruneArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
pub apply: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryLintArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub json: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemorySyncIndexArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub apply: bool,
}
#[derive(Debug, Clone, Args)]
pub struct MemoryStatsArgs {
#[arg(long)]
pub config: PathBuf,
}
#[derive(Debug, Clone, Args)]
pub struct McpArgs {
#[command(subcommand)]
pub command: McpCommand,
}
#[derive(Debug, Clone, Subcommand)]
pub enum McpCommand {
Install(McpInstallArgs),
Update(McpUpdateArgs),
Uninstall(McpUninstallArgs),
Doctor(McpDoctorArgs),
}
#[derive(Debug, Clone, Args)]
pub struct McpInstallArgs {
#[arg(long, value_enum, default_value_t = ClientValue::Claude)]
pub client: ClientValue,
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub binary_path: Option<PathBuf>,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
pub force: bool,
#[arg(long, value_enum, default_value_t = McpReportFormat::Text)]
pub format: McpReportFormat,
}
#[derive(Debug, Clone, Args)]
pub struct McpUpdateArgs {
#[arg(long, value_enum, default_value_t = ClientValue::Claude)]
pub client: ClientValue,
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub binary_path: Option<PathBuf>,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, value_enum, default_value_t = McpReportFormat::Text)]
pub format: McpReportFormat,
}
#[derive(Debug, Clone, Args)]
pub struct McpUninstallArgs {
#[arg(long, value_enum, default_value_t = ClientValue::Claude)]
pub client: ClientValue,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, value_enum, default_value_t = McpReportFormat::Text)]
pub format: McpReportFormat,
}
#[derive(Debug, Clone, Args)]
pub struct McpDoctorArgs {
#[arg(long, value_enum, default_value_t = ClientValue::Claude)]
pub client: ClientValue,
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub binary_path: Option<PathBuf>,
#[arg(long, value_enum, default_value_t = McpReportFormat::Text)]
pub format: McpReportFormat,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ClientValue {
Claude,
Codex,
Cursor,
Opencode,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum McpReportFormat {
Text,
Json,
}
#[derive(Debug, Clone, Args)]
pub struct HookArgs {
#[command(subcommand)]
pub command: HookCommand,
}
#[derive(Debug, Clone, Subcommand)]
pub enum HookCommand {
SessionStart(HookSessionStartArgs),
UserPrompt(HookSimpleArgs),
PostToolUse(HookPostToolUseArgs),
Stop(HookStopArgs),
PreCompact(HookSimpleArgs),
}
#[derive(Debug, Clone, Args)]
pub struct HookSessionStartArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub cwd: Option<PathBuf>,
#[arg(long)]
pub task: Option<String>,
#[arg(long, value_enum, default_value_t = WakeupProfileValue::Project)]
pub profile: WakeupProfileValue,
}
#[derive(Debug, Clone, Args)]
pub struct HookSimpleArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub cwd: Option<PathBuf>,
}
#[derive(Debug, Clone, Args)]
pub struct HookPostToolUseArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub cwd: Option<PathBuf>,
#[arg(long)]
pub tool_name: Option<String>,
#[arg(long)]
pub payload: Option<String>,
}
#[derive(Debug, Clone, Args)]
pub struct HookStopArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long)]
pub cwd: Option<PathBuf>,
#[arg(long)]
pub transcript_path: Option<PathBuf>,
#[arg(long)]
pub hook_input: Option<String>,
#[arg(long, hide = true)]
pub home: Option<PathBuf>,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum SessionProviderValue {
Claude,
Codex,
}
impl SessionProviderValue {
pub fn as_str(self) -> &'static str {
match self {
Self::Claude => "claude",
Self::Codex => "codex",
}
}
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum TargetValue {
Claude,
Codex,
Opencode,
}
impl From<TargetValue> for TargetTool {
fn from(value: TargetValue) -> Self {
match value {
TargetValue::Claude => TargetTool::Claude,
TargetValue::Codex => TargetTool::Codex,
TargetValue::Opencode => TargetTool::Opencode,
}
}
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum FormatValue {
Prompt,
Markdown,
Json,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum WakeupProfileValue {
Developer,
Project,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum MemoryListViewValue {
PendingReview,
WakeupReady,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum MemoryFormatValue {
Markdown,
Json,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum MemoryScopeValue {
User,
Project,
Workspace,
Team,
Agent,
}
impl From<FormatValue> for OutputFormat {
fn from(value: FormatValue) -> Self {
match value {
FormatValue::Prompt => OutputFormat::Prompt,
FormatValue::Markdown => OutputFormat::Markdown,
FormatValue::Json => OutputFormat::Json,
}
}
}
impl From<WakeupProfileValue> for WakeupProfile {
fn from(value: WakeupProfileValue) -> Self {
match value {
WakeupProfileValue::Developer => WakeupProfile::Developer,
WakeupProfileValue::Project => WakeupProfile::Project,
}
}
}
impl From<MemoryScopeValue> for MemoryScope {
fn from(value: MemoryScopeValue) -> Self {
match value {
MemoryScopeValue::User => MemoryScope::User,
MemoryScopeValue::Project => MemoryScope::Project,
MemoryScopeValue::Workspace => MemoryScope::Workspace,
MemoryScopeValue::Team => MemoryScope::Team,
MemoryScopeValue::Agent => MemoryScope::Agent,
}
}
}
#[cfg(feature = "embedding")]
#[derive(Debug, Clone, Args)]
pub struct EmbeddingArgs {
#[command(subcommand)]
pub command: EmbeddingCommand,
}
#[cfg(feature = "embedding")]
#[derive(Debug, Clone, Subcommand)]
pub enum EmbeddingCommand {
Build(EmbeddingBuildArgs),
Status(EmbeddingStatusArgs),
}
#[cfg(feature = "embedding")]
#[derive(Debug, Clone, Args)]
pub struct EmbeddingBuildArgs {
#[arg(long)]
pub config: PathBuf,
}
#[cfg(feature = "embedding")]
#[derive(Debug, Clone, Args)]
pub struct EmbeddingStatusArgs {
#[arg(long)]
pub config: PathBuf,
}
#[derive(Debug, Clone, Args)]
pub struct KnowledgeArgs {
#[command(subcommand)]
pub command: KnowledgeCommand,
}
#[derive(Debug, Clone, Subcommand)]
pub enum KnowledgeCommand {
Distill(KnowledgeDistillArgs),
}
#[derive(Debug, Clone, Args)]
pub struct KnowledgeDistillArgs {
#[arg(long)]
pub config: PathBuf,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long, default_value_t = false)]
pub apply: bool,
#[arg(long, default_value = "spool-knowledge")]
pub actor: String,
}