manifest: embed builtin resources

This commit is contained in:
2026-05-31 20:47:06 +09:00
parent 607923dfbd
commit 365ec8b7fa
7 changed files with 210 additions and 200 deletions
-29
View File
@@ -25,9 +25,6 @@
use std::path::PathBuf;
/// Environment variable that points at installed project resources.
pub const RESOURCE_DIR_ENV: &str = "INSOMNIA_RESOURCE_DIR";
/// 設定ディレクトリ。`profiles.toml`, `providers.toml`, `models.toml`,
/// `prompts/` などが置かれる。
pub fn config_dir() -> Option<PathBuf> {
@@ -75,32 +72,6 @@ pub fn user_prompts_dir() -> Option<PathBuf> {
user_prompts_dir_from_config_dir(config_dir())
}
/// Root resource directory used for bundled prompts, profiles, catalogs, and docs.
pub fn resource_dir() -> Option<PathBuf> {
if let Some(p) = env_path(RESOURCE_DIR_ENV) {
return Some(p);
}
if let Ok(exe) = std::env::current_exe() {
if let Some(prefix) = exe.parent().and_then(|bin| bin.parent()) {
let installed = prefix.join("share").join("insomnia").join("resources");
if installed.exists() {
return Some(installed);
}
}
}
Some(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join("resources"),
)
}
/// Bundled Lua profile registry directory. Missing directories are treated as
/// an empty builtin registry by discovery.
pub fn builtin_profiles_dir() -> Option<PathBuf> {
Some(resource_dir()?.join("profiles"))
}
/// `<config_dir>/prompts.toml` — user prompt pack。
pub fn user_pack_file() -> Option<PathBuf> {
user_pack_file_from_config_dir(config_dir())
+198 -151
View File
@@ -22,6 +22,8 @@ use crate::{
const PROFILE_FORMAT_V1: &str = "insomnia.lua-profile.v1";
const BUILTIN_DEFAULT_PROFILE_NAME: &str = "default";
const BUILTIN_DEFAULT_PROFILE: &str = include_str!("../../../resources/profiles/default.lua");
const BUILTIN_MODEL_CATALOG: &str = include_str!("../../../resources/models/builtin.toml");
const DEFAULT_POD_NAME: &str = "insomnia";
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
@@ -126,7 +128,10 @@ pub enum ProfileSource {
Registry {
source: ProfileRegistrySource,
name: String,
path: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
path: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
provenance: Option<String>,
},
}
@@ -134,15 +139,62 @@ pub enum ProfileSource {
pub struct ProfileRegistryEntry {
pub source: ProfileRegistrySource,
pub name: String,
pub path: PathBuf,
pub path: Option<PathBuf>,
pub provenance: String,
pub description: Option<String>,
pub is_default: bool,
artifact: ProfileRegistryArtifact,
}
impl ProfileRegistryEntry {
pub fn qualified_name(&self) -> String {
format!("{}:{}", self.source, self.name)
}
fn path(
source: ProfileRegistrySource,
name: String,
path: PathBuf,
description: Option<String>,
) -> Self {
let provenance = path.display().to_string();
Self {
source,
name,
path: Some(path.clone()),
provenance,
description,
is_default: false,
artifact: ProfileRegistryArtifact::Path(path),
}
}
fn embedded(
source: ProfileRegistrySource,
name: &'static str,
label: &'static str,
content: &'static str,
description: Option<String>,
) -> Self {
Self {
source,
name: name.to_string(),
path: None,
provenance: label.to_string(),
description,
is_default: false,
artifact: ProfileRegistryArtifact::Embedded { label, content },
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum ProfileRegistryArtifact {
Path(PathBuf),
Embedded {
label: &'static str,
content: &'static str,
},
}
#[derive(Debug, Clone, Default)]
@@ -241,7 +293,6 @@ struct ProfileDefault {
#[derive(Debug, Clone)]
pub struct ProfileDiscovery {
builtin_dir: Option<PathBuf>,
user_config: Option<PathBuf>,
project_config: Option<PathBuf>,
}
@@ -249,27 +300,19 @@ pub struct ProfileDiscovery {
impl ProfileDiscovery {
pub fn for_cwd(cwd: &Path) -> Self {
Self {
builtin_dir: paths::builtin_profiles_dir(),
user_config: paths::user_profiles_path(),
project_config: find_project_profiles_from(cwd),
}
}
pub fn with_sources(
builtin_dir: Option<PathBuf>,
user_config: Option<PathBuf>,
project_config: Option<PathBuf>,
) -> Self {
pub fn with_sources(user_config: Option<PathBuf>, project_config: Option<PathBuf>) -> Self {
Self {
builtin_dir,
user_config,
project_config,
}
}
pub fn discover(&self) -> Result<ProfileRegistry, ProfileError> {
let mut registry = ProfileRegistry::default();
if let Some(dir) = &self.builtin_dir {
discover_profile_dir(&mut registry, ProfileRegistrySource::Builtin, dir)?;
}
add_builtin_profiles(&mut registry);
if let Some(path) = &self.user_config {
load_profile_registry_file(&mut registry, ProfileRegistrySource::User, path)?;
}
@@ -371,15 +414,27 @@ impl ProfileResolver {
)),
ProfileSelector::Named { .. } | ProfileSelector::Default => {
let entry = registry.select(selector)?.clone();
self.resolve_path(
&entry.path,
ProfileSource::Registry {
source: entry.source,
name: entry.name,
path: absolutize(&entry.path)?,
},
options,
)
let source = ProfileSource::Registry {
source: entry.source,
name: entry.name.clone(),
path: entry.path.as_deref().map(absolutize).transpose()?,
provenance: (entry.path.is_none()).then(|| entry.provenance.clone()),
};
self.resolve_registry_entry(&entry, source, options)
}
}
}
fn resolve_registry_entry(
&self,
entry: &ProfileRegistryEntry,
source: ProfileSource,
options: ProfileResolveOptions,
) -> Result<ResolvedProfile, ProfileError> {
match &entry.artifact {
ProfileRegistryArtifact::Path(path) => self.resolve_path(path, source, options),
ProfileRegistryArtifact::Embedded { label, content } => {
self.resolve_embedded_profile(label, content, source, options)
}
}
}
@@ -431,6 +486,30 @@ impl ProfileResolver {
raw_artifact,
)
}
fn resolve_embedded_profile(
&self,
label: &'static str,
content: &'static str,
source: ProfileSource,
options: ProfileResolveOptions,
) -> Result<ResolvedProfile, ProfileError> {
let workspace_base = absolutize(
self.workspace_base
.as_deref()
.unwrap_or_else(|| Path::new(".")),
)?;
let lua_value = evaluate_embedded_lua_profile(label, content)?;
let raw_artifact = lua_value.clone();
resolve_lua_profile_value(
source,
&workspace_base,
&workspace_base,
options,
lua_value,
raw_artifact,
)
}
}
fn resolve_lua_profile_value(
@@ -591,13 +670,12 @@ fn load_profile_registry_file(
let base = path.parent().unwrap_or_else(|| Path::new("."));
for (name, entry_config) in config.profile {
let (entry_path, description) = entry_config.into_parts();
registry.push_entry(ProfileRegistryEntry {
registry.push_entry(ProfileRegistryEntry::path(
source,
name,
path: join_if_relative(base, &entry_path),
join_if_relative(base, &entry_path),
description,
is_default: false,
});
));
}
if let Some(default) = config.default {
let (default_source, default_name) = parse_profile_ref(&default);
@@ -625,49 +703,14 @@ fn find_project_profiles_from(start: &Path) -> Option<PathBuf> {
None
}
fn discover_profile_dir(
registry: &mut ProfileRegistry,
source: ProfileRegistrySource,
dir: &Path,
) -> Result<(), ProfileError> {
if !dir.is_dir() {
return Ok(());
}
for entry in std::fs::read_dir(dir).map_err(|source| ProfileError::ConfigRead {
path: dir.to_path_buf(),
source,
})? {
let entry = entry.map_err(|source| ProfileError::ConfigRead {
path: dir.to_path_buf(),
source,
})?;
let path = entry.path();
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("lua") {
if let Some(name) = path.file_stem().and_then(|s| s.to_str()) {
registry.push_entry(ProfileRegistryEntry {
source,
name: name.to_string(),
path,
description: None,
is_default: false,
});
}
} else if path.is_dir() {
let profile = path.join("profile.lua");
if profile.is_file()
&& let Some(name) = path.file_name().and_then(|s| s.to_str())
{
registry.push_entry(ProfileRegistryEntry {
source,
name: name.to_string(),
path: profile,
description: None,
is_default: false,
});
}
}
}
Ok(())
fn add_builtin_profiles(registry: &mut ProfileRegistry) {
registry.push_entry(ProfileRegistryEntry::embedded(
ProfileRegistrySource::Builtin,
BUILTIN_DEFAULT_PROFILE_NAME,
"builtin:default",
BUILTIN_DEFAULT_PROFILE,
Some("Bundled default Insomnia coding profile".into()),
));
}
fn parse_profile_ref(raw: &str) -> (Option<ProfileRegistrySource>, String) {
@@ -687,15 +730,38 @@ fn evaluate_lua_profile(
path: path.to_path_buf(),
source,
})?;
evaluate_lua_profile_source(
&content,
path.display().to_string(),
LocalModuleRoot::Filesystem(module_root.to_path_buf()),
)
}
fn evaluate_embedded_lua_profile(
label: &'static str,
content: &'static str,
) -> Result<serde_json::Value, ProfileError> {
evaluate_lua_profile_source(
content,
label.to_string(),
LocalModuleRoot::Disabled { label },
)
}
fn evaluate_lua_profile_source(
content: &str,
chunk_name: String,
module_root: LocalModuleRoot,
) -> Result<serde_json::Value, ProfileError> {
let lua = Lua::new_with(
StdLib::TABLE | StdLib::STRING | StdLib::MATH | StdLib::UTF8,
LuaOptions::default(),
)
.map_err(ProfileError::Lua)?;
install_lua_api(&lua, module_root.to_path_buf())?;
install_lua_api(&lua, module_root)?;
let value: LuaValue = lua
.load(&content)
.set_name(path.display().to_string())
.load(content)
.set_name(chunk_name)
.eval()
.map_err(ProfileError::Lua)?;
match value {
@@ -706,7 +772,7 @@ fn evaluate_lua_profile(
}
}
fn install_lua_api(lua: &Lua, module_root: PathBuf) -> Result<(), ProfileError> {
fn install_lua_api(lua: &Lua, module_root: LocalModuleRoot) -> Result<(), ProfileError> {
let loader = Rc::new(RefCell::new(LocalModuleLoader {
root: module_root,
cache: HashMap::new(),
@@ -743,11 +809,16 @@ fn install_lua_api(lua: &Lua, module_root: PathBuf) -> Result<(), ProfileError>
}
struct LocalModuleLoader {
root: PathBuf,
root: LocalModuleRoot,
cache: HashMap<String, RegistryKey>,
loading: HashSet<String>,
}
enum LocalModuleRoot {
Filesystem(PathBuf),
Disabled { label: &'static str },
}
fn require_module(
lua: &Lua,
loader: &Rc<RefCell<LocalModuleLoader>>,
@@ -773,7 +844,19 @@ fn require_module(
)));
}
}
let path = local_module_path(&loader.borrow().root, name).map_err(mlua::Error::RuntimeError)?;
let path = {
let state = loader.borrow();
match &state.root {
LocalModuleRoot::Filesystem(root) => {
local_module_path(root, name).map_err(mlua::Error::RuntimeError)?
}
LocalModuleRoot::Disabled { label } => {
return Err(mlua::Error::RuntimeError(format!(
"local require `{name}` is not available for embedded profile `{label}`"
)));
}
}
};
let content = std::fs::read_to_string(&path).map_err(|e| {
mlua::Error::RuntimeError(format!(
"failed to read local module `{name}` ({}): {e}",
@@ -1042,9 +1125,7 @@ fn model_context_window(model: Option<&ModelManifest>) -> Option<u64> {
}
fn builtin_model_context_window(reference: &str) -> Option<u64> {
let (provider, model_id) = reference.split_once('/')?;
let path = paths::resource_dir()?.join("models").join("builtin.toml");
let content = std::fs::read_to_string(path).ok()?;
let parsed: toml::Value = toml::from_str(&content).ok()?;
let parsed: toml::Value = toml::from_str(BUILTIN_MODEL_CATALOG).ok()?;
for entry in parsed.get("model")?.as_array()? {
let table = entry.as_table()?;
if table.get("provider")?.as_str()? == provider && table.get("id")?.as_str()? == model_id {
@@ -1187,58 +1268,8 @@ pub enum ProfileError {
mod tests {
use super::*;
use crate::{ReasoningControl, ReasoningEffort, SchemeKind};
use std::sync::{Mutex, MutexGuard, OnceLock};
use tempfile::TempDir;
fn env_lock() -> MutexGuard<'static, ()> {
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
LOCK.get_or_init(|| Mutex::new(()))
.lock()
.unwrap_or_else(|e| e.into_inner())
}
struct EnvGuard {
vars: Vec<(&'static str, Option<String>)>,
_lock: MutexGuard<'static, ()>,
}
impl EnvGuard {
fn new(overrides: &[(&'static str, Option<&str>)]) -> Self {
let lock = env_lock();
let names = [
"INSOMNIA_CONFIG_DIR",
"INSOMNIA_RESOURCE_DIR",
"INSOMNIA_HOME",
"XDG_CONFIG_HOME",
"HOME",
];
let saved: Vec<_> = names.iter().map(|n| (*n, std::env::var(n).ok())).collect();
unsafe {
for (n, _) in &saved {
std::env::remove_var(n);
}
for (n, v) in overrides {
if let Some(v) = v {
std::env::set_var(n, v);
}
}
}
Self {
vars: saved,
_lock: lock,
}
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
for (n, v) in &self.vars {
match v {
Some(v) => std::env::set_var(n, v),
None => std::env::remove_var(n),
}
}
}
}
}
fn write_profile(dir: &Path, name: &str, body: &str) -> PathBuf {
let path = dir.join(name);
std::fs::write(&path, body).unwrap();
@@ -1266,14 +1297,15 @@ mod tests {
}
#[test]
fn builtin_default_profile_is_registered_as_default() {
let registry = ProfileDiscovery::with_sources(paths::builtin_profiles_dir(), None, None)
let registry = ProfileDiscovery::with_sources(None, None)
.discover()
.unwrap();
let default = registry.default_entry().unwrap();
assert_eq!(default.source, ProfileRegistrySource::Builtin);
assert_eq!(default.name, BUILTIN_DEFAULT_PROFILE_NAME);
assert!(default.is_default);
assert!(default.path.ends_with("resources/profiles/default.lua"));
assert_eq!(default.path, None);
assert_eq!(default.provenance, "builtin:default");
}
#[test]
fn resolves_plain_lua_profile_with_runtime_pod_name_and_scope_intent() {
@@ -1458,6 +1490,15 @@ return profile {
resolved.profile.as_ref().unwrap().name.as_deref(),
Some("default")
);
assert_eq!(
resolved.source,
ProfileSource::Registry {
source: ProfileRegistrySource::Builtin,
name: "default".into(),
path: None,
provenance: Some("builtin:default".into()),
}
);
}
#[test]
fn unsupported_profile_extension_has_clear_diagnostic() {
@@ -1486,14 +1527,19 @@ return profile {
)
.unwrap();
std::fs::write(&project_config, "default = \"project:coder\"\n[profile.coder]\npath = \"profiles/project-coder.lua\"\ndescription = \"Project coder\"\n").unwrap();
let registry =
ProfileDiscovery::with_sources(None, Some(user_config), Some(project_config))
.discover()
.unwrap();
let registry = ProfileDiscovery::with_sources(Some(user_config), Some(project_config))
.discover()
.unwrap();
let default = registry.default_entry().unwrap();
assert_eq!(default.source, ProfileRegistrySource::Project);
assert_eq!(default.name, "coder");
assert!(default.path.ends_with("profiles/project-coder.lua"));
assert!(
default
.path
.as_ref()
.unwrap()
.ends_with("profiles/project-coder.lua")
);
}
#[test]
fn default_marks_direct_profile_entry() {
@@ -1506,7 +1552,7 @@ return profile {
"default = \"coder\"\n[profile]\ncoder = \"profiles/coder.lua\"\n",
)
.unwrap();
let registry = ProfileDiscovery::with_sources(None, None, Some(project_config))
let registry = ProfileDiscovery::with_sources(None, Some(project_config))
.discover()
.unwrap();
let default = registry.default_entry().unwrap();
@@ -1525,20 +1571,18 @@ return profile {
#[test]
fn unqualified_ambiguous_names_fail_closed() {
let mut registry = ProfileRegistry::default();
registry.push_entry(ProfileRegistryEntry {
source: ProfileRegistrySource::User,
name: "coder".to_string(),
path: PathBuf::from("/user/coder.lua"),
description: None,
is_default: false,
});
registry.push_entry(ProfileRegistryEntry {
source: ProfileRegistrySource::Project,
name: "coder".to_string(),
path: PathBuf::from("/project/coder.lua"),
description: None,
is_default: false,
});
registry.push_entry(ProfileRegistryEntry::path(
ProfileRegistrySource::User,
"coder".to_string(),
PathBuf::from("/user/coder.lua"),
None,
));
registry.push_entry(ProfileRegistryEntry::path(
ProfileRegistrySource::Project,
"coder".to_string(),
PathBuf::from("/project/coder.lua"),
None,
));
let err = registry
.select(&ProfileSelector::named("coder"))
.unwrap_err();
@@ -1549,6 +1593,9 @@ return profile {
"coder",
))
.unwrap();
assert_eq!(selected.path, PathBuf::from("/project/coder.lua"));
assert_eq!(
selected.path.as_deref(),
Some(Path::new("/project/coder.lua"))
);
}
}
+2 -2
View File
@@ -932,7 +932,7 @@ mod tests {
std::fs::write(&registry_path, registry_toml).unwrap();
AvailableProfiles {
registry: Some(
ProfileDiscovery::with_sources(None, None, Some(registry_path))
ProfileDiscovery::with_sources(None, Some(registry_path))
.discover()
.unwrap(),
),
@@ -1319,7 +1319,7 @@ return profile {
let project_config = project.join(".insomnia/profiles.toml");
let ambiguous = AvailableProfiles {
registry: Some(
ProfileDiscovery::with_sources(None, Some(user_config), Some(project_config))
ProfileDiscovery::with_sources(Some(user_config), Some(project_config))
.discover()
.unwrap(),
),