generated from nhcarrigan/template
feat: CLI v2.1.81 features + global CLAUDE.md editor (#263)
## 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:
@@ -303,6 +303,11 @@ impl WslBridge {
|
||||
cmd.arg("--worktree");
|
||||
}
|
||||
|
||||
// Add bare flag if requested (v2.1.81+)
|
||||
if options.bare_mode {
|
||||
cmd.arg("--bare");
|
||||
}
|
||||
|
||||
// Pass combined settings via --settings flag if any settings are specified
|
||||
{
|
||||
let has_memory_dir = options
|
||||
@@ -315,8 +320,13 @@ impl WslBridge {
|
||||
.as_ref()
|
||||
.map(|m| !m.is_empty())
|
||||
.unwrap_or(false);
|
||||
let suppress_clear_context = !options.show_clear_context_on_plan_accept;
|
||||
|
||||
if has_memory_dir || has_overrides || options.disable_skill_shell_execution {
|
||||
if has_memory_dir
|
||||
|| has_overrides
|
||||
|| options.disable_skill_shell_execution
|
||||
|| suppress_clear_context
|
||||
{
|
||||
let mut settings = serde_json::Map::new();
|
||||
if let Some(ref dir) = options.auto_memory_directory {
|
||||
if !dir.is_empty() {
|
||||
@@ -339,6 +349,12 @@ impl WslBridge {
|
||||
serde_json::Value::Bool(true),
|
||||
);
|
||||
}
|
||||
if suppress_clear_context {
|
||||
settings.insert(
|
||||
"showClearContextOnPlanAccept".to_string(),
|
||||
serde_json::Value::Bool(false),
|
||||
);
|
||||
}
|
||||
if let Ok(settings_json) = serde_json::to_string(&settings) {
|
||||
cmd.args(["--settings", &settings_json]);
|
||||
}
|
||||
@@ -379,6 +395,13 @@ impl WslBridge {
|
||||
cmd.env("ENABLE_CLAUDEAI_MCP_SERVERS", "false");
|
||||
}
|
||||
|
||||
// Set custom model option if specified (v2.1.81+)
|
||||
if let Some(ref custom_opt) = options.custom_model_option {
|
||||
if !custom_opt.is_empty() {
|
||||
cmd.env("ANTHROPIC_CUSTOM_MODEL_OPTION", custom_opt);
|
||||
}
|
||||
}
|
||||
|
||||
cmd
|
||||
} else {
|
||||
// Running on Windows - use wsl with bash login shell to ensure PATH is loaded
|
||||
@@ -446,6 +469,14 @@ impl WslBridge {
|
||||
claude_cmd.push_str("ENABLE_CLAUDEAI_MCP_SERVERS=false ");
|
||||
}
|
||||
|
||||
// Set custom model option if specified (v2.1.81+)
|
||||
if let Some(ref custom_opt) = options.custom_model_option {
|
||||
if !custom_opt.is_empty() {
|
||||
let escaped = custom_opt.replace('\'', "'\\''");
|
||||
claude_cmd.push_str(&format!("ANTHROPIC_CUSTOM_MODEL_OPTION='{}' ", escaped));
|
||||
}
|
||||
}
|
||||
|
||||
claude_cmd.push_str(
|
||||
"claude --output-format stream-json --input-format stream-json --verbose",
|
||||
);
|
||||
@@ -496,6 +527,11 @@ impl WslBridge {
|
||||
claude_cmd.push_str(" --worktree");
|
||||
}
|
||||
|
||||
// Add bare flag if requested (v2.1.81+)
|
||||
if options.bare_mode {
|
||||
claude_cmd.push_str(" --bare");
|
||||
}
|
||||
|
||||
// Pass combined settings via --settings flag if any settings are specified
|
||||
{
|
||||
let has_memory_dir = options
|
||||
@@ -508,8 +544,13 @@ impl WslBridge {
|
||||
.as_ref()
|
||||
.map(|m| !m.is_empty())
|
||||
.unwrap_or(false);
|
||||
let suppress_clear_context = !options.show_clear_context_on_plan_accept;
|
||||
|
||||
if has_memory_dir || has_overrides || options.disable_skill_shell_execution {
|
||||
if has_memory_dir
|
||||
|| has_overrides
|
||||
|| options.disable_skill_shell_execution
|
||||
|| suppress_clear_context
|
||||
{
|
||||
let mut settings = serde_json::Map::new();
|
||||
if let Some(ref dir) = options.auto_memory_directory {
|
||||
if !dir.is_empty() {
|
||||
@@ -532,6 +573,12 @@ impl WslBridge {
|
||||
serde_json::Value::Bool(true),
|
||||
);
|
||||
}
|
||||
if suppress_clear_context {
|
||||
settings.insert(
|
||||
"showClearContextOnPlanAccept".to_string(),
|
||||
serde_json::Value::Bool(false),
|
||||
);
|
||||
}
|
||||
if let Ok(settings_json) = serde_json::to_string(&settings) {
|
||||
let escaped = settings_json.replace('\'', "'\\''");
|
||||
claude_cmd.push_str(&format!(" --settings '{}'", escaped));
|
||||
@@ -2122,6 +2169,9 @@ fn process_json_line(
|
||||
usage,
|
||||
duration_ms,
|
||||
num_turns,
|
||||
fast_mode_state,
|
||||
model_usage,
|
||||
total_cost_usd,
|
||||
} => {
|
||||
tracing::info!(
|
||||
"Received Result message: subtype={}, has_denials={}, denial_count={:?}",
|
||||
@@ -2206,6 +2256,25 @@ fn process_json_line(
|
||||
});
|
||||
}
|
||||
|
||||
// Log fast mode state if present (v2.1.81+)
|
||||
if let Some(ref state) = fast_mode_state {
|
||||
tracing::debug!("Fast mode state: {}", state);
|
||||
}
|
||||
|
||||
// Log per-model usage if available (v2.1.81+)
|
||||
if let Some(ref model_usage_val) = model_usage {
|
||||
if let Some(map) = model_usage_val.as_object() {
|
||||
for (model_name, _usage_val) in map {
|
||||
tracing::debug!("Per-model usage logged for: {}", model_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log authoritative cost from Claude Code if available (v2.1.81+)
|
||||
if let Some(auth_cost) = total_cost_usd {
|
||||
tracing::debug!("Authoritative total cost from Claude Code: ${:.6}", auth_cost);
|
||||
}
|
||||
|
||||
// Clear tracking fields since request completed successfully
|
||||
{
|
||||
let mut stats_guard = stats.write();
|
||||
|
||||
Reference in New Issue
Block a user