pub const GIT_VERSION: &str = concat!(
env!("CARGO_PKG_VERSION"),
" (",
env!("FACULTIES_GIT_VERSION"),
")"
);
pub fn model_dir() -> std::path::PathBuf {
if let Some(dir) = std::env::var_os("FACULTIES_MODEL_DIR") {
return std::path::PathBuf::from(dir);
}
let home = std::env::var_os("HOME").unwrap_or_else(|| std::ffi::OsString::from("."));
std::path::PathBuf::from(home).join(".cache/faculties/models")
}
pub mod archive;
pub mod archive_agy;
pub mod archive_bm25;
pub mod archive_chatgpt;
pub mod archive_claude_code;
pub mod archive_claude_web;
pub mod archive_codex;
pub mod archive_collection;
pub mod archive_copilot;
pub mod archive_gemini;
pub mod archive_source;
pub mod atlas;
pub mod blockdag;
pub mod body;
pub mod bootstrap;
pub mod cli;
pub mod clock;
pub mod code;
pub mod cognition;
pub mod collection_names;
pub mod comb;
pub mod compass;
pub mod config;
pub mod decide;
pub mod discord;
pub mod duplex;
pub mod files;
pub mod gauge;
pub mod habits;
pub mod headspace;
pub mod hear;
pub mod imagine;
pub mod linkedin;
pub mod mail;
pub mod mail_pop;
pub mod mcp;
pub mod memory;
pub mod memory_cover;
pub mod message;
#[cfg(any(feature = "local-embed", feature = "voice", feature = "imagine"))]
mod model_storage;
#[cfg(feature = "local-embed")]
pub mod nomic;
mod organ_client;
pub mod orient;
pub mod out;
pub mod patience;
pub mod planner;
pub mod posture;
pub mod posture_finding;
pub mod posture_policy;
pub mod reason;
pub mod relations;
pub mod schemas;
pub mod spec;
pub mod status;
pub mod storage;
pub mod teams;
pub mod tokens;
pub mod triage;
pub mod turntaking;
pub mod viewer;
pub mod voice;
pub mod web;
pub mod wiki;
pub mod wiki_additive;
#[cfg(test)]
mod attribute_id_preservation_tests;
#[cfg(test)]
pub(crate) mod test_support;
pub fn text_arg(raw: &str, label: &str) -> anyhow::Result<String> {
use anyhow::Context;
use std::io::Read;
if let Some(rest) = raw.strip_prefix("@@") {
return Ok(format!("@{rest}"));
}
if let Some(path) = raw.strip_prefix('@') {
if path == "-" {
let mut value = String::new();
std::io::stdin()
.read_to_string(&mut value)
.with_context(|| format!("read {label} from stdin"))?;
return Ok(value);
}
return std::fs::read_to_string(path).with_context(|| format!("read {label} from {path}"));
}
Ok(raw.to_string())
}
pub mod secrets;
#[cfg(feature = "widgets")]
pub mod widgets;
pub fn resolve_id_prefix<I>(input: &str, candidates: I) -> anyhow::Result<triblespace::core::id::Id>
where
I: IntoIterator<Item = triblespace::core::id::Id>,
{
use anyhow::bail;
use triblespace::core::id::Id;
let trimmed = input.trim().to_ascii_lowercase();
if trimmed.is_empty() {
bail!("empty id");
}
if trimmed.len() == 32 {
return Id::from_hex(&trimmed).ok_or_else(|| anyhow::anyhow!("invalid id '{trimmed}'"));
}
let mut matches: std::collections::HashSet<Id> = std::collections::HashSet::new();
for id in candidates {
if format!("{id:x}").starts_with(&trimmed) {
matches.insert(id);
}
}
match matches.len() {
0 => bail!("no id starts with '{trimmed}'"),
1 => Ok(matches.into_iter().next().unwrap()),
n => bail!("{n} matches for prefix '{trimmed}'; provide a longer prefix"),
}
}