From 9baddeef18c8fa5e1ab8ad53a634554e0a044310 Mon Sep 17 00:00:00 2001 From: rob Date: Sat, 17 Jan 2026 06:27:23 -0400 Subject: [PATCH] Add Help menu and contextual tooltips to GUI - Add Help menu with quick guides: Getting Started, Create Tool, Install Tools, Publish Tools, Keyboard Shortcuts, About - F1 shortcut opens Getting Started guide - Add tooltips to Tool Builder section headings (Arguments, Steps, Output Template) that appear on hover over the label text - Add tooltips to Registry page controls (search, filters, pagination) - Enhance sidebar tooltips with keyboard shortcuts Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 12 + src/cmdforge/gui/dialogs/help_dialogs.py | 363 ++++++++++++++++++++ src/cmdforge/gui/main_window.py | 99 +++++- src/cmdforge/gui/pages/registry_page.py | 11 + src/cmdforge/gui/pages/tool_builder_page.py | 65 +++- src/cmdforge/gui/styles.py | 6 + 6 files changed, 540 insertions(+), 16 deletions(-) create mode 100644 src/cmdforge/gui/dialogs/help_dialogs.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c107f55..9b8d77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,18 @@ All notable changes to CmdForge will be documented in this file. - Automatically clears invalid/revoked tokens - Shows status bar message when connection is cleared - Prevents confusing errors when trying to publish with stale credentials +- **Help menu and quick guides**: Added Help menu with documentation guides + - Getting Started guide with quick start steps and keyboard shortcuts + - How to Create a Tool guide with step-by-step instructions + - How to Install Tools guide for registry browsing + - How to Publish Tools guide for sharing tools + - Keyboard Shortcuts reference + - About CmdForge dialog + - F1 shortcut opens Getting Started guide +- **Enhanced tooltips**: Added contextual tooltips throughout the GUI + - Section headings in Tool Builder (Arguments, Steps, Output Template) + - Registry page controls (search, filters, pagination, install) + - Sidebar navigation items with keyboard shortcuts #### CLI Features - `cmdforge config disconnect` - Clear registry token from local configuration diff --git a/src/cmdforge/gui/dialogs/help_dialogs.py b/src/cmdforge/gui/dialogs/help_dialogs.py new file mode 100644 index 0000000..b070052 --- /dev/null +++ b/src/cmdforge/gui/dialogs/help_dialogs.py @@ -0,0 +1,363 @@ +"""Help dialogs for CmdForge GUI.""" + +from PySide6.QtWidgets import ( + QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, + QTextBrowser +) +from PySide6.QtCore import Qt + + +# Help content for quick guides +HELP_CONTENT = { + "getting_started": { + "title": "Getting Started with CmdForge", + "content": """ +

Welcome to CmdForge!

+

CmdForge lets you create AI-powered command-line tools that work like any Unix command.

+ +

Quick Start Steps:

+
    +
  1. Configure a Provider - Go to Providers in the sidebar and add an AI backend (like Claude or GPT). This is required before running AI tools.
  2. +
  3. Browse the Registry - Check out the Registry to discover tools shared by the community.
  4. +
  5. Install Tools - Click on any tool and hit Install to add it to your system.
  6. +
  7. Create Your Own - Use the Tool Builder to create custom AI-powered commands.
  8. +
  9. Use in Terminal - Run your tools like any command: my-tool < input.txt
  10. +
+ +

Key Concepts:

+ + +

Keyboard Shortcuts:

+ + + + + + + +
Ctrl+NCreate new tool
Ctrl+SSave current tool
Ctrl+RRefresh current page
Ctrl+1-4Navigate to pages
Ctrl+QQuit
EscapeClose tool builder
+""" + }, + "create_tool": { + "title": "How to Create a Tool", + "content": """ +

Creating a New Tool

+ +

Step 1: Start the Tool Builder

+

Click Create Tool on the Welcome page, or press Ctrl+N from anywhere.

+ +

Step 2: Fill in Basic Info

+ + +

Step 3: Add Arguments (Optional)

+

Arguments let users customize tool behavior:

+ + +

Step 4: Add Steps

+

Steps define what your tool does:

+ + +

Step 5: Set Output Template

+

The output template defines what your tool prints. Use {variable} to include step outputs.

+

Example: {response} prints the last AI response.

+ +

Step 6: Save

+

Press Ctrl+S or click Save. Your tool is now available as a command!

+ +

