Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ATTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The original Claurst license is preserved in full in `LICENSE.md`.
- System prompt identity updated to reflect OpenCoven fork
- Repository and homepage URLs updated to OpenCoven GitHub
- Landing page (`index.html`), docs, and installer scripts rebranded
- Mascot renamed from "Rustle" to "Rune" (doc comments; internal Rust identifiers `RustlePose`/`rustle_lines` intentionally preserved for merge-friendliness)
- Mascot renamed from "Rustle" to "Rune" (internal Rust module and pose names now use companion/mascot terminology)
- ACP server identity updated to `coven-code`
- Share viewer URL updated to `opencoven.github.io/coven-code/session/`
- `CNAME` file removed (upstream pointed to `claurst.kuber.studio`)
Expand Down
4 changes: 2 additions & 2 deletions COVEN.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ Target OpenCoven brand palette:

Replace `default_theme()` return values when brand assets are finalized.

### 6. Companion mascot — `src-rust/crates/tui/src/rustle.rs`
### 6. Companion mascot — `src-rust/crates/tui/src/mascot.rs`

ASCII mascot renderer. Currently "Rune" (renamed from "Rustle" upstream).
To rebrand: rename `RustlePose` → `CompanionPose` (pending — "Rune" is the mascot name), update art in `rustle_lines()`, update call-sites in `render.rs` and `app.rs`.
The internal module and pose naming now use companion/mascot terminology; update art in `mascot_lines_for()` and call-sites in `render.rs` / `app.rs`.

### 7. Memory / session hooks — `src-rust/crates/core/src/memdir.rs`, `session_storage.rs`

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Coven Code is designed to grow into the OpenCoven ecosystem. Key seams for futur
| Command registry | `src-rust/crates/commands/` | Add `/slash` commands |
| TUI theme | `src-rust/crates/tui/src/theme_colors.rs` | OpenCoven violet/pink palette is the default; deuteranopia variant ships too. Diff viewer routes through `DiffPalette` so colour-blind users see orange/blue diffs. |
| Memory / session | `src-rust/crates/core/src/memdir.rs`, `session_storage.rs` | Hook for Coven session/memory integration |
| Companion mascot | `src-rust/crates/tui/src/rustle.rs` | ASCII mascot renderer; seven archetypes ship (`kitty`, `nova`, `cody`, `charm`, `sage`, `astra`, `echo`). F2 opens the live switcher. |
| Companion mascot | `src-rust/crates/tui/src/mascot.rs` | ASCII mascot renderer; seven archetypes ship (`kitty`, `nova`, `cody`, `charm`, `sage`, `astra`, `echo`). F2 opens the live switcher. |
| Coven daemon client | `src-rust/crates/core/src/coven_daemon.rs` | Typed `DaemonClient` over `~/.coven/coven.sock` speaking `coven.daemon.v1`. Powers `/coven` + the welcome status block. |

