Skip to content

Commit 86eac13

Browse files
authored
Merge pull request #9 from sopaco/v2
V2
2 parents a7ecba2 + 68e6e80 commit 86eac13

Some content is hidden

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

44 files changed

+10478
-11799
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ Cowork Forge's specialized agents work together like a real development team:
116116
- <strong>Coding Loop Agent</strong>: Plans and executes code changes with actor-critic refinement
117117
- <strong>Check Agent</strong>: Verifies code quality and completeness
118118
- <strong>Delivery Agent</strong>: Generates comprehensive delivery reports
119-
- <strong>Modify Agent</strong>: Analyzes and handles incremental change requests
120-
- <strong>Code Patch Agent</strong>: Implements precise code patches
119+
- <strong>Change Triage Agent</strong>: Analyzes and triages incremental change requests
120+
- <strong>Code Patch Agent</strong>: Implements precise code patches for modifications
121121
- <strong>Modify Delivery Agent</strong>: Generates modification delivery reports
122122

123123
### 3. Human-in-the-Loop Validation
@@ -227,7 +227,7 @@ graph TB
227227
Manages session lifecycle, stage dependencies, and workflow execution with support for full and partial pipeline assembly.
228228

229229
### AI Agents
230-
Specialized agents work collaboratively, each responsible for a specific stage of the development lifecycle. Four agents (PRD, Design, Plan, Coding) use actor-critic loop patterns for iterative refinement with human feedback. Includes: Idea, PRD, Design, Plan, Coding, Check, Delivery, Modify, CodePatch, ModifyDelivery.
230+
Specialized agents work collaboratively, each responsible for a specific stage of the development lifecycle. Four agents (PRD, Design, Plan, Coding) use actor-critic loop patterns for iterative refinement with human feedback. Includes: Idea, PRD, Design, Plan, Coding, Check, Delivery, Change Triage, Code Patch, Modify Delivery.
231231

232232
### Instruction Templates
233233
Provides specialized prompt templates for each agent, defining their behavior and output format.

README_zh.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ Cowork Forge 的专业智能体像真实开发团队一样协同工作:
125125
- <strong>Coding Loop Agent</strong>: 使用演员-评论家模式规划和执行代码变更
126126
- <strong>Check Agent</strong>: 验证代码质量和完整性
127127
- <strong>Delivery Agent</strong>: 生成全面的交付报告
128-
- <strong>Modify Agent</strong>: 分析和处理增量修改请求
128+
- <strong>Change Triage Agent</strong>: 分析和分流增量修改请求
129129
- <strong>Code Patch Agent</strong>: 实施精准的代码补丁
130130
- <strong>Modify Delivery Agent</strong>: 生成修改交付报告
131131

@@ -237,7 +237,7 @@ graph TB
237237
管理会话生命周期、阶段依赖和工作流执行,支持完整流程和部分流程的灵活组装。
238238

239239
### AI 智能体
240-
专业智能体协同工作,每个负责开发生命周期的特定阶段。其中 4 个智能体(PRD、设计、规划、编码)使用演员-评论家循环模式进行迭代优化和人类反馈整合。包括:Idea、PRD、Design、Plan、Coding、Check、Delivery、Modify、CodePatch、ModifyDelivery
240+
专业智能体协同工作,每个负责开发生命周期的特定阶段。其中 4 个智能体(PRD、设计、规划、编码)使用演员-评论家循环模式进行迭代优化和人类反馈整合。包括:Idea、PRD、Design、Plan、Coding、Check、Delivery、Change Triage、Code Patch、Modify Delivery
241241

242242
### 提示词模板
243243
为每个智能体提供专门的指令模板,定义其行为和输出格式。

