generated from nhcarrigan/template
Compare commits
10 Commits
v1.7.0
..
5063a4f415
| Author | SHA1 | Date | |
|---|---|---|---|
| 5063a4f415 | |||
| 54280b3920 | |||
| 108a1b16b2 | |||
| 1c02ca1bb5 | |||
| ac965ebe92 | |||
| 5cdb4508aa | |||
| b914240d20 | |||
| 302963f6c0 | |||
| 986dd54dd9 | |||
| 24313facca |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hikari-desktop",
|
"name": "hikari-desktop",
|
||||||
"version": "1.7.0",
|
"version": "1.6.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Generated
+1
-1
@@ -1636,7 +1636,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hikari-desktop"
|
name = "hikari-desktop"
|
||||||
version = "1.7.0"
|
version = "1.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "hikari-desktop"
|
name = "hikari-desktop"
|
||||||
version = "1.7.0"
|
version = "1.6.0"
|
||||||
description = "Hikari - Claude Code Visual Assistant"
|
description = "Hikari - Claude Code Visual Assistant"
|
||||||
authors = ["Naomi Carrigan"]
|
authors = ["Naomi Carrigan"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ pub struct ClaudeStartOptions {
|
|||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub use_worktree: bool,
|
pub use_worktree: bool,
|
||||||
|
|
||||||
#[serde(default)]
|
|
||||||
pub disable_1m_context: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -122,9 +119,6 @@ pub struct HikariConfig {
|
|||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub use_worktree: bool,
|
pub use_worktree: bool,
|
||||||
|
|
||||||
#[serde(default)]
|
|
||||||
pub disable_1m_context: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HikariConfig {
|
impl Default for HikariConfig {
|
||||||
@@ -158,7 +152,6 @@ impl Default for HikariConfig {
|
|||||||
budget_warning_threshold: 0.8,
|
budget_warning_threshold: 0.8,
|
||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,8 +259,6 @@ mod tests {
|
|||||||
assert_eq!(config.budget_action, BudgetAction::Warn);
|
assert_eq!(config.budget_action, BudgetAction::Warn);
|
||||||
assert!((config.budget_warning_threshold - 0.8).abs() < f32::EPSILON);
|
assert!((config.budget_warning_threshold - 0.8).abs() < f32::EPSILON);
|
||||||
assert!(config.discord_rpc_enabled);
|
assert!(config.discord_rpc_enabled);
|
||||||
assert!(!config.use_worktree);
|
|
||||||
assert!(!config.disable_1m_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -301,7 +292,6 @@ mod tests {
|
|||||||
budget_warning_threshold: 0.75,
|
budget_warning_threshold: 0.75,
|
||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
use_worktree: true,
|
use_worktree: true,
|
||||||
disable_1m_context: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string(&config).unwrap();
|
let json = serde_json::to_string(&config).unwrap();
|
||||||
|
|||||||
@@ -305,8 +305,6 @@ pub struct AgentEndEvent {
|
|||||||
pub duration_ms: Option<u64>,
|
pub duration_ms: Option<u64>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub num_turns: Option<u32>,
|
pub num_turns: Option<u32>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub last_assistant_message: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
+13
-212
@@ -279,11 +279,6 @@ impl WslBridge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable 1M context window if requested
|
|
||||||
if options.disable_1m_context {
|
|
||||||
cmd.env("CLAUDE_CODE_DISABLE_1M_CONTEXT", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd
|
cmd
|
||||||
} else {
|
} else {
|
||||||
// Running on Windows - use wsl with bash login shell to ensure PATH is loaded
|
// Running on Windows - use wsl with bash login shell to ensure PATH is loaded
|
||||||
@@ -324,11 +319,6 @@ impl WslBridge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable 1M context window if requested
|
|
||||||
if options.disable_1m_context {
|
|
||||||
claude_cmd.push_str("CLAUDE_CODE_DISABLE_1M_CONTEXT=1 ");
|
|
||||||
}
|
|
||||||
|
|
||||||
claude_cmd.push_str(
|
claude_cmd.push_str(
|
||||||
"claude --output-format stream-json --input-format stream-json --verbose",
|
"claude --output-format stream-json --input-format stream-json --verbose",
|
||||||
);
|
);
|
||||||
@@ -765,7 +755,6 @@ fn handle_stderr(
|
|||||||
conversation_id: conversation_id.clone(),
|
conversation_id: conversation_id.clone(),
|
||||||
duration_ms: None,
|
duration_ms: None,
|
||||||
num_turns: None,
|
num_turns: None,
|
||||||
last_assistant_message: stop_data.last_assistant_message,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -839,78 +828,27 @@ fn parse_subagent_start_hook(line: &str) -> Option<SubagentStartData> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SubagentStopData {
|
struct SubagentStopData {
|
||||||
parent_tool_use_id: Option<String>,
|
parent_tool_use_id: Option<String>,
|
||||||
last_assistant_message: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the content of a Rust Debug-formatted `Some("...")` field from a hook line.
|
|
||||||
/// Handles escaped characters (e.g. `\"` → `"`, `\\` → `\`, `\n` → newline).
|
|
||||||
/// Returns `None` if the field is absent or formatted as `None`.
|
|
||||||
fn extract_debug_string_value(line: &str, key: &str) -> Option<String> {
|
|
||||||
let prefix = format!("{}=Some(\"", key);
|
|
||||||
let start_idx = line.find(&prefix)? + prefix.len();
|
|
||||||
let rest = &line[start_idx..];
|
|
||||||
|
|
||||||
let mut result = String::new();
|
|
||||||
let mut chars = rest.chars();
|
|
||||||
loop {
|
|
||||||
match chars.next() {
|
|
||||||
Some('"') => return Some(result),
|
|
||||||
Some('\\') => match chars.next() {
|
|
||||||
Some('n') => result.push('\n'),
|
|
||||||
Some('t') => result.push('\t'),
|
|
||||||
Some('"') => result.push('"'),
|
|
||||||
Some('\\') => result.push('\\'),
|
|
||||||
Some(c) => {
|
|
||||||
result.push('\\');
|
|
||||||
result.push(c);
|
|
||||||
}
|
|
||||||
None => break,
|
|
||||||
},
|
|
||||||
Some(c) => result.push(c),
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_subagent_stop_hook(line: &str) -> Option<SubagentStopData> {
|
fn parse_subagent_stop_hook(line: &str) -> Option<SubagentStopData> {
|
||||||
// Parse: [SubagentStop Hook] ... parent_tool_use_id=Some("toolu_xxx"), last_assistant_message=Some("..."), ...
|
// Parse: [SubagentStop Hook] ... parent_tool_use_id=Some("toolu_xxx"), ...
|
||||||
|
|
||||||
let parent_tool_use_id = extract_debug_string_value(line, "parent_tool_use_id");
|
// Extract parent_tool_use_id if present
|
||||||
let last_assistant_message = extract_debug_string_value(line, "last_assistant_message");
|
let parent_tool_use_id = if line.contains("parent_tool_use_id=Some") {
|
||||||
|
line.split("parent_tool_use_id=Some(\"")
|
||||||
|
.nth(1)?
|
||||||
|
.split('"')
|
||||||
|
.next()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Some(SubagentStopData {
|
Some(SubagentStopData {
|
||||||
parent_tool_use_id,
|
parent_tool_use_id,
|
||||||
last_assistant_message,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract text content from a ToolResult's `content` field.
|
|
||||||
/// The content may be a JSON string or an array of typed content blocks.
|
|
||||||
fn extract_tool_result_text(content: &serde_json::Value) -> Option<String> {
|
|
||||||
match content {
|
|
||||||
serde_json::Value::String(s) if !s.is_empty() => Some(s.clone()),
|
|
||||||
serde_json::Value::Array(blocks) => {
|
|
||||||
let texts: Vec<String> = blocks
|
|
||||||
.iter()
|
|
||||||
.filter_map(|block| {
|
|
||||||
if block.get("type")?.as_str()? == "text" {
|
|
||||||
block.get("text")?.as_str().map(String::from)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
if texts.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(texts.join("\n"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_json_line(
|
fn process_json_line(
|
||||||
line: &str,
|
line: &str,
|
||||||
app: &AppHandle,
|
app: &AppHandle,
|
||||||
@@ -1212,8 +1150,8 @@ fn process_json_line(
|
|||||||
}
|
}
|
||||||
ContentBlock::ToolResult {
|
ContentBlock::ToolResult {
|
||||||
tool_use_id,
|
tool_use_id,
|
||||||
content,
|
|
||||||
is_error,
|
is_error,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
// Emit agent-end for all tool results
|
// Emit agent-end for all tool results
|
||||||
// The frontend will ignore IDs that don't match known agents
|
// The frontend will ignore IDs that don't match known agents
|
||||||
@@ -1231,7 +1169,6 @@ fn process_json_line(
|
|||||||
conversation_id: conversation_id.clone(),
|
conversation_id: conversation_id.clone(),
|
||||||
duration_ms: None,
|
duration_ms: None,
|
||||||
num_turns: None,
|
num_turns: None,
|
||||||
last_assistant_message: extract_tool_result_text(content),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1649,8 +1586,8 @@ fn process_json_line(
|
|||||||
for block in &message.content {
|
for block in &message.content {
|
||||||
if let ContentBlock::ToolResult {
|
if let ContentBlock::ToolResult {
|
||||||
tool_use_id,
|
tool_use_id,
|
||||||
content,
|
|
||||||
is_error,
|
is_error,
|
||||||
|
..
|
||||||
} = block
|
} = block
|
||||||
{
|
{
|
||||||
let now = SystemTime::now()
|
let now = SystemTime::now()
|
||||||
@@ -1667,7 +1604,6 @@ fn process_json_line(
|
|||||||
conversation_id: conversation_id.clone(),
|
conversation_id: conversation_id.clone(),
|
||||||
duration_ms: None,
|
duration_ms: None,
|
||||||
num_turns: None,
|
num_turns: None,
|
||||||
last_assistant_message: extract_tool_result_text(content),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2219,140 +2155,5 @@ mod tests {
|
|||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
let data = result.unwrap();
|
let data = result.unwrap();
|
||||||
assert_eq!(data.parent_tool_use_id, None);
|
assert_eq!(data.parent_tool_use_id, None);
|
||||||
assert_eq!(data.last_assistant_message, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_subagent_stop_hook_with_last_message() {
|
|
||||||
let line = r#"[SubagentStop Hook] stop_hook_active=true, parent_tool_use_id=Some("toolu_01ABC123"), last_assistant_message=Some("Task completed successfully."), session_id=123"#;
|
|
||||||
let result = parse_subagent_stop_hook(line);
|
|
||||||
|
|
||||||
assert!(result.is_some());
|
|
||||||
let data = result.unwrap();
|
|
||||||
assert_eq!(data.parent_tool_use_id, Some("toolu_01ABC123".to_string()));
|
|
||||||
assert_eq!(
|
|
||||||
data.last_assistant_message,
|
|
||||||
Some("Task completed successfully.".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_subagent_stop_hook_with_last_message_none() {
|
|
||||||
let line = r#"[SubagentStop Hook] stop_hook_active=true, parent_tool_use_id=Some("toolu_01ABC123"), last_assistant_message=None, session_id=123"#;
|
|
||||||
let result = parse_subagent_stop_hook(line);
|
|
||||||
|
|
||||||
assert!(result.is_some());
|
|
||||||
let data = result.unwrap();
|
|
||||||
assert_eq!(data.last_assistant_message, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_debug_string_value_simple() {
|
|
||||||
let line = r#"key=Some("hello world")"#;
|
|
||||||
assert_eq!(
|
|
||||||
extract_debug_string_value(line, "key"),
|
|
||||||
Some("hello world".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_debug_string_value_with_escaped_quotes() {
|
|
||||||
let line = r#"key=Some("say \"hi\" there")"#;
|
|
||||||
assert_eq!(
|
|
||||||
extract_debug_string_value(line, "key"),
|
|
||||||
Some(r#"say "hi" there"#.to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_debug_string_value_none_variant() {
|
|
||||||
let line = "key=None";
|
|
||||||
assert_eq!(extract_debug_string_value(line, "key"), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_debug_string_value_missing_key() {
|
|
||||||
let line = "other=Some(\"value\")";
|
|
||||||
assert_eq!(extract_debug_string_value(line, "key"), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_subagent_stop_hook_with_commas_in_message() {
|
|
||||||
let line = r#"[SubagentStop Hook] parent_tool_use_id=Some("toolu_01"), last_assistant_message=Some("Found 3 files, all passing.")"#;
|
|
||||||
let result = parse_subagent_stop_hook(line);
|
|
||||||
|
|
||||||
assert!(result.is_some());
|
|
||||||
let data = result.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
data.last_assistant_message,
|
|
||||||
Some("Found 3 files, all passing.".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract_tool_result_text tests
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_plain_string() {
|
|
||||||
let content = serde_json::json!("Hello from agent");
|
|
||||||
assert_eq!(
|
|
||||||
extract_tool_result_text(&content),
|
|
||||||
Some("Hello from agent".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_empty_string() {
|
|
||||||
let content = serde_json::json!("");
|
|
||||||
assert_eq!(extract_tool_result_text(&content), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_array_single_text_block() {
|
|
||||||
let content = serde_json::json!([{"type": "text", "text": "Agent completed the task."}]);
|
|
||||||
assert_eq!(
|
|
||||||
extract_tool_result_text(&content),
|
|
||||||
Some("Agent completed the task.".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_array_multiple_text_blocks() {
|
|
||||||
let content = serde_json::json!([
|
|
||||||
{"type": "text", "text": "First part."},
|
|
||||||
{"type": "text", "text": "Second part."}
|
|
||||||
]);
|
|
||||||
assert_eq!(
|
|
||||||
extract_tool_result_text(&content),
|
|
||||||
Some("First part.\nSecond part.".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_array_non_text_block() {
|
|
||||||
let content = serde_json::json!([{"type": "image", "source": {"type": "base64"}}]);
|
|
||||||
assert_eq!(extract_tool_result_text(&content), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_array_mixed_blocks() {
|
|
||||||
let content = serde_json::json!([
|
|
||||||
{"type": "image", "source": {}},
|
|
||||||
{"type": "text", "text": "Found results."}
|
|
||||||
]);
|
|
||||||
assert_eq!(
|
|
||||||
extract_tool_result_text(&content),
|
|
||||||
Some("Found results.".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_null() {
|
|
||||||
let content = serde_json::Value::Null;
|
|
||||||
assert_eq!(extract_tool_result_text(&content), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extract_tool_result_text_empty_array() {
|
|
||||||
let content = serde_json::json!([]);
|
|
||||||
assert_eq!(extract_tool_result_text(&content), None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.7.0",
|
"version": "1.6.0",
|
||||||
"identifier": "com.naomi.hikari-desktop",
|
"identifier": "com.naomi.hikari-desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "pnpm dev",
|
"beforeDevCommand": "pnpm dev",
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ async function changeDirectory(path: string): Promise<void> {
|
|||||||
mcp_servers_json: config.mcp_servers_json || null,
|
mcp_servers_json: config.mcp_servers_json || null,
|
||||||
allowed_tools: allAllowedTools,
|
allowed_tools: allAllowedTools,
|
||||||
use_worktree: config.use_worktree ?? false,
|
use_worktree: config.use_worktree ?? false,
|
||||||
disable_1m_context: config.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -138,7 +137,6 @@ async function startNewConversation(): Promise<void> {
|
|||||||
mcp_servers_json: config.mcp_servers_json || null,
|
mcp_servers_json: config.mcp_servers_json || null,
|
||||||
allowed_tools: allAllowedTools,
|
allowed_tools: allAllowedTools,
|
||||||
use_worktree: config.use_worktree ?? false,
|
use_worktree: config.use_worktree ?? false,
|
||||||
disable_1m_context: config.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -318,16 +318,6 @@
|
|||||||
<span class="text-[10px] text-red-400">Errored / Killed</span>
|
<span class="text-[10px] text-red-400">Errored / Killed</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Last assistant message snippet -->
|
|
||||||
{#if agent.lastAssistantMessage}
|
|
||||||
<p
|
|
||||||
class="mt-1 text-[10px] text-[var(--text-secondary)] italic truncate"
|
|
||||||
title={agent.lastAssistantMessage}
|
|
||||||
>
|
|
||||||
{agent.lastAssistantMessage}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
const SUPPORTED_CLI_VERSION = "2.1.50";
|
const SUPPORTED_CLI_VERSION = "2.1.33";
|
||||||
|
|
||||||
let installedVersion = $state("Loading...");
|
let installedVersion = $state("Loading...");
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@
|
|||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let showCustomThemeEditor = $state(false);
|
let showCustomThemeEditor = $state(false);
|
||||||
@@ -490,22 +489,6 @@
|
|||||||
Launch sessions with <code class="font-mono">--worktree</code> for isolated git worktree environments
|
Launch sessions with <code class="font-mono">--worktree</code> for isolated git worktree environments
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Disable 1M Context Window -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<label class="flex items-center gap-3 cursor-pointer">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
bind:checked={config.disable_1m_context}
|
|
||||||
class="w-4 h-4 rounded border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--accent-primary)] focus:ring-[var(--accent-primary)]"
|
|
||||||
/>
|
|
||||||
<span class="text-sm text-[var(--text-primary)]">Disable 1M context window</span>
|
|
||||||
</label>
|
|
||||||
<p class="text-xs text-[var(--text-tertiary)] mt-1 ml-7">
|
|
||||||
Sets <code class="font-mono">CLAUDE_CODE_DISABLE_1M_CONTEXT=1</code> to opt out of the extended
|
|
||||||
context window
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Greeting Section -->
|
<!-- Greeting Section -->
|
||||||
|
|||||||
@@ -363,7 +363,6 @@ User: ${formattedMessage}`;
|
|||||||
mcp_servers_json: config.mcp_servers_json || null,
|
mcp_servers_json: config.mcp_servers_json || null,
|
||||||
allowed_tools: allAllowedTools,
|
allowed_tools: allAllowedTools,
|
||||||
use_worktree: config.use_worktree ?? false,
|
use_worktree: config.use_worktree ?? false,
|
||||||
disable_1m_context: config.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,6 @@
|
|||||||
mcp_servers_json: config.mcp_servers_json || null,
|
mcp_servers_json: config.mcp_servers_json || null,
|
||||||
allowed_tools: newGrantedTools,
|
allowed_tools: newGrantedTools,
|
||||||
use_worktree: config.use_worktree ?? false,
|
use_worktree: config.use_worktree ?? false,
|
||||||
disable_1m_context: config.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,6 @@
|
|||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let streamerModeActive = $state(false);
|
let streamerModeActive = $state(false);
|
||||||
@@ -181,7 +180,6 @@
|
|||||||
mcp_servers_json: currentConfig.mcp_servers_json || null,
|
mcp_servers_json: currentConfig.mcp_servers_json || null,
|
||||||
allowed_tools: allAllowedTools,
|
allowed_tools: allAllowedTools,
|
||||||
use_worktree: currentConfig.use_worktree ?? false,
|
use_worktree: currentConfig.use_worktree ?? false,
|
||||||
disable_1m_context: currentConfig.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -294,7 +292,6 @@
|
|||||||
mcp_servers_json: currentConfig.mcp_servers_json || null,
|
mcp_servers_json: currentConfig.mcp_servers_json || null,
|
||||||
allowed_tools: allAllowedTools,
|
allowed_tools: allAllowedTools,
|
||||||
use_worktree: currentConfig.use_worktree ?? false,
|
use_worktree: currentConfig.use_worktree ?? false,
|
||||||
disable_1m_context: currentConfig.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,6 @@
|
|||||||
mcp_servers_json: config.mcp_servers_json || null,
|
mcp_servers_json: config.mcp_servers_json || null,
|
||||||
allowed_tools: grantedToolsList,
|
allowed_tools: grantedToolsList,
|
||||||
use_worktree: config.use_worktree ?? false,
|
use_worktree: config.use_worktree ?? false,
|
||||||
disable_1m_context: config.disable_1m_context ?? false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -177,32 +177,6 @@ describe("agents store", () => {
|
|||||||
const agents = get(getAgentsForConversation(conversationId));
|
const agents = get(getAgentsForConversation(conversationId));
|
||||||
expect(agents[0].status).toBe("running"); // Status unchanged
|
expect(agents[0].status).toBe("running"); // Status unchanged
|
||||||
});
|
});
|
||||||
|
|
||||||
it("stores lastAssistantMessage when provided", () => {
|
|
||||||
const agent = createMockAgent({ status: "running" });
|
|
||||||
agentStore.addAgent(conversationId, agent);
|
|
||||||
|
|
||||||
agentStore.endAgent(
|
|
||||||
conversationId,
|
|
||||||
agent.toolUseId,
|
|
||||||
Date.now(),
|
|
||||||
false,
|
|
||||||
"Task completed successfully."
|
|
||||||
);
|
|
||||||
|
|
||||||
const agents = get(getAgentsForConversation(conversationId));
|
|
||||||
expect(agents[0].lastAssistantMessage).toBe("Task completed successfully.");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("leaves lastAssistantMessage undefined when not provided", () => {
|
|
||||||
const agent = createMockAgent({ status: "running" });
|
|
||||||
agentStore.addAgent(conversationId, agent);
|
|
||||||
|
|
||||||
agentStore.endAgent(conversationId, agent.toolUseId, Date.now(), false);
|
|
||||||
|
|
||||||
const agents = get(getAgentsForConversation(conversationId));
|
|
||||||
expect(agents[0].lastAssistantMessage).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("markAllErrored", () => {
|
describe("markAllErrored", () => {
|
||||||
|
|||||||
@@ -45,13 +45,7 @@ function createAgentStore() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
endAgent(
|
endAgent(conversationId: string, toolUseId: string, endedAt: number, isError: boolean) {
|
||||||
conversationId: string,
|
|
||||||
toolUseId: string,
|
|
||||||
endedAt: number,
|
|
||||||
isError: boolean,
|
|
||||||
lastAssistantMessage?: string
|
|
||||||
) {
|
|
||||||
agentsByConversation.update((state) => {
|
agentsByConversation.update((state) => {
|
||||||
const agents = state[conversationId];
|
const agents = state[conversationId];
|
||||||
if (!agents) return state;
|
if (!agents) return state;
|
||||||
@@ -68,7 +62,6 @@ function createAgentStore() {
|
|||||||
endedAt,
|
endedAt,
|
||||||
status: isError ? "errored" : "completed",
|
status: isError ? "errored" : "completed",
|
||||||
durationMs,
|
durationMs,
|
||||||
lastAssistantMessage,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -195,7 +195,6 @@ describe("config store", () => {
|
|||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(config.model).toBe("claude-sonnet-4");
|
expect(config.model).toBe("claude-sonnet-4");
|
||||||
@@ -243,7 +242,6 @@ describe("config store", () => {
|
|||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(config.model).toBeNull();
|
expect(config.model).toBeNull();
|
||||||
@@ -790,7 +788,6 @@ describe("config store", () => {
|
|||||||
discord_rpc_enabled: false,
|
discord_rpc_enabled: false,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockInvokeImpl = vi.mocked(invoke);
|
const mockInvokeImpl = vi.mocked(invoke);
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ export interface HikariConfig {
|
|||||||
show_thinking_blocks: boolean;
|
show_thinking_blocks: boolean;
|
||||||
// Worktree isolation
|
// Worktree isolation
|
||||||
use_worktree: boolean;
|
use_worktree: boolean;
|
||||||
// Disable 1M context window
|
|
||||||
disable_1m_context: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultConfig: HikariConfig = {
|
const defaultConfig: HikariConfig = {
|
||||||
@@ -92,7 +90,6 @@ const defaultConfig: HikariConfig = {
|
|||||||
discord_rpc_enabled: true,
|
discord_rpc_enabled: true,
|
||||||
show_thinking_blocks: true,
|
show_thinking_blocks: true,
|
||||||
use_worktree: false,
|
use_worktree: false,
|
||||||
disable_1m_context: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function createConfigStore() {
|
function createConfigStore() {
|
||||||
|
|||||||
+2
-9
@@ -474,17 +474,10 @@ export async function initializeTauriListeners() {
|
|||||||
unlisteners.push(agentUpdateUnlisten);
|
unlisteners.push(agentUpdateUnlisten);
|
||||||
|
|
||||||
const agentEndUnlisten = await listen<AgentEndPayload>("claude:agent-end", (event) => {
|
const agentEndUnlisten = await listen<AgentEndPayload>("claude:agent-end", (event) => {
|
||||||
const { tool_use_id, ended_at, is_error, conversation_id, last_assistant_message } =
|
const { tool_use_id, ended_at, is_error, conversation_id } = event.payload;
|
||||||
event.payload;
|
|
||||||
const targetConversationId = conversation_id || get(claudeStore.activeConversationId);
|
const targetConversationId = conversation_id || get(claudeStore.activeConversationId);
|
||||||
if (targetConversationId) {
|
if (targetConversationId) {
|
||||||
agentStore.endAgent(
|
agentStore.endAgent(targetConversationId, tool_use_id, ended_at, is_error);
|
||||||
targetConversationId,
|
|
||||||
tool_use_id,
|
|
||||||
ended_at,
|
|
||||||
is_error,
|
|
||||||
last_assistant_message
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
unlisteners.push(agentEndUnlisten);
|
unlisteners.push(agentEndUnlisten);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export interface AgentInfo {
|
|||||||
durationMs?: number;
|
durationMs?: number;
|
||||||
characterName: string;
|
characterName: string;
|
||||||
characterAvatar: string;
|
characterAvatar: string;
|
||||||
lastAssistantMessage?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentStartPayload {
|
export interface AgentStartPayload {
|
||||||
@@ -32,5 +31,4 @@ export interface AgentEndPayload {
|
|||||||
conversation_id?: string;
|
conversation_id?: string;
|
||||||
duration_ms?: number;
|
duration_ms?: number;
|
||||||
num_turns?: number;
|
num_turns?: number;
|
||||||
last_assistant_message?: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user