Example: Simple Summarizer

+
+Name: summarize
+Steps:
+  1. Prompt [claude] -> response
+     "Summarize this text: {input}"
+Output: {response}
+
+

Run it: echo "Long text..." | summarize

+""" + }, + "install_tools": { + "title": "How to Install Tools", + "content": """ +

Installing Tools from the Registry

+ +

Step 1: Open the Registry

+

Click Registry in the sidebar to browse community tools.

+ +

Step 2: Find a Tool

+ + +

Step 3: Review Tool Details

+

Click on a tool to see:

+ + +

Step 4: Install

+ + +

Step 5: Use the Tool

+

Installed tools are available immediately in your terminal:

+
+echo "text" | tool-name
+cat file.txt | tool-name --flag value
+tool-name --help
+
+ +

Updates

+

Tools with available updates show a green arrow () in the list. Click Update to get the latest version.

+ +

Managing Installed Tools

+

Go to Tools in the sidebar to see all your installed tools, edit them, or delete ones you no longer need.

+""" + }, + "publish_tools": { + "title": "How to Publish Tools", + "content": """ +

Publishing Your Tools

+ +

Prerequisites

+ + +

Step 1: Connect Your Account

+
    +
  1. Go to the Providers page
  2. +
  3. Click Connect to Registry
  4. +
  5. Log in or register
  6. +
+ +

Step 2: Prepare Your Tool

+ + +

Step 3: Publish

+
    +
  1. Go to the Tools page
  2. +
  3. Select the tool you want to publish
  4. +
  5. Click Publish
  6. +
  7. Add tags to help users find it
  8. +
  9. Set the initial version number
  10. +
  11. Click Submit
  12. +
+ +

Versioning

+

When you update a published tool:

+ + +

Best Practices

+ +""" + }, + "keyboard_shortcuts": { + "title": "Keyboard Shortcuts", + "content": """ +

Keyboard Shortcuts

+ +

Global

+ + + + + + +
Ctrl+NCreate new tool
Ctrl+SSave current tool
Ctrl+RRefresh current page
Ctrl+QQuit application
F1Show help
+ +

Navigation

+ + + + + +
Ctrl+1Go to Welcome page
Ctrl+2Go to Tools page
Ctrl+3Go to Registry page
Ctrl+4Go to Providers page
+ +

Tool Builder

+ + + +
EscapeClose builder / cancel
Ctrl+SSave tool
+ +

Lists and Tables

