Skip to content

Commit dc6d969

Browse files
author
Test User
committed
Kanban and session items cleaning
1 parent 56267df commit dc6d969

70 files changed

Lines changed: 1464 additions & 638 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ Acepe uses the Compounding Engineering workflow as its engineering operating sys
154154

155155
- Suggest architecture overhauls when you find recurring smells, leaky provider logic, or brittle abstractions.
156156
- Do not preserve a bad pattern just because it is widespread. Prefer durable, tested abstractions grounded in real product needs.
157+
- Do not frame work as a migration, coexistence plan, or cutover strategy. Assume speed-of-light execution: design and plan for the clean replacement architecture directly, with old paths removed rather than accommodated in parallel.
157158

158159
### Debugging
159160

@@ -163,6 +164,7 @@ Acepe uses the Compounding Engineering workflow as its engineering operating sys
163164

164165
- NEVER run `bun dev` — the user manages the dev server.
165166
- NEVER run `git stash` without explicit user consent.
167+
- NEVER set `core.bare=true` in this repository's root `.git/config` or otherwise convert this checkout into a bare repository. If bare-style workflows are needed, use a separate bare mirror or linked worktree instead of changing the active checkout.
166168

167169
## Detailed Guides
168170

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ The agent panel follows a View–Model–Controller split across packages:
181181

182182
- NEVER run `bun dev` — the user manages the dev server.
183183
- NEVER run `git stash` without explicit user consent.
184+
- NEVER set `core.bare=true` in this repository's root `.git/config` or otherwise convert this checkout into a bare repository. If bare-style workflows are needed, use a separate bare mirror or linked worktree instead of changing the active checkout.
184185

185186
## Detailed Guides
186187

packages/desktop/messages/en.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@
611611
"tool_notebook_edit_completed": "Edited notebook",
612612
"tool_bash_preparing": "Generating command",
613613
"tool_bash_running": "Running command",
614-
"tool_bash_completed": "Ran command",
614+
"tool_bash_completed": "Executed",
615615
"tool_kill_shell_running": "Killing shell",
616616
"tool_kill_shell_completed": "Killed shell",
617617
"tool_task_output_running": "Getting output",
@@ -777,6 +777,7 @@
777777
"permission_deny": "Deny",
778778
"permission_allow": "Allow",
779779
"permission_always_allow": "Always",
780+
"permission_autonomous": "Autonomous",
780781
"tool_fetch_fetching": "Fetching",
781782
"tool_fetch_fetched": "Fetched",
782783
"tool_fetch_failed": "Fetch failed",
@@ -871,5 +872,9 @@
871872
"voice_error_load_failed": "Failed to load model",
872873
"voice_error_transcription_timeout": "Transcription timed out",
873874
"voice_model_menu_label": "Voice model",
874-
"voice_model_menu_downloading": "Downloading…"
875+
"voice_model_menu_downloading": "Downloading…",
876+
"error_boundary_panel_failed": "This panel encountered an error.",
877+
"error_boundary_sidebar_failed": "Sidebar encountered an error.",
878+
"error_boundary_session_item_failed": "Failed to render session.",
879+
"error_boundary_retry": "Retry"
875880
}