crates/cowork-core/src/instructions/code_patch.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ You have access to:
2929
- `list_files` - See current project structure
3030
- `read_file` - Read existing files
3131
- `write_file` - Create or modify files
32+
- `delete_file` - Delete a file
33+
- `delete_directory` - Delete a directory and all its contents
3234
- `run_command` - Run build/test commands (avoid long-running servers!)
3335
- `update_task_status` - Mark tasks as completed
3436
- `update_feature_status` - Mark features as completed
@@ -43,13 +45,22 @@ You have access to:
4345
- **Prefer modifying existing files** over creating new ones
4446
- Keep changes minimal and focused
4547
- Follow existing code style and patterns
48+
- **Delete deprecated files** using `delete_file` when removing features
4649
5. Test changes if possible (run build, but DON'T start servers)
4750
4851
### For Changes Requiring New Components:
4952
1. Create new files following project structure
5053
2. Update existing files to integrate the new component
5154
3. Follow the design spec for architecture
5255
56+
### For Removing Features:
57+
1. Use `list_files` to identify files related to the feature
58+
2. Read files to confirm they're safe to delete
59+
3. Use `delete_file` to remove individual files
60+
4. Use `delete_directory` to remove entire directories (e.g., old components)
61+
5. Update imports/references in other files
62+
6. Test to ensure no broken references remain
63+
5364
## Guidelines
5465
5566
- **Incremental changes**: Modify existing code when possible, don't rewrite everything

crates/cowork-core/src/pipeline/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,8 @@ pub fn create_modify_pipeline(
266266
vec![
267267
("triage".to_string(), agents[0].clone()),
268268
("patch".to_string(), agents[1].clone()),
269-
("code".to_string(), agents[2].clone()),
270-
("check".to_string(), agents[3].clone()),
271-
("delivery".to_string(), agents[4].clone()),
269+
("check".to_string(), agents[2].clone()),
270+
("delivery".to_string(), agents[3].clone()),
272271
],
273272
);
274273

@@ -327,6 +326,8 @@ fn create_code_patch_agent(
327326
.tool(Arc::new(ListFilesTool))
328327
.tool(Arc::new(ReadFileTool))
329328
.tool(Arc::new(WriteFileTool))
329+
.tool(Arc::new(DeleteFileTool))
330+
.tool(Arc::new(DeleteDirectoryTool))
330331
.tool(Arc::new(RunCommandTool))
331332
.tool(Arc::new(UpdateTaskStatusTool::new(session.clone())))
332333
.tool(Arc::new(UpdateFeatureStatusTool::new(session.clone())))

crates/cowork-core/src/tools/file_tools.rs

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ fn validate_path_security(path: &str) -> Result<PathBuf, String> {
3939
let current_dir = std::env::current_dir()
4040
.map_err(|e| format!("Failed to get current directory: {}", e))?;
4141

42+
// Normalize current_dir for consistent comparison (handle UNC paths on Windows)
43+
// On Windows, canonicalize() may return \\?\ prefix paths
44+
let normalized_current_dir = current_dir.canonicalize()
45+
.unwrap_or_else(|_| current_dir.clone());
46+
4247
let full_path = current_dir.join(path);
4348

4449
// Canonicalize if path exists, otherwise just check the constructed path
@@ -51,11 +56,13 @@ fn validate_path_security(path: &str) -> Result<PathBuf, String> {
5156
};
5257

5358
// Verify the path is within current directory
54-
if !canonical_path.starts_with(&current_dir) {
59+
// Use normalized paths for comparison to handle Windows UNC path prefixes
60+
if !canonical_path.starts_with(&normalized_current_dir) {
5561
return Err(format!(
56-
"Security: Path escapes current directory. Path '{}' resolves to '{}'",
62+
"Security: Path escapes current directory. Path '{}' resolves to '{}', expected to be within '{}'",
5763
path,
58-
canonical_path.display()
64+
canonical_path.display(),
65+
normalized_current_dir.display()
5966
));
6067
}
6168

@@ -486,3 +493,163 @@ impl Tool for RunCommandTool {
486493
}
487494
}
488495
}
496+
497+
// ============================================================================
498+
// DeleteFileTool
499+
// ============================================================================
500+
501+
pub struct DeleteFileTool;
502+
503+
#[async_trait]
504+
impl Tool for DeleteFileTool {
505+
fn name(&self) -> &str {
506+
"delete_file"
507+
}
508+
509+
fn description(&self) -> &str {
510+
"Delete a file from the project. \
511+
SECURITY: Only works within current directory. \
512+
Useful for removing deprecated or unused files during iterative changes."
513+
}
514+
515+
fn parameters_schema(&self) -> Option<Value> {
516+
Some(json!({
517+
"type": "object",
518+
"properties": {
519+
"path": {
520+
"type": "string",
521+
"description": "File path to delete (must be relative path within current directory)"
522+
}
523+
},
524+
"required": ["path"]
525+
}))
526+
}
527+
528+
async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> adk_core::Result<Value> {
529+
let path = args["path"].as_str().unwrap();
530+
531+
// Security check
532+
let safe_path = match validate_path_security(path) {
533+
Ok(p) => p,
534+
Err(e) => {
535+
return Ok(json!({
536+
"status": "security_error",
537+
"message": e
538+
}));
539+
}
540+
};
541+
542+
// Check if file exists
543+
if !safe_path.exists() {
544+
return Ok(json!({
545+
"status": "not_found",
546+
"message": format!("File not found: {}", path)
547+
}));
548+
}
549+
550+
// Check if it's a directory (we only delete files, not directories)
551+
if safe_path.is_dir() {
552+
return Ok(json!({
553+
"status": "error",
554+
"message": format!("Path '{}' is a directory. Use delete_directory for directories.", path)
555+
}));
556+
}
557+
558+
// Delete the file
559+
match fs::remove_file(&safe_path) {
560+
Ok(_) => {
561+
// Log file deletion for user visibility
562+
println!("🗑️ Deleted file: {}", path);
563+
Ok(json!({
564+
"status": "success",
565+
"path": path,
566+
"message": format!("File '{}' deleted successfully", path)
567+
}))
568+
},
569+
Err(e) => Ok(json!({
570+
"status": "error",
571+
"message": format!("Failed to delete file: {}", e)
572+
})),
573+
}
574+
}
575+
}
576+
577+
// ============================================================================
578+
// DeleteDirectoryTool
579+
// ============================================================================
580+
581+
pub struct DeleteDirectoryTool;
582+
583+
#[async_trait]
584+
impl Tool for DeleteDirectoryTool {
585+
fn name(&self) -> &str {
586+
"delete_directory"
587+
}
588+
589+
fn description(&self) -> &str {
590+
"Delete a directory and all its contents recursively. \
591+
SECURITY: Only works within current directory. \
592+
WARNING: This operation is irreversible! Use with caution."
593+
}
594+
595+
fn parameters_schema(&self) -> Option<Value> {
596+
Some(json!({
597+
"type": "object",
598+
"properties": {
599+
"path": {
600+
"type": "string",
601+
"description": "Directory path to delete (must be relative path within current directory)"
602+
}
603+
},
604+
"required": ["path"]
605+
}))
606+
}
607+
608+
async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> adk_core::Result<Value> {
609+
let path = args["path"].as_str().unwrap();
610+
611+
// Security check
612+
let safe_path = match validate_path_security(path) {
613+
Ok(p) => p,
614+
Err(e) => {
615+
return Ok(json!({
616+
"status": "security_error",
617+
"message": e
618+
}));
619+
}
620+
};
621+
622+
// Check if directory exists
623+
if !safe_path.exists() {
624+
return Ok(json!({
625+
"status": "not_found",
626+
"message": format!("Directory not found: {}", path)
627+
}));
628+
}
629+
630+
// Check if it's actually a directory
631+
if !safe_path.is_dir() {
632+
return Ok(json!({
633+
"status": "error",
634+
"message": format!("Path '{}' is a file. Use delete_file for files.", path)
635+
}));
636+
}
637+
638+
// Delete the directory recursively
639+
match fs::remove_dir_all(&safe_path) {
640+
Ok(_) => {
641+
// Log directory deletion for user visibility
642+
println!("🗑️ Deleted directory: {}", path);
643+
Ok(json!({
644+
"status": "success",
645+
"path": path,
646+
"message": format!("Directory '{}' and all its contents deleted successfully", path)
647+
}))
648+
},
649+
Err(e) => Ok(json!({
650+
"status": "error",
651+
"message": format!("Failed to delete directory: {}", e)
652+
})),
653+
}
654+
}
655+
}

0 commit comments

Comments
 (0)