Add tool settings files for configurable tool defaults

Tools can now ship with defaults.yaml containing configurable settings
that users can customize via settings.yaml (auto-created from defaults).

Features:
- ensure_settings() helper copies defaults to settings on first use
- Settings available as {settings.key} in templates (scalars only)
- Full dict access via settings['key'] in code steps
- CLI: cmdforge settings <tool> show/edit/reset/diff
- GUI: Defaults editor in Tool Builder, Configure button on Tools page
- Registry: defaults.yaml published with tools, included in downloads
- Secret detection warning on publish (api_key, password, token, etc.)

Fully backward compatible - tools without defaults work unchanged.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
rob
2026-01-27 11:56:07 -04:00
co-authored by Claude Opus 4.5
parent ce94ba89dc
commit 8eff55ed1e
19 changed files with 894 additions and 33 deletions
+38
View File
@@ -226,6 +226,13 @@ class ToolsPage(QWidget):
self.btn_edit.setEnabled(False)
btn_layout.addWidget(self.btn_edit)
self.btn_configure = QPushButton("Configure")
self.btn_configure.setObjectName("secondary")
self.btn_configure.setToolTip("Edit tool settings (only available for tools with configurable settings)")
self.btn_configure.clicked.connect(self._configure_tool)
self.btn_configure.setEnabled(False)
btn_layout.addWidget(self.btn_configure)
self.btn_delete = QPushButton("Delete")
self.btn_delete.setObjectName("danger")
self.btn_delete.clicked.connect(self._delete_tool)
@@ -582,12 +589,24 @@ class ToolsPage(QWidget):
self.info_text.setHtml("\n".join(lines))
def _has_settings(self, tool: Tool) -> bool:
"""Check if a tool has configurable settings."""
if not tool or not tool.path:
return False
defaults_path = tool.path.parent / "defaults.yaml"
settings_path = tool.path.parent / "settings.yaml"
return defaults_path.exists() or settings_path.exists()
def _update_buttons(self):
"""Update button enabled states."""
has_selection = self._current_tool is not None
self.btn_edit.setEnabled(has_selection)
self.btn_delete.setEnabled(has_selection)
# Configure button only for tools with settings
has_settings = has_selection and self._has_settings(self._current_tool)
self.btn_configure.setEnabled(has_settings)
config = load_config()
if config.registry.token:
# Connected - enable Publish when tool selected
@@ -605,6 +624,25 @@ class ToolsPage(QWidget):
if self._current_tool:
self.main_window.open_tool_builder(self._current_tool.name)
def _configure_tool(self):
"""Open settings dialog for the selected tool."""
if not self._current_tool:
return
if not self._has_settings(self._current_tool):
QMessageBox.information(
self,
"No Settings",
f"Tool '{self._current_tool.name}' has no configurable settings.\n\n"
"Add a defaults.yaml to the tool to enable settings."
)
return
from ..dialogs.settings_dialog import SettingsDialog
dialog = SettingsDialog(self, self._current_tool.name)
if dialog.exec():
self.main_window.show_status(f"Settings saved for '{self._current_tool.name}'")
def _delete_tool(self):
"""Delete the selected tool."""
if not self._current_tool: