From ed075bf1e85e63d7cfa7e7481cda98a9024d4ea7 Mon Sep 17 00:00:00 2001 From: Ismail Pelaseyed Date: Mon, 23 Mar 2026 22:12:01 +0100 Subject: [PATCH] feat: update app UI and add changelog (#206) --- CHANGELOG.md | 57 +++++++++++++++++++++++++++ src/ui/app.tsx | 103 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a27ae2f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,57 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Changed +- Clarify terminal support and unofficial status (#204) + +### Fixed +- Mirror Telegram tool activity in TUI (#202) + +## [1.0.0-rc5] - 2026-03-23 + +### Fixed +- Only send reasoningEffort for grok-3-mini (#200) + +## [1.0.0-rc4] - 2026-03-23 + +### Added +- Support for multi-agent Grok models (#197) +- Custom sub-agents with /agents TUI and reliable interrupt (#192) +- Loading animation on streaming (#190) + +### Changed +- Clarify headless json output format + +## [1.0.0-rc3] - 2026-03-22 + +### Added +- JSON output mode for headless runs (#185) +- Test helper coverage for rewrite utilities (#184) +- Compaction (#183) +- Support for review command (#182) + +### Fixed +- Use package.json version instead of hardcoded "1.0.0" (#188) + +### Removed +- Grok.md support (#181) + +## [1.0.0-rc2] - 2026-03-20 + +### Fixed +- Lint issues (#180) + +### Changed +- Asset link in README.md +- Image source link in README.md (#179) +- Readme and version (#178) + +## [1.0.0-rc1] - 2026-03-20 + +Initial release. \ No newline at end of file diff --git a/src/ui/app.tsx b/src/ui/app.tsx index 99e0465..8b7af76 100644 --- a/src/ui/app.tsx +++ b/src/ui/app.tsx @@ -280,6 +280,8 @@ const SLASH_MENU_ITEMS: SlashMenuItem[] = [ { id: "mcp", label: "mcp", description: "Manage MCP servers" }, { id: "models", label: "models", description: "Select a model" }, { id: "new", label: "new session", description: "Start a new session" }, + { id: "commit-push", label: "commit & push", description: "Commit and push" }, + { id: "commit-pr", label: "commit & pr", description: "Commit and open PR" }, { id: "review", label: "review", description: "Review recent changes" }, { id: "skills", label: "skills", description: "Manage skills" }, ]; @@ -308,6 +310,76 @@ Code quality, naming, performance, and best-practice improvements. If none, say ## Risk Assessment Rate the overall risk of these changes as **Low**, **Medium**, or **High** with a short justification.`; +const COMMIT_PUSH_PROMPT = `Create a git commit for the current repository changes and push the current branch to its remote. + +Before committing, inspect the current branch. If it is not already a feature branch, create and switch to a new feature branch with a descriptive name based on the changes. + +Follow the repository's commit workflow and safety checks. Inspect the current changes, stage any relevant untracked files, create an appropriate commit message, and push the branch if a commit was created. If there is nothing to commit, say so and stop.`; + +const COMMIT_PR_PROMPT = `Create a git commit for the current repository changes and open a pull request for the current branch. + +Before committing, inspect the current branch. If it is not already a feature branch, create and switch to a new feature branch with a descriptive name based on the changes. + +Follow the repository's commit and pull request workflows. Inspect the current changes, stage any relevant untracked files, create an appropriate commit, push the branch if needed, then open a pull request with a concise summary and test plan. Return the pull request URL. If there is nothing to commit or open in a pull request, explain why and stop.`; + +const BUILTIN_TYPED_SLASH_COMMANDS = new Set([ + "/clear", + "/model", + "/models", + "/remote-control", + "/mcp", + "/mcps", + "/agents", + "/agent", + "/quit", + "/exit", + "/q", + "/review", + "/commit-push", + "/commit-pr", +]); + +function parseCustomSubagentSlashCommand( + cmd: string, + subagents: CustomSubagentConfig[], +): { agentName: string; prompt: string } | null { + const trimmed = cmd.trim(); + if (!trimmed.startsWith("/")) return null; + + const body = trimmed.slice(1).trim(); + if (!body) return null; + + const commandToken = body.split(/\s+/, 1)[0]?.toLowerCase(); + if (commandToken && BUILTIN_TYPED_SLASH_COMMANDS.has(`/${commandToken}`)) { + return null; + } + + const lowerBody = body.toLowerCase(); + const sortedSubagents = [...subagents].sort((a, b) => b.name.length - a.name.length); + const match = sortedSubagents.find((item) => { + const lowerName = item.name.trim().toLowerCase(); + return lowerBody === lowerName || lowerBody.startsWith(`${lowerName} `); + }); + if (!match) return null; + + return { + agentName: match.name, + prompt: body.slice(match.name.length).trim(), + }; +} + +function buildCustomSubagentSlashPrompt(agentName: string, prompt: string): string { + return `Use the custom sub-agent "${agentName}" for this task. + +Delegate the work with the \`task\` tool using: +- \`agent\`: "${agentName}" +- \`description\`: a short summary of the work +- \`prompt\`: a detailed prompt based on the user's request + +User request: +${prompt}`; +} + const CONNECT_CHANNELS: { id: string; label: string; description: string }[] = [ { id: "telegram", label: "Telegram", description: "Chat with Grok from Telegram" }, ]; @@ -1696,9 +1768,32 @@ export function App({ agent, startupConfig, initialMessage, onExit }: AppProps) processMessage(REVIEW_PROMPT); return true; } + if (c === "/commit-push") { + processMessage(COMMIT_PUSH_PROMPT); + return true; + } + if (c === "/commit-pr") { + processMessage(COMMIT_PR_PROMPT); + return true; + } + const customSubagentCommand = parseCustomSubagentSlashCommand(cmd, subAgents); + if (customSubagentCommand) { + if (!customSubagentCommand.prompt) { + setMessages((prev) => [ + ...prev, + buildAssistantEntry( + `Usage: /${customSubagentCommand.agentName} \nExample: /${customSubagentCommand.agentName} review the latest changes`, + ), + ]); + return true; + } + + processMessage(buildCustomSubagentSlashPrompt(customSubagentCommand.agentName, customSubagentCommand.prompt)); + return true; + } return false; }, - [handleExit, openAgentsModal, openMcpModal, processMessage, resetToNewSession], + [handleExit, openAgentsModal, openMcpModal, processMessage, resetToNewSession, subAgents], ); const handleSlashMenuSelect = useCallback( @@ -1750,6 +1845,12 @@ export function App({ agent, startupConfig, initialMessage, onExit }: AppProps) case "review": processMessage(REVIEW_PROMPT); break; + case "commit-push": + processMessage(COMMIT_PUSH_PROMPT); + break; + case "commit-pr": + processMessage(COMMIT_PR_PROMPT); + break; } }, [agent, handleExit, openAgentsModal, openMcpModal, processMessage, resetToNewSession],