rename: adopt yoi identity

This commit is contained in:
2026-06-01 18:49:23 +09:00
parent 6e133a7229
commit e6c458021c
115 changed files with 945 additions and 732 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
//!
//! - [`PodClient`]: 既存 pod の Unix ソケットへ接続して `Method` を送り、
//! `Event` を受け取る低レベル接続。
//! - [`spawn`]: pod バイナリをサブプロセスとして起動し、`INSOMNIA-READY`
//! - [`spawn`]: pod バイナリをサブプロセスとして起動し、`YOI-READY`
//! ハンドシェイクが終わるまで待つフロー。subprocess を立ち上げる必要が
//! ない呼び出し側 (=既存 pod に attach する場合) は使わなくてよい。
//!
+14 -17
View File
@@ -3,7 +3,7 @@ use std::fmt;
use std::io;
use std::path::{Path, PathBuf};
const POD_RUNTIME_COMMAND_ENV: &str = "INSOMNIA_POD_RUNTIME_COMMAND";
const POD_RUNTIME_COMMAND_ENV: &str = "YOI_POD_RUNTIME_COMMAND";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PodRuntimeCommand {
@@ -29,9 +29,9 @@ impl PodRuntimeCommand {
/// Resolve the Pod runtime command used for subprocess launches.
///
/// The default launch path is always the current `insomnia` executable plus
/// The default launch path is always the current `yoi` executable plus
/// the unified `pod` prefix argument. During development, a non-empty
/// `INSOMNIA_POD_RUNTIME_COMMAND` value replaces only the executable path;
/// `YOI_POD_RUNTIME_COMMAND` value replaces only the executable path;
/// the `pod` prefix is still added here and the env value is not parsed as a
/// shell command.
pub fn resolve() -> io::Result<Self> {
@@ -89,10 +89,10 @@ mod tests {
use super::*;
#[test]
fn insomnia_binary_defaults_to_pod_prefix() {
let command = PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia");
fn yoi_binary_defaults_to_pod_prefix() {
let command = PodRuntimeCommand::for_executable("/opt/yoi/bin/yoi");
assert_eq!(command.program(), Path::new("/opt/insomnia/bin/insomnia"));
assert_eq!(command.program(), Path::new("/opt/yoi/bin/yoi"));
assert_eq!(command.prefix_args(), [OsString::from("pod")]);
assert_eq!(
command.argv_with(["--pod", "agent"]),
@@ -105,12 +105,9 @@ mod tests {
#[test]
fn any_runtime_executable_gets_pod_prefix() {
let command = PodRuntimeCommand::for_executable("/opt/insomnia/bin/custom-runtime");
let command = PodRuntimeCommand::for_executable("/opt/yoi/bin/custom-runtime");
assert_eq!(
command.program(),
Path::new("/opt/insomnia/bin/custom-runtime")
);
assert_eq!(command.program(), Path::new("/opt/yoi/bin/custom-runtime"));
assert_eq!(command.prefix_args(), [OsString::from("pod")]);
assert_eq!(
command.argv_with(["--pod", "agent"]),
@@ -124,38 +121,38 @@ mod tests {
#[test]
fn resolve_uses_current_exe_when_override_is_unset() {
let command = PodRuntimeCommand::resolve_from_env_value(None, || {
Ok(PathBuf::from("/opt/insomnia/bin/insomnia"))
Ok(PathBuf::from("/opt/yoi/bin/yoi"))
})
.unwrap();
assert_eq!(
command,
PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia")
PodRuntimeCommand::for_executable("/opt/yoi/bin/yoi")
);
}
#[test]
fn resolve_uses_current_exe_when_override_is_empty() {
let command = PodRuntimeCommand::resolve_from_env_value(Some(OsString::new()), || {
Ok(PathBuf::from("/opt/insomnia/bin/insomnia"))
Ok(PathBuf::from("/opt/yoi/bin/yoi"))
})
.unwrap();
assert_eq!(
command,
PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia")
PodRuntimeCommand::for_executable("/opt/yoi/bin/yoi")
);
}
#[test]
fn resolve_override_replaces_only_program_and_keeps_pod_prefix() {
let command = PodRuntimeCommand::resolve_from_env_value(
Some(OsString::from("/tmp/rebuilt insomnia")),
Some(OsString::from("/tmp/rebuilt yoi")),
|| panic!("override must not inspect current_exe"),
)
.unwrap();
assert_eq!(command.program(), Path::new("/tmp/rebuilt insomnia"));
assert_eq!(command.program(), Path::new("/tmp/rebuilt yoi"));
assert_eq!(command.prefix_args(), [OsString::from("pod")]);
assert_eq!(
command.argv_with(["--pod", "agent"]),
+5 -5
View File
@@ -1,9 +1,9 @@
//! Pod runtime command をサブプロセスとして立ち上げ、`INSOMNIA-READY` を待つ
//! Pod runtime command をサブプロセスとして立ち上げ、`YOI-READY` を待つ
//! ハンドシェイク。
//!
//! - 親プロセス (TUI / GUI / E2E) は profile/default/typed restore flags を
//! 指定してこの関数に渡す。pod はそれを受けて socket を bind し、stderr に
//! `INSOMNIA-READY\t<name>\t<socket>` を吐く。
//! `YOI-READY\t<name>\t<socket>` を吐く。
//! - 待機中の stderr 行は `progress` コールバック越しに呼び出し側へ流す。
//! UI の進捗表示や E2E のログ収集はここで賄う。
//! - `kill_on_drop = false` + `process_group(0)` により、親プロセス
@@ -19,7 +19,7 @@ use crate::PodRuntimeCommand;
use tokio::process::Command;
use uuid::Uuid;
const READY_PREFIX: &str = "INSOMNIA-READY\t";
const READY_PREFIX: &str = "YOI-READY\t";
const READY_TIMEOUT: Duration = Duration::from_secs(20);
/// `spawn_pod` の入力。
@@ -69,7 +69,7 @@ impl std::fmt::Display for SpawnError {
Self::Io(e) => write!(f, "io error: {e}"),
Self::RuntimeDirUnavailable => write!(
f,
"could not resolve runtime directory (set INSOMNIA_HOME, INSOMNIA_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
"could not resolve runtime directory (set YOI_HOME, YOI_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
),
Self::PodLaunchFailed { command, source } => write!(
f,
@@ -106,7 +106,7 @@ impl From<io::Error> for SpawnError {
}
}
/// pod を spawn し、`INSOMNIA-READY` ハンドシェイクが終わるまで待つ。
/// pod を spawn し、`YOI-READY` ハンドシェイクが終わるまで待つ。
///
/// `progress` は ready 行を見つけるまでに観測した stderr の各行で呼ばれる
/// (ready 行自体は除外される)。UI の表示更新や E2E ログ取得に使う。
@@ -2,7 +2,7 @@
//!
//! `response.*` 名前空間の SSE を共通の [`Event`](crate::llm_client::event::Event)
//! に変換する。Responses の (output_index, content_index) 2 次元座標と
//! insomnia 側 1 次元 `BlockStart/Delta/Stop::index` のマッピングは
//! yoi 側 1 次元 `BlockStart/Delta/Stop::index` のマッピングは
//! [`OpenAIResponsesState`] が保持する。
use std::collections::{BTreeMap, HashMap};
+1 -1
View File
@@ -1,6 +1,6 @@
//! LLM Client Common Types
//!
//! Core conversation types for insomnia's LLM interaction model.
//! Core conversation types for yoi's LLM interaction model.
//! The core abstraction is `Item` which represents different types of conversation elements:
//! - Message items (user/assistant messages with content parts)
//! - ToolCall items (tool invocations)
+3 -3
View File
@@ -688,7 +688,7 @@ mod tests {
use crate::{Permission, ReasoningEffort, ScopeRule};
fn abs(path: &str) -> PathBuf {
PathBuf::from(format!("/tmp/insomnia-test{path}"))
PathBuf::from(format!("/tmp/yoi-test{path}"))
}
fn api_key_file_auth(path: PathBuf) -> AuthRef {
@@ -791,14 +791,14 @@ mod tests {
fn resolve_paths_joins_relative_auth_file() {
let mut cfg = minimal_valid();
cfg.model.auth = Some(api_key_file_auth(PathBuf::from("keys/anthropic")));
let resolved = cfg.resolve_paths(Path::new("/home/user/.config/insomnia"));
let resolved = cfg.resolve_paths(Path::new("/home/user/.config/yoi"));
let file = match resolved.model.auth {
Some(AuthRef::ApiKey { file, .. }) => file,
_ => panic!("expected ApiKey"),
};
assert_eq!(
file.as_deref(),
Some(Path::new("/home/user/.config/insomnia/keys/anthropic"))
Some(Path::new("/home/user/.config/yoi/keys/anthropic"))
);
}
+2 -2
View File
@@ -44,8 +44,8 @@ pub const COMPACT_OVERVIEW_DEADLINE_TOKENS: u64 = 40_000;
/// Default instruction asset reference used when `worker.instruction`
/// is omitted. See the `PromptLoader` prefix addressing scheme for the
/// `$insomnia/` / `$user/` / `$workspace/` namespaces.
pub const DEFAULT_INSTRUCTION: &str = "$insomnia/default";
/// `$yoi/` / `$user/` / `$workspace/` namespaces.
pub const DEFAULT_INSTRUCTION: &str = "$yoi/default";
/// Default language policy used by the main worker for normal prose
/// responses. See [`crate::WorkerManifest::language`].
+1 -1
View File
@@ -256,7 +256,7 @@ pub struct PodMeta {
pub struct WorkerManifest {
/// Reference to the instruction prompt asset used as the body of
/// the worker's system prompt. Uses the `PromptLoader` prefix
/// addressing scheme (`$insomnia/...`, `$user/...`,
/// addressing scheme (`$yoi/...`, `$user/...`,
/// `$workspace/...`) and is always populated after resolution —
/// unset manifests fall through to [`defaults::DEFAULT_INSTRUCTION`].
#[serde(default = "default_instruction")]
+43 -43
View File
@@ -1,4 +1,4 @@
//! Insomnia のホームディレクトリ配下のパス解決を一元化するモジュール。
//! Yoi のホームディレクトリ配下のパス解決を一元化するモジュール。
//!
//! 用途別に三つの base directory を持つ:
//!
@@ -10,13 +10,13 @@
//!
//! ## 解決順 (優先順位高 → 低)
//!
//! | base | 1. `INSOMNIA_<KIND>_DIR` | 2. `INSOMNIA_HOME` | 3. `XDG_*` | 4. 既定 |
//! | base | 1. `YOI_<KIND>_DIR` | 2. `YOI_HOME` | 3. `XDG_*` | 4. 既定 |
//! |---|---|---|---|---|
//! | config | `INSOMNIA_CONFIG_DIR` | `$INSOMNIA_HOME/config` | `$XDG_CONFIG_HOME/insomnia` | `$HOME/.config/insomnia` |
//! | data | `INSOMNIA_DATA_DIR` | `$INSOMNIA_HOME` | — | `$HOME/.insomnia` |
//! | runtime | `INSOMNIA_RUNTIME_DIR` | `$INSOMNIA_HOME/run` | `$XDG_RUNTIME_DIR/insomnia` | `$HOME/.insomnia/run` |
//! | config | `YOI_CONFIG_DIR` | `$YOI_HOME/config` | `$XDG_CONFIG_HOME/yoi` | `$HOME/.config/yoi` |
//! | data | `YOI_DATA_DIR` | `$YOI_HOME` | — | `$HOME/.yoi` |
//! | runtime | `YOI_RUNTIME_DIR` | `$YOI_HOME/run` | `$XDG_RUNTIME_DIR/yoi` | `$HOME/.yoi/run` |
//!
//! `INSOMNIA_HOME=$X` のとき config は `$X/config`、data は `$X` 直下、
//! `YOI_HOME=$X` のとき config は `$X/config`、data は `$X` 直下、
//! runtime は `$X/run` に集約される。テストや sandbox 利用ではこれ一本
//! で全部 tempdir に向けられる。
//!
@@ -29,8 +29,8 @@ use std::path::PathBuf;
/// `prompts/` などが置かれる。
pub fn config_dir() -> Option<PathBuf> {
resolve_config_dir_from_parts(
env_path("INSOMNIA_CONFIG_DIR"),
env_path("INSOMNIA_HOME"),
env_path("YOI_CONFIG_DIR"),
env_path("YOI_HOME"),
env_path("XDG_CONFIG_HOME"),
env_path("HOME"),
)
@@ -40,8 +40,8 @@ pub fn config_dir() -> Option<PathBuf> {
/// 置き場。
pub fn data_dir() -> Option<PathBuf> {
resolve_data_dir_from_parts(
env_path("INSOMNIA_DATA_DIR"),
env_path("INSOMNIA_HOME"),
env_path("YOI_DATA_DIR"),
env_path("YOI_HOME"),
env_path("HOME"),
)
}
@@ -50,8 +50,8 @@ pub fn data_dir() -> Option<PathBuf> {
/// `status.json` 等が置かれる。再起動で消えて構わない。
pub fn runtime_dir() -> Option<PathBuf> {
resolve_runtime_dir_from_parts(
env_path("INSOMNIA_RUNTIME_DIR"),
env_path("INSOMNIA_HOME"),
env_path("YOI_RUNTIME_DIR"),
env_path("YOI_HOME"),
env_path("XDG_RUNTIME_DIR"),
env_path("HOME"),
)
@@ -111,53 +111,53 @@ pub fn pod_socket_path(pod_name: &str) -> Option<PathBuf> {
// ---- internals --------------------------------------------------------------
fn resolve_config_dir_from_parts(
insomnia_config_dir: Option<PathBuf>,
insomnia_home: Option<PathBuf>,
yoi_config_dir: Option<PathBuf>,
yoi_home: Option<PathBuf>,
xdg_config_home: Option<PathBuf>,
home: Option<PathBuf>,
) -> Option<PathBuf> {
if let Some(p) = insomnia_config_dir {
if let Some(p) = yoi_config_dir {
return Some(p);
}
if let Some(p) = insomnia_home {
if let Some(p) = yoi_home {
return Some(p.join("config"));
}
if let Some(p) = xdg_config_home {
return Some(p.join("insomnia"));
return Some(p.join("yoi"));
}
Some(home?.join(".config").join("insomnia"))
Some(home?.join(".config").join("yoi"))
}
fn resolve_data_dir_from_parts(
insomnia_data_dir: Option<PathBuf>,
insomnia_home: Option<PathBuf>,
yoi_data_dir: Option<PathBuf>,
yoi_home: Option<PathBuf>,
home: Option<PathBuf>,
) -> Option<PathBuf> {
if let Some(p) = insomnia_data_dir {
if let Some(p) = yoi_data_dir {
return Some(p);
}
if let Some(p) = insomnia_home {
if let Some(p) = yoi_home {
return Some(p);
}
Some(home?.join(".insomnia"))
Some(home?.join(".yoi"))
}
fn resolve_runtime_dir_from_parts(
insomnia_runtime_dir: Option<PathBuf>,
insomnia_home: Option<PathBuf>,
yoi_runtime_dir: Option<PathBuf>,
yoi_home: Option<PathBuf>,
xdg_runtime_dir: Option<PathBuf>,
home: Option<PathBuf>,
) -> Option<PathBuf> {
if let Some(p) = insomnia_runtime_dir {
if let Some(p) = yoi_runtime_dir {
return Some(p);
}
if let Some(p) = insomnia_home {
if let Some(p) = yoi_home {
return Some(p.join("run"));
}
if let Some(p) = xdg_runtime_dir {
return Some(p.join("insomnia"));
return Some(p.join("yoi"));
}
Some(home?.join(".insomnia").join("run"))
Some(home?.join(".yoi").join("run"))
}
fn user_profiles_path_from_config_dir(config_dir: Option<PathBuf>) -> Option<PathBuf> {
@@ -221,7 +221,7 @@ mod tests {
fn config_dir_falls_back_to_home_dot_config() {
assert_eq!(
resolve_config_dir_from_parts(None, None, None, Some(PathBuf::from("/h"))).unwrap(),
PathBuf::from("/h/.config/insomnia")
PathBuf::from("/h/.config/yoi")
);
}
@@ -235,12 +235,12 @@ mod tests {
Some(PathBuf::from("/h")),
)
.unwrap(),
PathBuf::from("/x/insomnia")
PathBuf::from("/x/yoi")
);
}
#[test]
fn config_dir_insomnia_home_outranks_xdg() {
fn config_dir_yoi_home_outranks_xdg() {
assert_eq!(
resolve_config_dir_from_parts(
None,
@@ -254,7 +254,7 @@ mod tests {
}
#[test]
fn config_dir_explicit_wins_over_insomnia_home() {
fn config_dir_explicit_wins_over_yoi_home() {
assert_eq!(
resolve_config_dir_from_parts(
Some(PathBuf::from("/explicit-cfg")),
@@ -268,15 +268,15 @@ mod tests {
}
#[test]
fn data_dir_default_is_dot_insomnia() {
fn data_dir_default_is_dot_yoi() {
assert_eq!(
resolve_data_dir_from_parts(None, None, Some(PathBuf::from("/h"))).unwrap(),
PathBuf::from("/h/.insomnia")
PathBuf::from("/h/.yoi")
);
}
#[test]
fn data_dir_insomnia_home_is_data_dir_itself() {
fn data_dir_yoi_home_is_data_dir_itself() {
assert_eq!(
resolve_data_dir_from_parts(
None,
@@ -289,7 +289,7 @@ mod tests {
}
#[test]
fn data_dir_explicit_wins_over_insomnia_home() {
fn data_dir_explicit_wins_over_yoi_home() {
assert_eq!(
resolve_data_dir_from_parts(
Some(PathBuf::from("/explicit-data")),
@@ -311,20 +311,20 @@ mod tests {
Some(PathBuf::from("/h")),
)
.unwrap(),
PathBuf::from("/xdg-runtime/insomnia")
PathBuf::from("/xdg-runtime/yoi")
);
}
#[test]
fn runtime_dir_falls_back_to_dot_insomnia_run() {
fn runtime_dir_falls_back_to_dot_yoi_run() {
assert_eq!(
resolve_runtime_dir_from_parts(None, None, None, Some(PathBuf::from("/h"))).unwrap(),
PathBuf::from("/h/.insomnia/run")
PathBuf::from("/h/.yoi/run")
);
}
#[test]
fn runtime_dir_insomnia_home_is_run_subdir() {
fn runtime_dir_yoi_home_is_run_subdir() {
assert_eq!(
resolve_runtime_dir_from_parts(
None,
@@ -338,7 +338,7 @@ mod tests {
}
#[test]
fn runtime_dir_explicit_wins_over_insomnia_home() {
fn runtime_dir_explicit_wins_over_yoi_home() {
assert_eq!(
resolve_runtime_dir_from_parts(
Some(PathBuf::from("/explicit-run")),
@@ -358,7 +358,7 @@ mod tests {
assert_eq!(
resolve_config_dir_from_parts(None, None, xdg_config_home, Some(PathBuf::from("/h")))
.unwrap(),
PathBuf::from("/h/.config/insomnia")
PathBuf::from("/h/.config/yoi")
);
}
+23 -23
View File
@@ -20,11 +20,11 @@ use crate::{
ScopeConfig, ScopeRule, SkillsConfig, WebConfig, WorkerManifestConfig, paths,
};
const PROFILE_FORMAT_V1: &str = "insomnia.lua-profile.v1";
const PROFILE_FORMAT_V1: &str = "yoi.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";
const DEFAULT_POD_NAME: &str = "yoi";
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
@@ -694,7 +694,7 @@ fn find_project_profiles_from(start: &Path) -> Option<PathBuf> {
.unwrap_or_else(|| start.to_path_buf());
let mut cur: Option<&Path> = Some(start.as_path());
while let Some(dir) = cur {
let candidate = dir.join(".insomnia").join("profiles.toml");
let candidate = dir.join(".yoi").join("profiles.toml");
if candidate.is_file() {
return Some(candidate);
}
@@ -709,7 +709,7 @@ fn add_builtin_profiles(registry: &mut ProfileRegistry) {
BUILTIN_DEFAULT_PROFILE_NAME,
"builtin:default",
BUILTIN_DEFAULT_PROFILE,
Some("Bundled default Insomnia coding profile".into()),
Some("Bundled default Yoi coding profile".into()),
));
}
@@ -827,7 +827,7 @@ fn require_module(
if let Some(value) = host_module(lua, name)? {
return Ok(value);
}
if name.starts_with("insomnia.") || name == "insomnia" {
if name.starts_with("yoi.") || name == "yoi" {
return Err(mlua::Error::RuntimeError(format!(
"unknown host module `{name}`"
)));
@@ -876,7 +876,7 @@ fn require_module(
fn host_module(lua: &Lua, name: &str) -> mlua::Result<Option<LuaValue>> {
match name {
"insomnia" => {
"yoi" => {
let t = lua.create_table()?;
t.set("profile", profile_function(lua)?)?;
t.set("models", models_module(lua)?)?;
@@ -884,10 +884,10 @@ fn host_module(lua: &Lua, name: &str) -> mlua::Result<Option<LuaValue>> {
t.set("scope", scope_module(lua)?)?;
Ok(Some(LuaValue::Table(t)))
}
"insomnia.profile" => Ok(Some(LuaValue::Function(profile_function(lua)?))),
"insomnia.models" => Ok(Some(LuaValue::Table(models_module(lua)?))),
"insomnia.compact" => Ok(Some(LuaValue::Table(compact_module(lua)?))),
"insomnia.scope" => Ok(Some(LuaValue::Table(scope_module(lua)?))),
"yoi.profile" => Ok(Some(LuaValue::Function(profile_function(lua)?))),
"yoi.models" => Ok(Some(LuaValue::Table(models_module(lua)?))),
"yoi.compact" => Ok(Some(LuaValue::Table(compact_module(lua)?))),
"yoi.scope" => Ok(Some(LuaValue::Table(scope_module(lua)?))),
_ => Ok(None),
}
}
@@ -997,7 +997,7 @@ fn reject_manifest_shaped_profile(value: &serde_json::Value) -> Result<(), Profi
for key in ["allow", "deny"] {
if scope.contains_key(key) {
return Err(ProfileError::InvalidProfile(format!(
"field `scope.{key}` grants concrete authority and is not allowed in reusable Profiles; use require(\"insomnia.scope\") intent helpers"
"field `scope.{key}` grants concrete authority and is not allowed in reusable Profiles; use require(\"yoi.scope\") intent helpers"
)));
}
}
@@ -1312,8 +1312,8 @@ mod tests {
tmp.path(),
"coder.lua",
r#"
local profile = require("insomnia.profile")
local scope = require("insomnia.scope")
local profile = require("yoi.profile")
local scope = require("yoi.scope")
return profile {
slug = "coder",
model = { scheme = "anthropic", model_id = "claude-sonnet-4-20250514" },
@@ -1352,19 +1352,19 @@ return profile {
let tmp = TempDir::new().unwrap();
std::fs::write(
tmp.path().join("shared.lua"),
r#"return { model = require("insomnia.models").catalog("codex-oauth/gpt-5.5") }"#,
r#"return { model = require("yoi.models").catalog("codex-oauth/gpt-5.5") }"#,
)
.unwrap();
let profile = write_profile(
tmp.path(),
"main.lua",
r#"
local insomnia = require("insomnia")
local yoi = require("yoi")
local shared = require("shared")
return insomnia.profile {
return yoi.profile {
slug = "main",
model = shared.model,
scope = insomnia.scope.workspace_write(),
scope = yoi.scope.workspace_write(),
}
"#,
);
@@ -1445,9 +1445,9 @@ return insomnia.profile {
tmp.path(),
"ratio.lua",
r#"
local profile = require("insomnia.profile")
local models = require("insomnia.models")
local compact = require("insomnia.compact")
local profile = require("yoi.profile")
local models = require("yoi.models")
local compact = require("yoi.compact")
return profile {
model = models.catalog("codex-oauth/gpt-5.5"),
compaction = compact.ratio { threshold = 0.5, request = 0.75, worker = 0.25 },
@@ -1473,7 +1473,7 @@ return profile {
.with_workspace_base(tmp.path())
.resolve(&ProfileSelector::Default, ProfileResolveOptions::default())
.unwrap();
assert_eq!(resolved.manifest.pod.name, "insomnia");
assert_eq!(resolved.manifest.pod.name, "yoi");
assert_eq!(
resolved.manifest.model.ref_.as_deref(),
Some("codex-oauth/gpt-5.5")
@@ -1516,7 +1516,7 @@ return profile {
fn discovery_reads_user_and_project_registry_and_project_default_wins() {
let tmp = TempDir::new().unwrap();
let user_config = tmp.path().join("profiles.toml");
let project_dir = tmp.path().join("project/.insomnia");
let project_dir = tmp.path().join("project/.yoi");
std::fs::create_dir_all(&project_dir).unwrap();
let project_config = project_dir.join("profiles.toml");
std::fs::write(
@@ -1542,7 +1542,7 @@ return profile {
#[test]
fn default_marks_direct_profile_entry() {
let tmp = TempDir::new().unwrap();
let project_dir = tmp.path().join("project/.insomnia");
let project_dir = tmp.path().join("project/.yoi");
std::fs::create_dir_all(&project_dir).unwrap();
let project_config = project_dir.join("profiles.toml");
std::fs::write(
+4 -4
View File
@@ -1,12 +1,12 @@
//! Append-only JSONL audit log for memory workers and tools.
//!
//! The log is evidence-only observability data under
//! `.insomnia/memory/_logs/current.log`. It is intentionally separate from
//! `.yoi/memory/_logs/current.log`. It is intentionally separate from
//! `_staging` and `_usage`, and consolidation never consumes it. Operators can
//! follow the latest stream with:
//!
//! ```text
//! tail -f .insomnia/memory/_logs/current.log
//! tail -f .yoi/memory/_logs/current.log
//! ```
use std::collections::BTreeMap;
@@ -260,7 +260,7 @@ pub struct RecordSnapshot {
pub hash: String,
}
/// Append one audit event to `.insomnia/memory/_logs/current.log`.
/// Append one audit event to `.yoi/memory/_logs/current.log`.
pub fn append_audit_event(layout: &WorkspaceLayout, event: &AuditEvent) -> io::Result<()> {
let path = layout.audit_current_log_path();
if let Some(parent) = path.parent() {
@@ -425,7 +425,7 @@ mod tests {
#[test]
fn counts_created_edited_deleted_records() {
let (dir, layout) = setup();
let decision_dir = dir.path().join(".insomnia/memory/decisions");
let decision_dir = dir.path().join(".yoi/memory/decisions");
fs::create_dir_all(&decision_dir).unwrap();
fs::write(decision_dir.join("a.md"), "old").unwrap();
fs::write(decision_dir.join("gone.md"), "old").unwrap();
+3 -3
View File
@@ -74,7 +74,7 @@ pub fn render_staging_records(entries: &[StagingEntry]) -> String {
out
}
/// `<workspace>/.insomnia/memory/{summary.md,decisions/*,requests/*}` を
/// `<workspace>/.yoi/memory/{summary.md,decisions/*,requests/*}` を
/// 「`### <kind>:<slug>` ヘッダ + raw markdown ブロック」で全文渡す。
pub fn render_existing_memory_records(layout: &WorkspaceLayout) -> String {
let mut out = String::new();
@@ -230,11 +230,11 @@ mod tests {
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
write(
&dir.path().join(".insomnia/memory/summary.md"),
&dir.path().join(".yoi/memory/summary.md"),
&format!("---\nupdated_at: {n}\n---\nstate of the world\n", n = now()),
);
write(
&dir.path().join(".insomnia/memory/decisions/dec.md"),
&dir.path().join(".yoi/memory/decisions/dec.md"),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\nbody\n",
n = now()
+1 -1
View File
@@ -9,7 +9,7 @@
//! が追加した分は残す
//!
//! 占有判定は Linux/macOS の `kill(pid, 0)` 経由で行う(`ESRCH` で死亡判定)。
//! Windows は対象外: INSOMNIA は POSIX 環境を前提にしている。
//! Windows は対象外: Yoi は POSIX 環境を前提にしている。
use std::fs;
use std::path::{Path, PathBuf};
+6 -7
View File
@@ -133,8 +133,8 @@ pub fn collect_tidy_hints(layout: &WorkspaceLayout) -> TidyHints {
hints
}
/// `<root>/.insomnia/memory/<kind>/*.md` (Knowledge は
/// `<root>/.insomnia/knowledge/*.md`) を slug ごとに `(slug, full content)`
/// `<root>/.yoi/memory/<kind>/*.md` (Knowledge は
/// `<root>/.yoi/knowledge/*.md`) を slug ごとに `(slug, full content)`
/// 化して返す。
fn read_kind_records(layout: &WorkspaceLayout, kind: RecordKind) -> BTreeMap<String, String> {
let dir = match kind {
@@ -280,14 +280,14 @@ mod tests {
fn collects_replaced_chain() {
let (dir, layout) = workspace();
write(
&dir.path().join(".insomnia/memory/decisions/replaced.md"),
&dir.path().join(".yoi/memory/decisions/replaced.md"),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: replaced\nreplaced_by: winner\n---\n",
n = now()
),
);
write(
&dir.path().join(".insomnia/memory/decisions/winner.md"),
&dir.path().join(".yoi/memory/decisions/winner.md"),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n",
n = now()
@@ -308,7 +308,7 @@ mod tests {
.map(|i| format!(" - segment_id: s{i}\n range: [{i}, {i}]\n"))
.collect();
write(
&dir.path().join(".insomnia/memory/decisions/big.md"),
&dir.path().join(".yoi/memory/decisions/big.md"),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nstatus: open\nsources:\n{m}---\n",
n = now(),
@@ -327,8 +327,7 @@ mod tests {
let (dir, layout) = workspace();
for slug in ["db-pool", "db-pol", "db-pools", "alpha"] {
write(
&dir.path()
.join(format!(".insomnia/memory/decisions/{slug}.md")),
&dir.path().join(format!(".yoi/memory/decisions/{slug}.md")),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n",
n = now()
+1 -1
View File
@@ -1,7 +1,7 @@
//! extract: 活動抽出。
//!
//! 通常 Pod の post-run hook で発火する disposable Worker と、その
//! 出力を `<workspace>/.insomnia/memory/_staging/<id>.json` に書き出す
//! 出力を `<workspace>/.yoi/memory/_staging/<id>.json` に書き出す
//! ヘルパーを提供する。Pod 側はこのモジュールから:
//!
//! - [`build_extract_input`] を sub-Worker の最初の user 入力に
+1 -1
View File
@@ -1,4 +1,4 @@
//! `<workspace>/.insomnia/memory/_staging/<id>.json` への書き出しヘルパー。
//! `<workspace>/.yoi/memory/_staging/<id>.json` への書き出しヘルパー。
//!
//! 1 件 1 ファイル、UUIDv7 命名(短命なので衝突回避と順序を兼ねる)。
//! `source` を機械付与した [`StagingRecord`] 形式で保存する。
+14 -16
View File
@@ -291,7 +291,7 @@ mod tests {
#[test]
fn decision_with_unknown_replaced_by_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nsources: []\nstatus: replaced\nreplaced_by: ghost\n---\nbody\n",
now = iso_now()
@@ -308,7 +308,7 @@ mod tests {
#[test]
fn decision_replaced_by_self_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nsources: []\nstatus: replaced\nreplaced_by: foo\n---\nbody\n",
now = iso_now()
@@ -326,7 +326,7 @@ mod tests {
fn decision_replaced_by_existing_ok() {
let (dir, linter) = workspace();
// Pre-create the target.
let target = dir.path().join(".insomnia/memory/decisions/bar.md");
let target = dir.path().join(".yoi/memory/decisions/bar.md");
write(
&target,
&format!(
@@ -334,7 +334,7 @@ mod tests {
now = iso_now()
),
);
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nsources: []\nstatus: replaced\nreplaced_by: bar\n---\nbody\n",
now = iso_now()
@@ -346,7 +346,7 @@ mod tests {
#[test]
fn missing_required_field_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
// Missing `status`.
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nsources: []\n---\nbody\n",
@@ -363,7 +363,7 @@ mod tests {
#[test]
fn knowledge_long_description_with_model_invokation_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/knowledge/foo.md");
let path = dir.path().join(".yoi/knowledge/foo.md");
let big_desc = "x".repeat(2000);
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nkind: rule\ndescription: {big_desc}\nmodel_invokation: true\nuser_invocable: true\nlast_sources: []\n---\nbody\n",
@@ -381,7 +381,7 @@ mod tests {
#[test]
fn knowledge_long_description_without_model_invokation_ok() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/knowledge/foo.md");
let path = dir.path().join(".yoi/knowledge/foo.md");
let big_desc = "x".repeat(2000);
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nkind: rule\ndescription: {big_desc}\nmodel_invokation: false\nuser_invocable: true\nlast_sources: []\n---\nbody\n",
@@ -394,7 +394,7 @@ mod tests {
#[test]
fn summary_path_accepted() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/summary.md");
let path = dir.path().join(".yoi/memory/summary.md");
let content = format!(
"---\nupdated_at: {now}\n---\nsummary body\n",
now = iso_now()
@@ -406,7 +406,7 @@ mod tests {
#[test]
fn create_when_existing_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
write(
&path,
&format!(
@@ -434,15 +434,14 @@ mod tests {
// `db-pol` (1 deletion), `db-pools` (1 insertion).
for slug in ["db-pol", "db-pools"] {
write(
&dir.path()
.join(format!(".insomnia/memory/decisions/{slug}.md")),
&dir.path().join(format!(".yoi/memory/decisions/{slug}.md")),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n",
n = iso_now()
),
);
}
let path = dir.path().join(".insomnia/memory/decisions/db-pool.md");
let path = dir.path().join(".yoi/memory/decisions/db-pool.md");
let content = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\nbody\n",
n = iso_now()
@@ -464,15 +463,14 @@ mod tests {
let (dir, linter) = workspace();
for slug in ["alpha", "bravo"] {
write(
&dir.path()
.join(format!(".insomnia/memory/decisions/{slug}.md")),
&dir.path().join(format!(".yoi/memory/decisions/{slug}.md")),
&format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n",
n = iso_now()
),
);
}
let path = dir.path().join(".insomnia/memory/decisions/charlie.md");
let path = dir.path().join(".yoi/memory/decisions/charlie.md");
let content = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n",
n = iso_now()
@@ -491,7 +489,7 @@ mod tests {
#[test]
fn body_size_limit_errors() {
let (dir, linter) = workspace();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
let big_body = "x".repeat(8001);
let content = format!(
"---\ncreated_at: {now}\nupdated_at: {now}\nsources: []\nstatus: open\n---\n{body}",
+12 -20
View File
@@ -5,7 +5,7 @@
//! - [`collect_resident_knowledge`] — resident-injection candidates
//! (`model_invokation: true`) returned as `(slug, description)` pairs.
//! - [`collect_resident_summary`] — the body of
//! `<workspace>/.insomnia/memory/summary.md` when it parses as a summary
//! `<workspace>/.yoi/memory/summary.md` when it parses as a summary
//! record and has non-empty body.
//! - [`list_knowledge_slugs`] — every slug whose file parses, regardless
//! of `model_invokation`. Used by the Pod IPC layer to answer TUI `#`
@@ -25,7 +25,7 @@ pub struct ResidentKnowledgeEntry {
pub description: String,
}
/// Walk `<workspace>/.insomnia/knowledge/*.md` and return entries whose
/// Walk `<workspace>/.yoi/knowledge/*.md` and return entries whose
/// frontmatter has `model_invokation: true`, sorted by slug. A missing
/// directory yields an empty vec.
pub fn collect_resident_knowledge(layout: &WorkspaceLayout) -> Vec<ResidentKnowledgeEntry> {
@@ -42,7 +42,7 @@ pub fn collect_resident_knowledge(layout: &WorkspaceLayout) -> Vec<ResidentKnowl
out
}
/// Read `<workspace>/.insomnia/memory/summary.md` for resident prompt
/// Read `<workspace>/.yoi/memory/summary.md` for resident prompt
/// injection. Returns only the markdown body (frontmatter stripped), and
/// degrades to `None` for missing, unreadable, malformed, or empty records.
pub fn collect_resident_summary(layout: &WorkspaceLayout) -> Option<String> {
@@ -115,7 +115,7 @@ mod tests {
}
fn write_summary(dir: &Path, body: &str) {
let path = dir.join(".insomnia/memory/summary.md");
let path = dir.join(".yoi/memory/summary.md");
let content = format!("---\nupdated_at: {n}\n---\n{body}", n = now());
std::fs::write(path, content).unwrap();
}
@@ -127,7 +127,7 @@ mod tests {
model_invokation: bool,
body: &str,
) {
let path = dir.join(".insomnia/knowledge").join(format!("{slug}.md"));
let path = dir.join(".yoi/knowledge").join(format!("{slug}.md"));
let content = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nkind: policy\ndescription: \"{description}\"\nmodel_invokation: {flag}\nuser_invocable: true\nlast_sources: []\n---\n{body}",
n = now(),
@@ -138,8 +138,8 @@ mod tests {
fn setup() -> (TempDir, WorkspaceLayout) {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/knowledge")).unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/memory")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/knowledge")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/memory")).unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
(dir, layout)
}
@@ -166,7 +166,7 @@ mod tests {
fn malformed_summary_returns_none() {
let (dir, layout) = setup();
std::fs::write(
dir.path().join(".insomnia/memory/summary.md"),
dir.path().join(".yoi/memory/summary.md"),
"---\nthis is not yaml: : :\n---\nbody\n",
)
.unwrap();
@@ -222,7 +222,7 @@ mod tests {
write_knowledge(dir.path(), "good", "ok", true, "");
// Garbage in frontmatter — must be skipped, not panic.
std::fs::write(
dir.path().join(".insomnia/knowledge/bad.md"),
dir.path().join(".yoi/knowledge/bad.md"),
"---\nthis is not yaml: : :\n---\nbody\n",
)
.unwrap();
@@ -236,11 +236,7 @@ mod tests {
fn non_md_files_ignored() {
let (dir, layout) = setup();
write_knowledge(dir.path(), "good", "ok", true, "");
std::fs::write(
dir.path().join(".insomnia/knowledge/note.txt"),
"not markdown\n",
)
.unwrap();
std::fs::write(dir.path().join(".yoi/knowledge/note.txt"), "not markdown\n").unwrap();
let got = collect_resident_knowledge(&layout);
assert_eq!(got.len(), 1);
@@ -269,15 +265,11 @@ mod tests {
let (dir, layout) = setup();
write_knowledge(dir.path(), "good", "ok", true, "");
std::fs::write(
dir.path().join(".insomnia/knowledge/bad.md"),
dir.path().join(".yoi/knowledge/bad.md"),
"---\nthis is not yaml: : :\n---\nbody\n",
)
.unwrap();
std::fs::write(
dir.path().join(".insomnia/knowledge/note.txt"),
"not markdown\n",
)
.unwrap();
std::fs::write(dir.path().join(".yoi/knowledge/note.txt"), "not markdown\n").unwrap();
let got = list_knowledge_slugs(&layout);
assert_eq!(got, vec!["good"]);
+2 -2
View File
@@ -41,9 +41,9 @@ mod tests {
let layout = WorkspaceLayout::new(PathBuf::from("/ws"));
let rules = deny_write_rules(&layout);
assert_eq!(rules.len(), 2);
assert_eq!(rules[0].target, PathBuf::from("/ws/.insomnia/memory"));
assert_eq!(rules[0].target, PathBuf::from("/ws/.yoi/memory"));
assert_eq!(rules[0].permission, Permission::Write);
assert!(rules[0].recursive);
assert_eq!(rules[1].target, PathBuf::from("/ws/.insomnia/knowledge"));
assert_eq!(rules[1].target, PathBuf::from("/ws/.yoi/knowledge"));
}
}
+1 -1
View File
@@ -294,7 +294,7 @@ mod tests {
fn setup() -> (TempDir, WorkspaceLayout, PathBuf) {
let dir = TempDir::new().unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
let initial = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\nbody body\n",
+15 -17
View File
@@ -6,11 +6,11 @@
//! omitted, returns one entry per file (no excerpt) so the agent can
//! enumerate what records exist without knowing what's inside them.
//!
//! - `MemoryQuery` walks `.insomnia/memory/{summary.md,decisions/,
//! requests/}`. `.insomnia/workflow/`, `.insomnia/memory/_staging/`,
//! `.insomnia/memory/_usage/`, and `.insomnia/memory/_logs/` are excluded
//! - `MemoryQuery` walks `.yoi/memory/{summary.md,decisions/,
//! requests/}`. `.yoi/workflow/`, `.yoi/memory/_staging/`,
//! `.yoi/memory/_usage/`, and `.yoi/memory/_logs/` are excluded
//! by construction.
//! - `KnowledgeQuery` walks `.insomnia/knowledge/*.md` and supports a
//! - `KnowledgeQuery` walks `.yoi/knowledge/*.md` and supports a
//! `kind` filter against the Knowledge frontmatter's `kind` field.
//!
//! No derived index — the file tree is the source of truth and is
@@ -513,18 +513,16 @@ mod tests {
fn setup() -> (TempDir, WorkspaceLayout) {
let dir = TempDir::new().unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
std::fs::create_dir_all(dir.path().join(".insomnia/memory/decisions")).unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/memory/requests")).unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/memory/_staging")).unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/workflow")).unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/knowledge")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/memory/decisions")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/memory/requests")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/memory/_staging")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/workflow")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/knowledge")).unwrap();
(dir, layout)
}
fn write_decision(dir: &Path, slug: &str, body: &str) {
let path = dir
.join(".insomnia/memory/decisions")
.join(format!("{slug}.md"));
let path = dir.join(".yoi/memory/decisions").join(format!("{slug}.md"));
let content = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\n{body}",
n = now()
@@ -533,7 +531,7 @@ mod tests {
}
fn write_knowledge(dir: &Path, slug: &str, kind: &str, description: &str, body: &str) {
let path = dir.join(".insomnia/knowledge").join(format!("{slug}.md"));
let path = dir.join(".yoi/knowledge").join(format!("{slug}.md"));
let content = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nkind: {kind}\ndescription: \"{description}\"\nmodel_invokation: false\nuser_invocable: true\nlast_sources: []\n---\n{body}",
n = now()
@@ -590,7 +588,7 @@ mod tests {
let (dir, layout) = setup();
write_decision(dir.path(), "alpha", "body\n");
write_decision(dir.path(), "beta", "body\n");
let summary_path = dir.path().join(".insomnia/memory/summary.md");
let summary_path = dir.path().join(".yoi/memory/summary.md");
std::fs::write(
&summary_path,
format!("---\nupdated_at: {n}\n---\nhello\n", n = now()),
@@ -610,7 +608,7 @@ mod tests {
#[tokio::test]
async fn memory_query_finds_summary() {
let (dir, layout) = setup();
let summary_path = dir.path().join(".insomnia/memory/summary.md");
let summary_path = dir.path().join(".yoi/memory/summary.md");
std::fs::write(
&summary_path,
format!("---\nupdated_at: {n}\n---\nthe needle is here\n", n = now()),
@@ -628,9 +626,9 @@ mod tests {
#[tokio::test]
async fn memory_query_excludes_workflow_and_staging() {
let (dir, layout) = setup();
let wf = dir.path().join(".insomnia/workflow/wf.md");
let wf = dir.path().join(".yoi/workflow/wf.md");
std::fs::write(&wf, "needle in workflow\n").unwrap();
let stg = dir.path().join(".insomnia/memory/_staging/abc.json");
let stg = dir.path().join(".yoi/memory/_staging/abc.json");
std::fs::write(&stg, "needle in staging\n").unwrap();
let (_, tool) = memory_query_tool(layout, QueryConfig::default())();
+4 -4
View File
@@ -219,7 +219,7 @@ mod tests {
#[tokio::test]
async fn read_decision_by_slug() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, "alpha\nbeta\n").unwrap();
@@ -234,7 +234,7 @@ mod tests {
#[tokio::test]
async fn read_summary_without_slug() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/summary.md");
let path = dir.path().join(".yoi/memory/summary.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, "summary body\n").unwrap();
@@ -274,7 +274,7 @@ mod tests {
#[tokio::test]
async fn knowledge_path_resolution() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/knowledge/policy.md");
let path = dir.path().join(".yoi/knowledge/policy.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, "k\n").unwrap();
@@ -287,7 +287,7 @@ mod tests {
#[tokio::test]
async fn read_logs_explicit_use_when_usage_session_is_set() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, "alpha\n").unwrap();
+3 -3
View File
@@ -219,7 +219,7 @@ mod tests {
#[tokio::test]
async fn write_creates_summary() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/summary.md");
let path = dir.path().join(".yoi/memory/summary.md");
let content = format!("---\nupdated_at: {n}\n---\nbody\n", n = now());
let (meta, tool) = write_tool(layout)();
@@ -257,7 +257,7 @@ mod tests {
#[tokio::test]
async fn write_update_existing() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
let initial = format!(
"---\ncreated_at: {n}\nupdated_at: {n}\nsources: []\nstatus: open\n---\nold\n",
@@ -290,7 +290,7 @@ mod tests {
#[tokio::test]
async fn write_does_not_persist_on_lint_failure() {
let (dir, layout) = setup();
let path = dir.path().join(".insomnia/memory/decisions/foo.md");
let path = dir.path().join(".yoi/memory/decisions/foo.md");
let bad = "no frontmatter at all";
let (_, tool) = write_tool(layout)();
let inp = serde_json::json!({
+1 -1
View File
@@ -1,6 +1,6 @@
//! Workspace-local usage event log for memory / knowledge / workflow records.
//!
//! The log is append-only JSONL under the workspace's `.insomnia/` tree. It is
//! The log is append-only JSONL under the workspace's `.yoi/` tree. It is
//! intentionally evidence-only: aggregation reports explicit context reads and
//! resident exposure cost telemetry, but it does not classify records as
//! Knowledge candidates or tidy-protected records.
+32 -32
View File
@@ -1,25 +1,25 @@
//! Workspace-level path layout for the memory subsystem.
//!
//! `WorkspaceLayout` carries the workspace root (typically the Pod's
//! pwd). All insomnia-managed content lives under the conventional
//! `<root>/.insomnia/` subdirectory — the same place that holds
//! pwd). All yoi-managed content lives under the conventional
//! `<root>/.yoi/` subdirectory — the same place that holds
//! `profiles.toml`, `prompts/`, workflow, knowledge, and generated
//! memory. The trees inside it:
//!
//! - `<root>/.insomnia/workflow/<slug>.md`
//! - `<root>/.insomnia/knowledge/<slug>.md`
//! - `<root>/.insomnia/memory/summary.md`
//! - `<root>/.insomnia/memory/decisions/<slug>.md`
//! - `<root>/.insomnia/memory/requests/<slug>.md`
//! - `<root>/.insomnia/memory/_staging/<id>.json`
//! - `<root>/.insomnia/memory/_logs/current.log` (append-only audit log)
//! - `<root>/.yoi/workflow/<slug>.md`
//! - `<root>/.yoi/knowledge/<slug>.md`
//! - `<root>/.yoi/memory/summary.md`
//! - `<root>/.yoi/memory/decisions/<slug>.md`
//! - `<root>/.yoi/memory/requests/<slug>.md`
//! - `<root>/.yoi/memory/_staging/<id>.json`
//! - `<root>/.yoi/memory/_logs/current.log` (append-only audit log)
//!
//! `memory/` is reserved for session-derived / generated state;
//! Workflows are human-managed and live one level up under
//! `.insomnia/workflow/`.
//! `.yoi/workflow/`.
//!
//! Configuring `[memory]` with an empty body is therefore sufficient
//! for any workspace that already uses the `.insomnia/` convention; no
//! for any workspace that already uses the `.yoi/` convention; no
//! `workspace_root` override is needed.
use std::path::{Path, PathBuf};
@@ -29,7 +29,7 @@ use crate::error::LintError;
#[cfg(test)]
use lint_common::RecordLintError;
const INSOMNIA_DIR: &str = ".insomnia";
const YOI_DIR: &str = ".yoi";
const MEMORY_DIR: &str = "memory";
const KNOWLEDGE_DIR: &str = "knowledge";
const WORKFLOW_DIR: &str = "workflow";
@@ -100,17 +100,17 @@ impl WorkspaceLayout {
&self.root
}
/// `<root>/.insomnia/`. The base of every other memory path.
pub fn insomnia_dir(&self) -> PathBuf {
self.root.join(INSOMNIA_DIR)
/// `<root>/.yoi/`. The base of every other memory path.
pub fn yoi_dir(&self) -> PathBuf {
self.root.join(YOI_DIR)
}
pub fn memory_dir(&self) -> PathBuf {
self.insomnia_dir().join(MEMORY_DIR)
self.yoi_dir().join(MEMORY_DIR)
}
pub fn knowledge_dir(&self) -> PathBuf {
self.insomnia_dir().join(KNOWLEDGE_DIR)
self.yoi_dir().join(KNOWLEDGE_DIR)
}
pub fn summary_path(&self) -> PathBuf {
@@ -125,9 +125,9 @@ impl WorkspaceLayout {
self.memory_dir().join(REQUESTS_DIR)
}
/// Workflow directory: `<root>/.insomnia/workflow/`.
/// Workflow directory: `<root>/.yoi/workflow/`.
pub fn workflow_dir(&self) -> PathBuf {
self.insomnia_dir().join(WORKFLOW_DIR)
self.yoi_dir().join(WORKFLOW_DIR)
}
pub fn staging_dir(&self) -> PathBuf {
@@ -149,7 +149,7 @@ impl WorkspaceLayout {
/// Tail-friendly latest memory audit log path.
///
/// Operators can inspect live memory worker and tool events with:
/// `tail -f .insomnia/memory/_logs/current.log`.
/// `tail -f .yoi/memory/_logs/current.log`.
pub fn audit_current_log_path(&self) -> PathBuf {
self.audit_logs_dir().join(AUDIT_CURRENT_LOG_FILE)
}
@@ -171,12 +171,12 @@ impl WorkspaceLayout {
}
/// Classify a path under the memory tree. Returns `None` if the
/// path is not under `.insomnia/memory/` or `.insomnia/knowledge/`
/// path is not under `.yoi/memory/` or `.yoi/knowledge/`
/// of this workspace, or if it lives in
/// `_staging/` / `_usage/` / `_logs/` (opaque subsystem-owned trees).
///
/// On a conventional path that's *almost* a record but malformed
/// (e.g. `.insomnia/memory/decisions/Foo.md` with an invalid slug),
/// (e.g. `.yoi/memory/decisions/Foo.md` with an invalid slug),
/// returns `Err(LintError::Record(InvalidSlug) | InvalidPath)` so the caller
/// can surface it as a write violation.
pub fn classify(&self, path: &Path) -> Result<Option<ClassifiedPath>, LintError> {
@@ -265,7 +265,7 @@ mod tests {
#[test]
fn classifies_summary() {
let cp = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/summary.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/summary.md"))
.unwrap()
.unwrap();
assert_eq!(cp.kind, RecordKind::Summary);
@@ -275,7 +275,7 @@ mod tests {
#[test]
fn classifies_decision_with_slug() {
let cp = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/decisions/foo-bar.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/decisions/foo-bar.md"))
.unwrap()
.unwrap();
assert_eq!(cp.kind, RecordKind::Decision);
@@ -285,7 +285,7 @@ mod tests {
#[test]
fn classifies_knowledge() {
let cp = layout()
.classify(&PathBuf::from("/ws/.insomnia/knowledge/x.md"))
.classify(&PathBuf::from("/ws/.yoi/knowledge/x.md"))
.unwrap()
.unwrap();
assert_eq!(cp.kind, RecordKind::Knowledge);
@@ -294,7 +294,7 @@ mod tests {
#[test]
fn workflow_under_memory_is_invalid_path() {
let err = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/workflow/wf.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/workflow/wf.md"))
.unwrap_err();
assert!(matches!(err, LintError::InvalidPath(_)));
}
@@ -303,7 +303,7 @@ mod tests {
fn staging_returns_none() {
assert!(
layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/_staging/abc.json"))
.classify(&PathBuf::from("/ws/.yoi/memory/_staging/abc.json"))
.unwrap()
.is_none()
);
@@ -312,7 +312,7 @@ mod tests {
#[test]
fn usage_tree_is_opaque_to_classifier() {
let cp = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/_usage/events.jsonl"))
.classify(&PathBuf::from("/ws/.yoi/memory/_usage/events.jsonl"))
.unwrap();
assert!(cp.is_none());
}
@@ -320,7 +320,7 @@ mod tests {
#[test]
fn logs_tree_is_opaque_to_classifier() {
let cp = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/_logs/current.log"))
.classify(&PathBuf::from("/ws/.yoi/memory/_logs/current.log"))
.unwrap();
assert!(cp.is_none());
}
@@ -344,7 +344,7 @@ mod tests {
#[test]
fn invalid_slug_rejected() {
let err = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/decisions/Foo.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/decisions/Foo.md"))
.unwrap_err();
assert!(matches!(
err,
@@ -355,7 +355,7 @@ mod tests {
#[test]
fn nested_under_record_dir_rejected() {
let err = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/decisions/sub/foo.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/decisions/sub/foo.md"))
.unwrap_err();
assert!(matches!(err, LintError::InvalidPath(_)));
}
@@ -363,7 +363,7 @@ mod tests {
#[test]
fn unknown_top_level_dir_rejected() {
let err = layout()
.classify(&PathBuf::from("/ws/.insomnia/memory/something/foo.md"))
.classify(&PathBuf::from("/ws/.yoi/memory/something/foo.md"))
.unwrap_err();
assert!(matches!(err, LintError::InvalidPath(_)));
}
+4 -4
View File
@@ -71,14 +71,14 @@ impl LockFile {
/// Default on-disk path: `<runtime_dir>/pods.json` resolved via
/// [`manifest::paths::pod_registry_path`]. Tests should point this
/// elsewhere by setting `INSOMNIA_HOME` or `INSOMNIA_RUNTIME_DIR` to a
/// elsewhere by setting `YOI_HOME` or `YOI_RUNTIME_DIR` to a
/// tempdir.
pub fn default_registry_path() -> io::Result<PathBuf> {
paths::pod_registry_path().ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"could not resolve pods.json path (no INSOMNIA_HOME / \
INSOMNIA_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
"could not resolve pods.json path (no YOI_HOME / \
YOI_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
)
})
}
@@ -190,7 +190,7 @@ mod tests {
fn open_creates_file_with_owner_only_permissions() {
use std::os::unix::fs::PermissionsExt;
let dir = TempDir::new().unwrap();
let parent = dir.path().join("insomnia");
let parent = dir.path().join("yoi");
let path = parent.join("pods.json");
let _guard = LockFileGuard::open(&path).unwrap();
let file_mode = std::fs::metadata(&path).unwrap().permissions().mode() & 0o777;
+10 -10
View File
@@ -20,8 +20,8 @@ pub(crate) fn sid() -> SegmentId {
/// parallel test's `default_registry_path()` lookup.
pub(crate) static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Sandbox `INSOMNIA_RUNTIME_DIR` to a tempdir for the duration of
/// a test; restore the previous value (and any `INSOMNIA_HOME` /
/// Sandbox `YOI_RUNTIME_DIR` to a tempdir for the duration of
/// a test; restore the previous value (and any `YOI_HOME` /
/// `XDG_RUNTIME_DIR` that would otherwise outrank it) on drop.
pub(crate) struct RuntimeDirSandbox {
prev_runtime: Option<String>,
@@ -33,16 +33,16 @@ pub(crate) struct RuntimeDirSandbox {
impl RuntimeDirSandbox {
pub(crate) fn new(dir: &Path) -> Self {
let guard = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_runtime = std::env::var("INSOMNIA_RUNTIME_DIR").ok();
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_runtime = std::env::var("YOI_RUNTIME_DIR").ok();
let prev_home = std::env::var("YOI_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
// SAFETY: ENV_LOCK serialises env writes across this test
// module; other modules that touch env vars rely on their
// own lock or `serial_test`.
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("YOI_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
std::env::set_var("INSOMNIA_RUNTIME_DIR", dir);
std::env::set_var("YOI_RUNTIME_DIR", dir);
}
Self {
prev_runtime,
@@ -57,12 +57,12 @@ impl Drop for RuntimeDirSandbox {
fn drop(&mut self) {
unsafe {
match &self.prev_runtime {
Some(v) => std::env::set_var("INSOMNIA_RUNTIME_DIR", v),
None => std::env::remove_var("INSOMNIA_RUNTIME_DIR"),
Some(v) => std::env::set_var("YOI_RUNTIME_DIR", v),
None => std::env::remove_var("YOI_RUNTIME_DIR"),
}
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
Some(v) => std::env::set_var("YOI_HOME", v),
None => std::env::remove_var("YOI_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
+1 -1
View File
@@ -18,5 +18,5 @@
### ランタイム
- `RuntimeDir``$XDG_RUNTIME_DIR/insomnia/{pod_name}/` 配下のランタイムディレクトリ管理(ステータス・履歴のアトミック書き込み)
- `RuntimeDir``$XDG_RUNTIME_DIR/yoi/{pod_name}/` 配下のランタイムディレクトリ管理(ステータス・履歴のアトミック書き込み)
- `SocketServer` — Pod Protocol 用 Unix ソケットサーバー
+1 -1
View File
@@ -1,6 +1,6 @@
//! Minimal example: Pod running a single prompt with persistence.
//!
//! Demonstrates the core insomnia abstraction — a TOML manifest drives
//! Demonstrates the core yoi abstraction — a TOML manifest drives
//! provider selection, model config, and system prompt, while FsStore
//! persists the session to disk automatically.
//!
+1 -1
View File
@@ -822,7 +822,7 @@ mod tests {
let runtime_base = root.path().join("runtime");
std::fs::create_dir_all(&runtime_base).unwrap();
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", &runtime_base);
std::env::set_var("YOI_RUNTIME_DIR", &runtime_base);
}
let store = FsPodStore::new(&store_dir).unwrap();
+31 -47
View File
@@ -191,7 +191,7 @@ fn load_single_manifest(
}
pub async fn run_cli() -> ExitCode {
run_cli_from("insomnia pod", std::env::args_os().skip(1)).await
run_cli_from("yoi pod", std::env::args_os().skip(1)).await
}
pub async fn run_cli_from<I, T>(bin_name: &'static str, args: I) -> ExitCode
@@ -246,7 +246,7 @@ async fn run_cli_inner(cli: Cli) -> ExitCode {
};
// Initialize persistent store. `paths::sessions_dir()` only
// returns None when none of INSOMNIA_HOME / INSOMNIA_DATA_DIR /
// returns None when none of YOI_HOME / YOI_DATA_DIR /
// HOME is set — surface that as a hard error to match the
// runtime-dir resolution below, rather than silently writing to a
// relative path under cwd.
@@ -257,7 +257,7 @@ async fn run_cli_inner(cli: Cli) -> ExitCode {
None => {
eprintln!(
"error: could not resolve sessions directory \
(set --store, INSOMNIA_HOME, INSOMNIA_DATA_DIR, or HOME)"
(set --store, YOI_HOME, YOI_DATA_DIR, or HOME)"
);
return ExitCode::FAILURE;
}
@@ -375,7 +375,7 @@ async fn run_cli_inner(cli: Cli) -> ExitCode {
None => {
eprintln!(
"error: could not resolve runtime directory \
(set INSOMNIA_HOME, INSOMNIA_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
(set YOI_HOME, YOI_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
);
return ExitCode::FAILURE;
}
@@ -393,7 +393,7 @@ async fn run_cli_inner(cli: Cli) -> ExitCode {
// (e.g. the TUI's interactive `spawn` flow). Tab-separated so a
// pod name with spaces still parses cleanly. Emit before the
// human line so a stderr-watching parent sees it first.
eprintln!("INSOMNIA-READY\t{pod_name}\t{}", socket_path.display());
eprintln!("YOI-READY\t{pod_name}\t{}", socket_path.display());
eprintln!("pod: {pod_name} listening on {:?}", socket_path);
tokio::select! {
@@ -443,36 +443,30 @@ permission = "write"
#[test]
fn user_manifest_flag_is_not_accepted() {
let err =
Cli::try_parse_from(["insomnia pod", "--user-manifest", "manifest.toml"]).unwrap_err();
let err = Cli::try_parse_from(["yoi pod", "--user-manifest", "manifest.toml"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
}
#[test]
fn subcommand_help_uses_insomnia_pod_invocation() {
let err = parse_cli_from("insomnia pod", ["--help"]).unwrap_err();
fn subcommand_help_uses_yoi_pod_invocation() {
let err = parse_cli_from("yoi pod", ["--help"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
let help = err.to_string();
assert!(help.contains("Usage: insomnia pod"), "{help}");
assert!(help.contains("Usage: yoi pod"), "{help}");
assert!(help.contains("--pod <NAME>"), "{help}");
}
#[test]
fn manifest_conflicts_with_project() {
let project_err = Cli::try_parse_from([
"insomnia pod",
"--manifest",
"manifest.toml",
"--project",
".",
])
.unwrap_err();
let project_err =
Cli::try_parse_from(["yoi pod", "--manifest", "manifest.toml", "--project", "."])
.unwrap_err();
assert_eq!(project_err.kind(), clap::error::ErrorKind::ArgumentConflict);
}
#[test]
fn overlay_flag_is_not_accepted() {
let err = Cli::try_parse_from(["insomnia pod", "--overlay", "pod.name = 'x'"]).unwrap_err();
let err = Cli::try_parse_from(["yoi pod", "--overlay", "pod.name = 'x'"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
}
@@ -481,8 +475,8 @@ permission = "write"
let tmp = TempDir::new().unwrap();
let manifest = tmp.path().join("manifest.toml");
write(&manifest, &manifest_toml("single", tmp.path()));
let cli = Cli::try_parse_from(["insomnia pod", "--manifest", manifest.to_str().unwrap()])
.unwrap();
let cli =
Cli::try_parse_from(["yoi pod", "--manifest", manifest.to_str().unwrap()]).unwrap();
let (manifest, loader) = resolve_manifest(&cli).unwrap();
@@ -496,7 +490,7 @@ permission = "write"
let tmp = TempDir::new().unwrap();
let profile = tmp.path().join("profile.lua");
let cli = Cli::try_parse_from([
"insomnia pod",
"yoi pod",
"--profile",
profile.to_str().unwrap(),
"--profile-pod-name",
@@ -529,7 +523,7 @@ permission = "write"
fn profile_accepts_source_qualified_discovered_name() {
let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from([
"insomnia pod",
"yoi pod",
"--profile",
"project:coder",
"--profile-pod-name",
@@ -564,7 +558,7 @@ permission = "write"
#[test]
fn normal_startup_uses_default_profile() {
let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from(["insomnia pod"]).unwrap();
let cli = Cli::try_parse_from(["yoi pod"]).unwrap();
let mut called = false;
let (manifest, _loader) =
@@ -585,7 +579,7 @@ permission = "write"
#[test]
fn project_flag_no_longer_enables_ambient_manifest_cascade() {
let cli = Cli::try_parse_from(["insomnia pod", "--project", "."]).unwrap();
let cli = Cli::try_parse_from(["yoi pod", "--project", "."]).unwrap();
let err = resolve_manifest_with_profile_loader(&cli, |_, _| {
panic!("default profile loader must not run when deprecated --project is present")
})
@@ -597,7 +591,7 @@ permission = "write"
fn pod_flag_conflicts_with_session() {
let segment_id = session_store::new_segment_id();
let segment_id = segment_id.to_string();
let err = Cli::try_parse_from(["insomnia pod", "--pod", "agent", "--session", &segment_id])
let err = Cli::try_parse_from(["yoi pod", "--pod", "agent", "--session", &segment_id])
.unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
}
@@ -608,7 +602,7 @@ permission = "write"
let manifest = tmp.path().join("manifest.toml");
write(&manifest, &manifest_toml("from-file", tmp.path()));
let cli = Cli::try_parse_from([
"insomnia pod",
"yoi pod",
"--manifest",
manifest.to_str().unwrap(),
"--pod",
@@ -640,7 +634,7 @@ permission = "write"
"#,
);
let cli = Cli::try_parse_from([
"insomnia pod",
"yoi pod",
"--manifest",
manifest.to_str().unwrap(),
"--pod",
@@ -657,7 +651,7 @@ permission = "write"
#[test]
fn pod_flag_with_no_manifest_creates_from_default_profile_with_typed_name() {
let tmp = TempDir::new().unwrap();
let cli = Cli::try_parse_from(["insomnia pod", "--pod", "agent"]).unwrap();
let cli = Cli::try_parse_from(["yoi pod", "--pod", "agent"]).unwrap();
let mut called = false;
let (manifest, _loader) =
@@ -683,15 +677,9 @@ permission = "write"
fn profile_conflicts_with_manifest_and_restore_modes() {
let segment_id = session_store::new_segment_id().to_string();
for args in [
vec!["insomnia pod", "--profile", "p.lua", "--manifest", "m.toml"],
vec!["insomnia pod", "--profile", "p.lua", "--pod", "agent"],
vec![
"insomnia pod",
"--profile",
"p.lua",
"--session",
&segment_id,
],
vec!["yoi pod", "--profile", "p.lua", "--manifest", "m.toml"],
vec!["yoi pod", "--profile", "p.lua", "--pod", "agent"],
vec!["yoi pod", "--profile", "p.lua", "--session", &segment_id],
] {
let err = Cli::try_parse_from(args).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::ArgumentConflict);
@@ -700,14 +688,14 @@ permission = "write"
#[test]
fn profile_pod_name_requires_profile() {
let err = Cli::try_parse_from(["insomnia pod", "--profile-pod-name", "agent"]).unwrap_err();
let err = Cli::try_parse_from(["yoi pod", "--profile-pod-name", "agent"]).unwrap_err();
assert_eq!(err.kind(), clap::error::ErrorKind::MissingRequiredArgument);
}
#[test]
fn profile_pod_name_is_not_restore_pod_flag() {
let cli = Cli::try_parse_from([
"insomnia pod",
"yoi pod",
"--profile",
"p.lua",
"--profile-pod-name",
@@ -724,13 +712,9 @@ permission = "write"
let single_manifest = tmp.path().join("single.toml");
write(&single_manifest, &manifest_toml("single-file", tmp.path()));
std::fs::create_dir_all(tmp.path().join("prompts")).unwrap();
std::fs::create_dir_all(tmp.path().join(".insomnia").join("prompts")).unwrap();
let cli = Cli::try_parse_from([
"insomnia pod",
"--manifest",
single_manifest.to_str().unwrap(),
])
.unwrap();
std::fs::create_dir_all(tmp.path().join(".yoi").join("prompts")).unwrap();
let cli = Cli::try_parse_from(["yoi pod", "--manifest", single_manifest.to_str().unwrap()])
.unwrap();
let (manifest, loader) = resolve_manifest(&cli).unwrap();
+8 -8
View File
@@ -333,7 +333,7 @@ pub struct Pod<C: LlmClient, St: Store> {
/// [`Self::from_manifest`], or defaults to the builtin pack when a
/// Pod is constructed through lower-level paths that have no loader.
prompts: Arc<PromptCatalog>,
/// Registry loaded from `<workspace>/.insomnia/workflow/*.md` when
/// Registry loaded from `<workspace>/.yoi/workflow/*.md` when
/// memory is enabled. Missing memory config keeps this empty.
workflow_registry: workflow_crate::WorkflowRegistry,
/// Memory workspace layout used by the workflow resolver to load required
@@ -5337,21 +5337,21 @@ mod build_summary_prompt_tests {
let pwd = dir.path().join("workspace");
std::fs::create_dir_all(&pwd).unwrap();
if let Some(doc) = summary_doc {
std::fs::create_dir_all(pwd.join(".insomnia/memory")).unwrap();
std::fs::write(pwd.join(".insomnia/memory/summary.md"), doc).unwrap();
std::fs::create_dir_all(pwd.join(".yoi/memory")).unwrap();
std::fs::write(pwd.join(".yoi/memory/summary.md"), doc).unwrap();
}
if include_knowledge {
std::fs::create_dir_all(pwd.join(".insomnia/knowledge")).unwrap();
std::fs::create_dir_all(pwd.join(".yoi/knowledge")).unwrap();
std::fs::write(
pwd.join(".insomnia/knowledge/resident-policy.md"),
pwd.join(".yoi/knowledge/resident-policy.md"),
knowledge_doc("knowledge resident desc"),
)
.unwrap();
}
if include_workflow {
std::fs::create_dir_all(pwd.join(".insomnia/workflow")).unwrap();
std::fs::create_dir_all(pwd.join(".yoi/workflow")).unwrap();
std::fs::write(
pwd.join(".insomnia/workflow/resident-flow.md"),
pwd.join(".yoi/workflow/resident-flow.md"),
workflow_doc("workflow resident desc"),
)
.unwrap();
@@ -5379,7 +5379,7 @@ mod build_summary_prompt_tests {
pod.set_resident_workflow_injection(gates.workflows);
}
let template = SystemPromptTemplate::parse(
"$insomnia/default",
"$yoi/default",
crate::prompt::loader::PromptLoader::builtins_only(),
)
.unwrap();
+5 -5
View File
@@ -18,7 +18,7 @@
//! binary. Must cover every [`PodPrompt`] variant (build-time check).
//! 2. **user** — `<config_dir>/prompts.toml`, when a caller supplies it.
//! Optional.
//! 3. **workspace** — `<project>/.insomnia/prompts.toml`, when a caller
//! 3. **workspace** — `<project>/.yoi/prompts.toml`, when a caller
//! supplies it. Optional.
//! 4. **manifest pack** — `manifest.pod.prompt_pack`, an explicit path
//! per-Pod. Optional.
@@ -258,7 +258,7 @@ struct PackFile {
/// Owns a `minijinja::Environment` with one template registered per
/// [`PodPrompt`] key (after the 4-layer merge). Includes inside templates
/// are resolved via a provided [`PromptLoader`], so values can pull from
/// `$insomnia` / `$user` / `$workspace`.
/// `$yoi` / `$user` / `$workspace`.
pub struct PromptCatalog {
env: Environment<'static>,
}
@@ -271,7 +271,7 @@ impl std::fmt::Debug for PromptCatalog {
impl PromptCatalog {
/// Builtin-only catalog. All `{% include %}` references must resolve
/// through `$insomnia` (user/workspace prefixes are unavailable).
/// through `$yoi` (user/workspace prefixes are unavailable).
pub fn builtins_only() -> Result<Arc<Self>, CatalogError> {
Self::load(&PromptLoader::builtins_only(), None)
}
@@ -707,7 +707,7 @@ interrupt_system_note = "[FROM-MANIFEST-PACK]"
#[test]
fn value_can_pull_long_text_via_include() {
// A runtime pack that overrides `compact_system` with an
// `{% include %}` into the same `$insomnia` namespace — exercises
// `{% include %}` into the same `$yoi` namespace — exercises
// the template resolver path through all four layers.
let tmp = TempDir::new().unwrap();
let pack = tmp.path().join("p.toml");
@@ -715,7 +715,7 @@ interrupt_system_note = "[FROM-MANIFEST-PACK]"
&pack,
r#"
[prompt]
compact_system = "PREFIX\n{% include \"$insomnia/internal/compact_system\" %}"
compact_system = "PREFIX\n{% include \"$yoi/internal/compact_system\" %}"
"#,
)
.unwrap();
+21 -25
View File
@@ -4,12 +4,12 @@
//!
//! | prefix | location |
//! |--------------|---------------------------------------------------------|
//! | `$insomnia` | builtin, baked into the binary via `include_dir!` |
//! | `$yoi` | builtin, baked into the binary via `include_dir!` |
//! | `$user` | `<config_dir>/prompts/` (resolved by `manifest::paths`) |
//! | `$workspace` | `<project>/.insomnia/prompts/` |
//! | `$workspace` | `<project>/.yoi/prompts/` |
//!
//! A reference is `$<prefix>/<path>` where `<path>` is a `/`-separated
//! name without the `.md` extension (e.g. `$insomnia/common/header`).
//! name without the `.md` extension (e.g. `$yoi/common/header`).
//! Unqualified names (no `$prefix/` at the front) are resolved relative
//! to an optional current reference — typically the file that issued
//! the `{% include %}` — so a prompt library can be authored as a
@@ -25,13 +25,13 @@ use thiserror::Error;
static BUILTIN_PROMPTS: Dir<'static> = include_dir!("$CARGO_MANIFEST_DIR/../../resources/prompts");
const PREFIX_INSOMNIA: &str = "$insomnia";
const PREFIX_YOI: &str = "$yoi";
const PREFIX_USER: &str = "$user";
const PREFIX_WORKSPACE: &str = "$workspace";
/// Prefix-resolved reference to a prompt asset. Produced by
/// [`PromptLoader::parse_ref`] from a user-supplied string such as
/// `"$insomnia/default"`.
/// `"$yoi/default"`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PromptRef {
prefix: Prefix,
@@ -42,7 +42,7 @@ pub struct PromptRef {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Prefix {
Insomnia,
Yoi,
User,
Workspace,
}
@@ -50,7 +50,7 @@ enum Prefix {
impl Prefix {
fn as_str(self) -> &'static str {
match self {
Self::Insomnia => PREFIX_INSOMNIA,
Self::Yoi => PREFIX_YOI,
Self::User => PREFIX_USER,
Self::Workspace => PREFIX_WORKSPACE,
}
@@ -116,7 +116,7 @@ pub struct PromptLoader {
}
impl PromptLoader {
/// Loader with only the builtin `$insomnia` library available.
/// Loader with only the builtin `$yoi` library available.
/// `$user` / `$workspace` references fail with
/// [`LoaderError::PrefixNotConfigured`].
pub fn builtins_only() -> Self {
@@ -221,7 +221,7 @@ impl PromptLoader {
/// when the prefix is not configured or the file does not exist.
pub fn load(&self, reference: &PromptRef) -> Result<String, LoaderError> {
match reference.prefix {
Prefix::Insomnia => load_from_include_dir(&BUILTIN_PROMPTS, reference),
Prefix::Yoi => load_from_include_dir(&BUILTIN_PROMPTS, reference),
Prefix::User => match self.user_dir.as_deref() {
Some(dir) => load_from_dir(dir, reference),
None => Err(LoaderError::PrefixNotConfigured {
@@ -252,7 +252,7 @@ impl PromptLoader {
fn parse_prefix(raw: &str, prefix_name: &str) -> Result<Prefix, LoaderError> {
match prefix_name {
"insomnia" => Ok(Prefix::Insomnia),
"yoi" => Ok(Prefix::Yoi),
"user" => Ok(Prefix::User),
"workspace" => Ok(Prefix::Workspace),
_ => Err(LoaderError::UnknownPrefix {
@@ -311,15 +311,15 @@ mod tests {
#[test]
fn builtin_default_resolves() {
let loader = PromptLoader::builtins_only();
let (r, source) = loader.resolve("$insomnia/default", None).unwrap();
assert_eq!(r.to_qualified_string(), "$insomnia/default");
let (r, source) = loader.resolve("$yoi/default", None).unwrap();
assert_eq!(r.to_qualified_string(), "$yoi/default");
assert!(!source.is_empty());
}
#[test]
fn builtin_subdirectory_lookup() {
let loader = PromptLoader::builtins_only();
let (_, source) = loader.resolve("$insomnia/common/tool-usage", None).unwrap();
let (_, source) = loader.resolve("$yoi/common/tool-usage", None).unwrap();
assert!(source.contains("tool"));
}
@@ -346,9 +346,7 @@ mod tests {
#[test]
fn missing_file_is_hard_error() {
let loader = PromptLoader::builtins_only();
let err = loader
.resolve("$insomnia/definitely-missing", None)
.unwrap_err();
let err = loader.resolve("$yoi/definitely-missing", None).unwrap_err();
assert!(matches!(err, LoaderError::NotFound { .. }));
}
@@ -379,20 +377,18 @@ mod tests {
#[test]
fn unqualified_ref_resolves_relative_to_current() {
let loader = PromptLoader::builtins_only();
let current = loader
.parse_ref("$insomnia/common/tool-usage", None)
.unwrap();
let current = loader.parse_ref("$yoi/common/tool-usage", None).unwrap();
// Sibling lookup under the same prefix and directory.
let sibling = loader.parse_ref("workspace", Some(&current)).unwrap();
assert_eq!(sibling.to_qualified_string(), "$insomnia/common/workspace");
assert_eq!(sibling.to_qualified_string(), "$yoi/common/workspace");
}
#[test]
fn unqualified_ref_from_root_file_has_empty_dir() {
let loader = PromptLoader::builtins_only();
let current = loader.parse_ref("$insomnia/default", None).unwrap();
let current = loader.parse_ref("$yoi/default", None).unwrap();
let sibling = loader.parse_ref("other", Some(&current)).unwrap();
assert_eq!(sibling.to_qualified_string(), "$insomnia/other");
assert_eq!(sibling.to_qualified_string(), "$yoi/other");
}
#[test]
@@ -402,8 +398,8 @@ mod tests {
std::fs::write(user_dir.join("custom.md"), "user-body").unwrap();
let loader = PromptLoader::new(Some(user_dir), None);
let current = loader.parse_ref("$insomnia/default", None).unwrap();
// Even with an $insomnia-rooted current, an explicit $user
let current = loader.parse_ref("$yoi/default", None).unwrap();
// Even with an $yoi-rooted current, an explicit $user
// prefix must win.
let (reference, source) = loader.resolve("$user/custom", Some(&current)).unwrap();
assert_eq!(reference.to_qualified_string(), "$user/custom");
@@ -413,7 +409,7 @@ mod tests {
#[test]
fn traversal_segments_rejected() {
let loader = PromptLoader::builtins_only();
let err = loader.resolve("$insomnia/../etc/passwd", None).unwrap_err();
let err = loader.resolve("$yoi/../etc/passwd", None).unwrap_err();
assert!(matches!(err, LoaderError::InvalidRef { .. }));
}
}
+10 -10
View File
@@ -155,7 +155,7 @@ pub struct SystemPromptContext<'a> {
/// Not visible from the template; consumed by the trailing-section
/// formatter in [`SystemPromptTemplate::render`].
pub agents_md: Option<String>,
/// The body of `<workspace>/.insomnia/memory/summary.md`, with
/// The body of `<workspace>/.yoi/memory/summary.md`, with
/// frontmatter stripped. `None` disables the resident summary section;
/// empty strings are ignored by the trailing-section formatter.
pub resident_summary: Option<&'a str>,
@@ -164,7 +164,7 @@ pub struct SystemPromptContext<'a> {
/// section entirely (memory disabled, or a consolidation worker that opts
/// out); `Some(&[])` also yields no section.
pub resident_knowledge: Option<&'a [ResidentKnowledgeEntry]>,
/// Resident workflow descriptions from `<workspace>/.insomnia/workflow/*`
/// Resident workflow descriptions from `<workspace>/.yoi/workflow/*`
/// whose frontmatter has `model_invokation: true`. `None` disables the
/// section; consolidation workers opt out together with resident Knowledge.
pub resident_workflows: Option<&'a [ResidentWorkflowEntry]>,
@@ -557,9 +557,9 @@ mod tests {
}
#[test]
fn instruction_default_resolves_to_insomnia_default() {
fn instruction_default_resolves_to_yoi_default() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$insomnia/default", loader).unwrap();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
@@ -582,7 +582,7 @@ mod tests {
#[test]
fn instruction_default_omits_memory_guidance_without_memory_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$insomnia/default", loader).unwrap();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
@@ -608,7 +608,7 @@ mod tests {
#[test]
fn memory_guidance_names_only_available_memory_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$insomnia/default", loader).unwrap();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
@@ -632,7 +632,7 @@ mod tests {
#[test]
fn pod_orchestration_guidance_is_included_for_pod_management_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$insomnia/default", loader).unwrap();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
@@ -651,7 +651,7 @@ mod tests {
#[test]
fn pod_orchestration_guidance_is_omitted_without_pod_management_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$insomnia/default", loader).unwrap();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
@@ -735,7 +735,7 @@ mod tests {
let tmp = TempDir::new().unwrap();
std::fs::write(
tmp.path().join("root.md"),
"U-ROOT\n{% include \"$insomnia/common/tool-usage\" %}",
"U-ROOT\n{% include \"$yoi/common/tool-usage\" %}",
)
.unwrap();
let loader = PromptLoader::new(Some(tmp.path().to_path_buf()), None);
@@ -758,7 +758,7 @@ mod tests {
#[test]
fn prefix_with_missing_file_is_hard_error() {
let loader = PromptLoader::builtins_only();
let err = SystemPromptTemplate::parse("$insomnia/definitely-missing", loader).unwrap_err();
let err = SystemPromptTemplate::parse("$yoi/definitely-missing", loader).unwrap_err();
assert!(matches!(err, SystemPromptError::LoaderResolve(_)));
}
+4 -4
View File
@@ -116,8 +116,8 @@ pub fn default_base() -> Result<PathBuf, io::Error> {
paths::runtime_dir().ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"could not resolve runtime directory (no INSOMNIA_HOME / \
INSOMNIA_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
"could not resolve runtime directory (no YOI_HOME / \
YOI_RUNTIME_DIR / XDG_RUNTIME_DIR / HOME)",
)
})
}
@@ -203,13 +203,13 @@ mod tests {
let records = vec![SpawnedPodRecord {
pod_name: "child".into(),
socket_path: "/run/insomnia/child/sock".into(),
socket_path: "/run/yoi/child/sock".into(),
scope_delegated: vec![ScopeRule {
target: "/tmp/work".into(),
permission: Permission::Write,
recursive: true,
}],
callback_address: "/run/insomnia/my-pod/sock".into(),
callback_address: "/run/yoi/my-pod/sock".into(),
}];
rt.write_spawned_pods(&records).await.unwrap();
+20 -29
View File
@@ -48,7 +48,7 @@ struct SpawnPodInput {
/// unambiguous profile slug. Raw/path selectors are rejected.
#[serde(default)]
profile: Option<String>,
/// Instruction-file reference (e.g. `$insomnia/default`, `$user/my-agent`).
/// Instruction-file reference (e.g. `$yoi/default`, `$user/my-agent`).
#[serde(default)]
instruction: Option<String>,
/// First message sent to the spawned Pod via `Method::Run`.
@@ -214,7 +214,7 @@ pub struct SpawnPodTool {
/// Path to the spawner's Unix socket. Handed to the child via
/// `--callback` so its `PodEvent` callbacks have somewhere to land.
callback_socket: PathBuf,
/// Root of the `$XDG_RUNTIME_DIR/insomnia/` tree, used to predict
/// Root of the `$XDG_RUNTIME_DIR/yoi/` tree, used to predict
/// the spawned Pod's socket path before the child has bound it.
runtime_base: PathBuf,
/// Directory the spawned Pod should run in when the LLM did not
@@ -890,7 +890,7 @@ mod tests {
..Default::default()
},
worker: WorkerManifestConfig {
instruction: Some("$insomnia/parent".into()),
instruction: Some("$yoi/parent".into()),
language: Some("Parentish".into()),
max_tokens: Some(1234),
stop_sequences: Some(vec!["STOP".into()]),
@@ -916,8 +916,8 @@ mod tests {
default: Option<&str>,
profiles: &[(&str, &str, &str)],
) -> AvailableProfiles {
let insomnia = project.join(".insomnia");
let profile_dir = insomnia.join("profiles");
let yoi = project.join(".yoi");
let profile_dir = yoi.join("profiles");
std::fs::create_dir_all(&profile_dir).unwrap();
let mut registry_toml = String::new();
if let Some(default) = default {
@@ -928,7 +928,7 @@ mod tests {
std::fs::write(profile_dir.join(file), body).unwrap();
registry_toml.push_str(&format!("{name} = \"profiles/{file}\"\n"));
}
let registry_path = insomnia.join("profiles.toml");
let registry_path = yoi.join("profiles.toml");
std::fs::write(&registry_path, registry_toml).unwrap();
AvailableProfiles {
registry: Some(
@@ -963,23 +963,23 @@ mod tests {
}
const CODER_PROFILE: &str = r#"
local profile = require("insomnia.profile")
local scope = require("insomnia.scope")
local profile = require("yoi.profile")
local scope = require("yoi.scope")
return profile {
slug = "coder",
model = { scheme = "anthropic", model_id = "coder-model" },
worker = { instruction = "$insomnia/coder", language = "Coderish", max_tokens = 2222 },
worker = { instruction = "$yoi/coder", language = "Coderish", max_tokens = 2222 },
scope = scope.workspace_write(),
}
"#;
const REVIEWER_PROFILE: &str = r#"
local profile = require("insomnia.profile")
local scope = require("insomnia.scope")
local profile = require("yoi.profile")
local scope = require("yoi.scope")
return profile {
slug = "reviewer",
model = { scheme = "anthropic", model_id = "reviewer-model" },
worker = { instruction = "$insomnia/reviewer", language = "Reviewerish", max_tokens = 3333 },
worker = { instruction = "$yoi/reviewer", language = "Reviewerish", max_tokens = 3333 },
scope = scope.workspace_write(),
}
"#;
@@ -997,7 +997,7 @@ return profile {
};
let config_json =
build_spawn_config_json("child", "$insomnia/default", &[], &model, false).unwrap();
build_spawn_config_json("child", "$yoi/default", &[], &model, false).unwrap();
let parsed: PodManifestConfig = serde_json::from_str(&config_json).unwrap();
assert_eq!(parsed.model.scheme, Some(SchemeKind::Anthropic));
@@ -1020,7 +1020,7 @@ return profile {
..Default::default()
};
let config_json =
build_spawn_config_json("child", "$insomnia/default", &[], &model, false).unwrap();
build_spawn_config_json("child", "$yoi/default", &[], &model, false).unwrap();
let parsed: PodManifestConfig = serde_json::from_str(&config_json).unwrap();
assert_eq!(
parsed.model.ref_.as_deref(),
@@ -1041,7 +1041,7 @@ return profile {
}];
let config_json =
build_spawn_config_json("child", "$insomnia/default", &scope, &model, true).unwrap();
build_spawn_config_json("child", "$yoi/default", &scope, &model, true).unwrap();
let parsed: PodManifestConfig = serde_json::from_str(&config_json).unwrap();
assert_eq!(
parsed.session.as_ref().and_then(|s| s.record_event_trace),
@@ -1062,7 +1062,7 @@ return profile {
..Default::default()
};
let config_json =
build_spawn_config_json("child", "$insomnia/default", &[], &model, false).unwrap();
build_spawn_config_json("child", "$yoi/default", &[], &model, false).unwrap();
let parsed: PodManifestConfig = serde_json::from_str(&config_json).unwrap();
assert!(parsed.session.is_none());
@@ -1098,10 +1098,7 @@ return profile {
assert_eq!(config.pod.name.as_deref(), Some("child-default"));
assert_eq!(config.model.model_id.as_deref(), Some("reviewer-model"));
assert_eq!(
config.worker.instruction.as_deref(),
Some("$insomnia/reviewer")
);
assert_eq!(config.worker.instruction.as_deref(), Some("$yoi/reviewer"));
assert_eq!(config.worker.language.as_deref(), Some("Reviewerish"));
assert_eq!(config.scope.allow, scope);
assert!(config.scope.deny.is_empty());
@@ -1140,10 +1137,7 @@ return profile {
assert_eq!(config.pod.name.as_deref(), Some("review-child"));
assert_eq!(config.model.model_id.as_deref(), Some("reviewer-model"));
assert_eq!(
config.worker.instruction.as_deref(),
Some("$insomnia/reviewer")
);
assert_eq!(config.worker.instruction.as_deref(), Some("$yoi/reviewer"));
assert_eq!(config.worker.language.as_deref(), Some("Reviewerish"));
assert_eq!(config.worker.max_tokens, Some(3333));
assert_eq!(config.scope.allow, scope);
@@ -1177,10 +1171,7 @@ return profile {
assert_eq!(config.pod.name.as_deref(), Some("inherited-child"));
assert_eq!(config.model.model_id.as_deref(), Some("parent-model"));
assert_eq!(
config.worker.instruction.as_deref(),
Some("$insomnia/parent")
);
assert_eq!(config.worker.instruction.as_deref(), Some("$yoi/parent"));
assert_eq!(config.worker.language.as_deref(), Some("Parentish"));
assert_eq!(config.worker.max_tokens, Some(1234));
assert_eq!(
@@ -1313,7 +1304,7 @@ return profile {
let user_config = tmp.path().join("user-profiles.toml");
std::fs::write(&user_config, "[profile]\ncoder = \"user-coder.lua\"\n").unwrap();
let project_config = project.join(".insomnia/profiles.toml");
let project_config = project.join(".yoi/profiles.toml");
let ambiguous = AvailableProfiles {
registry: Some(
ProfileDiscovery::with_sources(Some(user_config), Some(project_config))
+4 -4
View File
@@ -145,11 +145,11 @@ mod tests {
let dir = TempDir::new().unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
write(
&dir.path().join(".insomnia/knowledge/policy.md"),
&dir.path().join(".yoi/knowledge/policy.md"),
"---\ncreated_at: 2026-01-01T00:00:00Z\nupdated_at: 2026-01-01T00:00:00Z\nkind: policy\ndescription: p\nmodel_invokation: false\nuser_invocable: true\nlast_sources: []\n---\npolicy body\n",
);
write(
&dir.path().join(".insomnia/workflow/run-it.md"),
&dir.path().join(".yoi/workflow/run-it.md"),
"---\ndescription: run\nrequires: [policy]\n---\nworkflow body\n",
);
let registry = workflow_crate::load_workflows(&layout).unwrap();
@@ -173,7 +173,7 @@ mod tests {
fn user_invocable_false_errors() {
let (dir, layout, _registry) = setup();
write(
&dir.path().join(".insomnia/workflow/hidden.md"),
&dir.path().join(".yoi/workflow/hidden.md"),
"---\ndescription: hidden\nuser_invocable: false\n---\nbody\n",
);
let registry = workflow_crate::load_workflows(&layout).unwrap();
@@ -186,7 +186,7 @@ mod tests {
let dir = TempDir::new().unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
write(
&dir.path().join(".insomnia/workflow/bad.md"),
&dir.path().join(".yoi/workflow/bad.md"),
"---\ndescription: bad\nrequires: [ghost]\n---\nbody\n",
);
let registry = workflow_crate::load_workflows(&layout).unwrap();
+11 -11
View File
@@ -29,11 +29,11 @@ use tokio::sync::mpsc;
use tokio::task::JoinHandle;
/// Serialises env-mutating tests. The test harness runs tasks across
/// threads, and `INSOMNIA_RUNTIME_DIR` is a process-wide resource.
/// threads, and `YOI_RUNTIME_DIR` is a process-wide resource.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Take `ENV_LOCK` and clear any env vars that would outrank
/// `INSOMNIA_RUNTIME_DIR` in `paths::runtime_dir` resolution; restore
/// `YOI_RUNTIME_DIR` in `paths::runtime_dir` resolution; restore
/// previous values on drop.
struct EnvGuard {
prev_home: Option<String>,
@@ -44,10 +44,10 @@ struct EnvGuard {
impl EnvGuard {
fn acquire() -> Self {
let lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_home = std::env::var("YOI_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("YOI_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
}
Self {
@@ -62,14 +62,14 @@ impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
Some(v) => std::env::set_var("YOI_HOME", v),
None => std::env::remove_var("YOI_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
None => std::env::remove_var("XDG_RUNTIME_DIR"),
}
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
std::env::remove_var("YOI_RUNTIME_DIR");
}
}
}
@@ -400,7 +400,7 @@ async fn stop_pod_sends_shutdown_and_releases_scope() {
.unwrap(),
);
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", tmp.path());
std::env::set_var("YOI_RUNTIME_DIR", tmp.path());
}
let lock_path = tmp.path().join("pods.json");
@@ -486,7 +486,7 @@ async fn stop_pod_succeeds_even_when_child_unreachable() {
let _env = EnvGuard::acquire();
let (tmp, registry, _rd) = setup_registry().await;
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", tmp.path());
std::env::set_var("YOI_RUNTIME_DIR", tmp.path());
}
// No live listener — socket never bound. Registered record points
@@ -518,7 +518,7 @@ async fn restored_registry_uses_pod_state_without_runtime_file() {
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
);
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", runtime_tmp.path());
std::env::set_var("YOI_RUNTIME_DIR", runtime_tmp.path());
}
let rd = Arc::new(
@@ -633,7 +633,7 @@ async fn load_from_pod_state_reclaims_missing_child_scope_and_records_history()
FsPodStore::new(store_tmp.path().join("pods")).unwrap(),
);
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", runtime_tmp.path());
std::env::set_var("YOI_RUNTIME_DIR", runtime_tmp.path());
}
let rd = Arc::new(
RuntimeDir::create(runtime_tmp.path(), "spawner")
+10 -10
View File
@@ -18,11 +18,11 @@ use protocol::{Event, Greeting, Method, Permission, PodEvent, PodStatus, ScopeRu
use tempfile::TempDir;
use tokio::net::UnixListener;
/// Serialises tests that mutate `INSOMNIA_RUNTIME_DIR`.
/// Serialises tests that mutate `YOI_RUNTIME_DIR`.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
/// Take `ENV_LOCK` and clear any env vars that would outrank
/// `INSOMNIA_RUNTIME_DIR`; restore previous values on drop.
/// `YOI_RUNTIME_DIR`; restore previous values on drop.
struct EnvGuard {
prev_home: Option<String>,
prev_xdg: Option<String>,
@@ -32,10 +32,10 @@ struct EnvGuard {
impl EnvGuard {
fn acquire() -> Self {
let lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let prev_home = std::env::var("INSOMNIA_HOME").ok();
let prev_home = std::env::var("YOI_HOME").ok();
let prev_xdg = std::env::var("XDG_RUNTIME_DIR").ok();
unsafe {
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("YOI_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
}
Self {
@@ -50,29 +50,29 @@ impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
match &self.prev_home {
Some(v) => std::env::set_var("INSOMNIA_HOME", v),
None => std::env::remove_var("INSOMNIA_HOME"),
Some(v) => std::env::set_var("YOI_HOME", v),
None => std::env::remove_var("YOI_HOME"),
}
match &self.prev_xdg {
Some(v) => std::env::set_var("XDG_RUNTIME_DIR", v),
None => std::env::remove_var("XDG_RUNTIME_DIR"),
}
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
std::env::remove_var("YOI_RUNTIME_DIR");
}
}
}
/// Point `INSOMNIA_RUNTIME_DIR` at `dir`. The pod-registry then lives at
/// Point `YOI_RUNTIME_DIR` at `dir`. The pod-registry then lives at
/// `<dir>/pods.json` and Pod runtime sub-dirs at `<dir>/{pod_name}/`.
fn set_runtime_dir(dir: &std::path::Path) {
unsafe {
std::env::set_var("INSOMNIA_RUNTIME_DIR", dir);
std::env::set_var("YOI_RUNTIME_DIR", dir);
}
}
fn clear_runtime_dir() {
unsafe {
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
std::env::remove_var("YOI_RUNTIME_DIR");
}
}
+5 -5
View File
@@ -26,7 +26,7 @@ use std::sync::Arc;
use tempfile::TempDir;
use tokio::net::UnixListener;
/// Serialises tests that mutate `INSOMNIA_RUNTIME_DIR` across the
/// Serialises tests that mutate `YOI_RUNTIME_DIR` across the
/// thread-pooled test harness.
static ENV_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
@@ -42,7 +42,7 @@ impl EnvGuard {
}
}
/// Set up a tempdir, point `INSOMNIA_RUNTIME_DIR` at it (so
/// Set up a tempdir, point `YOI_RUNTIME_DIR` at it (so
/// `pods.json` and per-Pod runtime subdirs both land in the
/// sandbox), and install a live top-level "spawner" allocation so the
/// tool has something to delegate from. Returns the tempdir (keeps it
@@ -57,9 +57,9 @@ async fn setup_spawner(
unsafe {
// Outranking env vars must be cleared so `paths::runtime_dir`
// resolves to our sandbox instead of the developer's real one.
std::env::remove_var("INSOMNIA_HOME");
std::env::remove_var("YOI_HOME");
std::env::remove_var("XDG_RUNTIME_DIR");
std::env::set_var("INSOMNIA_RUNTIME_DIR", &runtime_base);
std::env::set_var("YOI_RUNTIME_DIR", &runtime_base);
}
let spawner_rd = RuntimeDir::create(&runtime_base, spawner_name)
@@ -209,7 +209,7 @@ fn shared_scope_for(allow_root: &Path) -> SharedScope {
fn clear_env() {
unsafe {
std::env::remove_var("INSOMNIA_RUNTIME_DIR");
std::env::remove_var("YOI_RUNTIME_DIR");
}
}
+2 -2
View File
@@ -1258,7 +1258,7 @@ mod tests {
let method = Method::PodEvent(PodEvent::ScopeSubDelegated {
parent_pod: "child".into(),
sub_pod: "grandchild".into(),
sub_socket: "/run/insomnia/grandchild/sock".into(),
sub_socket: "/run/yoi/grandchild/sock".into(),
scope: vec![ScopeRule {
target: "/tmp/work".into(),
permission: Permission::Write,
@@ -1276,7 +1276,7 @@ mod tests {
}) => {
assert_eq!(parent_pod, "child");
assert_eq!(sub_pod, "grandchild");
assert_eq!(sub_socket, PathBuf::from("/run/insomnia/grandchild/sock"));
assert_eq!(sub_socket, PathBuf::from("/run/yoi/grandchild/sock"));
assert_eq!(scope.len(), 1);
assert_eq!(scope[0].target, PathBuf::from("/tmp/work"));
assert_eq!(scope[0].permission, Permission::Write);
+1 -1
View File
@@ -12,7 +12,7 @@
## 責務
- プロバイダ / モデルカタログの builtin (`resources/{providers,models}/builtin.toml`) と user override (`$XDG_CONFIG_HOME/insomnia/{providers,models}.toml`) の解決
- プロバイダ / モデルカタログの builtin (`resources/{providers,models}/builtin.toml`) と user override (`$XDG_CONFIG_HOME/yoi/{providers,models}.toml`) の解決
- `ModelManifest` の ref 形を `(provider, model_id)` に split し、`ModelConfig` へ展開
- `AuthRef::SecretRef` / `AuthRef::ApiKey``ResolvedAuth::ApiKey` に解決(通常は local secret store、低レベル manifest では明示ファイルも可)
- `AuthRef::None` / `AuthRef::CodexOAuth` の解決
+7 -7
View File
@@ -636,9 +636,9 @@ auth_hint = { kind = "none" }
assert!(matches!(err, CatalogError::Parse { .. }));
}
/// `INSOMNIA_CONFIG_DIR` を tempdir に向けるテストガード。
/// `paths::config_dir` は他の env (INSOMNIA_HOME / XDG_CONFIG_HOME)
/// より高優先で `INSOMNIA_CONFIG_DIR` を尊重するため、これだけで
/// `YOI_CONFIG_DIR` を tempdir に向けるテストガード。
/// `paths::config_dir` は他の env (YOI_HOME / XDG_CONFIG_HOME)
/// より高優先で `YOI_CONFIG_DIR` を尊重するため、これだけで
/// 開発機の env 設定に左右されないテストになる。
struct ConfigDirGuard {
prev: Option<String>,
@@ -646,10 +646,10 @@ auth_hint = { kind = "none" }
impl ConfigDirGuard {
fn new(path: &Path) -> Self {
let prev = std::env::var("INSOMNIA_CONFIG_DIR").ok();
let prev = std::env::var("YOI_CONFIG_DIR").ok();
// SAFETY: serial_test の `#[serial]` 属性で env を弄るテスト
// 同士は直列化される。
unsafe { std::env::set_var("INSOMNIA_CONFIG_DIR", path) };
unsafe { std::env::set_var("YOI_CONFIG_DIR", path) };
Self { prev }
}
}
@@ -658,8 +658,8 @@ auth_hint = { kind = "none" }
fn drop(&mut self) {
unsafe {
match &self.prev {
Some(v) => std::env::set_var("INSOMNIA_CONFIG_DIR", v),
None => std::env::remove_var("INSOMNIA_CONFIG_DIR"),
Some(v) => std::env::set_var("YOI_CONFIG_DIR", v),
None => std::env::remove_var("YOI_CONFIG_DIR"),
}
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
//! `~/.codex/auth.json` の読み書き。
//!
//! Codex CLI と schema を共有するが、insomnia は知らないフィールドを
//! Codex CLI と schema を共有するが、yoi は知らないフィールドを
//! 失わないようファイル全体を `serde_json::Value` で保持し、必要箇所
//! のみアクセスする。書込は `mode 0o600` を再設定(Codex CLI 同様)、
//! ファイルロックは取らない(manager 側で guarded reload)。
@@ -106,7 +106,7 @@ pub async fn load(path: &Path) -> Result<AuthSnapshot, CodexAuthError> {
/// 既存ファイルを再読込し、`tokens.{id_token,access_token,refresh_token}` と
/// `last_refresh` を更新して書き戻す。Codex CLI の `persist_tokens` 相当。
///
/// 並行する Codex CLI / 別 insomnia プロセスが先に refresh していた場合の
/// 並行する Codex CLI / 別 yoi プロセスが先に refresh していた場合の
/// fields を保護するため、書込前に再 load して merge する。
pub async fn persist_refreshed(
path: &Path,
+1 -1
View File
@@ -8,7 +8,7 @@
//! [`CodexAuthProvider`] はこのクレートに置く(feedback_llm_worker_scope
//! - access_token JWT の `exp` を読み、`now` 以下で proactive refresh
//! Codex CLI と同じバッファなし)
//! - 並行する Codex CLI / 別 insomnia の refresh と取り違えないよう、
//! - 並行する Codex CLI / 別 yoi の refresh と取り違えないよう、
//! refresh 直前に再 load して account_id 一致を確認(guarded reload
//! - ファイルロックは取らず、書込前に再 load + diff merge で吸収
//! - Codex の Keyring storage は対象外。auth.json 不在ならエラーで案内
+1 -1
View File
@@ -78,7 +78,7 @@ impl SecretResolver for DefaultSecretResolver {
path: std::path::PathBuf::from("<data_dir>"),
source: std::io::Error::new(
std::io::ErrorKind::NotFound,
"could not determine insomnia data directory",
"could not determine yoi data directory",
),
})?;
SecretStore::new(data_dir).get(id)
+4 -4
View File
@@ -305,7 +305,7 @@ pub fn validate_id(id: &str) -> Result<()> {
fn derive_key(data_dir: &Path) -> [u8; KEY_LEN] {
let mut hasher = Sha256::new();
hasher.update(b"insomnia local secret store obfuscation key v1");
hasher.update(b"yoi local secret store obfuscation key v1");
hasher.update(data_dir.as_os_str().as_encoded_bytes());
hasher.finalize().into()
}
@@ -339,7 +339,7 @@ fn make_nonce(id: &str, plaintext: &[u8]) -> Vec<u8> {
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
hasher.update(b"insomnia nonce v1");
hasher.update(b"yoi nonce v1");
hasher.update(now.to_le_bytes());
hasher.update(std::process::id().to_le_bytes());
hasher.update(NONCE_COUNTER.fetch_add(1, Ordering::Relaxed).to_le_bytes());
@@ -353,7 +353,7 @@ fn xor_stream(key: &[u8; KEY_LEN], nonce: &[u8], input: &[u8]) -> Vec<u8> {
let mut counter = 0u64;
for chunk in input.chunks(KEY_LEN) {
let mut hasher = Sha256::new();
hasher.update(b"insomnia secret keystream v1");
hasher.update(b"yoi secret keystream v1");
hasher.update(key);
hasher.update(nonce);
hasher.update(counter.to_le_bytes());
@@ -368,7 +368,7 @@ fn xor_stream(key: &[u8; KEY_LEN], nonce: &[u8], input: &[u8]) -> Vec<u8> {
fn tag(key: &[u8; KEY_LEN], id: &str, nonce: &[u8], ciphertext: &[u8]) -> [u8; TAG_LEN] {
let mut hasher = Sha256::new();
hasher.update(b"insomnia secret tag v1");
hasher.update(b"yoi secret tag v1");
hasher.update(key);
hasher.update(id.as_bytes());
hasher.update(nonce);
+1 -1
View File
@@ -9,7 +9,7 @@
//!
//! Migration: this layout is incompatible with the pre-`session-grouping`
//! flat `{root}/{segment_id}.jsonl` form. Project policy is no
//! backward compatibility — discard `~/.insomnia/sessions/` (or whatever
//! backward compatibility — discard `~/.yoi/sessions/` (or whatever
//! `root` resolved to) before running the new code. `list_sessions`
//! ignores top-level files outside session directories, so leftover
//! flat files do not corrupt new sessions, but they are no longer
+1 -1
View File
@@ -141,7 +141,7 @@ impl Tool for BashTool {
// close before bash itself exits.
// exit $__exit propagate the user's exit
let wrapped = format!(
"exec >{out} 2>&1\n{{ {user_cmd}\n}}\n__insomnia_exit=$?\nwait 2>/dev/null\nexit $__insomnia_exit\n",
"exec >{out} 2>&1\n{{ {user_cmd}\n}}\n__yoi_exit=$?\nwait 2>/dev/null\nexit $__yoi_exit\n",
out = shell_single_quote(output_path_str),
user_cmd = params.command,
);
+1 -1
View File
@@ -1,4 +1,4 @@
//! Built-in tools for the Insomnia LLM agent.
//! Built-in tools for the Yoi LLM agent.
//!
//! Implements Read / Write / Edit / Glob / Grep / Bash on top of the
//! `llm-worker` `Tool` infrastructure. Filesystem access is mediated by
+1 -1
View File
@@ -33,7 +33,7 @@
//! let scope = Scope::writable("/workspace").unwrap();
//! let fs = ScopedFs::new(scope, PathBuf::from("/workspace")); // pod lifetime
//! let tracker = Tracker::new(); // session lifetime
//! let bash_outputs = PathBuf::from("/run/insomnia/bash-output");
//! let bash_outputs = PathBuf::from("/run/yoi/bash-output");
//! let task_store = tools::TaskStore::new();
//! let defs = builtin_tools(fs, tracker, task_store, bash_outputs, None);
//! ```
+7 -7
View File
@@ -44,7 +44,7 @@ impl WebTools {
pub fn new(config: Option<WebConfig>) -> Self {
let client = Client::builder()
.redirect(reqwest::redirect::Policy::none())
.user_agent("insomnia-web-tools/0.1")
.user_agent("yoi-web-tools/0.1")
.build()
.expect("static reqwest client configuration is valid");
let secret_store = manifest::paths::data_dir().map(SecretStore::new);
@@ -249,7 +249,7 @@ async fn brave_search(
let api_key_secret = cfg.api_key_secret.as_ref().ok_or_else(|| {
disabled_error(
"WebSearch",
"set web.search.api_key_secret to the insomnia keys secret id for the Brave API key",
"set web.search.api_key_secret to the yoi keys secret id for the Brave API key",
)
})?;
let store = secret_store.ok_or_else(|| {
@@ -1783,7 +1783,7 @@ mod tests {
);
let search_err = tools
.run_search(WebSearchInput {
query: "insomnia".into(),
query: "yoi".into(),
limit: None,
offset: None,
})
@@ -2099,7 +2099,7 @@ mod tests {
);
let result = tools
.run_search(WebSearchInput {
query: "insomnia".into(),
query: "yoi".into(),
limit: Some(1),
offset: Some(0),
})
@@ -2126,12 +2126,12 @@ mod tests {
fetch: None,
}));
let cfg = brave_search_config(format!("http://{addr}/search"));
let result = brave_search_with_api_key(&tools.client, &cfg, "test-key", "insomnia", 1, 0)
let result = brave_search_with_api_key(&tools.client, &cfg, "test-key", "yoi", 1, 0)
.await
.unwrap();
let value: Value = serde_json::from_str(result.content.as_deref().unwrap()).unwrap();
let request = captured.lock().await.clone().unwrap();
assert!(request.starts_with("GET /search?q=insomnia&count=1&offset=0 "));
assert!(request.starts_with("GET /search?q=yoi&count=1&offset=0 "));
assert!(
request
.to_ascii_lowercase()
@@ -2158,7 +2158,7 @@ mod tests {
fetch: None,
}));
let cfg = brave_search_config(format!("http://{addr}/search"));
let err = brave_search_with_api_key(&tools.client, &cfg, "test-key", "insomnia", 1, 0)
let err = brave_search_with_api_key(&tools.client, &cfg, "test-key", "yoi", 1, 0)
.await
.unwrap_err();
assert!(err.to_string().contains("Content-Length"));
+3 -3
View File
@@ -221,14 +221,14 @@ pub async fn launch() -> ExitCode {
let data_dir = match manifest::paths::data_dir() {
Some(path) => path,
None => {
eprintln!("insomnia keys: could not determine insomnia data directory");
eprintln!("yoi keys: could not determine yoi data directory");
return ExitCode::FAILURE;
}
};
match run(SecretStore::new(data_dir)) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("insomnia keys: {err}");
eprintln!("yoi keys: {err}");
ExitCode::FAILURE
}
}
@@ -391,7 +391,7 @@ fn draw(frame: &mut Frame<'_>, app: &KeysApp) {
fn title_line(app: &KeysApp) -> Line<'_> {
Line::from(vec![
Span::styled(
"insomnia keys local secrets",
"yoi keys local secrets",
Style::default().add_modifier(Modifier::BOLD),
),
Span::raw(" "),
+7 -7
View File
@@ -38,20 +38,20 @@ pub enum LaunchMode {
Spawn {
profile: Option<String>,
},
/// `insomnia <name>` / `insomnia --pod <name>`: attach to a live Pod by name if
/// `yoi <name>` / `yoi --pod <name>`: attach to a live Pod by name if
/// possible; otherwise launch the Pod runtime command with `--pod <name>` so it
/// resumes from name-keyed state or creates a fresh same-name Pod.
PodName {
pod_name: String,
socket_override: Option<PathBuf>,
},
/// `insomnia -r` / `insomnia --resume`: open the Pod picker, then attach to the
/// `yoi -r` / `yoi --resume`: open the Pod picker, then attach to the
/// selected live Pod or restore the selected stopped Pod by name.
Resume,
/// `insomnia --session <UUID>`: skip the picker, go straight to the
/// `yoi --session <UUID>`: skip the picker, go straight to the
/// resume name dialog with `id` baked in.
ResumeWithSession(SegmentId),
/// `insomnia --multi`: open the multi-Pod dashboard. This is intentionally
/// `yoi --multi`: open the multi-Pod dashboard. This is intentionally
/// separate from `-r`/`--resume`, which keeps its single-Pod picker
/// meaning.
Multi,
@@ -64,12 +64,12 @@ pub async fn launch(options: LaunchOptions) -> ExitCode {
} = options;
if let Err(e) = enable_raw_mode() {
eprintln!("insomnia: failed to enter raw mode: {e}");
eprintln!("yoi: failed to enter raw mode: {e}");
return ExitCode::FAILURE;
}
if let Err(e) = execute!(io::stdout(), EnableBracketedPaste) {
let _ = disable_raw_mode();
eprintln!("insomnia: {e}");
eprintln!("yoi: {e}");
return ExitCode::FAILURE;
}
@@ -110,7 +110,7 @@ pub async fn launch(options: LaunchOptions) -> ExitCode {
// duplicate. Other errors (pod-name failures, terminal setup
// hiccups, etc.) need surfacing here.
if e.downcast_ref::<spawn::SpawnError>().is_none() {
eprintln!("insomnia: {e}");
eprintln!("yoi: {e}");
}
ExitCode::FAILURE
}
+1 -1
View File
@@ -43,7 +43,7 @@ impl std::fmt::Display for MultiPodError {
Self::Store(e) => write!(f, "session store error: {e}"),
Self::NoPods => write!(
f,
"no pods found — start a fresh pod with `insomnia` or restore one with `insomnia -r`"
"no pods found — start a fresh pod with `yoi` or restore one with `yoi -r`"
),
}
}
+3 -3
View File
@@ -42,7 +42,7 @@ impl std::fmt::Display for PickerError {
Self::Store(e) => write!(f, "session store error: {e}"),
Self::NoPods => write!(
f,
"no pods found — start a fresh pod with `insomnia` and try again"
"no pods found — start a fresh pod with `yoi` and try again"
),
}
}
@@ -169,7 +169,7 @@ fn default_store_dir() -> Result<PathBuf, PickerError> {
PickerError::Io(io::Error::new(
io::ErrorKind::NotFound,
"could not resolve sessions directory \
(set INSOMNIA_HOME, INSOMNIA_DATA_DIR, or HOME)",
(set YOI_HOME, YOI_DATA_DIR, or HOME)",
))
})
}
@@ -181,7 +181,7 @@ fn default_pod_store_dir() -> Result<PathBuf, PickerError> {
PickerError::Io(io::Error::new(
io::ErrorKind::NotFound,
"could not resolve pod state directory \
(set INSOMNIA_HOME, INSOMNIA_DATA_DIR, or HOME)",
(set YOI_HOME, YOI_DATA_DIR, or HOME)",
))
})
}
+2 -2
View File
@@ -35,7 +35,7 @@ fn resolve_socket(pod_name: &str, override_path: Option<PathBuf>) -> PathBuf {
}
manifest::paths::pod_socket_path(pod_name).unwrap_or_else(|| {
PathBuf::from("/tmp")
.join("insomnia")
.join("yoi")
.join(pod_name)
.join("sock")
})
@@ -307,7 +307,7 @@ impl TerminalEventReader {
let stop = Arc::new(AtomicBool::new(false));
let thread_stop = Arc::clone(&stop);
let thread = thread::Builder::new()
.name("insomnia-tui-terminal-reader".to_string())
.name("yoi-tui-terminal-reader".to_string())
.spawn(move || read_terminal_events(thread_stop, tx))?;
Ok((
+10 -10
View File
@@ -1,11 +1,11 @@
//! Inline-viewport "spawn Pod and attach" UX.
//!
//! Rendered at the user's current cursor position when `insomnia` is invoked
//! with no positional argument. Discovers `.insomnia/profiles.toml` profile
//! Rendered at the user's current cursor position when `yoi` is invoked
//! with no positional argument. Discovers `.yoi/profiles.toml` profile
//! choices plus bundled profiles, defaults to the builtin profile, prompts for
//! the Pod's name, and on confirmation launches the Pod runtime command as an
//! independent process. Once the process reports its socket via the
//! `INSOMNIA-READY` stderr line, the dialog hands control back so main can
//! `YOI-READY` stderr line, the dialog hands control back so main can
//! switch the terminal to alternate-screen mode.
//!
//! The viewport's last frame stays in the terminal's scrollback so the
@@ -654,10 +654,10 @@ mod tests {
fn profile_choices_use_project_registry_default() {
let temp = tempfile::tempdir().unwrap();
let project = temp.path().join("project");
let insomnia = project.join(".insomnia");
std::fs::create_dir_all(&insomnia).unwrap();
let yoi = project.join(".yoi");
std::fs::create_dir_all(&yoi).unwrap();
std::fs::write(
insomnia.join("profiles.toml"),
yoi.join("profiles.toml"),
r#"
default = "coder"
[profile]
@@ -678,10 +678,10 @@ coder = "profiles/coder.lua"
fn profile_choices_include_builtin_and_project_default_marker() {
let temp = tempfile::tempdir().unwrap();
let project = temp.path().join("project");
let insomnia = project.join(".insomnia");
std::fs::create_dir_all(&insomnia).unwrap();
let yoi = project.join(".yoi");
std::fs::create_dir_all(&yoi).unwrap();
std::fs::write(
insomnia.join("profiles.toml"),
yoi.join("profiles.toml"),
r#"
default = "coder"
[profile.coder]
@@ -695,7 +695,7 @@ description = "Project coder"
assert_eq!(choices[0].selector.as_deref(), Some("builtin:default"));
assert_eq!(
choices[0].label,
"builtin:default — Bundled default Insomnia coding profile"
"builtin:default — Bundled default Yoi coding profile"
);
assert_eq!(default_index, 1);
assert_eq!(choices[1].selector.as_deref(), Some("project:coder"));
+1 -1
View File
@@ -176,7 +176,7 @@ mod tests {
fn workflow_lint_accepts_valid_file() {
let (dir, linter) = workspace();
write(
&dir.path().join(".insomnia/knowledge/policy.md"),
&dir.path().join(".yoi/knowledge/policy.md"),
"---\ndescription: p\n---\nbody",
);
let wf = "---\ndescription: run\nrequires: [policy]\n---\nbody";
+2 -2
View File
@@ -6,7 +6,7 @@ use manifest::{Permission, ScopeRule};
use memory::WorkspaceLayout;
/// Build deny rules that strip Write permission from
/// `<workspace>/.insomnia/workflow/` for generic CRUD tools.
/// `<workspace>/.yoi/workflow/` for generic CRUD tools.
pub fn deny_write_rules(layout: &WorkspaceLayout) -> Vec<ScopeRule> {
vec![deny_write(layout.workflow_dir().as_path())]
}
@@ -29,7 +29,7 @@ mod tests {
let layout = WorkspaceLayout::new(PathBuf::from("/ws"));
let rules = deny_write_rules(&layout);
assert_eq!(rules.len(), 1);
assert_eq!(rules[0].target, PathBuf::from("/ws/.insomnia/workflow"));
assert_eq!(rules[0].target, PathBuf::from("/ws/.yoi/workflow"));
assert_eq!(rules[0].permission, Permission::Write);
assert!(rules[0].recursive);
}
+3 -3
View File
@@ -3,13 +3,13 @@
//! Skills follow the [agentskills.io](https://agentskills.io/specification)
//! spec: a directory `<root>/<name>/` containing `SKILL.md` (YAML frontmatter
//! + Markdown body) and optional `scripts/` / `references/` / `assets/`
//! subdirectories. The body is procedural agent guidance; insomnia ingests
//! subdirectories. The body is procedural agent guidance; yoi ingests
//! it as a Workflow so `/<name>` resolves to it just like an internal
//! Workflow.
//!
//! Parsing is intentionally lenient at the directory-scan level — one
//! malformed SKILL.md emits `tracing::warn!` and is skipped, leaving sibling
//! skills loadable. Internal Workflows (`.insomnia/workflow/<slug>.md`) keep
//! skills loadable. Internal Workflows (`.yoi/workflow/<slug>.md`) keep
//! their hard-error semantics.
use std::io;
@@ -30,7 +30,7 @@ pub const SKILL_FILENAME: &str = "SKILL.md";
/// SKILL.md frontmatter as defined by the agent-skills spec.
///
/// Fields beyond `name` / `description` are accepted to be spec-compatible
/// but not used by insomnia today: `license`, `compatibility`, and
/// but not used by yoi today: `license`, `compatibility`, and
/// `metadata` are documentary, while `allowed-tools` is recognised and
/// emits a warning until [`permission-extension-point.md`] lands.
#[derive(Debug, Clone, Deserialize)]
+8 -8
View File
@@ -1,6 +1,6 @@
//! Workflow loader and registry.
//!
//! Workflows live under `<workspace>/.insomnia/workflow/<slug>.md`. They are
//! Workflows live under `<workspace>/.yoi/workflow/<slug>.md`. They are
//! human-authored Markdown documents with YAML frontmatter. The loader is
//! intentionally strict about malformed records because Pod startup should
//! fail rather than silently ignoring a broken procedural instruction.
@@ -27,7 +27,7 @@ pub const WORKFLOW_DESCRIPTION_HARD_CAP: usize = 1024;
/// win over external skills.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WorkflowSource {
/// `<workspace>/.insomnia/workflow/<slug>.md`. Authored in-tree by
/// `<workspace>/.yoi/workflow/<slug>.md`. Authored in-tree by
/// the project.
WorkspaceWorkflow,
/// SKILL.md ingested from a `[skills] directories` entry in the
@@ -316,13 +316,13 @@ mod tests {
fn setup() -> (TempDir, WorkspaceLayout) {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".insomnia/workflow")).unwrap();
std::fs::create_dir_all(dir.path().join(".yoi/workflow")).unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
(dir, layout)
}
fn write_workflow(root: &Path, slug: &str, frontmatter: &str, body: &str) {
let path = root.join(".insomnia/workflow").join(format!("{slug}.md"));
let path = root.join(".yoi/workflow").join(format!("{slug}.md"));
std::fs::write(path, format!("---\n{frontmatter}\n---\n{body}")).unwrap();
}
@@ -380,12 +380,12 @@ mod tests {
#[test]
fn workflow_under_memory_is_ignored() {
// The legacy `.insomnia/memory/workflow/` location is no longer
// The legacy `.yoi/memory/workflow/` location is no longer
// a Workflow source. Files placed there must be ignored (the
// loader is rooted at `.insomnia/workflow/` only).
// loader is rooted at `.yoi/workflow/` only).
let dir = TempDir::new().unwrap();
let layout = WorkspaceLayout::new(dir.path().to_path_buf());
let legacy = dir.path().join(".insomnia/memory/workflow");
let legacy = dir.path().join(".yoi/memory/workflow");
std::fs::create_dir_all(&legacy).unwrap();
std::fs::write(
legacy.join("ghost.md"),
@@ -509,7 +509,7 @@ mod tests {
let s = ShadowedSkill {
slug: Slug::parse("x").unwrap(),
kept_source: WorkflowSource::WorkspaceWorkflow,
kept_path: std::path::PathBuf::from("/ws/.insomnia/workflow/x.md"),
kept_path: std::path::PathBuf::from("/ws/.yoi/workflow/x.md"),
shadowed_source: WorkflowSource::Skill {
dir: std::path::PathBuf::from("/skills"),
},
@@ -1,5 +1,5 @@
[package]
name = "insomnia"
name = "yoi"
version = "0.1.0"
edition.workspace = true
license.workspace = true
@@ -7,6 +7,7 @@ license.workspace = true
[dependencies]
client = { workspace = true }
memory = { workspace = true }
manifest = { workspace = true }
pod = { workspace = true }
session-store = { workspace = true }
tui = { workspace = true }
@@ -35,8 +35,8 @@ async fn main() -> ExitCode {
let mode = match parse_args() {
Ok(mode) => mode,
Err(e) => {
eprintln!("insomnia: {e}");
eprintln!("try `insomnia --help` for usage.");
eprintln!("yoi: {e}");
eprintln!("try `yoi --help` for usage.");
return ExitCode::FAILURE;
}
};
@@ -54,17 +54,17 @@ async fn main() -> ExitCode {
Ok(LintStatus::Clean) => ExitCode::SUCCESS,
Ok(LintStatus::Failed) => ExitCode::FAILURE,
Err(e) => {
eprintln!("insomnia memory lint: {e}");
eprintln!("yoi memory lint: {e}");
ExitCode::FAILURE
}
},
Mode::PodRuntime(args) => pod::entrypoint::run_cli_from("insomnia pod", args).await,
Mode::PodRuntime(args) => pod::entrypoint::run_cli_from("yoi pod", args).await,
Mode::Keys => tui::keys::launch().await,
Mode::Tui(mode) => {
let runtime_command = match PodRuntimeCommand::resolve() {
Ok(command) => command,
Err(e) => {
eprintln!("insomnia: failed to resolve Pod runtime command: {e}");
eprintln!("yoi: failed to resolve Pod runtime command: {e}");
return ExitCode::FAILURE;
}
};
@@ -100,7 +100,7 @@ fn parse_args_slice(args: &[String]) -> Result<Mode, ParseError> {
"pod" => return Ok(Mode::PodRuntime(args[1..].to_vec())),
"keys" => {
if args.len() != 1 {
return Err(ParseError("insomnia keys does not accept arguments".into()));
return Err(ParseError("yoi keys does not accept arguments".into()));
}
return Ok(Mode::Keys);
}
@@ -322,13 +322,13 @@ fn parse_session_id(value: &str) -> Result<SegmentId, ParseError> {
fn print_help() {
println!(
"insomnia\n\nUsage:\n insomnia [OPTIONS] [POD_NAME]\n insomnia keys\n insomnia pod [POD_OPTIONS]\n insomnia memory lint [OPTIONS]\n\nOptions:\n -r, --resume Open the Pod picker and resume/attach a Pod\n --multi Open the multi-Pod dashboard\n --pod <NAME> Attach/restore/create a Pod by name\n --socket <PATH> Attach to a specific Pod socket with --pod\n --session <UUID> Resume a specific session segment\n --profile <REF> Start a fresh Pod from a profile\n -h, --help Print help\n"
"yoi\n\nUsage:\n yoi [OPTIONS] [POD_NAME]\n yoi keys\n yoi pod [POD_OPTIONS]\n yoi memory lint [OPTIONS]\n\nOptions:\n -r, --resume Open the Pod picker and resume/attach a Pod\n --multi Open the multi-Pod dashboard\n --pod <NAME> Attach/restore/create a Pod by name\n --socket <PATH> Attach to a specific Pod socket with --pod\n --session <UUID> Resume a specific session segment\n --profile <REF> Start a fresh Pod from a profile\n -h, --help Print help\n"
);
}
fn print_memory_lint_help() {
println!(
"insomnia memory lint\n\nUsage:\n insomnia memory lint [OPTIONS]\n\nOptions:\n --workspace <PATH> Workspace root to lint (defaults to cwd)\n --json Emit a JSON report\n --warnings-as-errors Return failure when warnings are present\n -h, --help Print help\n"
"yoi memory lint\n\nUsage:\n yoi memory lint [OPTIONS]\n\nOptions:\n --workspace <PATH> Workspace root to lint (defaults to cwd)\n --json Emit a JSON report\n --warnings-as-errors Return failure when warnings are present\n -h, --help Print help\n"
);
}
@@ -524,7 +524,7 @@ mod tests {
"--profile".to_string(),
"p.lua".to_string(),
"--socket".to_string(),
"/tmp/insomnia/sock".to_string(),
"/tmp/yoi/sock".to_string(),
],
"--profile can only be used for fresh spawn",
),
@@ -416,19 +416,16 @@ mod tests {
fn lints_only_workspace_memory_and_knowledge_records() {
let dir = TempDir::new().unwrap();
let root = dir.path();
write(&root.join(".insomnia/memory/summary.md"), valid_summary());
write(&root.join(".yoi/memory/summary.md"), valid_summary());
write(
&root.join(".insomnia/memory/requests/request-one.md"),
&root.join(".yoi/memory/requests/request-one.md"),
valid_request(),
);
write(
&root.join(".insomnia/memory/_logs/ignored.md"),
"not frontmatter",
);
write(
&root.join(".insomnia/workflow/ignored.md"),
&root.join(".yoi/memory/_logs/ignored.md"),
"not frontmatter",
);
write(&root.join(".yoi/workflow/ignored.md"), "not frontmatter");
let report = lint_workspace(root).unwrap();
assert_eq!(
@@ -438,8 +435,8 @@ mod tests {
.map(|file| file.path.as_str())
.collect::<Vec<_>>(),
vec![
".insomnia/memory/requests/request-one.md",
".insomnia/memory/summary.md",
".yoi/memory/requests/request-one.md",
".yoi/memory/summary.md",
]
);
assert_eq!(report.counts.files, 2);
@@ -450,10 +447,7 @@ mod tests {
fn invalid_records_count_as_lint_failures() {
let dir = TempDir::new().unwrap();
let root = dir.path();
write(
&root.join(".insomnia/memory/summary.md"),
"missing frontmatter",
);
write(&root.join(".yoi/memory/summary.md"), "missing frontmatter");
let report = lint_workspace(root).unwrap();
assert_eq!(report.counts.files, 1);
@@ -467,7 +461,7 @@ mod tests {
let dir = TempDir::new().unwrap();
let root = dir.path();
write(
&root.join(".insomnia/memory/requests/large-record.md"),
&root.join(".yoi/memory/requests/large-record.md"),
&warning_request(),
);
@@ -492,7 +486,7 @@ mod tests {
fn json_output_is_machine_readable() {
let dir = TempDir::new().unwrap();
let root = dir.path();
write(&root.join(".insomnia/memory/summary.md"), valid_summary());
write(&root.join(".yoi/memory/summary.md"), valid_summary());
let mut output = Vec::new();
let status = run_with_writer(
@@ -509,7 +503,7 @@ mod tests {
let parsed: Value = serde_json::from_slice(&output).unwrap();
assert_eq!(parsed["workspace"], root.display().to_string());
assert_eq!(parsed["counts"]["files"], 1);
assert_eq!(parsed["files"][0]["path"], ".insomnia/memory/summary.md");
assert_eq!(parsed["files"][0]["path"], ".yoi/memory/summary.md");
assert!(parsed["files"][0]["errors"].as_array().unwrap().is_empty());
}
}