From 4d27629010442c2c0563050cb11011bb119c6056 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Thu, 16 Oct 2025 13:55:15 -0400 Subject: [PATCH 1/3] Revert "feat: enhance goose to search sessions for easy recall (#5177)" (#5209) --- .../goose/src/agents/chat_recall_extension.rs | 352 ------------------ crates/goose/src/agents/extension.rs | 14 - crates/goose/src/agents/mod.rs | 1 - crates/goose/src/agents/platform_tools.rs | 4 +- .../goose/src/session/chat_history_search.rs | 286 -------------- crates/goose/src/session/mod.rs | 1 - crates/goose/src/session/session_manager.rs | 37 -- 7 files changed, 2 insertions(+), 693 deletions(-) delete mode 100644 crates/goose/src/agents/chat_recall_extension.rs delete mode 100644 crates/goose/src/session/chat_history_search.rs diff --git a/crates/goose/src/agents/chat_recall_extension.rs b/crates/goose/src/agents/chat_recall_extension.rs deleted file mode 100644 index b4b50534b0..0000000000 --- a/crates/goose/src/agents/chat_recall_extension.rs +++ /dev/null @@ -1,352 +0,0 @@ -use crate::agents::extension::PlatformExtensionContext; -use crate::agents::mcp_client::{Error, McpClientTrait}; -use crate::session::SessionManager; -use anyhow::Result; -use async_trait::async_trait; -use indoc::indoc; -use rmcp::model::{ - CallToolResult, Content, GetPromptResult, Implementation, InitializeResult, JsonObject, - ListPromptsResult, ListResourcesResult, ListToolsResult, ProtocolVersion, ReadResourceResult, - ServerCapabilities, ServerNotification, Tool, ToolAnnotations, ToolsCapability, -}; -use schemars::{schema_for, JsonSchema}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use tokio::sync::mpsc; -use tokio_util::sync::CancellationToken; - -pub static EXTENSION_NAME: &str = "chat_recall"; - -/// Parameters for the chat_recall tool -#[derive(Debug, Serialize, Deserialize, JsonSchema)] -struct ChatRecallParams { - /// Search keywords. Use multiple related terms/synonyms (e.g., 'database postgres sql'). Mutually exclusive with session_id. - #[serde(skip_serializing_if = "Option::is_none")] - query: Option, - /// Session ID to load. Returns first/last 3 messages. Mutually exclusive with query. - #[serde(skip_serializing_if = "Option::is_none")] - session_id: Option, - /// Max results (default: 10, max: 50). Search mode only. - #[serde(skip_serializing_if = "Option::is_none")] - limit: Option, - /// ISO 8601 date (e.g., '2025-10-01T00:00:00Z'). Search mode only. - #[serde(skip_serializing_if = "Option::is_none")] - after_date: Option, - /// ISO 8601 date (e.g., '2025-10-15T23:59:59Z'). Search mode only. - #[serde(skip_serializing_if = "Option::is_none")] - before_date: Option, -} - -pub struct ChatRecallClient { - info: InitializeResult, - context: PlatformExtensionContext, -} - -impl ChatRecallClient { - pub fn new(context: PlatformExtensionContext) -> Result { - let info = InitializeResult { - protocol_version: ProtocolVersion::V_2025_03_26, - capabilities: ServerCapabilities { - tools: Some(ToolsCapability { - list_changed: Some(false), - }), - resources: None, - prompts: None, - completions: None, - experimental: None, - logging: None, - }, - server_info: Implementation { - name: EXTENSION_NAME.to_string(), - title: Some("Chat Recall".to_string()), - version: "1.0.0".to_string(), - icons: None, - website_url: None, - }, - instructions: Some(indoc! {r#" - Chat Recall - - Search past conversations and load session summaries when the user expects some memory or context. - - Two modes: - - Search mode: Use query with keywords/synonyms to find relevant messages - - Load mode: Use session_id to get first and last messages of a specific session - "#}.to_string()), - }; - - Ok(Self { info, context }) - } - - #[allow(clippy::too_many_lines)] - async fn handle_chat_recall( - &self, - arguments: Option, - ) -> Result, String> { - let arguments = arguments.ok_or("Missing arguments")?; - - let session_id = arguments - .get("session_id") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()); - - if let Some(sid) = session_id { - // LOAD MODE: Get session summary (first and last few messages) - match SessionManager::get_session(&sid, true).await { - Ok(loaded_session) => { - let conversation = loaded_session.conversation.as_ref(); - - if conversation.is_none() { - return Ok(vec![Content::text(format!( - "Session {} has no conversation.", - sid - ))]); - } - - let msgs = conversation.unwrap().messages(); - let total = msgs.len(); - - if total == 0 { - return Ok(vec![Content::text(format!( - "Session {} has no messages.", - sid - ))]); - } - - let mut output = format!( - "Session: {} (ID: {})\nWorking Dir: {}\nTotal Messages: {}\n\n", - loaded_session.description, - sid, - loaded_session.working_dir.display(), - total - ); - - // Show first 3 messages - let first_count = std::cmp::min(3, total); - output.push_str("--- First Few Messages ---\n\n"); - for (idx, msg) in msgs.iter().take(first_count).enumerate() { - output.push_str(&format!("{}. [{:?}] ", idx + 1, msg.role)); - for content in &msg.content { - if let Some(text) = content.as_text() { - output.push_str(text); - output.push('\n'); - } - } - output.push('\n'); - } - - // Show last 3 messages (if different from first) - if total > first_count { - output.push_str("--- Last Few Messages ---\n\n"); - let last_count = std::cmp::min(3, total); - let skip_count = total.saturating_sub(last_count); - for (idx, msg) in msgs.iter().skip(skip_count).enumerate() { - output.push_str(&format!( - "{}. [{:?}] ", - skip_count + idx + 1, - msg.role - )); - for content in &msg.content { - if let Some(text) = content.as_text() { - output.push_str(text); - output.push('\n'); - } - } - output.push('\n'); - } - } - - Ok(vec![Content::text(output)]) - } - Err(e) => Err(format!("Failed to load session: {}", e)), - } - } else { - // SEARCH MODE: Search across all sessions - let query = arguments - .get("query") - .and_then(|v| v.as_str()) - .ok_or("Missing required parameter: query or session_id")? - .to_string(); - - let limit = arguments - .get("limit") - .and_then(|v| v.as_i64()) - .map(|l| l as usize) - .unwrap_or(10) - .min(50); - - let after_date = arguments - .get("after_date") - .and_then(|v| v.as_str()) - .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok()) - .map(|dt| dt.with_timezone(&chrono::Utc)); - - let before_date = arguments - .get("before_date") - .and_then(|v| v.as_str()) - .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok()) - .map(|dt| dt.with_timezone(&chrono::Utc)); - - // Exclude current session from results to avoid self-referential loops - let exclude_session_id = self.context.session_id.clone(); - - match SessionManager::search_chat_history( - &query, - Some(limit), - after_date, - before_date, - exclude_session_id, - ) - .await - { - Ok(results) => { - let formatted_results = if results.total_matches == 0 { - format!("No results found for query: '{}'", query) - } else { - let mut output = format!( - "Found {} matching message(s) across {} session(s) for query: '{}'\n\n", - results.total_matches, - results.results.len(), - query - ); - for (idx, result) in results.results.iter().enumerate() { - output.push_str(&format!( - "{}. Session: {} (ID: {})\n Working Dir: {}\n Last Activity: {}\n Showing {} of {} total message(s) in session:\n\n", - idx + 1, - result.session_description, - result.session_id, - result.session_working_dir, - result.last_activity.format("%Y-%m-%d"), - result.messages.len(), - result.total_messages_in_session - )); - - for (msg_idx, message) in result.messages.iter().enumerate() { - output.push_str(&format!( - " {}.{} [{}]\n {}\n\n", - idx + 1, - msg_idx + 1, - message.role, - message - .content - .lines() - .map(|line| format!(" {}", line)) - .collect::>() - .join("\n") - )); - } - } - output - }; - Ok(vec![Content::text(formatted_results)]) - } - Err(e) => Err(format!("Chat recall failed: {}", e)), - } - } - } - - fn get_tools() -> Vec { - // Generate JSON schema from the ChatRecallParams struct - let schema = schema_for!(ChatRecallParams); - let schema_value = - serde_json::to_value(schema).expect("Failed to serialize ChatRecallParams schema"); - - let input_schema = schema_value - .as_object() - .expect("Schema should be an object") - .clone(); - - vec![Tool::new( - "chat_recall".to_string(), - indoc! {r#" - Search past chat or load session summaries. Use when it is clear user expects some memory or context. - - search mode (query): Use multiple keywords/synonyms. Returns messages grouped by session, ordered by recency. Supports date filters. - load mode (session_id): Returns first/last 3 messages of a session. - "#} - .to_string(), - input_schema, - ) - .annotate(ToolAnnotations { - title: Some("Recall past conversations".to_string()), - read_only_hint: Some(true), - destructive_hint: Some(false), - idempotent_hint: Some(true), - open_world_hint: Some(false), - })] - } -} - -#[async_trait] -impl McpClientTrait for ChatRecallClient { - async fn list_resources( - &self, - _next_cursor: Option, - _cancellation_token: CancellationToken, - ) -> Result { - Err(Error::TransportClosed) - } - - async fn read_resource( - &self, - _uri: &str, - _cancellation_token: CancellationToken, - ) -> Result { - Err(Error::TransportClosed) - } - - async fn list_tools( - &self, - _next_cursor: Option, - _cancellation_token: CancellationToken, - ) -> Result { - Ok(ListToolsResult { - tools: Self::get_tools(), - next_cursor: None, - }) - } - - async fn call_tool( - &self, - name: &str, - arguments: Option, - _cancellation_token: CancellationToken, - ) -> Result { - let content = match name { - "chat_recall" => self.handle_chat_recall(arguments).await, - _ => Err(format!("Unknown tool: {}", name)), - }; - - match content { - Ok(content) => Ok(CallToolResult::success(content)), - Err(error) => Ok(CallToolResult::error(vec![Content::text(format!( - "Error: {}", - error - ))])), - } - } - - async fn list_prompts( - &self, - _next_cursor: Option, - _cancellation_token: CancellationToken, - ) -> Result { - Err(Error::TransportClosed) - } - - async fn get_prompt( - &self, - _name: &str, - _arguments: Value, - _cancellation_token: CancellationToken, - ) -> Result { - Err(Error::TransportClosed) - } - - async fn subscribe(&self) -> mpsc::Receiver { - mpsc::channel(1).1 - } - - fn get_info(&self) -> Option<&InitializeResult> { - Some(&self.info) - } -} diff --git a/crates/goose/src/agents/extension.rs b/crates/goose/src/agents/extension.rs index 53b808a016..0af92592c4 100644 --- a/crates/goose/src/agents/extension.rs +++ b/crates/goose/src/agents/extension.rs @@ -1,4 +1,3 @@ -use crate::agents::chat_recall_extension; use crate::agents::todo_extension; use std::collections::HashMap; @@ -50,19 +49,6 @@ pub static PLATFORM_EXTENSIONS: Lazy }, ); - map.insert( - chat_recall_extension::EXTENSION_NAME, - PlatformExtensionDef { - name: chat_recall_extension::EXTENSION_NAME, - description: - "Enable chat recall to search past conversations and load session summaries", - default_enabled: true, - client_factory: |ctx| { - Box::new(chat_recall_extension::ChatRecallClient::new(ctx).unwrap()) - }, - }, - ); - map }); diff --git a/crates/goose/src/agents/mod.rs b/crates/goose/src/agents/mod.rs index 54e5550610..23dabbb8b0 100644 --- a/crates/goose/src/agents/mod.rs +++ b/crates/goose/src/agents/mod.rs @@ -1,5 +1,4 @@ mod agent; -pub(crate) mod chat_recall_extension; pub mod extension; pub mod extension_malware_check; pub mod extension_manager; diff --git a/crates/goose/src/agents/platform_tools.rs b/crates/goose/src/agents/platform_tools.rs index 544c1a12a9..bdebac8ed9 100644 --- a/crates/goose/src/agents/platform_tools.rs +++ b/crates/goose/src/agents/platform_tools.rs @@ -116,11 +116,11 @@ pub fn manage_schedule_tool() -> Tool { PLATFORM_MANAGE_SCHEDULE_TOOL_NAME.to_string(), indoc! {r#" Manage scheduled recipe execution for this goose instance. - + Actions: - "list": List all scheduled jobs - "create": Create a new scheduled job from a recipe file - - "run_now": Execute a scheduled job immediately + - "run_now": Execute a scheduled job immediately - "pause": Pause a scheduled job - "unpause": Resume a paused job - "delete": Remove a scheduled job diff --git a/crates/goose/src/session/chat_history_search.rs b/crates/goose/src/session/chat_history_search.rs deleted file mode 100644 index f3436701ee..0000000000 --- a/crates/goose/src/session/chat_history_search.rs +++ /dev/null @@ -1,286 +0,0 @@ -use crate::conversation::message::MessageContent; -use anyhow::Result; -use chrono::{DateTime, Utc}; -use serde::Serialize; -use sqlx::{Pool, Sqlite}; -use std::collections::HashMap; - -#[derive(Debug, Clone, Serialize)] -pub struct ChatRecallResult { - pub session_id: String, - pub session_description: String, - pub session_working_dir: String, - pub last_activity: DateTime, - pub total_messages_in_session: usize, - pub messages: Vec, -} - -#[derive(Debug, Clone, Serialize)] -pub struct ChatRecallMessage { - pub role: String, - pub content: String, - pub timestamp: DateTime, -} - -#[derive(Debug, Serialize)] -pub struct ChatRecallResults { - pub results: Vec, - pub total_matches: usize, -} - -type SqlQueryRow = ( - String, - String, - String, - DateTime, - String, - String, - DateTime, -); - -type SessionMessageGroup = ( - String, - String, - DateTime, - Vec<(String, String, DateTime)>, -); - -pub struct ChatHistorySearch<'a> { - pool: &'a Pool, - query: &'a str, - limit: usize, - after_date: Option>, - before_date: Option>, - exclude_session_id: Option, -} - -impl<'a> ChatHistorySearch<'a> { - pub fn new( - pool: &'a Pool, - query: &'a str, - limit: Option, - after_date: Option>, - before_date: Option>, - exclude_session_id: Option, - ) -> Self { - Self { - pool, - query, - limit: limit.unwrap_or(10), - after_date, - before_date, - exclude_session_id, - } - } - - pub async fn execute(self) -> Result { - let keywords = self.parse_keywords(); - if keywords.is_empty() { - return Ok(ChatRecallResults { - results: vec![], - total_matches: 0, - }); - } - - let rows = self.fetch_rows(&keywords).await?; - let session_messages = self.process_rows(rows); - let session_totals = self.get_session_totals(&session_messages).await?; - let results = self.convert_to_results(session_messages, session_totals); - - Ok(results) - } - - async fn fetch_rows(&self, keywords: &[String]) -> Result> { - let sql = self.build_sql(keywords); - let mut query_builder = sqlx::query_as::<_, SqlQueryRow>(&sql); - - for keyword in keywords { - query_builder = query_builder.bind(keyword); - } - - if let Some(exclude_id) = &self.exclude_session_id { - query_builder = query_builder.bind(exclude_id); - } - - if let Some(after) = self.after_date { - query_builder = query_builder.bind(after); - } - if let Some(before) = self.before_date { - query_builder = query_builder.bind(before); - } - - query_builder = query_builder.bind(self.limit as i64); - - Ok(query_builder.fetch_all(self.pool).await?) - } - - fn parse_keywords(&self) -> Vec { - self.query - .split_whitespace() - .map(|word| format!("%{}%", word.to_lowercase())) - .collect() - } - - fn build_sql(&self, keywords: &[String]) -> String { - let mut sql = String::from( - r#" - SELECT - s.id as session_id, - s.description as session_description, - s.working_dir as session_working_dir, - s.created_at as session_created_at, - m.role, - m.content_json, - m.timestamp - FROM messages m - INNER JOIN sessions s ON m.session_id = s.id - WHERE EXISTS ( - SELECT 1 FROM json_each(m.content_json) - WHERE json_extract(value, '$.type') = 'text' - AND ( - "#, - ); - - for (i, _) in keywords.iter().enumerate() { - if i > 0 { - sql.push_str(" OR "); - } - sql.push_str("LOWER(json_extract(value, '$.text')) LIKE ?"); - } - - sql.push_str( - r#" - ) - ) - "#, - ); - - if self.exclude_session_id.is_some() { - sql.push_str(" AND s.id != ?"); - } - - if self.after_date.is_some() { - sql.push_str(" AND m.timestamp >= ?"); - } - if self.before_date.is_some() { - sql.push_str(" AND m.timestamp <= ?"); - } - - sql.push_str(" ORDER BY m.timestamp DESC LIMIT ?"); - - sql - } - - fn process_rows(&self, rows: Vec) -> HashMap { - let mut session_messages: HashMap = HashMap::new(); - - for ( - session_id, - session_description, - session_working_dir, - session_created_at, - role, - content_json, - timestamp, - ) in rows - { - if let Ok(content_vec) = serde_json::from_str::>(&content_json) { - let text_parts = Self::extract_text_content(content_vec); - - if !text_parts.is_empty() { - let entry = session_messages.entry(session_id.clone()).or_insert(( - session_description.clone(), - session_working_dir.clone(), - session_created_at, - Vec::new(), - )); - entry - .3 - .push((role.clone(), text_parts.join("\n"), timestamp)); - } - } - } - - session_messages - } - - fn extract_text_content(content_vec: Vec) -> Vec { - content_vec - .into_iter() - .filter_map(|content| match content { - MessageContent::Text(ref tc) => Some(tc.text.clone()), - MessageContent::ToolRequest(ref tr) => { - Some(format!("[Tool: {}]", tr.to_readable_string())) - } - MessageContent::ToolResponse(_) => Some("[Tool Response]".to_string()), - MessageContent::Thinking(ref t) => Some(format!("[Thinking: {}]", t.thinking)), - _ => None, - }) - .collect() - } - - async fn get_session_totals( - &self, - session_messages: &HashMap, - ) -> Result> { - let mut session_totals: HashMap = HashMap::new(); - for session_id in session_messages.keys() { - let count: i64 = - sqlx::query_scalar("SELECT COUNT(*) FROM messages WHERE session_id = ?") - .bind(session_id) - .fetch_one(self.pool) - .await - .unwrap_or(0); - session_totals.insert(session_id.clone(), count as usize); - } - Ok(session_totals) - } - - fn convert_to_results( - &self, - session_messages: HashMap, - session_totals: HashMap, - ) -> ChatRecallResults { - let mut results: Vec = session_messages - .into_iter() - .map( - |(session_id, (description, working_dir, _created_at, messages))| { - let message_vec: Vec = messages - .into_iter() - .map(|(role, content, timestamp)| ChatRecallMessage { - role, - content, - timestamp, - }) - .collect(); - - let last_activity = message_vec - .iter() - .map(|m| m.timestamp) - .max() - .unwrap_or_else(chrono::Utc::now); - - let total_messages_in_session = - session_totals.get(&session_id).copied().unwrap_or(0); - - ChatRecallResult { - session_id, - session_description: description, - session_working_dir: working_dir, - last_activity, - total_messages_in_session, - messages: message_vec, - } - }, - ) - .collect(); - - results.sort_by(|a, b| b.last_activity.cmp(&a.last_activity)); - - let total_matches = results.iter().map(|r| r.messages.len()).sum(); - ChatRecallResults { - results, - total_matches, - } - } -} diff --git a/crates/goose/src/session/mod.rs b/crates/goose/src/session/mod.rs index 879c057d2c..221f89d70b 100644 --- a/crates/goose/src/session/mod.rs +++ b/crates/goose/src/session/mod.rs @@ -1,4 +1,3 @@ -mod chat_history_search; pub mod extension_data; mod legacy; pub mod session_manager; diff --git a/crates/goose/src/session/session_manager.rs b/crates/goose/src/session/session_manager.rs index e4b0f70456..0002d4199a 100644 --- a/crates/goose/src/session/session_manager.rs +++ b/crates/goose/src/session/session_manager.rs @@ -69,8 +69,6 @@ pub struct SessionInsights { total_tokens: i64, } -pub type SessionId = String; - impl SessionUpdateBuilder { fn new(session_id: String) -> Self { Self { @@ -243,19 +241,6 @@ impl SessionManager { Ok(()) } } - - pub async fn search_chat_history( - query: &str, - limit: Option, - after_date: Option>, - before_date: Option>, - exclude_session_id: Option, - ) -> Result { - Self::instance() - .await? - .search_chat_history(query, limit, after_date, before_date, exclude_session_id) - .await - } } pub struct SessionStorage { @@ -980,28 +965,6 @@ impl SessionStorage { self.get_session(&session.id, true).await } - - async fn search_chat_history( - &self, - query: &str, - limit: Option, - after_date: Option>, - before_date: Option>, - exclude_session_id: Option, - ) -> Result { - use crate::session::chat_history_search::ChatHistorySearch; - - ChatHistorySearch::new( - &self.pool, - query, - limit, - after_date, - before_date, - exclude_session_id, - ) - .execute() - .await - } } #[cfg(test)] From b48a7ffd2981e20afef607ba7e23c1fa27126a3a Mon Sep 17 00:00:00 2001 From: Arya Pratap Singh Date: Fri, 17 Oct 2025 01:02:05 +0530 Subject: [PATCH 2/3] feat: add Code Documentation Generator recipe (#5121) (#5125) Signed-off-by: Arya Pratap Singh --- .../recipes/code-documentation-generator.yaml | 302 ++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 documentation/src/pages/recipes/data/recipes/code-documentation-generator.yaml diff --git a/documentation/src/pages/recipes/data/recipes/code-documentation-generator.yaml b/documentation/src/pages/recipes/data/recipes/code-documentation-generator.yaml new file mode 100644 index 0000000000..b4d0b6d01e --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/code-documentation-generator.yaml @@ -0,0 +1,302 @@ +version: 1.0.0 +title: Code Documentation Generator +description: Automatically generates comprehensive documentation for codebases by analyzing source files, extracting APIs, and creating formatted documentation with examples and best practices +author: + contact: ARYPROGRAMMER + +activities: + - Scan and analyze source code files in the project + - Extract functions, classes, methods, and their signatures + - Generate documentation with descriptions and usage examples + - Create API reference documentation with type information + - Build interactive documentation with cross-references + - Store documentation patterns in repository files for consistency + +prompt: | + You are a Code Documentation Generator that creates comprehensive, well-structured documentation for codebases. + Your goal is to analyze source code, extract relevant information, and generate clear, helpful documentation. + + Key capabilities: + - Analyze code structure and extract documentable elements + - Generate consistent documentation following best practices + - Create usage examples and code snippets + - Build cross-referenced documentation with links + - Store project-specific documentation styles in repository files + - Research documentation standards for the detected language + + IMPORTANT: Always detect the programming language first and apply language-specific documentation standards. + +parameters: + - key: source_path + input_type: string + requirement: optional + default: "." + description: "Path to the source code directory or specific file to document" + + - key: doc_format + input_type: string + requirement: optional + default: "html" + description: "Documentation format: 'markdown', 'html', 'restructuredtext', 'javadoc', 'jsdoc'" + + - key: include_examples + input_type: string + requirement: optional + default: "true" + description: "Whether to generate usage examples for documented items (true/false)" + + - key: output_location + input_type: string + requirement: optional + default: "./docs" + description: "Directory where documentation files will be saved" + + - key: doc_style + input_type: string + requirement: optional + default: "comprehensive" + description: "Documentation style: 'minimal' (brief descriptions), 'standard' (descriptions + params), 'comprehensive' (full with examples and cross-refs)" + + - key: language_hint + input_type: string + requirement: optional + default: "" + description: "Optional: specify programming language if auto-detection is insufficient (e.g., 'python', 'javascript', 'rust', 'go')" + +extensions: + - type: builtin + name: developer + display_name: Developer + timeout: 600 + bundled: true + description: For file operations, code analysis, and documentation generation + + - type: builtin + name: browser + display_name: Browser + timeout: 300 + bundled: true + description: For researching documentation standards and best practices + +settings: + temperature: 0.3 + +instructions: | + Generate comprehensive documentation for the codebase with the following configuration: + - Source Path: {{ source_path }} + - Documentation Format: {{ doc_format }} + - Include Examples: {{ include_examples }} + - Output Location: {{ output_location }} + - Documentation Style: {{ doc_style }} + {% if language_hint %} + - Language Hint: {{ language_hint }} + {% endif %} + + Follow this workflow: + + ## Phase 1: Project Analysis and Setup + + 1. **Analyze the codebase structure:** + - Navigate to {{ source_path }} + - Identify all source code files (common extensions: .py, .js, .ts, .rs, .go, .java, .cpp, .rb, etc.) + - {% if language_hint %}Focus on {{ language_hint }} files{% else %}Detect the primary programming language(s){% endif %} + - Map the project structure (modules, packages, components) + + 2. **Check for existing documentation:** + - Look for existing doc files, READMEs, or inline documentation + - Check if there are documentation standards already in use + - Check for `.goosehints`, `AGENTS.md`, or `DOCS_GUIDELINES.md` files with documentation preferences + - If documentation already exists, analyze it to maintain consistency in style and format + - Preserve existing documentation structure while filling in gaps for undocumented items + - Extract inline docstrings/comments to use as foundation for generated documentation + + 3. **Research documentation standards:** + - Use the browser to look up the standard documentation format for the detected language + - For Python: Look for PEP 257 docstring conventions and Sphinx documentation + - For JavaScript/TypeScript: Look for JSDoc standards + - For Rust: Look for rustdoc conventions + - For Go: Look for godoc conventions + - Check if `.goosehints` or `AGENTS.md` already exists and use those guidelines if present + - If no local guidelines exist, prepare to create them based on detected language standards + + ## Phase 2: Code Analysis and Extraction + + 4. **Extract documentable elements:** + For each source file, identify and extract: + - **Functions/Methods:** + * Name and signature + * Parameters with types (if available) + * Return type + * Existing comments or docstrings + * Purpose based on implementation analysis + * Cyclomatic complexity level (simple: 1-5 branches, moderate: 6-10, complex: 11+) + + - **Classes/Structs/Types:** + * Name and inheritance/implementation + * Constructor/initialization + * Properties/fields + * Methods + * Usage patterns + + - **Constants and Variables:** + * Public constants + * Configuration variables + * Exported values + + - **Modules/Packages:** + * Module purpose (inferred from: exported functions, file name, directory structure, and existing comments) + * Exported interfaces + * Dependencies + * Note: If purpose cannot be confidently determined, use placeholder like "TODO: Add module description" and flag for manual review + + 5. **Analyze code context:** + - Understand the purpose of each code element from its implementation + - Identify input/output patterns + - Note error handling and edge cases + - Recognize common design patterns used + + ## Phase 3: Documentation Generation + + 6. **Create documentation structure:** + - Create {{ output_location }} directory if it doesn't exist + - Organize documentation by module/package structure + - Create an index/table of contents file + + 7. **Generate documentation for each element:** + + {% if doc_style == "minimal" %} + For minimal style, include: + - Brief one-line description + - Function/method signature + - Parameter list + {% elif doc_style == "standard" %} + For standard style, include: + - Clear description of purpose + - Full parameter documentation with types and descriptions + - Return value documentation + - Basic usage information + {% else %} + For comprehensive style, include: + - Detailed description of purpose and behavior + - Complete parameter documentation with types, descriptions, and constraints + - Return value documentation with possible values + - Exceptions/errors that may be raised + {% if include_examples == "true" %} + - Usage examples demonstrating common scenarios + - Code snippets showing best practices + {% endif %} + - Links to related functions/classes + - Notes on performance, thread-safety, or other important considerations + {% endif %} + + 8. **Format documentation:** + {% if doc_format == "markdown" %} + - Use Markdown formatting with proper headers (##, ###) + - Create code blocks with language-specific syntax highlighting + - Use tables for parameter lists + - Add hyperlinks using [text](#anchor) for internal links and [text](file.md#section) for cross-file references + - Create anchor links using header IDs (e.g., ## Function Name creates #function-name anchor) + {% elif doc_format == "html" %} + - Generate valid HTML5 documentation + - Include CSS styling for readability + - Add navigation links using tags + - Create searchable index + {% elif doc_format == "restructuredtext" %} + - Use reStructuredText formatting + - Proper directive usage for code blocks + - Cross-reference using :ref:`label` and :doc:`filename` + - Use :py:func:`module.function` for Python cross-references + {% elif doc_format == "javadoc" or doc_format == "jsdoc" %} + - Generate language-specific doc comments + - Use @param, @return, @throws tags + - Include @example tags for usage + - Use @see and @link for cross-references + {% endif %} + + {% if include_examples == "true" %} + 9. **Generate usage examples:** + For each documented function/class: + - Generate synthetic but realistic usage examples that demonstrate the API + - Show input data and expected output based on the function's signature and implementation + - Demonstrate error handling where applicable + - Include edge cases where relevant + - Mark examples clearly as "Example Usage" or "Code Example" + - Ensure examples use the actual function signatures from the codebase + - If you find actual usage in test files or other parts of the codebase, you may reference or adapt those patterns + - Keep examples simple and focused on demonstrating the specific functionality + {% endif %} + + ## Phase 4: Cross-Referencing and Index + + 10. **Build cross-references:** + {% if doc_format == "markdown" %} + - Link related functions and classes using [FunctionName](#functionname) format + - Create "See Also" sections with links to related documentation + - Build dependency graphs showing relationships + - Add links from examples back to detailed docs using relative paths + {% elif doc_format == "html" %} + - Link related functions and classes using tags + - Create "See Also" sections + - Build dependency graphs showing relationships + - Add links from examples back to detailed docs + {% elif doc_format == "restructuredtext" %} + - Use :ref:`label` for internal references + - Use :doc:`filename` for cross-file references + - Create "See Also" sections with proper reST directives + {% else %} + - Use format-appropriate linking mechanisms + - Create "See Also" sections + - Build relationship documentation + {% endif %} + + 11. **Generate documentation index:** + - Create a master index file (index.md, index.html, etc.) + - Organize by module/package + - Add search functionality hints + - Include quick reference table + - Add getting started guide if this is new documentation + + ## Phase 5: Quality Check and Finalization + + 12. **Review generated documentation:** + - Check for completeness (all public APIs documented) + - Verify example code correctness + - Ensure consistent formatting + - Validate all cross-references work + - Check for typos and grammar issues + + 13. **Save documentation patterns:** + - Create or update `.goosehints` file in {{ source_path }} with documentation preferences + - Store documentation style, format preferences, and project-specific conventions + - Include example patterns that worked well + - Consider updating `AGENTS.md` with documentation standards for team reference + - Optionally create `DOCS_GUIDELINES.md` with detailed documentation style guide + + 14. **Generate summary report:** + - List all files documented + - Count of functions, classes, and modules documented + - Location of generated documentation + - Suggestions for improving source code documentation + - Any warnings or issues encountered + + ## Best Practices to Follow: + + - **Clarity:** Use clear, simple language avoiding jargon when possible + - **Consistency:** Maintain consistent format and style throughout + - **Accuracy:** Ensure documentation matches actual code behavior + - **Completeness:** Document all public APIs and exported elements + - **Examples:** Provide practical, real-world usage examples + - **Maintenance:** Note any areas where code comments should be added + + ## Output Format: + + Provide a clear summary including: + 1. Number of files analyzed + 2. Number of elements documented (functions, classes, etc.) + 3. Location of generated documentation files + 4. Quick preview of the documentation structure + 5. Suggestions for improving inline code documentation + 6. Confirmation that documentation guidelines have been saved to `.goosehints` or `AGENTS.md` + + **Note**: Documentation preferences and patterns are stored in repository files (`.goosehints`, `AGENTS.md`, or `DOCS_GUIDELINES.md`) rather than memory to avoid cluttering the LLM context on unrelated tasks. + From f0da14bff820db6595acce9421a8284f37ba1118 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:11:30 -0700 Subject: [PATCH 3/3] fix: revert built app name to uppercase Goose (#5206) --- .github/workflows/bundle-desktop-intel.yml | 20 +++++----- .github/workflows/bundle-desktop-linux.yml | 6 +-- .github/workflows/bundle-desktop-windows.yml | 40 +++++++++---------- .github/workflows/bundle-desktop.yml | 20 +++++----- .github/workflows/canary.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/pr-comment-bundle-intel.yml | 4 +- .../workflows/pr-comment-bundle-windows.yml | 6 +-- .github/workflows/pr-comment-bundle.yml | 4 +- .github/workflows/release-branches.yml | 2 +- .github/workflows/release.yml | 4 +- .../components/MacDesktopInstallButtons.js | 4 +- .../WindowsDesktopInstallButtons.js | 2 +- ui/desktop/forge.config.ts | 8 ++-- ui/desktop/package.json | 12 +++--- ui/desktop/src/utils/githubUpdater.ts | 8 ++-- 16 files changed, 72 insertions(+), 72 deletions(-) diff --git a/.github/workflows/bundle-desktop-intel.yml b/.github/workflows/bundle-desktop-intel.yml index db88b7bac3..6c0c14a481 100644 --- a/.github/workflows/bundle-desktop-intel.yml +++ b/.github/workflows/bundle-desktop-intel.yml @@ -192,10 +192,10 @@ jobs: source_job_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" unsigned_url="s3://block-goose-artifacts-bucket-production/unsigned/goose-${GITHUB_SHA}-${{ github.run_id }}-intel.zip" - zip -q -u -r out/goose-darwin-x64/goose_intel_mac.zip entitlements.plist + zip -q -u -r out/Goose-darwin-x64/Goose_intel_mac.zip entitlements.plist # upload unsigned goose to transfer bucket so it can be passed to lambda - aws s3 cp --quiet out/goose-darwin-x64/goose_intel_mac.zip "${unsigned_url}" + aws s3 cp --quiet out/Goose-darwin-x64/Goose_intel_mac.zip "${unsigned_url}" # begin signing echo "🚀 launching signing process" @@ -247,7 +247,7 @@ jobs: # download the signed app from S3 echo "⬇️ downloading signed app" - aws s3 cp --quiet "${signed_url}" out/goose-darwin-x64/goose_intel_mac.zip + aws s3 cp --quiet "${signed_url}" out/Goose-darwin-x64/Goose_intel_mac.zip working-directory: ui/desktop - name: Final cleanup before artifact upload @@ -261,26 +261,26 @@ jobs: - name: Upload Desktop artifact uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # pin@v4 with: - name: goose-darwin-x64 - path: ui/desktop/out/goose-darwin-x64/goose_intel_mac.zip + name: Goose-darwin-x64 + path: ui/desktop/out/Goose-darwin-x64/Goose_intel_mac.zip - name: Quick launch test (macOS) if: ${{ inputs.quick_test }} run: | # Ensure no quarantine attributes (if needed) - xattr -cr "ui/desktop/out/goose-darwin-x64/goose.app" - echo "Opening goose.app..." - open -g "ui/desktop/out/goose-darwin-x64/goose.app" + xattr -cr "ui/desktop/out/Goose-darwin-x64/Goose.app" + echo "Opening Goose.app..." + open -g "ui/desktop/out/Goose-darwin-x64/Goose.app" # Give the app a few seconds to start and write logs sleep 5 # Check if it's running - if pgrep -f "goose.app/Contents/MacOS/goose" > /dev/null; then + if pgrep -f "Goose.app/Contents/MacOS/Goose" > /dev/null; then echo "App appears to be running." else echo "App did not stay open. Possible crash or startup error." exit 1 fi # Kill the app to clean up - pkill -f "goose.app/Contents/MacOS/goose" + pkill -f "Goose.app/Contents/MacOS/Goose" diff --git a/.github/workflows/bundle-desktop-linux.yml b/.github/workflows/bundle-desktop-linux.yml index 4ff6ee2ab5..bcd384b013 100644 --- a/.github/workflows/bundle-desktop-linux.yml +++ b/.github/workflows/bundle-desktop-linux.yml @@ -180,21 +180,21 @@ jobs: - name: Upload .deb package uses: actions/upload-artifact@v4 with: - name: goose-linux-x64-deb + name: Goose-linux-x64-deb path: ui/desktop/out/make/deb/x64/*.deb if-no-files-found: error - name: Upload .rpm package uses: actions/upload-artifact@v4 with: - name: goose-linux-x64-rpm + name: Goose-linux-x64-rpm path: ui/desktop/out/make/rpm/x64/*.rpm if-no-files-found: error - name: Upload combined Linux packages uses: actions/upload-artifact@v4 with: - name: goose-linux-x64 + name: Goose-linux-x64 path: | ui/desktop/out/make/deb/x64/*.deb ui/desktop/out/make/rpm/x64/*.rpm diff --git a/.github/workflows/bundle-desktop-windows.yml b/.github/workflows/bundle-desktop-windows.yml index e10c19bfcc..fb23ba1675 100644 --- a/.github/workflows/bundle-desktop-windows.yml +++ b/.github/workflows/bundle-desktop-windows.yml @@ -284,12 +284,12 @@ jobs: - name: Copy exe/dll to final out folder and prepare flat distribution run: | cd ui/desktop - mkdir -p ./out/goose-win32-x64/resources/bin - rsync -av src/bin/ out/goose-win32-x64/resources/bin/ + mkdir -p ./out/Goose-win32-x64/resources/bin + rsync -av src/bin/ out/Goose-win32-x64/resources/bin/ # Create flat distribution structure mkdir -p ./dist-windows - cp -r ./out/goose-win32-x64/* ./dist-windows/ + cp -r ./out/Goose-win32-x64/* ./dist-windows/ # Verify the final structure echo "📋 Final flat distribution structure:" @@ -318,8 +318,8 @@ jobs: wget -q https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar -O jsign.jar echo "05ca18d4ab7b8c2183289b5378d32860f0ea0f3bdab1f1b8cae5894fb225fa8a jsign.jar" | sha256sum -c - # Sign the main Electron executable (goose.exe) - echo "🔐 Signing main Electron executable: goose.exe" + # Sign the main Electron executable (Goose.exe) + echo "🔐 Signing main Electron executable: Goose.exe" cd ui/desktop/dist-windows/ java -jar ${GITHUB_WORKSPACE}/jsign.jar \ @@ -329,12 +329,12 @@ jobs: --alias windows-codesign \ --certfile "${GITHUB_WORKSPACE}/block-codesign-cert.pem" \ --tsaurl "http://timestamp.digicert.com" \ - --name "goose" \ + --name "Goose" \ --url "https://github.com/block/goose" \ - "goose.exe" + "Goose.exe" - osslsigncode verify goose.exe - echo "✅ Main executable goose.exe signed successfully" + osslsigncode verify Goose.exe + echo "✅ Main executable Goose.exe signed successfully" # Sign the backend executable (goosed.exe) echo "🔐 Signing backend executable: goosed.exe" @@ -347,7 +347,7 @@ jobs: --alias windows-codesign \ --certfile "${GITHUB_WORKSPACE}/block-codesign-cert.pem" \ --tsaurl "http://timestamp.digicert.com" \ - --name "goose Backend" \ + --name "Goose Backend" \ --url "https://github.com/block/goose" \ "goosed.exe" @@ -357,8 +357,8 @@ jobs: # Show final file status echo "📋 Final signed files:" cd ../../ - ls -la goose.exe - sha256sum goose.exe + ls -la Goose.exe + sha256sum Goose.exe ls -la resources/bin/goosed.exe sha256sum resources/bin/goosed.exe @@ -371,8 +371,8 @@ jobs: run: | echo "📋 Verifying both signed executables in final distribution:" echo "Main executable:" - ls -la ui/desktop/dist-windows/goose.exe - osslsigncode verify ui/desktop/dist-windows/goose.exe + ls -la ui/desktop/dist-windows/Goose.exe + osslsigncode verify ui/desktop/dist-windows/Goose.exe echo "✅ Main executable signature verification passed" echo "Backend executable:" @@ -387,18 +387,18 @@ jobs: echo "📦 Creating Windows zip package..." # Create a zip file from the dist-windows directory - zip -r "goose-win32-x64.zip" dist-windows/ + zip -r "Goose-win32-x64.zip" dist-windows/ echo "✅ Windows zip package created:" - ls -la goose-win32-x64.zip + ls -la Goose-win32-x64.zip # Also create the zip in the expected output structure for consistency - mkdir -p out/goose-win32-x64/ - cp goose-win32-x64.zip out/goose-win32-x64/ + mkdir -p out/Goose-win32-x64/ + cp Goose-win32-x64.zip out/Goose-win32-x64/ # 11) Upload the final Windows build - name: Upload Windows build artifacts uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # pin@v4 with: - name: goose-win32-x64 - path: ui/desktop/out/goose-win32-x64/goose-win32-x64.zip + name: Goose-win32-x64 + path: ui/desktop/out/Goose-win32-x64/Goose-win32-x64.zip diff --git a/.github/workflows/bundle-desktop.yml b/.github/workflows/bundle-desktop.yml index 308bcd1cbe..e371de2426 100644 --- a/.github/workflows/bundle-desktop.yml +++ b/.github/workflows/bundle-desktop.yml @@ -226,10 +226,10 @@ jobs: source_job_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" unsigned_url="s3://block-goose-artifacts-bucket-production/unsigned/goose-${GITHUB_SHA}-${{ github.run_id }}-arm64.zip" - zip -q -u -r out/goose-darwin-arm64/goose.zip entitlements.plist + zip -q -u -r out/Goose-darwin-arm64/Goose.zip entitlements.plist # upload unsigned goose to transfer bucket so it can be passed to lambda - aws s3 cp --quiet out/goose-darwin-arm64/goose.zip "${unsigned_url}" + aws s3 cp --quiet out/Goose-darwin-arm64/Goose.zip "${unsigned_url}" # begin signing echo "🚀 launching signing process" @@ -281,7 +281,7 @@ jobs: # download the signed app from S3 echo "⬇️ downloading signed app" - aws s3 cp --quiet "${signed_url}" out/goose-darwin-arm64/goose.zip + aws s3 cp --quiet "${signed_url}" out/Goose-darwin-arm64/Goose.zip working-directory: ui/desktop - name: Final cleanup before artifact upload @@ -296,26 +296,26 @@ jobs: id: upload-app-bundle uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # pin@v4 with: - name: goose-darwin-arm64 - path: ui/desktop/out/goose-darwin-arm64/goose.zip + name: Goose-darwin-arm64 + path: ui/desktop/out/Goose-darwin-arm64/Goose.zip - name: Quick launch test (macOS) if: ${{ inputs.quick_test }} run: | # Ensure no quarantine attributes (if needed) - xattr -cr "ui/desktop/out/goose-darwin-arm64/goose.app" - echo "Opening goose.app..." - open -g "ui/desktop/out/goose-darwin-arm64/goose.app" + xattr -cr "ui/desktop/out/Goose-darwin-arm64/Goose.app" + echo "Opening Goose.app..." + open -g "ui/desktop/out/Goose-darwin-arm64/Goose.app" # Give the app a few seconds to start and write logs sleep 5 # Check if it's running - if pgrep -f "goose.app/Contents/MacOS/goose" > /dev/null; then + if pgrep -f "Goose.app/Contents/MacOS/Goose" > /dev/null; then echo "App appears to be running." else echo "App did not stay open. Possible crash or startup error." exit 1 fi # Kill the app to clean up - pkill -f "goose.app/Contents/MacOS/goose" \ No newline at end of file + pkill -f "Goose.app/Contents/MacOS/Goose" \ No newline at end of file diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 46ac740acb..25a416e3f1 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -116,7 +116,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} artifacts: | goose-*.tar.bz2 - goose*.zip + Goose*.zip *.deb *.rpm download_cli.sh diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 58e2d31aae..78a36b6aeb 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -118,7 +118,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} artifacts: | goose-*.tar.bz2 - goose*.zip + Goose*.zip *.deb *.rpm download_cli.sh diff --git a/.github/workflows/pr-comment-bundle-intel.yml b/.github/workflows/pr-comment-bundle-intel.yml index c30c9495ca..e908c1a2f4 100644 --- a/.github/workflows/pr-comment-bundle-intel.yml +++ b/.github/workflows/pr-comment-bundle-intel.yml @@ -81,7 +81,7 @@ jobs: - name: Download Intel artifact uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # pin@v4 with: - name: goose-darwin-x64 + name: Goose-darwin-x64 path: intel-dist - name: Comment on PR with Intel download link @@ -91,7 +91,7 @@ jobs: body: | ### macOS Intel Desktop App (x64) - [💻 Download macOS Desktop App (Intel x64, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/goose-darwin-x64.zip) + [💻 Download macOS Desktop App (Intel x64, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-darwin-x64.zip) **Instructions:** After downloading, unzip the file and drag the goose.app to your Applications folder. The app is signed and notarized for macOS. diff --git a/.github/workflows/pr-comment-bundle-windows.yml b/.github/workflows/pr-comment-bundle-windows.yml index 63f2636991..182f1d304d 100644 --- a/.github/workflows/pr-comment-bundle-windows.yml +++ b/.github/workflows/pr-comment-bundle-windows.yml @@ -82,7 +82,7 @@ jobs: - name: Download Windows artifact uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # pin@v4 with: - name: desktop-windows-dist + name: Goose-win32-x64 path: windows-dist - name: Comment on PR with Windows download link @@ -92,9 +92,9 @@ jobs: body: | ### Windows Desktop App - [🪟 Download Windows Desktop App (x64, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/desktop-windows-dist.zip) + [🪟 Download Windows Desktop App (x64, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-win32-x64.zip) **Instructions:** - After downloading, unzip the file and run goose.exe. The app is signed for Windows. + After downloading, unzip the file and run Goose.exe. The app is signed for Windows. This link is provided by nightly.link and will work even if you're not logged into GitHub. diff --git a/.github/workflows/pr-comment-bundle.yml b/.github/workflows/pr-comment-bundle.yml index 3325f93cf7..48de6bd8e3 100644 --- a/.github/workflows/pr-comment-bundle.yml +++ b/.github/workflows/pr-comment-bundle.yml @@ -123,7 +123,7 @@ jobs: - name: Download ARM64 artifact uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # pin@v4 with: - name: goose-darwin-arm64 + name: Goose-darwin-arm64 path: arm64-dist - name: Comment on PR with ARM64 download link @@ -133,7 +133,7 @@ jobs: body: | ### macOS ARM64 Desktop App (Apple Silicon) - [📱 Download macOS Desktop App (arm64, unsigned)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/goose-darwin-arm64.zip) + [📱 Download macOS Desktop App (arm64, unsigned)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-darwin-arm64.zip) **Instructions:** After downloading, unzip the file and drag the goose.app to a location you prefer. The app is unsigned, so to run it run `xattr -r -d com.apple.quarantine '/path/to/goose.app'` and then open the app \ No newline at end of file diff --git a/.github/workflows/release-branches.yml b/.github/workflows/release-branches.yml index 73eb91a1ef..c3f0c13735 100644 --- a/.github/workflows/release-branches.yml +++ b/.github/workflows/release-branches.yml @@ -24,7 +24,7 @@ jobs: body: | ### macOS ARM64 Desktop App (Apple Silicon) - [📱 Download macOS Desktop App (arm64, unsigned)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/goose-darwin-arm64.zip) + [📱 Download macOS Desktop App (arm64, unsigned)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-darwin-arm64.zip) **Instructions:** After downloading, unzip the file and drag the goose.app to a location you prefer. The app is unsigned, so to run it run `xattr -r -d com.apple.quarantine '/path/to/goose.app'` and then open the app diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2cd9e26351..e2b7c90652 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,7 +105,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} artifacts: | goose-*.tar.bz2 - goose*.zip + Goose*.zip *.deb *.rpm download_cli.sh @@ -122,7 +122,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} artifacts: | goose-*.tar.bz2 - goose*.zip + Goose*.zip *.deb *.rpm download_cli.sh diff --git a/documentation/src/components/MacDesktopInstallButtons.js b/documentation/src/components/MacDesktopInstallButtons.js index 96dff23a0d..e9aae272b1 100644 --- a/documentation/src/components/MacDesktopInstallButtons.js +++ b/documentation/src/components/MacDesktopInstallButtons.js @@ -8,13 +8,13 @@ const DesktopInstallButtons = () => {
macOS Silicon macOS Intel diff --git a/documentation/src/components/WindowsDesktopInstallButtons.js b/documentation/src/components/WindowsDesktopInstallButtons.js index 2364fbe6df..f33cf5f243 100644 --- a/documentation/src/components/WindowsDesktopInstallButtons.js +++ b/documentation/src/components/WindowsDesktopInstallButtons.js @@ -8,7 +8,7 @@ const WindowsDesktopInstallButtons = () => {
Windows diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts index 557f8cd4ad..34c91dfb82 100644 --- a/ui/desktop/forge.config.ts +++ b/ui/desktop/forge.config.ts @@ -65,8 +65,8 @@ module.exports = { { name: '@electron-forge/maker-deb', config: { - name: 'goose', - bin: 'goose', + name: 'Goose', + bin: 'Goose', maintainer: 'Block, Inc.', homepage: 'https://block.github.io/goose/', categories: ['Development'], @@ -79,8 +79,8 @@ module.exports = { { name: '@electron-forge/maker-rpm', config: { - name: 'goose', - bin: 'goose', + name: 'Goose', + bin: 'Goose', maintainer: 'Block, Inc.', homepage: 'https://block.github.io/goose/', categories: ['Development'], diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 4d64a7b4be..1f249af156 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -1,8 +1,8 @@ { "name": "goose-app", - "productName": "goose", + "productName": "Goose", "version": "1.9.0", - "description": "goose App", + "description": "Goose App", "engines": { "node": "^22.17.1" }, @@ -16,11 +16,11 @@ "start:test-error": "GOOSE_TEST_ERROR=true electron-forge start", "package": "electron-forge package", "make": "electron-forge make", - "bundle:default": "node scripts/prepare-platform-binaries.js && npm run make && (cd out/goose-darwin-arm64 && ditto -c -k --sequesterRsrc --keepParent goose.app goose.zip) || echo 'out/goose-darwin-arm64 not found; either the binary is not built or you are not on macOS'", - "bundle:alpha": "ALPHA=true node scripts/prepare-platform-binaries.js && ALPHA=true npm run make && (cd out/goose-darwin-arm64 && ditto -c -k --sequesterRsrc --keepParent goose.app goose_alpha.zip) || echo 'out/goose-darwin-arm64 not found; either the binary is not built or you are not on macOS'", + "bundle:default": "node scripts/prepare-platform-binaries.js && npm run make && (cd out/Goose-darwin-arm64 && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose.zip) || echo 'out/Goose-darwin-arm64 not found; either the binary is not built or you are not on macOS'", + "bundle:alpha": "ALPHA=true node scripts/prepare-platform-binaries.js && ALPHA=true npm run make && (cd out/Goose-darwin-arm64 && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose_alpha.zip) || echo 'out/Goose-darwin-arm64 not found; either the binary is not built or you are not on macOS'", "bundle:windows": "node scripts/build-main.js && ELECTRON_PLATFORM=win32 node scripts/prepare-platform-binaries.js && npm run make -- --platform=win32 --arch=x64", - "bundle:intel": "node scripts/prepare-platform-binaries.js && npm run make -- --arch=x64 && cd out/goose-darwin-x64 && ditto -c -k --sequesterRsrc --keepParent goose.app goose_intel_mac.zip", - "debug": "echo 'run --remote-debugging-port=8315' && lldb out/goose-darwin-arm64/goose.app", + "bundle:intel": "node scripts/prepare-platform-binaries.js && npm run make -- --arch=x64 && cd out/Goose-darwin-x64 && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose_intel_mac.zip", + "debug": "echo 'run --remote-debugging-port=8315' && lldb out/Goose-darwin-arm64/Goose.app", "test-e2e": "npm run generate-api && playwright test", "test-e2e:dev": "npm run generate-api && playwright test --reporter=list --retries=0 --max-failures=1", "test-e2e:ui": "npm run generate-api && playwright test --ui", diff --git a/ui/desktop/src/utils/githubUpdater.ts b/ui/desktop/src/utils/githubUpdater.ts index ec5b7f95b1..4516a2aee4 100644 --- a/ui/desktop/src/utils/githubUpdater.ts +++ b/ui/desktop/src/utils/githubUpdater.ts @@ -91,16 +91,16 @@ export class GitHubUpdater { if (platform === 'darwin') { // macOS if (arch === 'arm64') { - assetName = 'goose.zip'; + assetName = 'Goose.zip'; } else { - assetName = 'goose_intel_mac.zip'; + assetName = 'Goose_intel_mac.zip'; } } else if (platform === 'win32') { // Windows - for future support - assetName = 'goose-win32-x64.zip'; + assetName = 'Goose-win32-x64.zip'; } else { // Linux - for future support - assetName = `goose-linux-${arch}.zip`; + assetName = `Goose-linux-${arch}.zip`; } log.info(`GitHubUpdater: Looking for asset named: ${assetName}`);