#![allow(dead_code)]
use anyhow::Result;
use std::fs;
use std::path::{Path, PathBuf};
use crate::paths;
#[derive(Debug, Default, Clone)]
pub struct Rules {
pub global: Option<String>,
pub project: Option<String>,
}
impl Rules {
pub fn load(monitor_dir: &Path, project: &str) -> Self {
let global = paths::worker_rules_file()
.ok()
.and_then(|p| read_nonempty(&p));
let project_rules = read_nonempty(&project_rules_path(monitor_dir, project));
Self {
global,
project: project_rules,
}
}
pub fn render(&self) -> String {
let mut out = String::new();
if let Some(g) = &self.global {
out.push_str("# Global rules\n\n");
out.push_str(g.trim());
out.push_str("\n\n");
}
if let Some(p) = &self.project {
out.push_str("# Project rules\n\n");
out.push_str(p.trim());
out.push('\n');
}
out.trim_end().to_string()
}
pub fn is_empty(&self) -> bool {
self.global.is_none() && self.project.is_none()
}
}
pub fn project_rules_path(monitor_dir: &Path, project: &str) -> PathBuf {
monitor_dir.join(project).join(".devist").join("rules.md")
}
pub fn ensure_global_template() -> Result<PathBuf> {
let path = paths::worker_rules_file()?;
if path.exists() {
return Ok(path);
}
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&path, DEFAULT_GLOBAL_TEMPLATE)?;
Ok(path)
}
pub fn ensure_project_template(monitor_dir: &Path, project: &str) -> Result<PathBuf> {
let path = project_rules_path(monitor_dir, project);
if path.exists() {
return Ok(path);
}
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&path, DEFAULT_PROJECT_TEMPLATE)?;
Ok(path)
}
fn read_nonempty(path: &Path) -> Option<String> {
let s = fs::read_to_string(path).ok()?;
if s.trim().is_empty() {
None
} else {
Some(s)
}
}
const DEFAULT_GLOBAL_TEMPLATE: &str = "# devist worker — global rules
These rules apply to every project the worker observes.
Edit freely; they're injected verbatim into the advice prompt.
## Tone
- Respond in Korean.
- Be concise. No filler.
## Focus
- Flag missing tests, security issues, dependency mismatches.
- Skip nitpicks (formatting, micro-style).
## Memory
- Only persist DURABLE facts to mem0 (preferences, conventions).
- Skip transient changes.
";
const DEFAULT_PROJECT_TEMPLATE: &str = "# devist worker — project rules
Project-specific overrides. Loaded after global rules.
## Domain
- (Add domain context here, e.g. \"This is a fintech app; PII handling matters.\")
## Conventions
- (Add stack-specific conventions here.)
";