1use crate::commands::*;
2use crate::i18n::{current, Language};
3use clap::{Parser, Subcommand};
4
5fn max_concurrency_ceiling() -> usize {
7 std::thread::available_parallelism()
8 .map(|n| n.get() * 2)
9 .unwrap_or(8)
10}
11
12#[derive(Copy, Clone, Debug, clap::ValueEnum)]
13pub enum RelationKind {
14 AppliesTo,
15 Uses,
16 DependsOn,
17 Causes,
18 Fixes,
19 Contradicts,
20 Supports,
21 Follows,
22 Related,
23 Mentions,
24 Replaces,
25 TrackedIn,
26}
27
28impl RelationKind {
29 pub fn as_str(&self) -> &'static str {
30 match self {
31 Self::AppliesTo => "applies_to",
32 Self::Uses => "uses",
33 Self::DependsOn => "depends_on",
34 Self::Causes => "causes",
35 Self::Fixes => "fixes",
36 Self::Contradicts => "contradicts",
37 Self::Supports => "supports",
38 Self::Follows => "follows",
39 Self::Related => "related",
40 Self::Mentions => "mentions",
41 Self::Replaces => "replaces",
42 Self::TrackedIn => "tracked_in",
43 }
44 }
45}
46
47#[derive(Copy, Clone, Debug, clap::ValueEnum)]
48pub enum GraphExportFormat {
49 Json,
50 Dot,
51 Mermaid,
52}
53
54#[derive(Parser)]
55#[command(name = "sqlite-graphrag")]
56#[command(version)]
57#[command(about = "Local GraphRAG memory for LLMs in a single SQLite file")]
58#[command(arg_required_else_help = true)]
59pub struct Cli {
60 #[arg(long, global = true, value_name = "N")]
65 pub max_concurrency: Option<usize>,
66
67 #[arg(long, global = true, value_name = "SECONDS")]
72 pub wait_lock: Option<u64>,
73
74 #[arg(long, global = true, hide = true, default_value_t = false)]
78 pub skip_memory_guard: bool,
79
80 #[arg(long, global = true, value_enum, value_name = "LANG")]
86 pub lang: Option<crate::i18n::Language>,
87
88 #[arg(long, global = true, value_name = "IANA")]
93 pub tz: Option<chrono_tz::Tz>,
94
95 #[command(subcommand)]
96 pub command: Commands,
97}
98
99impl Cli {
100 pub fn validate_flags(&self) -> Result<(), String> {
105 if let Some(n) = self.max_concurrency {
106 if n == 0 {
107 return Err(match current() {
108 Language::English => "--max-concurrency must be >= 1".to_string(),
109 Language::Portugues => "--max-concurrency deve ser >= 1".to_string(),
110 });
111 }
112 let teto = max_concurrency_ceiling();
113 if n > teto {
114 return Err(match current() {
115 Language::English => format!(
116 "--max-concurrency {n} exceeds the ceiling of {teto} (2×nCPUs) on this system"
117 ),
118 Language::Portugues => format!(
119 "--max-concurrency {n} excede o teto de {teto} (2×nCPUs) neste sistema"
120 ),
121 });
122 }
123 }
124 Ok(())
125 }
126}
127
128#[derive(Subcommand)]
129pub enum Commands {
130 Init(init::InitArgs),
132 Remember(remember::RememberArgs),
134 Recall(recall::RecallArgs),
136 Read(read::ReadArgs),
138 List(list::ListArgs),
140 Forget(forget::ForgetArgs),
142 Purge(purge::PurgeArgs),
144 Rename(rename::RenameArgs),
146 Edit(edit::EditArgs),
148 History(history::HistoryArgs),
150 Restore(restore::RestoreArgs),
152 HybridSearch(hybrid_search::HybridSearchArgs),
154 Health(health::HealthArgs),
156 Migrate(migrate::MigrateArgs),
158 NamespaceDetect(namespace_detect::NamespaceDetectArgs),
160 Optimize(optimize::OptimizeArgs),
162 Stats(stats::StatsArgs),
164 SyncSafeCopy(sync_safe_copy::SyncSafeCopyArgs),
166 Vacuum(vacuum::VacuumArgs),
168 Link(link::LinkArgs),
170 Unlink(unlink::UnlinkArgs),
172 Related(related::RelatedArgs),
174 Graph(graph_export::GraphArgs),
176 CleanupOrphans(cleanup_orphans::CleanupOrphansArgs),
178 #[command(name = "__debug_schema", hide = true)]
179 DebugSchema(debug_schema::DebugSchemaArgs),
180}
181
182#[derive(Copy, Clone, Debug, clap::ValueEnum)]
183pub enum MemoryType {
184 User,
185 Feedback,
186 Project,
187 Reference,
188 Decision,
189 Incident,
190 Skill,
191}
192
193impl MemoryType {
194 pub fn as_str(&self) -> &'static str {
195 match self {
196 Self::User => "user",
197 Self::Feedback => "feedback",
198 Self::Project => "project",
199 Self::Reference => "reference",
200 Self::Decision => "decision",
201 Self::Incident => "incident",
202 Self::Skill => "skill",
203 }
204 }
205}