Add cmdforge list --json, --filter, and run-once for LLM-friendly one-shot execution
This commit is contained in:
parent
56cb34276e
commit
23723eaddb
|
|
@ -6,7 +6,7 @@ import sys
|
|||
from .. import __version__
|
||||
|
||||
from .tool_commands import (
|
||||
cmd_list, cmd_create, cmd_edit, cmd_delete, cmd_test, cmd_run,
|
||||
cmd_list, cmd_create, cmd_edit, cmd_delete, cmd_test, cmd_run, cmd_run_once,
|
||||
cmd_ui, cmd_refresh, cmd_docs, cmd_check
|
||||
)
|
||||
from .provider_commands import cmd_providers
|
||||
|
|
@ -33,6 +33,8 @@ def main():
|
|||
# No command = launch UI
|
||||
# 'list' command
|
||||
p_list = subparsers.add_parser("list", help="List all tools")
|
||||
p_list.add_argument("--json", action="store_true", help="Output as JSON")
|
||||
p_list.add_argument("--filter", help="Filter by name or description (substring match)")
|
||||
p_list.set_defaults(func=cmd_list)
|
||||
|
||||
# 'create' command
|
||||
|
|
@ -77,6 +79,14 @@ def main():
|
|||
p_run.add_argument("tool_args", nargs=argparse.REMAINDER, help="Additional tool-specific arguments (use -- to separate)")
|
||||
p_run.set_defaults(func=cmd_run)
|
||||
|
||||
# 'run-once' command — one-shot without creating a tool
|
||||
p_run_once = subparsers.add_parser("run-once", help="Run a one-shot prompt through a provider without creating a tool")
|
||||
p_run_once.add_argument("prompt", help="Prompt text (or '-' to read from stdin)")
|
||||
p_run_once.add_argument("-p", "--provider", default="opencode-pickle", help="Provider to use")
|
||||
p_run_once.add_argument("--max-tokens", type=int, help="Max output tokens")
|
||||
p_run_once.add_argument("--timeout", type=int, default=60, help="Timeout in seconds")
|
||||
p_run_once.set_defaults(func=cmd_run_once)
|
||||
|
||||
# 'ui' command (explicit)
|
||||
p_ui = subparsers.add_parser("ui", help="Launch interactive UI")
|
||||
p_ui.set_defaults(func=cmd_ui)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,26 @@ from ..gui import run_gui
|
|||
|
||||
def cmd_list(args):
|
||||
"""List all tools."""
|
||||
import json
|
||||
import sys
|
||||
|
||||
tools = list_tools()
|
||||
|
||||
filter_text = getattr(args, "filter", "") or ""
|
||||
|
||||
if getattr(args, "json", False):
|
||||
result = []
|
||||
for name in sorted(tools):
|
||||
tool = load_tool(name)
|
||||
if not tool:
|
||||
continue
|
||||
if filter_text and filter_text.lower() not in name.lower() and filter_text.lower() not in (tool.description or "").lower():
|
||||
continue
|
||||
result.append(tool.to_dict())
|
||||
json.dump(result, sys.stdout, indent=2)
|
||||
print()
|
||||
return 0
|
||||
|
||||
if not tools:
|
||||
print("No tools found.")
|
||||
print("Create your first tool with: cmdforge ui")
|
||||
|
|
@ -22,36 +40,66 @@ def cmd_list(args):
|
|||
print(f"Available tools ({len(tools)}):\n")
|
||||
for name in tools:
|
||||
tool = load_tool(name)
|
||||
if tool:
|
||||
# Show source indicator for imported tools
|
||||
source_marker = ""
|
||||
if tool.source and tool.source.type == "imported":
|
||||
source_marker = " [imported]"
|
||||
elif tool.source and tool.source.type == "forked":
|
||||
source_marker = " [forked]"
|
||||
if not tool:
|
||||
continue
|
||||
if filter_text and filter_text.lower() not in name.lower() and filter_text.lower() not in (tool.description or "").lower():
|
||||
continue
|
||||
|
||||
print(f" {name}{source_marker}")
|
||||
print(f" {tool.description or 'No description'}")
|
||||
# Show source indicator for imported tools
|
||||
source_marker = ""
|
||||
if tool.source and tool.source.type == "imported":
|
||||
source_marker = " [imported]"
|
||||
elif tool.source and tool.source.type == "forked":
|
||||
source_marker = " [forked]"
|
||||
|
||||
# Show arguments
|
||||
if tool.arguments:
|
||||
args_str = ", ".join(arg.flag for arg in tool.arguments)
|
||||
print(f" Arguments: {args_str}")
|
||||
print(f" {name}{source_marker}")
|
||||
print(f" {tool.description or 'No description'}")
|
||||
|
||||
# Show steps
|
||||
if tool.steps:
|
||||
step_info = []
|
||||
for step in tool.steps:
|
||||
if isinstance(step, PromptStep):
|
||||
step_info.append(f"PROMPT[{step.provider}]")
|
||||
elif isinstance(step, CodeStep):
|
||||
step_info.append("CODE")
|
||||
elif isinstance(step, ToolStep):
|
||||
step_info.append(f"TOOL[{step.tool}]")
|
||||
print(f" Steps: {' -> '.join(step_info)}")
|
||||
# Show arguments
|
||||
if tool.arguments:
|
||||
args_str = ", ".join(arg.flag for arg in tool.arguments)
|
||||
print(f" Arguments: {args_str}")
|
||||
|
||||
print()
|
||||
# Show steps
|
||||
if tool.steps:
|
||||
step_info = []
|
||||
for step in tool.steps:
|
||||
if isinstance(step, PromptStep):
|
||||
step_info.append(f"PROMPT[{step.provider}]")
|
||||
elif isinstance(step, CodeStep):
|
||||
step_info.append("CODE")
|
||||
elif isinstance(step, ToolStep):
|
||||
step_info.append(f"TOOL[{step.tool}]")
|
||||
print(f" Steps: {' -> '.join(step_info)}")
|
||||
|
||||
print()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_run_once(args):
|
||||
"""Run a one-shot prompt through a provider without creating a tool."""
|
||||
import sys
|
||||
from ..providers import call_provider
|
||||
|
||||
prompt = args.prompt
|
||||
if prompt == "-":
|
||||
prompt = sys.stdin.read()
|
||||
|
||||
if not prompt.strip():
|
||||
print("Error: No prompt provided.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
provider = args.provider or "opencode-pickle"
|
||||
|
||||
print(f"[run-once] Provider: {provider}", file=sys.stderr)
|
||||
result = call_provider(provider, prompt, timeout=args.timeout, max_tokens=args.max_tokens)
|
||||
|
||||
if not result.success:
|
||||
print(f"Error: {result.error}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(result.text)
|
||||
return 0
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue