Compare commits

..

5 Commits

Author SHA1 Message Date
minori 79de8ace44 deps: update @tauri-apps/plugin-fs to 2.5.0
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m21s
CI / Lint & Test (pull_request) Successful in 20m40s
CI / Build Linux (pull_request) Failing after 7m50s
CI / Build Windows (cross-compile) (pull_request) Failing after 8m37s
2026-04-15 07:02:47 -07:00
naomi 7a1ab89ad8 release: v1.14.0
CI / Lint & Test (push) Successful in 17m53s
CI / Build Linux (push) Successful in 24m6s
CI / Build Windows (cross-compile) (push) Successful in 38m42s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 2m29s
2026-04-13 15:59:52 -07:00
hikari c4af551375 fix: read/write global CLAUDE.md via WSL on Windows (#264)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m0s
CI / Lint & Test (push) Successful in 16m37s
CI / Build Linux (push) Has been cancelled
CI / Build Windows (cross-compile) (push) Has been cancelled
## Summary

- `get_global_claude_md` and `save_global_claude_md` were using `dirs::home_dir()` which resolves to the Windows home directory (`C:\Users\accou`) on Windows builds
- The actual `~/.claude/CLAUDE.md` lives in the WSL home directory, so the editor was always showing an empty text box and would have written to the wrong location on save
- Added `get_global_claude_md_via_wsl()` and `save_global_claude_md_via_wsl()` helpers that shell out to WSL (matching the existing pattern used by `list_skills` and `list_memory_files`)
- Both Tauri commands now branch on `cfg!(target_os = "windows")` to use the appropriate path

## Test plan

- [ ] Open Settings sidebar on a Windows build — Global Instructions textarea should load the contents of `~/.claude/CLAUDE.md` from WSL
- [ ] Edit the content and click Save — verify the WSL file is updated
- [ ] Verify Linux/macOS builds are unaffected (native filesystem path unchanged)

✨ This issue was created with help from Hikari~ 🌸

Reviewed-on: #264
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-04-13 15:56:53 -07:00
hikari b88f25a61b 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>
2026-04-13 13:32:03 -07:00
hikari 5663b1c09a feat: CLI v2.1.81–v2.1.104 support (#261)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m33s
CI / Lint & Test (push) Successful in 20m29s
CI / Build Linux (push) Successful in 24m9s
CI / Build Windows (cross-compile) (push) Successful in 40m28s
## Summary

Implements support for all Claude Code CLI changes from v2.1.81 through v2.1.104, closing issues #253–#260.

### Changes

- **#253** — New `CwdChanged` hook event: parse and emit `claude:cwd-changed` Tauri event; new `CwdChangedEvent` type
- **#254** — New `FileChanged` hook event: parse and emit `claude:file-changed` Tauri event; new `FileChangedEvent` type
- **#255** — Idle-return prompt: TUI-only feature, not present in `--output-format stream-json` mode — closed as not applicable
- **#256** — New `TaskCreated` and `PermissionDenied` hook events: parse and emit `claude:task-created` / `claude:permission-denied` Tauri events; `PermissionDenied` also triggers `CharacterState::Permission` character animation
- **#257** — Defer permission request: no PreToolUse hook response mechanism in Hikari Desktop — closed as not applicable
- **#258** — `Monitor` tool: added `"Monitor"` to `SEARCH_TOOLS` constant so it maps to `CharacterState::Searching`
- **#259** — `disableSkillShellExecution` setting: wired through `ClaudeStartOptions`, `HikariConfig`, `--settings` JSON, TypeScript interface, and exposed in the Config Sidebar UI
- **#260** — Updated `SUPPORTED_CLI_VERSION` constant from `"2.1.80"` to `"2.1.104"`

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: #261
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-04-13 12:05:57 -07:00
6 changed files with 91 additions and 27 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "hikari-desktop", "name": "hikari-desktop",
"version": "1.13.0", "version": "1.14.0",
"description": "", "description": "",
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -56,7 +56,7 @@
"@tauri-apps/api": "2.10.1", "@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2", "@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-dialog": "2.6.0", "@tauri-apps/plugin-dialog": "2.6.0",
"@tauri-apps/plugin-fs": "2.4.5", "@tauri-apps/plugin-fs": "2.5.0",
"@tauri-apps/plugin-notification": "2.3.3", "@tauri-apps/plugin-notification": "2.3.3",
"@tauri-apps/plugin-opener": "2.5.3", "@tauri-apps/plugin-opener": "2.5.3",
"@tauri-apps/plugin-os": "2.3.2", "@tauri-apps/plugin-os": "2.3.2",
+5 -5
View File
@@ -96,8 +96,8 @@ importers:
specifier: 2.6.0 specifier: 2.6.0
version: 2.6.0 version: 2.6.0
'@tauri-apps/plugin-fs': '@tauri-apps/plugin-fs':
specifier: 2.4.5 specifier: 2.5.0
version: 2.4.5 version: 2.5.0
'@tauri-apps/plugin-notification': '@tauri-apps/plugin-notification':
specifier: 2.3.3 specifier: 2.3.3
version: 2.3.3 version: 2.3.3
@@ -993,8 +993,8 @@ packages:
'@tauri-apps/plugin-dialog@2.6.0': '@tauri-apps/plugin-dialog@2.6.0':
resolution: {integrity: sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==} resolution: {integrity: sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==}
'@tauri-apps/plugin-fs@2.4.5': '@tauri-apps/plugin-fs@2.5.0':
resolution: {integrity: sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA==} resolution: {integrity: sha512-c83kbz61AK+rKjhS+je9+stIO27nXj7p9cqeg36TwkIUtxpCFTttlHHtqon6h6FN54cXjyAjlMPOJcW3mwE5XQ==}
'@tauri-apps/plugin-notification@2.3.3': '@tauri-apps/plugin-notification@2.3.3':
resolution: {integrity: sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==} resolution: {integrity: sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==}
@@ -2935,7 +2935,7 @@ snapshots:
dependencies: dependencies:
'@tauri-apps/api': 2.10.1 '@tauri-apps/api': 2.10.1
'@tauri-apps/plugin-fs@2.4.5': '@tauri-apps/plugin-fs@2.5.0':
dependencies: dependencies:
'@tauri-apps/api': 2.10.1 '@tauri-apps/api': 2.10.1
+1 -1
View File
@@ -1648,7 +1648,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "hikari-desktop" name = "hikari-desktop"
version = "1.13.0" version = "1.14.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"dirs 5.0.1", "dirs 5.0.1",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "hikari-desktop" name = "hikari-desktop"
version = "1.13.0" version = "1.14.0"
description = "Hikari - Claude Code Visual Assistant" description = "Hikari - Claude Code Visual Assistant"
authors = ["Naomi Carrigan"] authors = ["Naomi Carrigan"]
edition = "2021" edition = "2021"
+64
View File
@@ -2618,10 +2618,67 @@ pub async fn open_binary_file(app: AppHandle, path: String) -> Result<(), String
} }
} }
/// Read `~/.claude/CLAUDE.md` via WSL (for Windows).
/// Returns an empty string if the file does not exist.
#[cfg(target_os = "windows")]
async fn get_global_claude_md_via_wsl() -> Result<String, String> {
use std::process::Command;
let output = Command::new("wsl")
.hide_window()
.args(["-e", "bash", "-l", "-c", "cat ~/.claude/CLAUDE.md 2>/dev/null || true"])
.output()
.map_err(|e| format!("Failed to execute WSL command: {}", e))?;
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
/// Write content to `~/.claude/CLAUDE.md` via WSL (for Windows).
/// Creates the file (and `~/.claude/` directory) if they do not exist.
#[cfg(target_os = "windows")]
async fn save_global_claude_md_via_wsl(content: String) -> Result<(), String> {
use std::io::Write;
use std::process::{Command, Stdio};
let mut child = Command::new("wsl")
.hide_window()
.args([
"-e",
"bash",
"-l",
"-c",
"mkdir -p ~/.claude && cat > ~/.claude/CLAUDE.md",
])
.stdin(Stdio::piped())
.spawn()
.map_err(|e| format!("Failed to execute WSL command: {}", e))?;
if let Some(stdin) = child.stdin.as_mut() {
stdin
.write_all(content.as_bytes())
.map_err(|e| format!("Failed to write content to WSL stdin: {}", e))?;
}
let status = child
.wait()
.map_err(|e| format!("Failed to wait for WSL command: {}", e))?;
if !status.success() {
return Err("Failed to save CLAUDE.md via WSL".to_string());
}
Ok(())
}
/// Read the contents of `~/.claude/CLAUDE.md`. /// Read the contents of `~/.claude/CLAUDE.md`.
/// Returns an empty string if the file does not exist. /// Returns an empty string if the file does not exist.
#[tauri::command] #[tauri::command]
pub async fn get_global_claude_md() -> Result<String, String> { pub async fn get_global_claude_md() -> Result<String, String> {
#[cfg(target_os = "windows")]
return get_global_claude_md_via_wsl().await;
#[cfg(not(target_os = "windows"))]
{
let path = dirs::home_dir() let path = dirs::home_dir()
.ok_or_else(|| "Could not determine home directory".to_string())? .ok_or_else(|| "Could not determine home directory".to_string())?
.join(".claude") .join(".claude")
@@ -2633,11 +2690,17 @@ pub async fn get_global_claude_md() -> Result<String, String> {
std::fs::read_to_string(&path).map_err(|e| format!("Failed to read CLAUDE.md: {}", e)) std::fs::read_to_string(&path).map_err(|e| format!("Failed to read CLAUDE.md: {}", e))
} }
}
/// Write content to `~/.claude/CLAUDE.md`. /// Write content to `~/.claude/CLAUDE.md`.
/// Creates the file (and `~/.claude/` directory) if they do not exist. /// Creates the file (and `~/.claude/` directory) if they do not exist.
#[tauri::command] #[tauri::command]
pub async fn save_global_claude_md(content: String) -> Result<(), String> { pub async fn save_global_claude_md(content: String) -> Result<(), String> {
#[cfg(target_os = "windows")]
return save_global_claude_md_via_wsl(content).await;
#[cfg(not(target_os = "windows"))]
{
let claude_dir = dirs::home_dir() let claude_dir = dirs::home_dir()
.ok_or_else(|| "Could not determine home directory".to_string())? .ok_or_else(|| "Could not determine home directory".to_string())?
.join(".claude"); .join(".claude");
@@ -2650,6 +2713,7 @@ pub async fn save_global_claude_md(content: String) -> Result<(), String> {
let path = claude_dir.join("CLAUDE.md"); let path = claude_dir.join("CLAUDE.md");
std::fs::write(&path, content).map_err(|e| format!("Failed to write CLAUDE.md: {}", e)) std::fs::write(&path, content).map_err(|e| format!("Failed to write CLAUDE.md: {}", e))
} }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "hikari-desktop", "productName": "hikari-desktop",
"version": "1.13.0", "version": "1.14.0",
"identifier": "com.naomi.hikari-desktop", "identifier": "com.naomi.hikari-desktop",
"build": { "build": {
"beforeDevCommand": "pnpm dev", "beforeDevCommand": "pnpm dev",