+ + + +
Double-clickEdit selected item
Drag & DropReorder steps
+""" + } +} + + +class QuickGuideDialog(QDialog): + """Dialog showing a quick guide on a topic.""" + + def __init__(self, guide_key: str, parent=None): + super().__init__(parent) + + guide = HELP_CONTENT.get(guide_key, {}) + self.setWindowTitle(guide.get("title", "Help")) + self.setMinimumSize(550, 450) + self.resize(600, 500) + self.setModal(True) + + self._setup_ui(guide) + + def _setup_ui(self, guide: dict): + """Set up the dialog UI.""" + layout = QVBoxLayout(self) + layout.setContentsMargins(24, 24, 24, 24) + layout.setSpacing(16) + + # Content browser with styled HTML + browser = QTextBrowser() + browser.setOpenExternalLinks(True) + browser.setStyleSheet(""" + QTextBrowser { + border: none; + background-color: transparent; + font-size: 13px; + } + """) + + # Build styled content + content = f""" + + {guide.get("content", "")} + """ + browser.setHtml(content) + layout.addWidget(browser, 1) + + # Close button + btn_layout = QHBoxLayout() + btn_layout.addStretch() + + btn_close = QPushButton("Close") + btn_close.setMinimumWidth(100) + btn_close.clicked.connect(self.accept) + btn_layout.addWidget(btn_close) + + layout.addLayout(btn_layout) + + +class AboutDialog(QDialog): + """About CmdForge dialog.""" + + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("About CmdForge") + self.setFixedSize(400, 300) + self.setModal(True) + self._setup_ui() + + def _setup_ui(self): + """Set up the dialog UI.""" + layout = QVBoxLayout(self) + layout.setContentsMargins(32, 32, 32, 32) + layout.setSpacing(16) + + # Logo/title + title = QLabel("CmdForge") + title.setStyleSheet(""" + font-size: 32px; + font-weight: bold; + color: #667eea; + """) + title.setAlignment(Qt.AlignCenter) + layout.addWidget(title) + + # Tagline + tagline = QLabel("AI-Powered CLI Tool Builder") + tagline.setStyleSheet("font-size: 14px; color: #718096;") + tagline.setAlignment(Qt.AlignCenter) + layout.addWidget(tagline) + + layout.addSpacing(16) + + # Version info + try: + from cmdforge import __version__ + version = __version__ + except ImportError: + version = "unknown" + + version_label = QLabel(f"Version {version}") + version_label.setStyleSheet("color: #4a5568;") + version_label.setAlignment(Qt.AlignCenter) + layout.addWidget(version_label) + + # Description + desc = QLabel( + "Create custom terminal commands that call AI providers,\n" + "chain prompts with Python code, and use them like\n" + "any Unix pipe command." + ) + desc.setStyleSheet("color: #718096; font-size: 12px;") + desc.setAlignment(Qt.AlignCenter) + layout.addWidget(desc) + + layout.addStretch() + + # Links + links = QLabel( + 'Website' + ) + links.setOpenExternalLinks(True) + links.setAlignment(Qt.AlignCenter) + layout.addWidget(links) + + # Close button + btn_close = QPushButton("Close") + btn_close.clicked.connect(self.accept) + layout.addWidget(btn_close) diff --git a/src/cmdforge/gui/main_window.py b/src/cmdforge/gui/main_window.py index 2b1ed03..9840bd5 100644 --- a/src/cmdforge/gui/main_window.py +++ b/src/cmdforge/gui/main_window.py @@ -3,10 +3,10 @@ from PySide6.QtWidgets import ( QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QListWidget, QListWidgetItem, QStackedWidget, - QStatusBar, QLabel, QSplitter + QStatusBar, QLabel, QSplitter, QMenuBar, QMenu ) from PySide6.QtCore import Qt, QSize, QSettings, QTimer -from PySide6.QtGui import QIcon, QFont, QShortcut, QKeySequence +from PySide6.QtGui import QIcon, QFont, QShortcut, QKeySequence, QAction from .styles import STYLESHEET @@ -65,6 +65,9 @@ class MainWindow(QMainWindow): # Setup keyboard shortcuts self._setup_shortcuts() + # Setup menu bar + self._setup_menu_bar() + # Restore window geometry self._restore_geometry() @@ -98,11 +101,11 @@ class MainWindow(QMainWindow): def _setup_sidebar(self): """Set up sidebar navigation items.""" items = [ - ("CmdForge", "Welcome to CmdForge"), - ("Tools", "Manage your tools"), - ("Registry", "Browse and install tools"), - ("Providers", "Configure AI providers"), - ("Profiles", "AI persona profiles"), + ("CmdForge", "Welcome page - Quick actions and getting started (Ctrl+1)"), + ("Tools", "View, edit, delete, and test your local tools (Ctrl+2)"), + ("Registry", "Browse and install tools from the community (Ctrl+3)"), + ("Providers", "Configure AI backends like Claude, GPT, etc. (Ctrl+4)"), + ("Profiles", "AI persona profiles for customizing tool behavior"), ] font = QFont() @@ -228,6 +231,88 @@ class MainWindow(QMainWindow): shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self) shortcut_quit.activated.connect(self.close) + # F1: Help + shortcut_help = QShortcut(QKeySequence("F1"), self) + shortcut_help.activated.connect(self._show_getting_started) + + def _setup_menu_bar(self): + """Set up the menu bar with Help menu.""" + menubar = self.menuBar() + + # Help menu + help_menu = menubar.addMenu("&Help") + + # Getting Started + action_getting_started = QAction("&Getting Started", self) + action_getting_started.setShortcut("F1") + action_getting_started.triggered.connect(self._show_getting_started) + help_menu.addAction(action_getting_started) + + help_menu.addSeparator() + + # Quick Guides + action_create_tool = QAction("How to &Create a Tool", self) + action_create_tool.triggered.connect(self._show_create_tool_guide) + help_menu.addAction(action_create_tool) + + action_install_tools = QAction("How to &Install Tools", self) + action_install_tools.triggered.connect(self._show_install_tools_guide) + help_menu.addAction(action_install_tools) + + action_publish = QAction("How to &Publish Tools", self) + action_publish.triggered.connect(self._show_publish_guide) + help_menu.addAction(action_publish) + + help_menu.addSeparator() + + # Keyboard Shortcuts + action_shortcuts = QAction("&Keyboard Shortcuts", self) + action_shortcuts.triggered.connect(self._show_keyboard_shortcuts) + help_menu.addAction(action_shortcuts) + + help_menu.addSeparator() + + # About + action_about = QAction("&About CmdForge", self) + action_about.triggered.connect(self._show_about) + help_menu.addAction(action_about) + + def _show_getting_started(self): + """Show Getting Started guide.""" + from .dialogs.help_dialogs import QuickGuideDialog + dialog = QuickGuideDialog("getting_started", self) + dialog.exec() + + def _show_create_tool_guide(self): + """Show Create Tool guide.""" + from .dialogs.help_dialogs import QuickGuideDialog + dialog = QuickGuideDialog("create_tool", self) + dialog.exec() + + def _show_install_tools_guide(self): + """Show Install Tools guide.""" + from .dialogs.help_dialogs import QuickGuideDialog + dialog = QuickGuideDialog("install_tools", self) + dialog.exec() + + def _show_publish_guide(self): + """Show Publish Tools guide.""" + from .dialogs.help_dialogs import QuickGuideDialog + dialog = QuickGuideDialog("publish_tools", self) + dialog.exec() + + def _show_keyboard_shortcuts(self): + """Show Keyboard Shortcuts guide.""" + from .dialogs.help_dialogs import QuickGuideDialog + dialog = QuickGuideDialog("keyboard_shortcuts", self) + dialog.exec() + + def _show_about(self): + """Show About dialog.""" + from .dialogs.help_dialogs import AboutDialog + dialog = AboutDialog(self) + dialog.exec() + def _shortcut_new_tool(self): """Handle Ctrl+N: Create new tool.""" self.open_tool_builder() diff --git a/src/cmdforge/gui/pages/registry_page.py b/src/cmdforge/gui/pages/registry_page.py index 1b4dd6f..8892ba7 100644 --- a/src/cmdforge/gui/pages/registry_page.py +++ b/src/cmdforge/gui/pages/registry_page.py @@ -129,6 +129,7 @@ class RegistryPage(QWidget): # Browse all button self.btn_browse = QPushButton("Browse All") + self.btn_browse.setToolTip("Clear filters and show all available tools") self.btn_browse.clicked.connect(self._browse_all) header.addWidget(self.btn_browse) @@ -143,6 +144,7 @@ class RegistryPage(QWidget): # Search input self.search_input = QLineEdit() self.search_input.setPlaceholderText("Search tools...") + self.search_input.setToolTip("Search by name, description, or keywords (press Enter)") self.search_input.returnPressed.connect(self._do_search) filters_layout.addWidget(self.search_input, 2) @@ -152,6 +154,7 @@ class RegistryPage(QWidget): self.category_combo = QComboBox() self.category_combo.addItems(["All", "Text", "Developer", "Data", "Other"]) self.category_combo.setMinimumWidth(100) + self.category_combo.setToolTip("Filter by tool category") self.category_combo.currentTextChanged.connect(self._on_filter_changed) filters_layout.addWidget(self.category_combo) @@ -163,11 +166,13 @@ class RegistryPage(QWidget): self.sort_combo.addItem("Newest", "published_at") self.sort_combo.addItem("Name (A-Z)", "name") self.sort_combo.setMinimumWidth(120) + self.sort_combo.setToolTip("Change sort order of results") self.sort_combo.currentIndexChanged.connect(self._on_filter_changed) filters_layout.addWidget(self.sort_combo) # Search button self.btn_search = QPushButton("Search") + self.btn_search.setToolTip("Search with current filters") self.btn_search.clicked.connect(self._do_search) filters_layout.addWidget(self.btn_search) @@ -196,6 +201,7 @@ class RegistryPage(QWidget): self.results_table = QTableWidget() self.results_table.setColumnCount(6) self.results_table.setHorizontalHeaderLabels(["", "Name", "Owner", "Rating", "Downloads", "Version"]) + self.results_table.setToolTip("Click a tool to see details. ✓ = installed, ↑ = update available") self.results_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed) self.results_table.setColumnWidth(0, 30) # Installed indicator self.results_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) @@ -215,6 +221,7 @@ class RegistryPage(QWidget): pag_layout.setContentsMargins(0, 8, 0, 0) self.btn_prev = QPushButton("← Previous") + self.btn_prev.setToolTip("Go to previous page of results") self.btn_prev.clicked.connect(self._prev_page) self.btn_prev.setEnabled(False) pag_layout.addWidget(self.btn_prev) @@ -228,6 +235,7 @@ class RegistryPage(QWidget): pag_layout.addStretch() self.btn_next = QPushButton("Next →") + self.btn_next.setToolTip("Go to next page of results") self.btn_next.clicked.connect(self._next_page) self.btn_next.setEnabled(False) pag_layout.addWidget(self.btn_next) @@ -263,6 +271,7 @@ class RegistryPage(QWidget): self.version_combo.setMinimumWidth(120) self.version_combo.addItem("Latest", None) self.version_combo.setEnabled(False) + self.version_combo.setToolTip("Select which version to install") version_row.addWidget(self.version_combo) version_row.addStretch() @@ -272,11 +281,13 @@ class RegistryPage(QWidget): actions = QHBoxLayout() self.btn_install = QPushButton("Install") + self.btn_install.setToolTip("Download and install this tool locally") self.btn_install.clicked.connect(self._install_tool) self.btn_install.setEnabled(False) actions.addWidget(self.btn_install) self.btn_update = QPushButton("Update Available") + self.btn_update.setToolTip("Update to the latest version from the registry") self.btn_update.clicked.connect(self._install_tool) self.btn_update.setEnabled(False) self.btn_update.setStyleSheet("background-color: #48bb78; color: white;") diff --git a/src/cmdforge/gui/pages/tool_builder_page.py b/src/cmdforge/gui/pages/tool_builder_page.py index 3d4d95e..f8ee2e8 100644 --- a/src/cmdforge/gui/pages/tool_builder_page.py +++ b/src/cmdforge/gui/pages/tool_builder_page.py @@ -51,10 +51,12 @@ class ToolBuilderPage(QWidget): self.btn_cancel = QPushButton("Cancel") self.btn_cancel.setObjectName("secondary") + self.btn_cancel.setToolTip("Cancel and return to tools page (Escape)") self.btn_cancel.clicked.connect(self._cancel) header_layout.addWidget(self.btn_cancel) self.btn_save = QPushButton("Save") + self.btn_save.setToolTip("Save this tool (Ctrl+S)") self.btn_save.clicked.connect(self._save) header_layout.addWidget(self.btn_save) @@ -76,14 +78,17 @@ class ToolBuilderPage(QWidget): self.name_input = QLineEdit() self.name_input.setPlaceholderText("my-tool") + self.name_input.setToolTip("Unique tool name using lowercase letters, numbers, and hyphens") info_layout.addRow("Name:", self.name_input) self.desc_input = QLineEdit() self.desc_input.setPlaceholderText("A brief description of what this tool does") + self.desc_input.setToolTip("Brief description shown in tool listings and help text") info_layout.addRow("Description:", self.desc_input) self.category_combo = QComboBox() self.category_combo.setEditable(True) + self.category_combo.setToolTip("Category for organizing tools (select or type custom)") for cat in DEFAULT_CATEGORIES: self.category_combo.addItem(cat) info_layout.addRow("Category:", self.category_combo) @@ -91,9 +96,19 @@ class ToolBuilderPage(QWidget): left_layout.addWidget(info_box) # Arguments group - args_box = QGroupBox("Arguments") + args_box = QGroupBox() args_layout = QVBoxLayout(args_box) + args_label = QLabel("Arguments") + args_label.setObjectName("sectionHeading") + args_label.setToolTip( + "

