diff --git a/src/apps/desktop/src/computer_use/ui_locate_common.rs b/src/apps/desktop/src/computer_use/ui_locate_common.rs index 55a755e6..af8dbdec 100644 --- a/src/apps/desktop/src/computer_use/ui_locate_common.rs +++ b/src/apps/desktop/src/computer_use/ui_locate_common.rs @@ -274,6 +274,7 @@ mod tests { } /// Whether an element's global bounds fall within any visible display. +#[allow(dead_code)] pub fn is_element_on_screen(gx: f64, gy: f64, width: f64, height: f64) -> bool { // Element must have reasonable size (not a giant container) if width > 3000.0 || height > 2000.0 { diff --git a/src/apps/desktop/src/lib.rs b/src/apps/desktop/src/lib.rs index 4110d00e..3780f50b 100644 --- a/src/apps/desktop/src/lib.rs +++ b/src/apps/desktop/src/lib.rs @@ -138,6 +138,9 @@ pub async fn run() { .level_for("ignore", log::LevelFilter::Off) .level_for("ignore::walk", log::LevelFilter::Off) .level_for("globset", log::LevelFilter::Off) + .level_for("tracing", log::LevelFilter::Off) + .level_for("opentelemetry_sdk", log::LevelFilter::Off) + .level_for("opentelemetry-otlp", log::LevelFilter::Off) .level_for("hyper_util", log::LevelFilter::Info) .level_for("h2", log::LevelFilter::Info) .level_for("portable_pty", log::LevelFilter::Info) diff --git a/src/crates/core/src/agentic/agents/init_agent.rs b/src/crates/core/src/agentic/agents/init_agent.rs new file mode 100644 index 00000000..3cb946c3 --- /dev/null +++ b/src/crates/core/src/agentic/agents/init_agent.rs @@ -0,0 +1,53 @@ +use super::Agent; +use async_trait::async_trait; + +pub struct InitAgent { + default_tools: Vec, +} + +impl InitAgent { + pub fn new() -> Self { + Self { + default_tools: vec![ + "LS".to_string(), + "Read".to_string(), + "Grep".to_string(), + "Glob".to_string(), + "Write".to_string(), + "Edit".to_string(), + "Bash".to_string(), + ], + } + } +} + +#[async_trait] +impl Agent for InitAgent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn id(&self) -> &str { + "Init" + } + + fn name(&self) -> &str { + "Init" + } + + fn description(&self) -> &str { + "Agent for /init command" + } + + fn prompt_template_name(&self, _model_name: Option<&str>) -> &str { + "init_agent" + } + + fn default_tools(&self) -> Vec { + self.default_tools.clone() + } + + fn is_readonly(&self) -> bool { + false + } +} diff --git a/src/crates/core/src/agentic/agents/mod.rs b/src/crates/core/src/agentic/agents/mod.rs index 1d506639..37e7ebb0 100644 --- a/src/crates/core/src/agentic/agents/mod.rs +++ b/src/crates/core/src/agentic/agents/mod.rs @@ -17,6 +17,7 @@ mod file_finder_agent; // Hidden agents mod code_review_agent; mod generate_doc_agent; +mod init_agent; use crate::util::errors::{BitFunError, BitFunResult}; pub use agentic_mode::AgenticMode; @@ -29,6 +30,7 @@ pub use debug_mode::DebugMode; pub use explore_agent::ExploreAgent; pub use file_finder_agent::FileFinderAgent; pub use generate_doc_agent::GenerateDocAgent; +pub use init_agent::InitAgent; pub use plan_mode::PlanMode; pub use prompt_builder::{PromptBuilder, PromptBuilderContext, RemoteExecutionHints}; pub use registry::{ diff --git a/src/crates/core/src/agentic/agents/prompts/init_agent.md b/src/crates/core/src/agentic/agents/prompts/init_agent.md new file mode 100644 index 00000000..7903c1f6 --- /dev/null +++ b/src/crates/core/src/agentic/agents/prompts/init_agent.md @@ -0,0 +1,18 @@ +Please analyze this codebase and generate the content of an AGENTS.md file, which will be given to future instances of coding agents to operate in this repository. + +What to add: +1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test. +2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the "big picture" architecture that requires reading multiple files to understand. + +Usage notes: +- "AGENTS.md", "CLAUDE.md", and ".github/copilot-instructions.md" serves the same purpose. If these files already exist, suggest improvements to them. +- When you make the initial AGENTS.md, do not repeat yourself and do not include obvious instructions like "Provide helpful error messages to users", "Write unit tests for all new utilities", "Never include sensitive information (API keys, tokens) in code or commits". +- Avoid listing every component or file structure that can be easily discovered. +- Don't include generic development practices. +- If there are Cursor rules (in .cursor/rules/ or .cursorrules), make sure to include the important parts. +- If there is a README.md, make sure to include the important parts. +- Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read. + +{LANGUAGE_PREFERENCE} +{ENV_INFO} +{PROJECT_LAYOUT} \ No newline at end of file diff --git a/src/crates/core/src/agentic/agents/registry.rs b/src/crates/core/src/agentic/agents/registry.rs index 3775b102..78a9ef5e 100644 --- a/src/crates/core/src/agentic/agents/registry.rs +++ b/src/crates/core/src/agentic/agents/registry.rs @@ -1,6 +1,6 @@ use super::{ Agent, AgenticMode, ClawMode, CodeReviewAgent, CoworkMode, DebugMode, ExploreAgent, - FileFinderAgent, GenerateDocAgent, PlanMode, + FileFinderAgent, GenerateDocAgent, InitAgent, PlanMode, }; use crate::agentic::agents::custom_subagents::{ CustomSubagent, CustomSubagentKind, CustomSubagentLoader, @@ -271,6 +271,7 @@ impl AgentRegistry { let hidden_subagents: Vec> = vec![ Arc::new(CodeReviewAgent::new()), Arc::new(GenerateDocAgent::new()), + Arc::new(InitAgent::new()), ]; for hidden_agent in hidden_subagents { register(&mut agents, hidden_agent, AgentCategory::Hidden, None); diff --git a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx index ff5a4526..0957acb0 100644 --- a/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx +++ b/src/web-ui/src/app/components/NavPanel/sections/workspaces/WorkspaceItem.tsx @@ -1,8 +1,9 @@ import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; -import { Folder, FolderOpen, MoreHorizontal, GitBranch, FolderSearch, Plus, ChevronDown, Trash2, RotateCcw, Copy } from 'lucide-react'; +import { Folder, FolderOpen, MoreHorizontal, GitBranch, FolderSearch, Plus, ChevronDown, Trash2, RotateCcw, Copy, FileText } from 'lucide-react'; import { ConfirmDialog, Tooltip } from '@/component-library'; import { useI18n } from '@/infrastructure/i18n'; +import { i18nService } from '@/infrastructure/i18n'; import { useWorkspaceContext } from '@/infrastructure/contexts/WorkspaceContext'; import { createWorktreeWorkspace, @@ -285,6 +286,41 @@ const WorkspaceItem: React.FC = ({ void handleCreateSession('Cowork'); }, [handleCreateSession]); + const handleCreateInitSession = useCallback(async () => { + setMenuOpen(false); + + try { + const sessionId = await flowChatManager.createChatSession( + { + workspacePath: workspace.rootPath, + ...(isRemoteWorkspace(workspace) && workspace.connectionId + ? { remoteConnectionId: workspace.connectionId } + : {}), + ...(isRemoteWorkspace(workspace) && workspace.sshHost + ? { remoteSshHost: workspace.sshHost } + : {}), + }, + 'Init' + ); + + await openMainSession(sessionId, { + workspaceId: workspace.id, + activateWorkspace: setActiveWorkspace, + }); + + const initPrompt = i18nService.t('flow-chat:chatInput.initPrompt', { + defaultValue: 'Please generate or update AGENTS.md so it matches the current project. Write it in English and keep the English version complete.', + }); + + await flowChatManager.sendMessage(initPrompt, sessionId, initPrompt, 'Init'); + } catch (error) { + notificationService.error( + error instanceof Error ? error.message : t('nav.workspaces.initSessionFailed'), + { duration: 4000 } + ); + } + }, [setActiveWorkspace, t, workspace]); + const handleCreateWorktree = useCallback(async (result: BranchSelectResult) => { try { const created = await createWorktreeWorkspace({ @@ -609,6 +645,10 @@ const WorkspaceItem: React.FC = ({ {t('nav.sessions.newCoworkSessionShort')} + {isLinkedWorktree ? (