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
+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(_)));
}