packages/desktop/src-tauri/src/acp/parsers/arguments.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,14 @@ pub(crate) fn extract_parser_string_list(
4545
pub(crate) fn parse_generic_edit_arguments(raw_arguments: &serde_json::Value) -> ToolArguments {
4646
let file_path = extract_parser_string(raw_arguments, &["file_path", "filePath", "path"]);
4747
let move_from = extract_parser_string(raw_arguments, &["move_from", "moveFrom"]);
48-
let old_string = extract_parser_string(raw_arguments, &["old_string", "oldString", "oldText"]);
49-
let new_string = extract_parser_string(raw_arguments, &["new_string", "newString", "newText"]);
48+
let old_string = extract_parser_string(
49+
raw_arguments,
50+
&["old_string", "oldString", "oldText", "old_str"],
51+
);
52+
let new_string = extract_parser_string(
53+
raw_arguments,
54+
&["new_string", "newString", "newText", "new_str"],
55+
);
5056
let content = extract_parser_string(raw_arguments, &["content"]);
5157

5258
ToolArguments::Edit {

packages/desktop/src-tauri/src/acp/parsers/shared_chat.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@ pub(crate) fn infer_tool_kind_from_raw_arguments(
1717
if object.contains_key("file_path")
1818
|| object.contains_key("filePath")
1919
|| object.contains_key("path")
20+
|| object.contains_key("query")
21+
|| object.contains_key("cmd")
2022
|| object.contains_key("command")
2123
|| object.contains_key("pattern")
2224
|| object.contains_key("url")
25+
|| object.contains_key("from")
26+
|| object.contains_key("to")
27+
|| object.contains_key("source")
28+
|| object.contains_key("destination")
2329
{
2430
return None;
2531
}
@@ -133,6 +139,22 @@ pub(crate) fn detect_update_type(data: &serde_json::Value) -> Result<UpdateType,
133139
))
134140
}
135141

142+
#[cfg(test)]
143+
mod tests {
144+
use super::infer_tool_kind_from_raw_arguments;
145+
use crate::acp::session_update::ToolKind;
146+
147+
#[test]
148+
fn description_and_query_do_not_infer_task_kind() {
149+
let inferred = infer_tool_kind_from_raw_arguments(&serde_json::json!({
150+
"description": "Create planning todos",
151+
"query": "INSERT INTO todos VALUES ('todo-1')"
152+
}));
153+
154+
assert_ne!(inferred, Some(ToolKind::Task));
155+
}
156+
}
157+
136158
pub(crate) fn parse_tool_call_update(
137159
data: &serde_json::Value,
138160
normalize_tool_kind: fn(&str) -> ToolKind,

packages/desktop/src-tauri/src/acp/providers/copilot.rs

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use sea_orm::DbConn;
1414
use serde_json::Value;
1515
use std::collections::HashMap;
1616
use std::future::Future;
17-
use std::path::Path;
17+
use std::path::{Path, PathBuf};
1818
use std::pin::Pin;
1919
use tauri::{AppHandle, Manager};
2020

@@ -109,32 +109,7 @@ impl AgentProvider for CopilotProvider {
109109
return Ok(Vec::new());
110110
};
111111

112-
let agents_root = cwd.join(".agents");
113-
let skills_root = agents_root.join("skills");
114-
let nested_skill_commands =
115-
crate::acp::preconnection_slash::load_preconnection_commands_from_root(
116-
&skills_root,
117-
)
118-
.await?;
119-
let nested_agent_commands =
120-
crate::acp::preconnection_slash::load_preconnection_commands_from_root(
121-
&agents_root,
122-
)
123-
.await?;
124-
let flat_agent_commands =
125-
crate::acp::preconnection_slash::load_preconnection_commands_from_flat_markdown_root(
126-
&agents_root,
127-
)
128-
.await?;
129-
130-
Ok(
131-
crate::acp::preconnection_slash::dedupe_preconnection_commands(
132-
nested_skill_commands
133-
.into_iter()
134-
.chain(nested_agent_commands)
135-
.chain(flat_agent_commands),
136-
),
137-
)
112+
load_copilot_preconnection_commands(cwd, dirs::home_dir().as_deref()).await
138113
})
139114
}
140115

@@ -234,6 +209,51 @@ fn filtered_env() -> HashMap<String, String> {
234209
crate::shell_env::build_env(crate::shell_env::EnvStrategy::Allowlist(ALLOWED_ENV_KEYS))
235210
}
236211

