From 365ec8b7fad008ab36bdc4de3adadb3696739a07 Mon Sep 17 00:00:00 2001 From: Hare Date: Sun, 31 May 2026 20:47:06 +0900 Subject: [PATCH] manifest: embed builtin resources --- crates/manifest/src/paths.rs | 29 --- crates/manifest/src/profile.rs | 349 +++++++++++++++++++-------------- crates/pod/src/spawn/tool.rs | 4 +- docs/environment.md | 11 +- docs/nix.md | 7 +- docs/pod-factory.md | 4 +- package.nix | 6 +- 7 files changed, 210 insertions(+), 200 deletions(-) diff --git a/crates/manifest/src/paths.rs b/crates/manifest/src/paths.rs index 22db9351..0325be01 100644 --- a/crates/manifest/src/paths.rs +++ b/crates/manifest/src/paths.rs @@ -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 { @@ -75,32 +72,6 @@ pub fn user_prompts_dir() -> Option { user_prompts_dir_from_config_dir(config_dir()) } -/// Root resource directory used for bundled prompts, profiles, catalogs, and docs. -pub fn resource_dir() -> Option { - 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 { - Some(resource_dir()?.join("profiles")) -} - /// `/prompts.toml` — user prompt pack。 pub fn user_pack_file() -> Option { user_pack_file_from_config_dir(config_dir()) diff --git a/crates/manifest/src/profile.rs b/crates/manifest/src/profile.rs index 05dc37ec..3937fd4f 100644 --- a/crates/manifest/src/profile.rs +++ b/crates/manifest/src/profile.rs @@ -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, + #[serde(default, skip_serializing_if = "Option::is_none")] + provenance: Option, }, } @@ -134,15 +139,62 @@ pub enum ProfileSource { pub struct ProfileRegistryEntry { pub source: ProfileRegistrySource, pub name: String, - pub path: PathBuf, + pub path: Option, + pub provenance: String, pub description: Option, 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, + ) -> 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, + ) -> 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, user_config: Option, project_config: Option, } @@ -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, - user_config: Option, - project_config: Option, - ) -> Self { + pub fn with_sources(user_config: Option, project_config: Option) -> Self { Self { - builtin_dir, user_config, project_config, } } pub fn discover(&self) -> Result { 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 { + 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 { + 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 { 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, 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 { + 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 { 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, loading: HashSet, } +enum LocalModuleRoot { + Filesystem(PathBuf), + Disabled { label: &'static str }, +} + fn require_module( lua: &Lua, loader: &Rc>, @@ -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 { } fn builtin_model_context_window(reference: &str) -> Option { 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> = OnceLock::new(); - LOCK.get_or_init(|| Mutex::new(())) - .lock() - .unwrap_or_else(|e| e.into_inner()) - } - struct EnvGuard { - vars: Vec<(&'static str, Option)>, - _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")) + ); } } diff --git a/crates/pod/src/spawn/tool.rs b/crates/pod/src/spawn/tool.rs index 2f68d9e0..86b2e651 100644 --- a/crates/pod/src/spawn/tool.rs +++ b/crates/pod/src/spawn/tool.rs @@ -932,7 +932,7 @@ mod tests { std::fs::write(®istry_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(), ), diff --git a/docs/environment.md b/docs/environment.md index f99638be..14f69c83 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -2,7 +2,7 @@ INSOMNIA では、プロセス境界で本当に必要な場合を除き、環境変数の利用を避ける。新しい ambient な入力を増やすより、明示的な profile / manifest / config file / typed secret reference / CLI argument を優先する。 -それでも、path discovery、runtime directory、package resource lookup、外部 provider の credential 慣習との移行互換のために、一部の環境変数はまだサポートしている。この文書に載せた環境変数は公開 surface として扱う。ただし、fallback 変数は独立した設定項目ではなく、対応する main key の解決順の一部として扱う。開発・テスト都合だけの環境変数は追加しない。 +それでも、path discovery、runtime directory、外部 provider の credential 慣習との移行互換のために、一部の環境変数はまだサポートしている。この文書に載せた環境変数は公開 surface として扱う。ただし、fallback 変数は独立した設定項目ではなく、対応する main key の解決順の一部として扱う。開発・テスト都合だけの環境変数は追加しない。 ## 原則 @@ -23,7 +23,6 @@ Path 系の環境変数は論理的な key ごとに立項する。`XDG_*` や ` | `config_dir` | `INSOMNIA_CONFIG_DIR` | `$INSOMNIA_HOME/config` → `$XDG_CONFIG_HOME/insomnia` → `$HOME/.config/insomnia` | 人が書く設定・override の置き場。`profiles.toml`、prompt override、model/provider override など。 | | `data_dir` | `INSOMNIA_DATA_DIR` | `$INSOMNIA_HOME` → `$HOME/.insomnia` | プログラムが書く永続データの置き場。session log、Pod metadata など、再起動後も restore / replay の根拠になるもの。通常ユーザー向けの primary knob ではなく、migration、test、isolated data store 用の advanced override。 | | `runtime_dir` | `INSOMNIA_RUNTIME_DIR` | `$INSOMNIA_HOME/run` → `$XDG_RUNTIME_DIR/insomnia` → `$HOME/.insomnia/run` | socket、pid/status file、live registry mirror など、再起動で捨ててよい runtime state の置き場。 | -| `resource_dir` | `INSOMNIA_RESOURCE_DIR` | installed executable から見た `share/insomnia/resources` → build tree の `resources/` | bundled prompts、builtin profiles、provider/model catalog など、package が所有する immutable-ish な builtin asset の置き場。通常 user configuration ではなく、packaging / development / debug 用の override。 | 空の path 環境変数は、`manifest::paths` では原則として unset 相当に扱う。 @@ -35,13 +34,9 @@ Path 系の環境変数は論理的な key ごとに立項する。`XDG_*` や ` このため、socket や pid file を `data_dir` に置かない。永続データと揮発 runtime state は分ける。 -### `resource_dir` と `config_dir` の違い +### Builtin assets と `config_dir` -`resource_dir` は package-owned builtin asset の場所である。installed package では `share/insomnia/resources` に置かれ、binary version と対応する。ユーザーが普段編集する場所ではない。 - -`config_dir` は user/project-owned override の場所である。`profiles.toml` や prompt/model/provider override はここに置き、package update で上書きされない。 - -つまり、builtin fallback は `resource_dir`、user override は `config_dir` で扱う。`INSOMNIA_RESOURCE_DIR` を user configuration の代わりに使わない。 +Builtin profiles and catalogs are embedded in the binary at build time. User/project-owned overrides remain under `config_dir` and project `.insomnia/` files such as `profiles.toml`; package runtime resource lookup is not a supported configuration surface. ## Credential と外部 auth diff --git a/docs/nix.md b/docs/nix.md index d77b7751..73f1e031 100644 --- a/docs/nix.md +++ b/docs/nix.md @@ -15,7 +15,6 @@ The default package is implemented by `package.nix` and builds the Cargo package The package output contains: - `bin/insomnia` — terminal UI and `insomnia pod ...` runtime entrypoint. -- `share/insomnia/resources/` — bundled runtime resources, including `resources/prompts/`. - `share/doc/insomnia/nix.md` — this document. - `share/doc/insomnia/environment.md` — environment-variable policy and supported variables. @@ -47,7 +46,7 @@ The Nix package does not put user configuration, sessions, sockets, or other mut | Persistent data (`sessions/`, Pod metadata) | `INSOMNIA_DATA_DIR` | `$INSOMNIA_HOME` | `$HOME/.insomnia` | | Runtime state (sockets, lock files, live registry) | `INSOMNIA_RUNTIME_DIR` | `$INSOMNIA_HOME/run` | `$XDG_RUNTIME_DIR/insomnia`, then `$HOME/.insomnia/run` | -Normal fresh startup is profile-based. The package ships a builtin default profile, user/project `profiles.toml` files may select or define profiles, and `insomnia pod --manifest ` remains a one-file compatibility/debug input. `INSOMNIA_USER_MANIFEST` and ambient `.insomnia/manifest.toml` discovery are not part of normal Pod/TUI startup. See [`environment.md`](environment.md) for the environment-variable policy; new configuration should prefer profiles/manifests/config files over additional environment variables. +Normal fresh startup is profile-based. The package includes the builtin default profile in the binary, user/project `profiles.toml` files may select or define profiles, and `insomnia pod --manifest ` remains a one-file compatibility/debug input. `INSOMNIA_USER_MANIFEST` and ambient `.insomnia/manifest.toml` discovery are not part of normal Pod/TUI startup. See [`environment.md`](environment.md) for the environment-variable policy; new configuration should prefer profiles/manifests/config files over additional environment variables. ## Validation @@ -56,7 +55,8 @@ The package derivation has a credential-free install check that verifies: - `insomnia pod --help` starts successfully. - `insomnia` is installed and reaches argument parsing. - `bin/insomnia-pod` is not installed. -- bundled prompt resources and this Nix usage document are present in the output. +- embedded builtin profiles do not require `share/insomnia/resources` at runtime. +- this Nix usage document is present in the output. For full validation before handing changes to review, run: @@ -73,4 +73,3 @@ These checks do not require provider credentials. - The package currently installs only the `insomnia` command; development-only wrappers from `devshell.nix` are not part of the installable package. - The TUI does not currently expose a conventional `--help` / `--version` CLI path, so the package smoke check uses an argument-parse failure path for the TUI rather than launching an interactive session. -- Bundled resources are installed under `share/insomnia/resources/` for packaging completeness and inspection. Built-in prompt/resource loading remains governed by the existing application code and user/project override rules. diff --git a/docs/pod-factory.md b/docs/pod-factory.md index 05812809..d98a8d75 100644 --- a/docs/pod-factory.md +++ b/docs/pod-factory.md @@ -119,12 +119,12 @@ Use `--manifest` only when you need the complete low-level Manifest escape hatch ## Builtin defaults -Base defaults that are independent of profile choice live in Rust constants under `crates/manifest/src/defaults.rs` and in `PodManifestConfig::builtin_defaults()`. The bundled default role profile lives at `resources/profiles/default.lua` and is discovered as `builtin:default`. +Base defaults that are independent of profile choice live in Rust constants under `crates/manifest/src/defaults.rs` and in `PodManifestConfig::builtin_defaults()`. The default role profile is embedded from `resources/profiles/default.lua` at build time and is discovered as `builtin:default`. デフォルト値を変更するときは、次のどちらを変更するのかを明確にする。 - all manifests/profiles の baseline default: Rust defaults -- ordinary dogfooding/default role: `resources/profiles/default.lua` +- ordinary dogfooding/default role: embedded `builtin:default` profile sourced from `resources/profiles/default.lua` ## Path resolution diff --git a/package.nix b/package.nix index b5a5643d..21e2e33d 100644 --- a/package.nix +++ b/package.nix @@ -40,7 +40,7 @@ rustPlatform.buildRustPackage rec { filter = sourceFilter; }; - cargoHash = "sha256-fisV77ZqAPsI0eLZIqw06HTj1CfmnL3NBHhjruZPZUE="; + cargoHash = "sha256-Nu+QAXwRhqqSwgc5/9XLwQEpjEnF54tWoEknM17wYq8="; depsExtraArgs = { # nixpkgs 25.11's fetchCargoVendor still uses crates.io's API @@ -94,8 +94,6 @@ rustPlatform.buildRustPackage rec { postInstall = '' install -Dm644 docs/nix.md "$out/share/doc/insomnia/nix.md" install -Dm644 docs/environment.md "$out/share/doc/insomnia/environment.md" - mkdir -p "$out/share/insomnia" - cp -R resources "$out/share/insomnia/resources" ''; doInstallCheck = true; @@ -105,13 +103,13 @@ rustPlatform.buildRustPackage rec { "$out/bin/insomnia" pod --help >/dev/null test -x "$out/bin/insomnia" test ! -e "$out/bin/insomnia-pod" + test ! -e "$out/share/insomnia/resources" if "$out/bin/insomnia" --session not-a-uuid 2>insomnia.err; then echo "insomnia unexpectedly accepted an invalid --session value" >&2 exit 1 fi grep -q "invalid --session UUID" insomnia.err - test -d "$out/share/insomnia/resources/prompts" test -f "$out/share/doc/insomnia/nix.md" test -f "$out/share/doc/insomnia/environment.md"