Arguments are command-line flags users can pass to your tool.

" + "

Example: Adding --max with variable 'max' lets users run:
" + "my-tool --max 100 < input.txt

" + "

Use {max} in your prompts to reference the value.

" + ) + args_layout.addWidget(args_label) + self.args_list = QListWidget() self.args_list.itemDoubleClicked.connect(self._edit_argument) args_layout.addWidget(self.args_list) @@ -127,21 +142,37 @@ class ToolBuilderPage(QWidget): right_layout.setSpacing(16) # Steps group with view toggle - steps_box = QGroupBox("Steps") + steps_box = QGroupBox() steps_layout = QVBoxLayout(steps_box) - # View toggle header - view_header = QHBoxLayout() + # Steps header with label and view toggle + steps_header = QHBoxLayout() + steps_label = QLabel("Steps") + steps_label.setObjectName("sectionHeading") + steps_label.setToolTip( + "

Steps define what your tool does, executed in order.

" + "

Step types:
" + "- Prompt: Call an AI provider with a template
" + "- Code: Run Python code to process data
" + "- Tool: Call another CmdForge tool

" + "

Use {variable} syntax to pass data between steps.
" + "Built-in: {input} contains stdin content.

" + ) + steps_header.addWidget(steps_label) + steps_header.addStretch() + # View toggle buttons self.btn_list_view = QPushButton("List") self.btn_list_view.setCheckable(True) self.btn_list_view.setChecked(True) self.btn_list_view.setObjectName("viewToggle") + self.btn_list_view.setToolTip("View steps as a list (drag to reorder)") self.btn_list_view.clicked.connect(lambda: self._set_view_mode(0)) self.btn_flow_view = QPushButton("Flow") self.btn_flow_view.setCheckable(True) self.btn_flow_view.setObjectName("viewToggle") + self.btn_flow_view.setToolTip("View steps as a visual flow graph") self.btn_flow_view.clicked.connect(lambda: self._set_view_mode(1)) # Button group for mutual exclusivity @@ -149,10 +180,9 @@ class ToolBuilderPage(QWidget): self.view_group.addButton(self.btn_list_view, 0) self.view_group.addButton(self.btn_flow_view, 1) - view_header.addWidget(self.btn_list_view) - view_header.addWidget(self.btn_flow_view) - view_header.addStretch() - steps_layout.addLayout(view_header) + steps_header.addWidget(self.btn_list_view) + steps_header.addWidget(self.btn_flow_view) + steps_layout.addLayout(steps_header) # Stacked widget for list/flow views self.steps_stack = QStackedWidget() @@ -183,24 +213,29 @@ class ToolBuilderPage(QWidget): # Step action buttons steps_btns = QHBoxLayout() self.btn_add_prompt = QPushButton("Add Prompt") + self.btn_add_prompt.setToolTip("Add an AI prompt step - calls your provider with a template") self.btn_add_prompt.clicked.connect(self._add_prompt_step) steps_btns.addWidget(self.btn_add_prompt) self.btn_add_code = QPushButton("Add Code") + self.btn_add_code.setToolTip("Add a Python code step - process or transform data") self.btn_add_code.clicked.connect(self._add_code_step) steps_btns.addWidget(self.btn_add_code) self.btn_add_tool = QPushButton("Add Tool") + self.btn_add_tool.setToolTip("Add a tool step - chain another CmdForge tool") self.btn_add_tool.clicked.connect(self._add_tool_step) steps_btns.addWidget(self.btn_add_tool) self.btn_edit_step = QPushButton("Edit") self.btn_edit_step.setObjectName("secondary") + self.btn_edit_step.setToolTip("Edit the selected step (or double-click)") self.btn_edit_step.clicked.connect(self._edit_step) steps_btns.addWidget(self.btn_edit_step) self.btn_del_step = QPushButton("Delete") self.btn_del_step.setObjectName("danger") + self.btn_del_step.setToolTip("Delete the selected step") self.btn_del_step.clicked.connect(self._delete_step) steps_btns.addWidget(self.btn_del_step) @@ -210,9 +245,21 @@ class ToolBuilderPage(QWidget): right_layout.addWidget(steps_box, 1) # Steps box gets stretch priority # Output group - output_box = QGroupBox("Output Template") + output_box = QGroupBox() output_layout = QVBoxLayout(output_box) + output_label = QLabel("Output Template") + output_label.setObjectName("sectionHeading") + output_label.setToolTip( + "

The output template defines what your tool prints.

" + "

Use {variable} to include step outputs:
" + "- {response} - typical AI response variable
" + "- {result} - common code step output
" + "- Any output_var you defined in steps

" + "

Example: {response} prints just the AI response.

" + ) + output_layout.addWidget(output_label) + self.output_input = QTextEdit() self.output_input.setPlaceholderText("Use {variable} to reference step outputs, e.g. {response}") self.output_input.setPlainText("{response}") # Default value diff --git a/src/cmdforge/gui/styles.py b/src/cmdforge/gui/styles.py index fdf57b5..0ed31a5 100644 --- a/src/cmdforge/gui/styles.py +++ b/src/cmdforge/gui/styles.py @@ -225,6 +225,12 @@ QLabel#label { color: #4a5568; } +QLabel#sectionHeading { + font-weight: 600; + font-size: 13px; + color: #2d3748; +} + /* Scrollbars */ QScrollBar:vertical { background-color: #f7fafc;