feat: CLI v2.1.81 features + global CLAUDE.md editor (#263)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m9s
CI / Lint & Test (push) Successful in 18m55s
CI / Build Linux (push) Successful in 22m9s
CI / Build Windows (cross-compile) (push) Successful in 31m38s

## Summary

Implements support for Claude Code CLI v2.1.81 features and adds a global CLAUDE.md editor, closing issues #237, #239, #244, #245, #246, #247, #248, and #262.

### Stream-JSON forward-compatibility (#245, #246, #247, #248)

- **#248** — `output_style` field added to `System` init message; silently accepted for forward-compat
- **#245** — `fast_mode_state` field added to `Result` message; logged at debug level
- **#246** — `model_usage` field added to `Result` message; per-model breakdown logged at debug level
- **#247** — `total_cost_usd` field added to `Result` message; authoritative cost logged at debug level

### New config options (#237, #239, #244)

- **#237** — `bare_mode` config toggle: passes `--bare` to Claude Code, suppressing UI chrome for scripted headless `-p` calls
- **#239** — `show_clear_context_on_plan_accept` toggle: passes `showClearContextOnPlanAccept: false` in `--settings` when disabled
- **#244** — `custom_model_option` text field: sets `ANTHROPIC_CUSTOM_MODEL_OPTION` env var for custom model providers

### Global CLAUDE.md editor (#262)

- New Tauri commands `get_global_claude_md` / `save_global_claude_md` read/write `~/.claude/CLAUDE.md` (creates file + directory if absent)
- New "Global Instructions" section in the Config Sidebar with a textarea and Save button

### Bug fix (pre-existing)

`disable_cron` and `disable_skill_shell_execution` were saved to `HikariConfig` but never passed to `start_claude` invocations — fixed in all 9 call sites. All 3 new config fields are also wired through all 9 call sites.

All changes pass `check-all.sh` (ESLint → Prettier → svelte-check → Vitest → Clippy → cargo test with llvm-cov).

 This PR was created with help from Hikari~ 🌸

Reviewed-on: #263
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #263.
This commit is contained in:
2026-04-13 13:32:03 -07:00
committed by Naomi Carrigan
parent 5663b1c09a
commit b88f25a61b
15 changed files with 432 additions and 2 deletions
+51
View File
@@ -2618,6 +2618,39 @@ pub async fn open_binary_file(app: AppHandle, path: String) -> Result<(), String
}
}
/// Read the contents of `~/.claude/CLAUDE.md`.
/// Returns an empty string if the file does not exist.
#[tauri::command]
pub async fn get_global_claude_md() -> Result<String, String> {
let path = dirs::home_dir()
.ok_or_else(|| "Could not determine home directory".to_string())?
.join(".claude")
.join("CLAUDE.md");
if !path.exists() {
return Ok(String::new());
}
std::fs::read_to_string(&path).map_err(|e| format!("Failed to read CLAUDE.md: {}", e))
}
/// Write content to `~/.claude/CLAUDE.md`.
/// Creates the file (and `~/.claude/` directory) if they do not exist.
#[tauri::command]
pub async fn save_global_claude_md(content: String) -> Result<(), String> {
let claude_dir = dirs::home_dir()
.ok_or_else(|| "Could not determine home directory".to_string())?
.join(".claude");
if !claude_dir.exists() {
std::fs::create_dir_all(&claude_dir)
.map_err(|e| format!("Failed to create ~/.claude directory: {}", e))?;
}
let path = claude_dir.join("CLAUDE.md");
std::fs::write(&path, content).map_err(|e| format!("Failed to write CLAUDE.md: {}", e))
}
#[cfg(test)]
mod tests {
use super::*;
@@ -3367,4 +3400,22 @@ gitea: gitea-mcp -t stdio (STDIO) - ✓ Connected"#;
let (_, args) = build_wslpath_command(path);
assert_eq!(args[2], path);
}
#[test]
fn test_get_global_claude_md_path_construction() {
// Verify that home_dir() resolves successfully on the test platform
let home = dirs::home_dir();
assert!(home.is_some(), "home_dir() should be available in test environment");
let expected = home.unwrap().join(".claude").join("CLAUDE.md");
assert!(expected.to_string_lossy().contains(".claude"));
assert!(expected.to_string_lossy().ends_with("CLAUDE.md"));
}
#[test]
fn test_save_global_claude_md_dir_path_construction() {
let home = dirs::home_dir();
assert!(home.is_some());
let dir = home.unwrap().join(".claude");
assert!(dir.to_string_lossy().contains(".claude"));
}
}