212+
async fn load_copilot_preconnection_commands(
213+
cwd: &Path,
214+
home_dir: Option<&Path>,
215+
) -> Result<Vec<AvailableCommand>, String> {
216+
let agent_roots = copilot_agent_roots(cwd, home_dir);
217+
let skill_roots = agent_roots
218+
.iter()
219+
.map(|root: &PathBuf| root.join("skills"))
220+
.collect::<Vec<_>>();
221+
222+
let nested_skill_commands =
223+
crate::acp::preconnection_slash::load_preconnection_commands_from_roots(&skill_roots)
224+
.await?;
225+
let nested_agent_commands =
226+
crate::acp::preconnection_slash::load_preconnection_commands_from_roots(&agent_roots)
227+
.await?;
228+
229+
let mut flat_agent_commands = Vec::new();
230+
for root in &agent_roots {
231+
let commands =
232+
crate::acp::preconnection_slash::load_preconnection_commands_from_flat_markdown_root(
233+
root,
234+
)
235+
.await?;
236+
flat_agent_commands.extend(commands);
237+
}
238+
239+
Ok(crate::acp::preconnection_slash::dedupe_preconnection_commands(
240+
nested_skill_commands
241+
.into_iter()
242+
.chain(nested_agent_commands)
243+
.chain(flat_agent_commands),
244+
))
245+
}
246+
247+
fn copilot_agent_roots(cwd: &Path, home_dir: Option<&Path>) -> Vec<PathBuf> {
248+
let mut roots = vec![cwd.join(".agents")];
249+
250+
if let Some(home_dir) = home_dir {
251+
roots.push(home_dir.join(".agents"));
252+
}
253+
254+
roots
255+
}
256+
237257
fn copilot_debug_binary_override() -> Option<String> {
238258
let override_value = std::env::var(COPILOT_BINARY_OVERRIDE_ENV).ok()?;
239259
let trimmed = override_value.trim();
@@ -298,6 +318,14 @@ mod tests {
298318
use crate::acp::client::{AvailableModel, SessionModelState, SessionModes};
299319
use serde_json::json;
300320
use std::fs;
321+
use tempfile::tempdir;
322+
323+
fn skill_file_content(name: &str, description: &str) -> String {
324+
format!(
325+
"---\nname: \"{}\"\ndescription: \"{}\"\n---\n\n# {}\n",
326+
name, description, name
327+
)
328+
}
301329

302330
#[test]
303331
fn resolve_spawn_configs_prefers_cached_binary_before_debug_override() {
@@ -405,9 +433,64 @@ mod tests {
405433
assert!(error.to_string().contains("copilot login"));
406434
}
407435

436+
#[test]
437+
fn copilot_agent_roots_prioritize_project_before_home() {
438+
let roots = copilot_agent_roots(Path::new("/repo"), Some(Path::new("/Users/tester")));
439+
440+
assert_eq!(
441+
roots,
442+
vec![
443+
PathBuf::from("/repo/.agents"),
444+
PathBuf::from("/Users/tester/.agents"),
445+
]
446+
);
447+
}
448+
449+
#[tokio::test]
450+
async fn copilot_preconnection_commands_merge_home_and_project_agents() {
451+
let temp = tempdir().expect("temp dir");
452+
let project = temp.path().join("project");
453+
let home = temp.path().join("home");
454+
455+
tokio::fs::create_dir_all(project.join(".agents/skills/systematic-debugging"))
456+
.await
457+
.expect("create project skill dir");
458+
tokio::fs::create_dir_all(home.join(".agents/skills/ce-review"))
459+
.await
460+
.expect("create home skill dir");
461+
tokio::fs::write(
462+
project.join(".agents/skills/systematic-debugging/SKILL.md"),
463+
skill_file_content(
464+
"systematic-debugging",
465+
"Project-specific systematic debugging flow",
466+
),
467+
)
468+
.await
469+
.expect("write project skill");
470+
tokio::fs::write(
471+
home.join(".agents/skills/ce-review/SKILL.md"),
472+
skill_file_content("ce-review", "Review code changes"),
473+
)
474+
.await
475+
.expect("write home skill");
476+
477+
let commands = load_copilot_preconnection_commands(&project, Some(&home))
478+
.await
479+
.expect("load commands");
480+
481+
assert_eq!(commands.len(), 2);
482+
assert_eq!(commands[0].name, "systematic-debugging");
483+
assert_eq!(
484+
commands[0].description,
485+
"Project-specific systematic debugging flow"
486+
);
487+
assert_eq!(commands[1].name, "ce-review");
488+
assert_eq!(commands[1].description, "Review code changes");
489+
}
490+
408491
#[test]
409492
fn configured_copilot_model_prefers_project_config_over_user_config() {
410-
let temp = tempfile::tempdir().expect("tempdir");
493+
let temp = tempdir().expect("tempdir");
411494
let home = temp.path().join("home");
412495
let project = temp.path().join("project");
413496
fs::create_dir_all(home.join(".copilot")).expect("create user copilot dir");

packages/desktop/src-tauri/src/acp/session_update/tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,38 @@ mod parse_tool_call_from_acp {
988988
}
989989
}
990990

991+
#[test]
992+
fn copilot_parses_edit_arguments_with_short_snake_case_keys() {
993+
let data = json!({
994+
"toolCallId": "tool-edit-short-snake",
995+
"status": "pending",
996+
"_meta": {
997+
"claudeCode": {
998+
"toolName": "Edit"
999+
}
1000+
},
1001+
"rawInput": {
1002+
"path": "/path/to/file.ts",
1003+
"old_str": "old content",
1004+
"new_str": "new content"
1005+
}
1006+
});
1007+
1008+
let result: Result<ToolCallData, serde_json::Error> = parse_tool_call_from_acp(&data);
1009+
1010+
assert!(result.is_ok());
1011+
let tool_call = result.unwrap();
1012+
match tool_call.arguments {
1013+
ToolArguments::Edit { edits } => {
1014+
let e = edits.first().expect("edit entry");
1015+
assert_eq!(e.file_path, Some("/path/to/file.ts".to_string()));
1016+
assert_eq!(e.old_string, Some("old content".to_string()));
1017+
assert_eq!(e.new_string, Some("new content".to_string()));
1018+
}
1019+
_ => panic!("Expected edit tool arguments"),
1020+
}
1021+
}
1022+
9911023
#[test]
9921024
fn parses_normalized_questions_for_ask_user_question_tool() {
9931025
let data = json!({
@@ -2289,6 +2321,37 @@ mod parse_tool_call_update_from_acp {
22892321
});
22902322
}
22912323

2324+
#[test]
2325+
fn copilot_tool_call_update_maps_short_snake_case_edit_arguments() {
2326+
with_agent(AgentType::Copilot, || {
2327+
let data = json!({
2328+
"toolCallId": "tool-copilot-edit-short-snake",
2329+
"status": "completed",
2330+
"kind": "edit",
2331+
"rawInput": {
2332+
"path": "/tmp/example.ts",
2333+
"old_str": "const value = 1;",
2334+
"new_str": "const value = 2;"
2335+
}
2336+
});
2337+
2338+
let result: Result<ToolCallUpdateData, serde_json::Error> =
2339+
parse_tool_call_update_from_acp(&data, None);
2340+
2341+
assert!(result.is_ok(), "Expected Ok, got {:?}", result);
2342+
let update = result.unwrap();
2343+
match update.arguments {
2344+
Some(ToolArguments::Edit { edits }) => {
2345+
let edit = edits.first().expect("edit entry");
2346+
assert_eq!(edit.file_path.as_deref(), Some("/tmp/example.ts"));
2347+
assert_eq!(edit.old_string.as_deref(), Some("const value = 1;"));
2348+
assert_eq!(edit.new_string.as_deref(), Some("const value = 2;"));
2349+
}
2350+
other => panic!("Expected edit tool arguments, got {:?}", other),
2351+
}
2352+
});
2353+
}
2354+
22922355
#[test]
22932356
fn copilot_tool_call_update_infers_task_arguments_without_tool_name() {
22942357
with_agent(AgentType::Copilot, || {

0 commit comments

Comments
 (0)