diff --git a/src/cmdforge/gui/pages/tool_builder_page.py b/src/cmdforge/gui/pages/tool_builder_page.py
index 145ec9c..02f1e04 100644
--- a/src/cmdforge/gui/pages/tool_builder_page.py
+++ b/src/cmdforge/gui/pages/tool_builder_page.py
@@ -133,6 +133,47 @@ class ToolBuilderPage(QWidget):
left_layout.addWidget(args_box)
+ # Dependencies group
+ deps_box = QGroupBox()
+ deps_layout = QVBoxLayout(deps_box)
+
+ deps_label = QLabel("Dependencies")
+ deps_label.setObjectName("sectionHeading")
+ deps_label.setToolTip(
+ "
Dependencies are other CmdForge tools this tool requires.
"
+ "If your code steps call other tools via subprocess,
"
+ "declare them here so the dependency system knows about them.
"
+ "Use this when you can't use a Tool step directly
"
+ "(e.g., calling tools in a loop or with complex logic).
"
+ )
+ deps_layout.addWidget(deps_label)
+
+ self.deps_list = QListWidget()
+ self.deps_list.setMaximumHeight(100)
+ deps_layout.addWidget(self.deps_list)
+
+ # Dependency add row: combo + add button
+ deps_add_row = QHBoxLayout()
+ self.deps_combo = QComboBox()
+ self.deps_combo.setEditable(True)
+ self.deps_combo.setPlaceholderText("Select or type tool name...")
+ self.deps_combo.setToolTip("Select an installed tool or type a tool reference (e.g., official/summarize)")
+ self._populate_deps_combo()
+ deps_add_row.addWidget(self.deps_combo, 1)
+
+ self.btn_add_dep = QPushButton("Add")
+ self.btn_add_dep.clicked.connect(self._add_dependency)
+ deps_add_row.addWidget(self.btn_add_dep)
+
+ self.btn_del_dep = QPushButton("Remove")
+ self.btn_del_dep.setObjectName("danger")
+ self.btn_del_dep.clicked.connect(self._delete_dependency)
+ deps_add_row.addWidget(self.btn_del_dep)
+
+ deps_layout.addLayout(deps_add_row)
+
+ left_layout.addWidget(deps_box)
+
splitter.addWidget(left)
# Right: Steps and output
@@ -406,6 +447,9 @@ class ToolBuilderPage(QWidget):
# Load arguments
self._refresh_arguments()
+ # Load dependencies
+ self._refresh_dependencies()
+
# Load steps
self._refresh_steps()
@@ -579,6 +623,66 @@ class ToolBuilderPage(QWidget):
del self._tool.arguments[idx]
self._refresh_arguments()
+ def _populate_deps_combo(self):
+ """Populate dependencies combo with installed tools."""
+ from ...tool import TOOLS_DIR
+ self.deps_combo.clear()
+
+ # Get all installed tools
+ tools = []
+ if TOOLS_DIR.exists():
+ for item in TOOLS_DIR.iterdir():
+ if item.is_dir():
+ config = item / "config.yaml"
+ if config.exists():
+ tools.append(item.name)
+
+ # Sort and add to combo
+ for tool in sorted(tools):
+ self.deps_combo.addItem(tool)
+
+ def _add_dependency(self):
+ """Add selected tool to dependencies."""
+ tool_ref = self.deps_combo.currentText().strip()
+ if not tool_ref:
+ return
+
+ if not self._tool:
+ # Create a minimal tool object if none exists
+ self._tool = Tool(name="", description="")
+
+ # Initialize dependencies list if needed
+ if not hasattr(self._tool, 'dependencies') or self._tool.dependencies is None:
+ self._tool.dependencies = []
+
+ # Check if already in list
+ if tool_ref in self._tool.dependencies:
+ self.main_window.show_status(f"'{tool_ref}' is already a dependency")
+ return
+
+ self._tool.dependencies.append(tool_ref)
+ self._refresh_dependencies()
+ self.deps_combo.setCurrentText("")
+ self.main_window.show_status(f"Added dependency: {tool_ref}")
+
+ def _delete_dependency(self):
+ """Remove selected dependency."""
+ items = self.deps_list.selectedItems()
+ if not items:
+ return
+
+ dep = items[0].text()
+ if self._tool and self._tool.dependencies and dep in self._tool.dependencies:
+ self._tool.dependencies.remove(dep)
+ self._refresh_dependencies()
+
+ def _refresh_dependencies(self):
+ """Refresh dependencies list widget."""
+ self.deps_list.clear()
+ if self._tool and self._tool.dependencies:
+ for dep in self._tool.dependencies:
+ self.deps_list.addItem(dep)
+
def _add_tool_dependency(self, tool_ref: str):
"""Add a tool reference to the dependencies list if not already present.
@@ -830,13 +934,18 @@ class ToolBuilderPage(QWidget):
category=category,
arguments=self._tool.arguments if self._tool else [],
steps=self._tool.steps if self._tool else [],
- output=output
+ output=output,
+ dependencies=self._tool.dependencies if self._tool else []
)
# Preserve source if editing
if self._tool and self._tool.source:
tool.source = self._tool.source
+ # Preserve version if editing
+ if self._tool and self._tool.version:
+ tool.version = self._tool.version
+
try:
save_tool(tool)
self.main_window.show_status(f"Saved tool '{name}'")