use camino::Utf8PathBuf;
use cordance_core::pack::CordancePack;
use crate::agents_md::{
commands_body, doctrine_pointers_body, forbidden_surfaces_body, resolve_axiom_info,
};
use crate::{EmitError, TargetEmitter};
pub struct CursorEmitter;
fn mdc_file(description: &str, content: &str) -> Vec<u8> {
format!("---\ndescription: {description}\nglobs: [\"**/*\"]\n---\n{content}\n").into_bytes()
}
const fn cortex_boundary_content() -> &'static str {
"Cordance writes to Cortex only via `cordance-cortex-receipt-v1-candidate` receipts.\n\
Never write directly to the cortex repo or modify cortex storage.\n\
The operator hands receipts to Cortex's own acceptance flow."
}
fn authority_content(version: &str, axiom_source: &str) -> String {
let version = cordance_core::fence::sanitise_fenced_value(version);
let axiom_source = cordance_core::fence::sanitise_fenced_value(axiom_source);
let axiom_source_win = axiom_source.replace('/', "\\");
format!(
"## Authority Order\n\
\n\
Load axiom before acting on any multi-step task:\n\
\n\
Axiom source (configure in `cordance.toml` → `[axiom].source`): `{axiom_source}`\n\
Algorithm version: `{version}`\n\
\n\
**POSIX / WSL:**\n\
- `{axiom_source}/PAI/Algorithm/{version}.md`\n\
- `{axiom_source}/PAI/CONTEXT_ROUTING.md`\n\
\n\
**Native Windows (replace `/` with `\\`):**\n\
- `{axiom_source_win}\\PAI\\Algorithm\\{version}.md`\n\
- `{axiom_source_win}\\PAI\\CONTEXT_ROUTING.md`\n\
\n\
Adjust `cordance.toml` → `[axiom].source` if axiom lives at a different path."
)
}
impl TargetEmitter for CursorEmitter {
fn name(&self) -> &'static str {
"cursor"
}
fn render(&self, pack: &CordancePack) -> Result<Vec<(Utf8PathBuf, Vec<u8>)>, EmitError> {
let (version, axiom_source) = resolve_axiom_info(pack);
let auth = authority_content(&version, &axiom_source);
let commands = commands_body(pack);
let doctrine = doctrine_pointers_body(pack);
let forbidden = forbidden_surfaces_body();
let files: Vec<(Utf8PathBuf, Vec<u8>)> = vec![
(
".cursor/rules/authority.mdc".into(),
mdc_file("Doctrine authority order", &auth),
),
(
".cursor/rules/commands.mdc".into(),
mdc_file("Project build and test commands", &commands),
),
(
".cursor/rules/doctrine-pointers.mdc".into(),
mdc_file("Engineering doctrine pointers", &doctrine),
),
(
".cursor/rules/forbidden-surfaces.mdc".into(),
mdc_file("Blocked surfaces — never import or commit", forbidden),
),
(
".cursor/rules/cortex-boundary.mdc".into(),
mdc_file("Cortex non-write boundary", cortex_boundary_content()),
),
];
Ok(files)
}
}