---
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/welcome-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function render() {
<div class="tui-grid">
<div>
<div class="tui-greeting">Welcome back, val!</div>
<pre class="tui-rustle"> ∧___∧
<pre class="tui-mascot"> ∧___∧
( ・ω・ )
o_(")(")</pre>
</div>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ a {
font-weight: 600;
margin-bottom: 8px;
}
.tui-rustle {
.tui-mascot {
color: var(--color-accent-light);
white-space: pre;
font-size: 10.5px;
Expand Down
File renamed without changes
File renamed without changes
44 changes: 44 additions & 0 deletions scripts/mascot-rebrand.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const repoRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));

function exists(relativePath) {
return fs.existsSync(path.join(repoRoot, relativePath));
}

function read(relativePath) {
return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
}

assert.equal(exists('src-rust/crates/tui/src/mascot.rs'), true, 'mascot module file should exist');
assert.equal(exists('src-rust/crates/tui/src/rustle.rs'), false, 'legacy rustle module file should be removed');
assert.match(read('src-rust/crates/tui/src/lib.rs'), /pub mod mascot;/, 'tui lib should export mascot module');
assert.doesNotMatch(read('src-rust/crates/tui/src/lib.rs'), /pub mod rustle;/, 'tui lib should not export rustle module');

for (const file of [
'src-rust/crates/tui/src/mascot.rs',
'src-rust/crates/tui/src/familiar_card.rs',
'src-rust/crates/tui/src/app.rs',
'src-rust/crates/tui/src/render.rs',
'src-rust/crates/cli/src/main.rs',
]) {
const source = read(file);
assert.doesNotMatch(
source,
/RustlePose|rustle_lines_for|crate::rustle|tick_rustle_pose|rustle_current_pose|rustle_look_down/,
`${file} should not use legacy Rustle identifiers`,
);
}

assert.match(read('src-rust/crates/tui/src/mascot.rs'), /pub enum CompanionPose/, 'pose type should be CompanionPose');
assert.match(read('src-rust/crates/tui/src/mascot.rs'), /pub fn mascot_lines_for/, 'legacy rustle_lines_for should be renamed');

assert.equal(exists('public/Rune.png'), true, 'Rune mascot asset should exist');
assert.equal(exists('public/Pirate-Rune.png'), true, 'Pirate Rune asset should exist');
assert.equal(exists('public/Rustle.png'), false, 'legacy Rustle asset should be removed');
assert.equal(exists('public/Pirate-Rustle.png'), false, 'legacy Pirate Rustle asset should be removed');

console.log('mascot rebrand smoke test passed');
2 changes: 1 addition & 1 deletion src-rust/crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2457,7 +2457,7 @@ async fn run_interactive(
cmd_ctx.mcp_auth_runner = Some(mcp_auth_runner.clone());
'main: loop {
app.frame_count = app.frame_count.wrapping_add(1);
app.tick_rustle_pose();
app.tick_companion_pose();
app.notifications.tick();

// Process file injection dialog outcome (if any)
Expand Down
18 changes: 9 additions & 9 deletions src-rust/crates/tui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,7 @@ pub struct App {
/// Current familiar pose for rendering. `Static` when idle; `Loading {
/// frame }` while streaming has stalled long enough to surface a spinner.
/// The glyph itself never walks or blinks.
pub rustle_current_pose: crate::rustle::RustlePose,
pub companion_current_pose: crate::mascot::CompanionPose,
/// Instant the current turn's streaming began (reset each time streaming starts).
pub turn_start: Option<std::time::Instant>,
/// Elapsed time string for the last completed turn, e.g. "2m 5s".
Expand Down Expand Up @@ -1833,7 +1833,7 @@ impl App {
new_messages_while_scrolled: 0,
token_warning_threshold_shown: 0,
session_start: std::time::Instant::now(),
rustle_current_pose: crate::rustle::RustlePose::Static,
companion_current_pose: crate::mascot::CompanionPose::Static,
turn_start: None,
last_turn_elapsed: None,
last_turn_verb: None,
Expand Down Expand Up @@ -2402,24 +2402,24 @@ impl App {
/// The glyph itself is static — this just toggles between `Static` and
/// `Loading { frame }` so the eye-spinner kicks in when the assistant has
/// gone quiet for 3+ seconds. Call once per frame before rendering.
pub fn tick_rustle_pose(&mut self) {
pub fn tick_companion_pose(&mut self) {
let stalled = self.is_streaming
&& self
.stall_start
.map(|s| s.elapsed() > std::time::Duration::from_secs(3))
.unwrap_or(false);
self.rustle_current_pose = if stalled {
crate::rustle::RustlePose::Loading {
self.companion_current_pose = if stalled {
crate::mascot::CompanionPose::Loading {
frame: self.frame_count,
}
} else {
crate::rustle::RustlePose::Static
crate::mascot::CompanionPose::Static
};
}

/// No-op retained for callsites left over from the animated era (Tab /
/// mode-switch handlers). The static glyph has no look-down pose.
pub fn rustle_look_down(&mut self) {}
pub fn companion_look_down(&mut self) {}

/// Cycle to the next agent mode: build → plan → explore → build.
/// Sets `agent_mode_changed` so the main loop can update the query config
Expand Down Expand Up @@ -5078,7 +5078,7 @@ impl App {
} else if !self.is_streaming && self.prompt_input.is_empty() {
// Cycle agent mode: build → plan → explore → build
self.cycle_agent_mode();
self.rustle_look_down();
self.companion_look_down();
}
}

Expand Down Expand Up @@ -5952,7 +5952,7 @@ impl App {
self.refresh_prompt_input();
} else if self.prompt_input.is_empty() {
self.cycle_agent_mode();
self.rustle_look_down();
self.companion_look_down();
}
}
false
Expand Down
10 changes: 5 additions & 5 deletions src-rust/crates/tui/src/familiar_card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//! the user still has a signal that work is in progress.
//!
//! Built-in archetypes dispatch to the pixel-art builders in
//! [`crate::rustle`]. Procedural archetypes ([`Archetype::SigilCrystal`] etc.)
//! [`crate::mascot`]. Procedural archetypes ([`Archetype::SigilCrystal`] etc.)
//! draw a colored frame around the familiar's emoji so any user-defined entry
//! from `~/.coven/familiars.toml` gets first-class visual identity.

use crate::familiar_theme::{Archetype, FamiliarPalette, FamiliarTheme};
use crate::rustle::{archetype_lines, RustlePose};
use crate::mascot::{archetype_lines, CompanionPose};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};

Expand Down Expand Up @@ -51,8 +51,8 @@ pub fn render_card(
loading: Option<u64>,
) -> Vec<Line<'static>> {
let pose = match loading {
Some(frame) => RustlePose::Loading { frame },
None => RustlePose::Static,
Some(frame) => CompanionPose::Loading { frame },
None => CompanionPose::Static,
};
let glyph = glyph_lines(theme, &pose);

Expand Down Expand Up @@ -240,7 +240,7 @@ fn access_line(theme: &FamiliarTheme, primary: Color, inner_w: u16) -> Line<'sta

// ── Glyph dispatch ───────────────────────────────────────────────────────────

fn glyph_lines(theme: &FamiliarTheme, pose: &RustlePose) -> Vec<Line<'static>> {
fn glyph_lines(theme: &FamiliarTheme, pose: &CompanionPose) -> Vec<Line<'static>> {
match theme.archetype {
Archetype::SigilCrystal => sigil_crystal(&theme.palette, &theme.emoji),
Archetype::SigilHex => sigil_hex(&theme.palette, &theme.emoji),
Expand Down
4 changes: 2 additions & 2 deletions src-rust/crates/tui/src/familiar_theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use ratatui::style::Color;

/// Four-color palette covering body fill, accent details, eye sockets, and
/// the deep background behind the eyes. Eye + bg are intentionally shared
/// across all themes so the eye rendering helpers in [`crate::rustle`] can
/// across all themes so the eye rendering helpers in [`crate::mascot`] can
/// stay archetype-agnostic.
#[derive(Debug, Clone, Copy)]
pub struct FamiliarPalette {
Expand All @@ -51,7 +51,7 @@ impl FamiliarPalette {

// ── Archetype ────────────────────────────────────────────────────────────────

/// Which renderer in [`crate::rustle`] / [`crate::familiar_card`] draws the
/// Which renderer in [`crate::mascot`] / [`crate::familiar_card`] draws the
/// glyph body. The first seven variants map to the hand-crafted built-ins;
/// `SigilCrystal`/`SigilHex`/`SigilRune`/`SigilSeal` are procedural frames
/// used for any user-defined familiar.
Expand Down
4 changes: 2 additions & 2 deletions src-rust/crates/tui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ pub mod invalid_config_dialog;
pub mod key_input_dialog;
/// Inline image rendering via the Kitty graphics protocol (with text fallback).
pub mod kitty_image;
/// Rune mascot rendering.
pub mod mascot;
/// MCP server management UI.
pub mod mcp_view;
/// Memory file selector overlay (AGENTS.md browser).
Expand Down Expand Up @@ -125,8 +127,6 @@ pub mod plugin_views;
pub mod prompt_input;
/// All ratatui rendering logic.
pub mod render;
/// Rune mascot rendering.
pub mod rustle;
/// Session branching overlay (Ctrl+B) — create and switch between conversation branches.
pub mod session_branching;
/// Session browser overlay (/session, /resume, /rename, /export).
Expand Down
Loading