Rename project from SmartTools to CmdForge

Major rename operation:
- Rename Python package: smarttools -> cmdforge
- Update CLI entry point: smarttools -> cmdforge
- Update all imports and module references
- Update pyproject.toml with new name, URLs, entry point
- Update all HTML templates with new branding
- Update documentation (CLAUDE.md, README.md, docs/*, wiki/*)
- Update environment variables:
  - SMARTTOOLS_ENV -> CMDFORGE_ENV
  - SMARTTOOLS_REGISTRY_DB -> CMDFORGE_REGISTRY_DB
  - SMARTTOOLS_TOKEN -> CMDFORGE_TOKEN
  - SMARTTOOLS_REGISTRY_* -> CMDFORGE_REGISTRY_*
- Update Dockerfile and docker-compose.yml
- Update tests to use new package name
- Update scripts and examples
- Update package.json and tailwind.config.js

All 158 unit tests pass. The CLI is working correctly with the
new cmdforge command.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
rob
2026-01-02 22:15:55 -04:00
co-authored by Claude Opus 4.5
parent 2939dd806b
commit 497fe87fc5
113 changed files with 822 additions and 822 deletions
+3
View File
@@ -0,0 +1,3 @@
"""CmdForge - A lightweight personal tool builder for AI-powered CLI commands."""
__version__ = "0.1.0"
@@ -1,4 +1,4 @@
"""CLI entry point for SmartTools.
"""CLI entry point for CmdForge.
This module is a thin wrapper for backwards compatibility.
The actual implementation is in the cli/ package.
@@ -1,4 +1,4 @@
"""CLI entry point for SmartTools."""
"""CLI entry point for CmdForge."""
import argparse
import sys
@@ -18,7 +18,7 @@ from .config_commands import cmd_config
def main():
"""Main CLI entry point."""
parser = argparse.ArgumentParser(
prog="smarttools",
prog="cmdforge",
description="A lightweight personal tool builder for AI-powered CLI commands"
)
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
@@ -179,7 +179,7 @@ def main():
p_deps.set_defaults(func=cmd_deps)
# 'install' command (for dependencies)
p_install = subparsers.add_parser("install", help="Install dependencies from smarttools.yaml")
p_install = subparsers.add_parser("install", help="Install dependencies from cmdforge.yaml")
p_install.set_defaults(func=cmd_install_deps)
# 'add' command
@@ -190,7 +190,7 @@ def main():
p_add.set_defaults(func=cmd_add)
# 'init' command
p_init = subparsers.add_parser("init", help="Initialize smarttools.yaml")
p_init = subparsers.add_parser("init", help="Initialize cmdforge.yaml")
p_init.add_argument("-n", "--name", help="Project name")
p_init.add_argument("-v", "--version", help="Project version")
p_init.add_argument("-f", "--force", action="store_true", help="Overwrite existing")
@@ -4,7 +4,7 @@ from ..config import load_config, save_config, set_registry_token
def cmd_config(args):
"""Manage SmartTools configuration."""
"""Manage CmdForge configuration."""
if args.config_cmd == "show":
return _cmd_config_show(args)
elif args.config_cmd == "set-token":
@@ -22,7 +22,7 @@ def cmd_config(args):
def _cmd_config_show(args):
"""Show current configuration."""
config = load_config()
print("SmartTools Configuration:")
print("CmdForge Configuration:")
print(f" Registry URL: {config.registry.url}")
print(f" Token: {'***' if config.registry.token else '(not set)'}")
print(f" Client ID: {config.client_id}")
@@ -13,12 +13,12 @@ from ..resolver import (
def cmd_deps(args):
"""Show project dependencies from smarttools.yaml."""
"""Show project dependencies from cmdforge.yaml."""
manifest = load_manifest()
if manifest is None:
print("No smarttools.yaml found in current project.")
print("Create one with: smarttools init")
print("No cmdforge.yaml found in current project.")
print("Create one with: cmdforge init")
return 1
print(f"Project: {manifest.name} v{manifest.version}")
@@ -26,7 +26,7 @@ def cmd_deps(args):
if not manifest.dependencies:
print("No dependencies defined.")
print("Add one with: smarttools add <owner/name>")
print("Add one with: cmdforge add <owner/name>")
return 0
print(f"Dependencies ({len(manifest.dependencies)}):")
@@ -52,14 +52,14 @@ def cmd_deps(args):
def cmd_install_deps(args):
"""Install dependencies from smarttools.yaml."""
"""Install dependencies from cmdforge.yaml."""
from ..registry_client import RegistryError
manifest = load_manifest()
if manifest is None:
print("No smarttools.yaml found in current project.")
print("Create one with: smarttools init")
print("No cmdforge.yaml found in current project.")
print("Create one with: cmdforge init")
return 1
if not manifest.dependencies:
@@ -150,19 +150,19 @@ def cmd_add(args):
print(f"It's been added to your dependencies - you can install it manually later.", file=sys.stderr)
elif e.code == "CONNECTION_ERROR":
print(f"Could not connect to registry.", file=sys.stderr)
print("Run 'smarttools install' to try again later.", file=sys.stderr)
print("Run 'cmdforge install' to try again later.", file=sys.stderr)
else:
print(f"Install failed: {e.message}", file=sys.stderr)
print("Run 'smarttools install' to try again.", file=sys.stderr)
print("Run 'cmdforge install' to try again.", file=sys.stderr)
except Exception as e:
print(f"Install failed: {e}", file=sys.stderr)
print("Run 'smarttools install' to try again.", file=sys.stderr)
print("Run 'cmdforge install' to try again.", file=sys.stderr)
return 0
def cmd_init(args):
"""Initialize a new smarttools.yaml."""
"""Initialize a new cmdforge.yaml."""
manifest_path = Path.cwd() / MANIFEST_FILENAME
if manifest_path.exists() and not args.force:
@@ -196,7 +196,7 @@ def cmd_init(args):
print(f"Created {MANIFEST_FILENAME}")
print()
print("Add dependencies with: smarttools add <owner/name>")
print("Install them with: smarttools install")
print("Add dependencies with: cmdforge add <owner/name>")
print("Install them with: cmdforge install")
return 0
@@ -48,7 +48,7 @@ PROVIDER_INSTALL_INFO = {
"cost": "FREE (runs entirely on your machine)",
"variants": [],
"custom": True,
"post_install_note": "After installing, add the provider:\n smarttools providers add ollama 'ollama run llama3' -d 'Local Llama 3'",
"post_install_note": "After installing, add the provider:\n cmdforge providers add ollama 'ollama run llama3' -d 'Local Llama 3'",
},
}
@@ -73,7 +73,7 @@ def cmd_providers(args):
def _cmd_providers_install(args):
"""Interactive guide to install AI providers."""
print("=" * 60)
print("SmartTools Provider Installation Guide")
print("CmdForge Provider Installation Guide")
print("=" * 60)
print()
@@ -185,9 +185,9 @@ def _cmd_providers_install(args):
print(f" 2. {info['setup']}")
if info.get('post_install_note'):
print(f" 3. {info['post_install_note']}")
print(f" 4. Test with: smarttools providers test {selected}")
print(f" 4. Test with: cmdforge providers test {selected}")
else:
print(f" 3. Test with: smarttools providers test {info['variants'][0] if info['variants'] else selected}")
print(f" 3. Test with: cmdforge providers test {info['variants'][0] if info['variants'] else selected}")
else:
print()
print(f"Installation failed (exit code {result.returncode})")
@@ -86,7 +86,7 @@ def _cmd_registry_search(args):
return 1
except Exception as e:
print(f"Error searching registry: {e}", file=sys.stderr)
print("If the problem persists, check: smarttools config show", file=sys.stderr)
print("If the problem persists, check: cmdforge config show", file=sys.stderr)
return 1
return 0
@@ -120,7 +120,7 @@ def _cmd_registry_install(args):
except RegistryError as e:
if e.code == "TOOL_NOT_FOUND":
print(f"Tool '{tool_spec}' not found in the registry.", file=sys.stderr)
print(f"Try: smarttools registry search {tool_spec.split('/')[-1]}", file=sys.stderr)
print(f"Try: cmdforge registry search {tool_spec.split('/')[-1]}", file=sys.stderr)
elif e.code == "VERSION_NOT_FOUND" or e.code == "CONSTRAINT_UNSATISFIABLE":
print(f"Error: {e.message}", file=sys.stderr)
if e.details and "available_versions" in e.details:
@@ -191,12 +191,12 @@ def _cmd_registry_info(args):
if len(versions) > 5:
print(f" ...and {len(versions) - 5} more")
print(f"\nInstall: smarttools registry install {tool_info.owner}/{tool_info.name}")
print(f"\nInstall: cmdforge registry install {tool_info.owner}/{tool_info.name}")
except RegistryError as e:
if e.code == "TOOL_NOT_FOUND":
print(f"Tool '{tool_spec}' not found in the registry.", file=sys.stderr)
print(f"Try: smarttools registry search {parsed.name}", file=sys.stderr)
print(f"Try: cmdforge registry search {parsed.name}", file=sys.stderr)
elif e.code == "CONNECTION_ERROR":
print("Could not connect to the registry.", file=sys.stderr)
print("Check your internet connection or try again later.", file=sys.stderr)
@@ -380,7 +380,7 @@ def _cmd_registry_my_tools(args):
if not tools:
print("You haven't published any tools yet.")
print("Publish your first tool with: smarttools registry publish")
print("Publish your first tool with: cmdforge registry publish")
return 0
print(f"Your published tools ({len(tools)}):\n")
@@ -393,7 +393,7 @@ def _cmd_registry_my_tools(args):
except RegistryError as e:
if e.code == "UNAUTHORIZED":
print("Not logged in. Set your registry token first:", file=sys.stderr)
print(" smarttools config set-token <token>", file=sys.stderr)
print(" cmdforge config set-token <token>", file=sys.stderr)
print()
print("Don't have a token? Register at the registry website.", file=sys.stderr)
elif e.code == "CONNECTION_ERROR":
@@ -418,8 +418,8 @@ def _cmd_registry_browse(args):
return run_registry_browser()
except ImportError:
print("TUI browser requires urwid. Install with:", file=sys.stderr)
print(" pip install 'smarttools[tui]'", file=sys.stderr)
print(" pip install 'cmdforge[tui]'", file=sys.stderr)
print()
print("Or search from command line:", file=sys.stderr)
print(" smarttools registry search <query>", file=sys.stderr)
print(" cmdforge registry search <query>", file=sys.stderr)
return 1
@@ -16,7 +16,7 @@ def cmd_list(args):
if not tools:
print("No tools found.")
print("Create your first tool with: smarttools ui")
print("Create your first tool with: cmdforge ui")
return 0
print(f"Available tools ({len(tools)}):\n")
@@ -76,7 +76,7 @@ def cmd_create(args):
path = save_tool(tool)
print(f"Created tool '{name}'")
print(f"Config: {path}")
print(f"\nUse 'smarttools ui' to add arguments, steps, and customize.")
print(f"\nUse 'cmdforge ui' to add arguments, steps, and customize.")
print(f"Or run: {name} < input.txt")
return 0
@@ -326,7 +326,7 @@ echo "input" | {args.name}
# View README
if not readme_path.exists():
print(f"No documentation found for '{args.name}'.")
print(f"Create it with: smarttools docs {args.name} --edit")
print(f"Create it with: cmdforge docs {args.name} --edit")
return 1
print(readme_path.read_text())
@@ -1,6 +1,6 @@
"""Global configuration handling for SmartTools.
"""Global configuration handling for CmdForge.
Manages ~/.smarttools/config.yaml with registry settings, tokens, and preferences.
Manages ~/.cmdforge/config.yaml with registry settings, tokens, and preferences.
"""
import uuid
@@ -12,7 +12,7 @@ import yaml
# Default configuration directory
CONFIG_DIR = Path.home() / ".smarttools"
CONFIG_DIR = Path.home() / ".cmdforge"
CONFIG_FILE = CONFIG_DIR / "config.yaml"
# Default registry URL (canonical base path)
@@ -41,7 +41,7 @@ class RegistryConfig:
@dataclass
class Config:
"""Global SmartTools configuration."""
"""Global CmdForge configuration."""
registry: RegistryConfig = field(default_factory=RegistryConfig)
client_id: str = ""
auto_fetch_from_registry: bool = True
@@ -1,4 +1,4 @@
"""Project manifest (smarttools.yaml) handling.
"""Project manifest (cmdforge.yaml) handling.
Manages project-level tool dependencies and overrides.
"""
@@ -11,7 +11,7 @@ from typing import Optional, List, Dict
import yaml
MANIFEST_FILENAME = "smarttools.yaml"
MANIFEST_FILENAME = "cmdforge.yaml"
@dataclass
@@ -76,7 +76,7 @@ class ToolOverride:
@dataclass
class Manifest:
"""Project manifest (smarttools.yaml)."""
"""Project manifest (cmdforge.yaml)."""
name: str = "my-project"
version: str = "1.0.0"
dependencies: List[Dependency] = field(default_factory=list)
@@ -144,7 +144,7 @@ class Manifest:
def find_manifest(start_dir: Optional[Path] = None) -> Optional[Path]:
"""
Find smarttools.yaml by searching up from start_dir.
Find cmdforge.yaml by searching up from start_dir.
Args:
start_dir: Directory to start searching from (default: cwd)
@@ -201,7 +201,7 @@ def save_manifest(manifest: Manifest, path: Optional[Path] = None) -> Path:
Args:
manifest: Manifest to save
path: Path to save to (default: ./smarttools.yaml)
path: Path to save to (default: ./cmdforge.yaml)
Returns:
Path where manifest was saved
@@ -12,7 +12,7 @@ import yaml
# Default providers config location
PROVIDERS_FILE = Path.home() / ".smarttools" / "providers.yaml"
PROVIDERS_FILE = Path.home() / ".cmdforge" / "providers.yaml"
@dataclass
@@ -161,7 +161,7 @@ def call_provider(provider_name: str, prompt: str, timeout: int = 300) -> Provid
return ProviderResult(
text="",
success=False,
error=f"Provider '{provider_name}' not found. Use 'smarttools providers' to manage providers."
error=f"Provider '{provider_name}' not found. Use 'cmdforge providers' to manage providers."
)
# Parse command (expand environment variables)
@@ -181,7 +181,7 @@ def call_provider(provider_name: str, prompt: str, timeout: int = 300) -> Provid
return ProviderResult(
text="",
success=False,
error=f"Command '{base_cmd}' not found. Is it installed and in PATH?\n\nTo install AI providers, run: smarttools providers install"
error=f"Command '{base_cmd}' not found. Is it installed and in PATH?\n\nTo install AI providers, run: cmdforge providers install"
)
try:
@@ -197,7 +197,7 @@ def call_provider(provider_name: str, prompt: str, timeout: int = 300) -> Provid
if result.returncode != 0:
error_msg = f"Provider exited with code {result.returncode}: {result.stderr}"
if "not found" in result.stderr.lower() or "not installed" in result.stderr.lower():
error_msg += "\n\nTo install AI providers, run: smarttools providers install"
error_msg += "\n\nTo install AI providers, run: cmdforge providers install"
return ProviderResult(
text="",
success=False,
@@ -224,14 +224,14 @@ def call_provider(provider_name: str, prompt: str, timeout: int = 300) -> Provid
f"To fix this, either:\n"
f" 1. Run 'opencode' to connect the {provider_id} provider\n"
f" 2. Use --provider to pick a different model (e.g., --provider opencode-pickle)\n"
f" 3. Run 'smarttools ui' to edit the tool's default provider"
f" 3. Run 'cmdforge ui' to edit the tool's default provider"
)
stderr_hint = f" (stderr: {stderr[:200]}...)" if len(stderr) > 200 else (f" (stderr: {stderr})" if stderr else "")
return ProviderResult(
text="",
success=False,
error=f"Provider returned empty output{stderr_hint}.\n\nThis may mean the model is not available. Try a different provider or run: smarttools providers install"
error=f"Provider returned empty output{stderr_hint}.\n\nThis may mean the model is not available. Try a different provider or run: cmdforge providers install"
)
return ProviderResult(text=result.stdout, success=True)
@@ -1,4 +1,4 @@
"""Flask app for SmartTools Registry API (Phase 2)."""
"""Flask app for CmdForge Registry API (Phase 2)."""
from __future__ import annotations
@@ -51,7 +51,7 @@ ALLOWED_SORT = {
TOOL_NAME_RE = re.compile(r"^[A-Za-z0-9-]{1,64}$")
OWNER_RE = re.compile(r"^[a-z0-9][a-z0-9-]{0,37}[a-z0-9]$")
EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
RESERVED_SLUGS = {"official", "admin", "system", "api", "registry", "smarttools"}
RESERVED_SLUGS = {"official", "admin", "system", "api", "registry", "cmdforge"}
rate_limiter = RateLimiter()
password_hasher = PasswordHasher(memory_cost=65536, time_cost=3, parallelism=4)
@@ -1517,7 +1517,7 @@ def create_app() -> Flask:
status=413,
details={"limit": MAX_BODY_BYTES},
)
secret = os.environ.get("SMARTTOOLS_REGISTRY_WEBHOOK_SECRET", "")
secret = os.environ.get("CMDFORGE_REGISTRY_WEBHOOK_SECRET", "")
if not secret:
return error_response("UNAUTHORIZED", "Webhook secret not configured", 401)
status, payload = process_webhook(request.data, dict(request.headers), secret)
@@ -232,8 +232,8 @@ CREATE INDEX IF NOT EXISTS idx_pageviews_date ON pageviews(date(viewed_at), path
def get_db_path() -> Path:
default_path = Path.home() / ".smarttools" / "registry" / "registry.db"
return Path(os.environ.get("SMARTTOOLS_REGISTRY_DB", default_path))
default_path = Path.home() / ".cmdforge" / "registry" / "registry.db"
return Path(os.environ.get("CMDFORGE_REGISTRY_DB", default_path))
def ensure_db_directory(path: Path) -> None:
@@ -19,22 +19,22 @@ from .db import connect_db, query_one
def get_repo_dir() -> Path:
default_dir = Path.home() / ".smarttools" / "registry" / "repo"
return Path(os.environ.get("SMARTTOOLS_REGISTRY_REPO_DIR", default_dir))
default_dir = Path.home() / ".cmdforge" / "registry" / "repo"
return Path(os.environ.get("CMDFORGE_REGISTRY_REPO_DIR", default_dir))
def get_repo_url() -> str:
return os.environ.get("SMARTTOOLS_REGISTRY_REPO_URL", "https://gitea.brrd.tech/rob/SmartTools-Registry.git")
return os.environ.get("CMDFORGE_REGISTRY_REPO_URL", "https://gitea.brrd.tech/rob/CmdForge-Registry.git")
def get_repo_branch() -> str:
return os.environ.get("SMARTTOOLS_REGISTRY_REPO_BRANCH", "main")
return os.environ.get("CMDFORGE_REGISTRY_REPO_BRANCH", "main")
def get_categories_cache_path() -> Path:
return Path(os.environ.get(
"SMARTTOOLS_REGISTRY_CATEGORIES_CACHE",
Path.home() / ".smarttools" / "registry" / "categories_cache.json",
"CMDFORGE_REGISTRY_CATEGORIES_CACHE",
Path.home() / ".cmdforge" / "registry" / "categories_cache.json",
))
@@ -249,7 +249,7 @@ def process_webhook(body: bytes, headers: Dict[str, str], secret: str, timeout:
if is_delivery_processed(conn, delivery_id):
return 200, {"data": {"status": "already_processed"}}
lock_path = Path.home() / ".smarttools" / "registry" / "locks" / "webhook.lock"
lock_path = Path.home() / ".cmdforge" / "registry" / "locks" / "webhook.lock"
if not acquire_lock(lock_path, timeout):
return 200, {"data": {"status": "skipped", "reason": "sync_in_progress"}}
@@ -1,4 +1,4 @@
"""Registry API client for SmartTools.
"""Registry API client for CmdForge.
Handles all HTTP communication with the registry server.
"""
@@ -114,7 +114,7 @@ class DownloadResult:
class RegistryClient:
"""Client for interacting with the SmartTools registry API."""
"""Client for interacting with the CmdForge registry API."""
def __init__(
self,
@@ -141,8 +141,8 @@ class RegistryClient:
# Session for connection pooling
self._session = requests.Session()
self._session.headers.update({
"User-Agent": "SmartTools-CLI/1.0",
"X-SmartTools-Client": "cli/1.0.0",
"User-Agent": "CmdForge-CLI/1.0",
"X-CmdForge-Client": "cli/1.0.0",
"Accept": "application/json"
})
@@ -198,7 +198,7 @@ class RegistryClient:
if not self.token:
raise RegistryError(
code="UNAUTHORIZED",
message="Authentication required. Set registry token with 'smarttools config set-token'",
message="Authentication required. Set registry token with 'cmdforge config set-token'",
http_status=401
)
headers.update(self._auth_headers())
@@ -1,8 +1,8 @@
"""Tool resolution with proper search order.
Implements the tool resolution order:
1. Local project: ./.smarttools/<owner>/<name>/config.yaml
2. Global user: ~/.smarttools/<owner>/<name>/config.yaml
1. Local project: ./.cmdforge/<owner>/<name>/config.yaml
2. Global user: ~/.cmdforge/<owner>/<name>/config.yaml
3. Registry: Fetch from API, install to global, then run
4. Error if not found
"""
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
# Local project tools directories (support both legacy and documented paths)
LOCAL_TOOLS_DIRS = [Path(".smarttools"), Path("smarttools")]
LOCAL_TOOLS_DIRS = [Path(".cmdforge"), Path("cmdforge")]
@dataclass
@@ -436,9 +436,9 @@ class ToolResolver:
python_path = sys.executable
script = f"""#!/bin/bash
# SmartTools wrapper for '{owner}/{name}'
# CmdForge wrapper for '{owner}/{name}'
# Auto-generated - do not edit
exec {python_path} -m smarttools.runner {owner}/{name} "$@"
exec {python_path} -m cmdforge.runner {owner}/{name} "$@"
"""
wrapper_path.write_text(script)
@@ -450,9 +450,9 @@ exec {python_path} -m smarttools.runner {owner}/{name} "$@"
"""Extract owner from existing wrapper script."""
try:
content = wrapper_path.read_text()
# Look for pattern: smarttools.runner owner/name
# Look for pattern: cmdforge.runner owner/name
# Owner slugs can contain lowercase alphanumeric and hyphens
match = re.search(r'smarttools\.runner\s+([a-z0-9][a-z0-9-]*)/([a-zA-Z0-9_-]+)', content)
match = re.search(r'cmdforge\.runner\s+([a-z0-9][a-z0-9-]*)/([a-zA-Z0-9_-]+)', content)
if match:
return match.group(1)
return None
@@ -210,7 +210,7 @@ def create_argument_parser(tool: Tool) -> argparse.ArgumentParser:
"""
parser = argparse.ArgumentParser(
prog=tool.name,
description=tool.description or f"SmartTools: {tool.name}"
description=tool.description or f"CmdForge: {tool.name}"
)
# Universal flags
@@ -244,7 +244,7 @@ def create_argument_parser(tool: Tool) -> argparse.ArgumentParser:
def main():
"""Entry point for tool execution via wrapper script."""
if len(sys.argv) < 2:
print("Usage: python -m smarttools.runner <tool_name> [args...]", file=sys.stderr)
print("Usage: python -m cmdforge.runner <tool_name> [args...]", file=sys.stderr)
sys.exit(1)
tool_spec = sys.argv[1]
@@ -10,7 +10,7 @@ import yaml
# Default tools directory
TOOLS_DIR = Path.home() / ".smarttools"
TOOLS_DIR = Path.home() / ".cmdforge"
# Default bin directory for wrapper scripts
BIN_DIR = Path.home() / ".local" / "bin"
@@ -106,7 +106,7 @@ DEFAULT_CATEGORIES = ["Text", "Developer", "Data", "Other"]
@dataclass
class Tool:
"""A SmartTools tool definition."""
"""A CmdForge tool definition."""
name: str
description: str = ""
category: str = "Other" # Tool category for organization
@@ -275,13 +275,13 @@ def create_wrapper_script(name: str) -> Path:
bin_dir = get_bin_dir()
wrapper_path = bin_dir / name
# Use the current Python interpreter to ensure smarttools is available
# Use the current Python interpreter to ensure cmdforge is available
python_path = sys.executable
script = f"""#!/bin/bash
# SmartTools wrapper for '{name}'
# CmdForge wrapper for '{name}'
# Auto-generated - do not edit
exec {python_path} -m smarttools.runner {name} "$@"
exec {python_path} -m cmdforge.runner {name} "$@"
"""
wrapper_path.write_text(script)
+2 -2
View File
@@ -1,4 +1,4 @@
"""Dialog-based UI for managing SmartTools."""
"""Dialog-based UI for managing CmdForge."""
import subprocess
import sys
@@ -762,7 +762,7 @@ def main_menu(dialog_prog: str):
"""Show the main menu."""
while True:
choice = show_menu(
"SmartTools Manager",
"CmdForge Manager",
[
("list", "List all tools"),
("create", "Create new tool"),
@@ -1,4 +1,4 @@
"""TUI for browsing the SmartTools Registry using urwid.
"""TUI for browsing the CmdForge Registry using urwid.
Uses threading for non-blocking network operations.
"""
@@ -170,7 +170,7 @@ class AsyncOperation:
class RegistryBrowser:
"""TUI browser for the SmartTools Registry."""
"""TUI browser for the CmdForge Registry."""
def __init__(self):
self.client = get_client()
@@ -195,7 +195,7 @@ class RegistryBrowser:
"""Build the main UI layout."""
# Header
self.header = urwid.AttrMap(
urwid.Text(" SmartTools Registry Browser ", align='center'),
urwid.Text(" CmdForge Registry Browser ", align='center'),
'header'
)
@@ -344,7 +344,7 @@ Downloads: {downloads}
Tags: {', '.join(tags) if tags else 'None'}
Install command:
smarttools registry install {owner}/{name}
cmdforge registry install {owner}/{name}
Press 'i' to install this tool
"""
@@ -1,4 +1,4 @@
"""BIOS-style TUI for SmartTools using snack (python3-newt)."""
"""BIOS-style TUI for CmdForge using snack (python3-newt)."""
import sys
# Ensure system packages are accessible
@@ -15,8 +15,8 @@ from .tool import (
from .providers import Provider, load_providers, add_provider, delete_provider, get_provider
class SmartToolsUI:
"""BIOS-style UI for SmartTools."""
class CmdForgeUI:
"""BIOS-style UI for CmdForge."""
def __init__(self):
self.screen = None
@@ -51,7 +51,7 @@ class SmartToolsUI:
for label, value in items:
listbox.append(label, value)
grid = snack.GridForm(self.screen, "SmartTools Manager", 1, 1)
grid = snack.GridForm(self.screen, "CmdForge Manager", 1, 1)
grid.add(listbox, 0, 0)
result = grid.runOnce()
@@ -698,7 +698,7 @@ class SmartToolsUI:
def run_ui():
"""Entry point for the snack UI."""
ui = SmartToolsUI()
ui = CmdForgeUI()
ui.run()
@@ -1,10 +1,10 @@
"""BIOS-style TUI for SmartTools using urwid.
"""BIOS-style TUI for CmdForge using urwid.
This module is a thin wrapper for backwards compatibility.
The actual implementation is in the ui_urwid/ package.
"""
from .ui_urwid import run_ui, SmartToolsUI
from .ui_urwid import run_ui, CmdForgeUI
from .ui_urwid.palette import PALETTE
from .ui_urwid.widgets import (
SelectableText, Button3D, Button3DCompact, ClickableButton,
@@ -13,7 +13,7 @@ from .ui_urwid.widgets import (
)
__all__ = [
'run_ui', 'SmartToolsUI', 'PALETTE',
'run_ui', 'CmdForgeUI', 'PALETTE',
'SelectableText', 'Button3D', 'Button3DCompact', 'ClickableButton',
'SelectableToolItem', 'ToolListBox', 'TabCyclePile', 'TabPassEdit',
'UndoableEdit', 'DOSScrollBar', 'ToolBuilderLayout', 'Dialog'
@@ -1,4 +1,4 @@
"""BIOS-style TUI for SmartTools using urwid (with mouse support)."""
"""BIOS-style TUI for CmdForge using urwid (with mouse support)."""
import urwid
from typing import Optional, Callable
@@ -18,8 +18,8 @@ from .widgets import (
)
class SmartToolsUI:
"""Urwid-based UI for SmartTools with mouse support."""
class CmdForgeUI:
"""Urwid-based UI for CmdForge with mouse support."""
def __init__(self):
self.loop = None
@@ -226,7 +226,7 @@ class SmartToolsUI:
], tab_positions=[0, 1, 5]) # Tool list, buttons row, exit button
# Header
header = urwid.Text(('header', ' SmartTools Manager '), align='center')
header = urwid.Text(('header', ' CmdForge Manager '), align='center')
# Footer
footer = urwid.Text(('footer', ' Arrow:Navigate list | Tab:Jump to buttons | Enter/Click:Select | Q:Quit '), align='center')
@@ -1566,5 +1566,5 @@ No explanations, no markdown fencing, just the code."""
def run_ui():
"""Entry point for the urwid UI."""
ui = SmartToolsUI()
ui = CmdForgeUI()
ui.run()
@@ -1,4 +1,4 @@
"""Web UI blueprint for SmartTools."""
"""Web UI blueprint for CmdForge."""
import os
from flask import Blueprint
@@ -1,4 +1,4 @@
"""Web app factory for SmartTools UI."""
"""Web app factory for CmdForge UI."""
from __future__ import annotations
@@ -19,13 +19,13 @@ if _sentry_dsn:
integrations=[FlaskIntegration()],
traces_sample_rate=float(os.environ.get("SENTRY_TRACES_RATE", "0.1")),
profiles_sample_rate=float(os.environ.get("SENTRY_PROFILES_RATE", "0.1")),
environment=os.environ.get("SMARTTOOLS_ENV", "development"),
environment=os.environ.get("CMDFORGE_ENV", "development"),
send_default_pii=False, # Privacy: don't send user IPs, emails, etc.
)
except ImportError:
pass # sentry-sdk not installed
from smarttools.registry import app as registry_app
from cmdforge.registry import app as registry_app
from . import web_bp
from .auth import login, register, logout
@@ -44,10 +44,10 @@ def create_web_app() -> Flask:
app.register_blueprint(forum_bp)
# Session configuration
app.session_interface = SQLiteSessionInterface(cookie_name="smarttools_session")
app.config["SESSION_COOKIE_NAME"] = "smarttools_session"
app.config["SESSION_COOKIE_SECURE"] = os.environ.get("SMARTTOOLS_ENV") == "production"
app.config["SHOW_ADS"] = os.environ.get("SMARTTOOLS_SHOW_ADS", "").lower() == "true"
app.session_interface = SQLiteSessionInterface(cookie_name="cmdforge_session")
app.config["SESSION_COOKIE_NAME"] = "cmdforge_session"
app.config["SESSION_COOKIE_SECURE"] = os.environ.get("CMDFORGE_ENV") == "production"
app.config["SHOW_ADS"] = os.environ.get("CMDFORGE_SHOW_ADS", "").lower() == "true"
# CSRF token generator
app.config["CSRF_GENERATOR"] = lambda: secrets.token_urlsafe(32)
@@ -1,4 +1,4 @@
"""Documentation content for SmartTools web UI.
"""Documentation content for CmdForge web UI.
This module contains the actual documentation text that gets rendered
on the /docs pages. Content is stored as markdown-ish HTML for simplicity.
@@ -7,13 +7,13 @@ on the /docs pages. Content is stored as markdown-ish HTML for simplicity.
DOCS = {
"getting-started": {
"title": "Getting Started",
"description": "Learn how to install SmartTools and create your first AI-powered CLI tool",
"description": "Learn how to install CmdForge and create your first AI-powered CLI tool",
"content": """
<p class="lead">SmartTools lets you build custom AI-powered CLI commands using simple YAML configuration.
<p class="lead">CmdForge lets you build custom AI-powered CLI commands using simple YAML configuration.
Create tools that work with any AI provider and compose them like Unix pipes.</p>
<h2 id="what-is-smarttools">What is SmartTools?</h2>
<p>SmartTools is a lightweight personal tool builder that lets you:</p>
<h2 id="what-is-cmdforge">What is CmdForge?</h2>
<p>CmdForge is a lightweight personal tool builder that lets you:</p>
<ul>
<li><strong>Create custom CLI commands</strong> that call AI providers</li>
<li><strong>Chain prompts with Python code</strong> for complex workflows</li>
@@ -24,23 +24,23 @@ Create tools that work with any AI provider and compose them like Unix pipes.</p
<h2 id="quick-start">Quick Start</h2>
<p>Get up and running in under a minute:</p>
<pre><code class="language-bash"># Install SmartTools
pip install smarttools
<pre><code class="language-bash"># Install CmdForge
pip install cmdforge
# Create your first tool (choose your style)
smarttools ui # Visual builder with menus
smarttools create # CLI wizard
cmdforge ui # Visual builder with menus
cmdforge create # CLI wizard
# Or install a tool from the registry
smarttools registry install official/summarize
cmdforge registry install official/summarize
# Use it!
cat article.txt | summarize</code></pre>
<div class="bg-cyan-50 border-l-4 border-cyan-500 p-4 my-4">
<p class="font-semibold text-cyan-800">Two Ways to Build</p>
<p class="text-cyan-700"><code>smarttools ui</code> launches a visual builder with menus and forms.
<code>smarttools create</code> uses a command-line wizard. Both create the same YAML config files.</p>
<p class="text-cyan-700"><code>cmdforge ui</code> launches a visual builder with menus and forms.
<code>cmdforge create</code> uses a command-line wizard. Both create the same YAML config files.</p>
</div>
<h2 id="how-it-works">How It Works</h2>
@@ -87,11 +87,11 @@ output: "{summary}"</code></pre>
<ul>
<li><a href="/forum">Community Forum</a> - Ask questions, share projects, and connect with other users</li>
<li><a href="/forum/c/help">Help &amp; Support</a> - Get help with installation, configuration, or usage</li>
<li><a href="https://gitea.brrd.tech/rob/SmartTools/issues" target="_blank">Report a Bug</a> - Found an issue? Let us know</li>
<li><a href="https://gitea.brrd.tech/rob/CmdForge/issues" target="_blank">Report a Bug</a> - Found an issue? Let us know</li>
</ul>
""",
"headings": [
("what-is-smarttools", "What is SmartTools?"),
("what-is-cmdforge", "What is CmdForge?"),
("quick-start", "Quick Start"),
("how-it-works", "How It Works"),
("next-steps", "Next Steps"),
@@ -101,24 +101,24 @@ output: "{summary}"</code></pre>
"installation": {
"title": "Installation",
"description": "How to install SmartTools on your system",
"description": "How to install CmdForge on your system",
"parent": "getting-started",
"content": """
<p class="lead">SmartTools requires Python 3.8+ and works on Linux, macOS, and Windows.</p>
<p class="lead">CmdForge requires Python 3.8+ and works on Linux, macOS, and Windows.</p>
<h2 id="pip-install">Install with pip</h2>
<p>The simplest way to install SmartTools:</p>
<pre><code class="language-bash">pip install smarttools</code></pre>
<p>The simplest way to install CmdForge:</p>
<pre><code class="language-bash">pip install cmdforge</code></pre>
<p>Or with pipx for isolated installation:</p>
<pre><code class="language-bash">pipx install smarttools</code></pre>
<pre><code class="language-bash">pipx install cmdforge</code></pre>
<h2 id="verify">Verify Installation</h2>
<pre><code class="language-bash">smarttools --version
smarttools --help</code></pre>
<pre><code class="language-bash">cmdforge --version
cmdforge --help</code></pre>
<h2 id="configure-provider">Configure a Provider</h2>
<p>SmartTools needs at least one AI provider configured. The easiest is Claude CLI:</p>
<p>CmdForge needs at least one AI provider configured. The easiest is Claude CLI:</p>
<pre><code class="language-bash"># Install Claude CLI (if you have an Anthropic API key)
pip install claude-cli
@@ -127,17 +127,17 @@ pip install claude-cli
pip install openai
# Configure your provider
smarttools config</code></pre>
cmdforge config</code></pre>
<h2 id="wrapper-scripts">Wrapper Scripts Location</h2>
<p>SmartTools installs wrapper scripts to <code>~/.local/bin/</code>. Make sure this is in your PATH:</p>
<p>CmdForge installs wrapper scripts to <code>~/.local/bin/</code>. Make sure this is in your PATH:</p>
<pre><code class="language-bash"># Add to ~/.bashrc or ~/.zshrc
export PATH="$HOME/.local/bin:$PATH"</code></pre>
<h2 id="development-install">Development Installation</h2>
<p>To contribute or modify SmartTools:</p>
<pre><code class="language-bash">git clone https://gitea.brrd.tech/rob/SmartTools.git
cd SmartTools
<p>To contribute or modify CmdForge:</p>
<pre><code class="language-bash">git clone https://gitea.brrd.tech/rob/CmdForge.git
cd CmdForge
pip install -e ".[dev]"</code></pre>
""",
"headings": [
@@ -151,16 +151,16 @@ pip install -e ".[dev]"</code></pre>
"first-tool": {
"title": "Your First Tool",
"description": "Create your first SmartTools command step by step",
"description": "Create your first CmdForge command step by step",
"parent": "getting-started",
"content": """
<p class="lead">Let's create a simple tool that explains code. You'll learn the basics of tool configuration.</p>
<h2 id="create-tool">Create the Tool</h2>
<p>Run the interactive creator:</p>
<pre><code class="language-bash">smarttools create</code></pre>
<pre><code class="language-bash">cmdforge create</code></pre>
<p>Or create the file manually at <code>~/.smarttools/explain/config.yaml</code>:</p>
<p>Or create the file manually at <code>~/.cmdforge/explain/config.yaml</code>:</p>
<pre><code class="language-yaml">name: explain
version: "1.0.0"
description: Explain code or concepts in simple terms
@@ -230,9 +230,9 @@ cat complex_algorithm.py | explain --level expert</code></pre>
"publishing": {
"title": "Publishing Tools",
"description": "Share your tools with the SmartTools community",
"description": "Share your tools with the CmdForge community",
"content": """
<p class="lead">Share your tools with the community by publishing to the SmartTools Registry.</p>
<p class="lead">Share your tools with the community by publishing to the CmdForge Registry.</p>
<h2 id="before-publishing">Before Publishing</h2>
<p>Make sure your tool has:</p>
@@ -255,20 +255,20 @@ cat complex_algorithm.py | explain --level expert</code></pre>
<h2 id="publish">Publish Your Tool</h2>
<pre><code class="language-bash"># Navigate to your tool directory
cd ~/.smarttools/my-tool/
cd ~/.cmdforge/my-tool/
# First time: enter your token when prompted
smarttools registry publish
cmdforge registry publish
# Dry run to validate without publishing
smarttools registry publish --dry-run</code></pre>
cmdforge registry publish --dry-run</code></pre>
<h2 id="versioning">Versioning</h2>
<p>Published versions are <strong>immutable</strong>. To update a tool:</p>
<ol>
<li>Make your changes</li>
<li>Bump the version in <code>config.yaml</code></li>
<li>Run <code>smarttools registry publish</code></li>
<li>Run <code>cmdforge registry publish</code></li>
</ol>
<h2 id="best-practices">Best Practices</h2>
@@ -294,11 +294,11 @@ smarttools registry publish --dry-run</code></pre>
"title": "AI Providers",
"description": "Configure different AI providers for your tools",
"content": """
<p class="lead">SmartTools works with any AI provider that has a CLI interface. Configure providers in
<code>~/.smarttools/providers.yaml</code>.</p>
<p class="lead">CmdForge works with any AI provider that has a CLI interface. Configure providers in
<code>~/.cmdforge/providers.yaml</code>.</p>
<h2 id="provider-config">Provider Configuration</h2>
<p>Create or edit <code>~/.smarttools/providers.yaml</code>:</p>
<p>Create or edit <code>~/.cmdforge/providers.yaml</code>:</p>
<pre><code class="language-yaml">providers:
- name: claude
@@ -397,9 +397,9 @@ providers:
"parallel-orchestration": {
"title": "Parallel Orchestration",
"description": "Run multiple SmartTools concurrently for faster workflows",
"description": "Run multiple CmdForge concurrently for faster workflows",
"content": """
<p class="lead">SmartTools executes steps sequentially within a tool, but you can run
<p class="lead">CmdForge executes steps sequentially within a tool, but you can run
<strong>multiple tools in parallel</strong> using Python's ThreadPoolExecutor. This pattern
is ideal for multi-agent workflows, parallel analysis, or any task where you need responses
from multiple AI providers simultaneously.</p>
@@ -412,7 +412,7 @@ from multiple AI providers simultaneously.</p>
</ul>
<h2 id="basic-pattern">Basic Pattern</h2>
<p>Use Python's <code>concurrent.futures</code> to run multiple SmartTools in parallel:</p>
<p>Use Python's <code>concurrent.futures</code> to run multiple CmdForge in parallel:</p>
<pre><code class="language-python">import subprocess
from concurrent.futures import ThreadPoolExecutor, as_completed
@@ -604,11 +604,11 @@ def run_with_progress(tools: list[str], input_text: str):
</ul>
<h2 id="example-project">Full Example: orchestrated-discussions</h2>
<p>For a complete implementation of parallel SmartTools orchestration, see the
<p>For a complete implementation of parallel CmdForge orchestration, see the
<a href="https://gitea.brrd.tech/rob/orchestrated-discussions" target="_blank">orchestrated-discussions</a>
project. It implements:</p>
<ul>
<li>Multiple AI "participants" as SmartTools</li>
<li>Multiple AI "participants" as CmdForge</li>
<li>Parallel execution with live progress logging</li>
<li>Shared log files for real-time monitoring</li>
<li>Discussion workflows with voting and consensus</li>
@@ -656,7 +656,7 @@ steps:
output: "{result}"</code></pre>
<p>Save this to <code>~/.smarttools/shout/config.yaml</code> and you've got a working command:</p>
<p>Save this to <code>~/.cmdforge/shout/config.yaml</code> and you've got a working command:</p>
<pre><code class="language-bash">$ echo "hello world" | shout
HELLO WORLD!!!</code></pre>
@@ -1697,7 +1697,7 @@ loops, and more.</p>
<li>Using different AI models for different tasks</li>
<li>Building tools that adapt to their input</li>
<li>Self-critiquing workflows that iterate to perfection</li>
<li>Calling external tools from within your SmartTools</li>
<li>Calling external tools from within your CmdForge</li>
</ul>
</div>
@@ -1912,7 +1912,7 @@ output: "{result}"</code></pre>
<h2 id="external-tools">Calling External Tools</h2>
<p>SmartTools can wrap any command-line tool:</p>
<p>CmdForge can wrap any command-line tool:</p>
<pre><code class="language-yaml">name: lint-explain
version: "1.0.0"
@@ -2087,7 +2087,7 @@ output: "{formatted}"</code></pre>
"title": "The Visual Builder",
"description": "Build tools without touching YAML using the terminal UI",
"content": """
<p class="lead">Not everyone wants to write YAML by hand. SmartTools includes a full-featured
<p class="lead">Not everyone wants to write YAML by hand. CmdForge includes a full-featured
terminal UI that lets you create, edit, and test tools with menus and forms—no text editor required.</p>
<div class="bg-indigo-50 border-l-4 border-indigo-500 p-4 my-6">
@@ -2104,13 +2104,13 @@ terminal UI that lets you create, edit, and test tools with menus and forms—no
<p>Start the UI with a single command:</p>
<pre><code class="language-bash">smarttools ui</code></pre>
<pre><code class="language-bash">cmdforge ui</code></pre>
<p>You'll see a menu-driven interface that works in any terminal:</p>
<div class="bg-gray-900 text-gray-100 rounded-lg p-4 my-6 font-mono text-sm">
<pre>┌─────────────────────────────────────────────────────────┐
│ SmartTools Manager │
│ CmdForge Manager │
├─────────────────────────────────────────────────────────┤
│ │
│ [ List all tools ] │
@@ -2158,7 +2158,7 @@ terminal UI that lets you create, edit, and test tools with menus and forms—no
<h3>Step-by-Step: Creating a Summarizer</h3>
<ol class="space-y-3">
<li><strong>Launch:</strong> Run <code>smarttools ui</code></li>
<li><strong>Launch:</strong> Run <code>cmdforge ui</code></li>
<li><strong>Select:</strong> Choose "Create new tool"</li>
<li><strong>Info:</strong> Go to "Info & Args", set name to <code>summarize</code></li>
<li><strong>Add Argument:</strong> Click "Add Argument", set flag to <code>--length</code>, default to <code>100</code></li>
@@ -2243,7 +2243,7 @@ terminal UI that lets you create, edit, and test tools with menus and forms—no
<h2 id="ui-backends">UI Backends</h2>
<p>SmartTools automatically uses the best available terminal UI library:</p>
<p>CmdForge automatically uses the best available terminal UI library:</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 my-6 text-sm">
<div class="bg-green-50 border border-green-200 rounded-lg p-3">
@@ -2276,7 +2276,7 @@ terminal UI that lets you create, edit, and test tools with menus and forms—no
</thead>
<tbody>
<tr class="border-b">
<td class="px-4 py-2">You're new to SmartTools</td>
<td class="px-4 py-2">You're new to CmdForge</td>
<td class="px-4 py-2">You're comfortable with YAML</td>
</tr>
<tr class="border-b">
+5
View File
@@ -0,0 +1,5 @@
"""Forum blueprint for CmdForge community discussions."""
from .routes import forum_bp
__all__ = ["forum_bp"]
@@ -6,7 +6,7 @@ import re
import sqlite3
from typing import Any
from smarttools.registry.db import connect_db, query_one, query_all
from cmdforge.registry.db import connect_db, query_one, query_all
FORUM_SCHEMA = """
@@ -51,9 +51,9 @@ CREATE INDEX IF NOT EXISTS idx_forum_replies_topic ON forum_replies(topic_id);
"""
DEFAULT_CATEGORIES = [
("general", "General Discussion", "Chat about anything SmartTools related", "chat", 1),
("general", "General Discussion", "Chat about anything CmdForge related", "chat", 1),
("help", "Help & Support", "Get help with installation, configuration, or usage", "question", 2),
("showcase", "Showcase", "Share tools and projects you've built with SmartTools", "star", 3),
("showcase", "Showcase", "Share tools and projects you've built with CmdForge", "star", 3),
("ideas", "Ideas & Feedback", "Suggest features and improvements", "lightbulb", 4),
("tutorials", "Tutorials & Guides", "Community-written guides and how-tos", "book", 5),
]
@@ -19,7 +19,7 @@ from flask import (
url_for,
)
from smarttools.registry.db import connect_db
from cmdforge.registry.db import connect_db
from .models import (
create_reply,
@@ -1,4 +1,4 @@
"""Public web routes for the SmartTools UI."""
"""Public web routes for the CmdForge UI."""
from __future__ import annotations
@@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, Tuple
from markupsafe import Markup, escape
from flask import current_app, redirect, render_template, request, session, url_for
from smarttools.registry.db import connect_db, query_all, query_one
from cmdforge.registry.db import connect_db, query_all, query_one
from . import web_bp
@@ -499,7 +499,7 @@ def docs(path: str):
else:
page = SimpleNamespace(
title=_title_case(current),
description="SmartTools documentation",
description="CmdForge documentation",
content_html=Markup(f"<p>Documentation for <strong>{escape(current)}</strong> is coming soon.</p>"),
headings=[],
parent=None,
@@ -7,7 +7,7 @@ from typing import List
from flask import Response, current_app, url_for
from smarttools.registry.db import connect_db, query_all
from cmdforge.registry.db import connect_db, query_all
SITEMAP_TTL = timedelta(hours=6)
_sitemap_cache = {"generated_at": None, "xml": ""}
@@ -10,7 +10,7 @@ from typing import Optional
from flask.sessions import SessionInterface, SessionMixin
from werkzeug.datastructures import CallbackDict
from smarttools.registry.db import connect_db
from cmdforge.registry.db import connect_db
SESSION_TTL = timedelta(days=7)
@@ -22,7 +22,7 @@ class SQLiteSession(CallbackDict, SessionMixin):
class SQLiteSessionInterface(SessionInterface):
def __init__(self, cookie_name: str = "smarttools_session"):
def __init__(self, cookie_name: str = "cmdforge_session"):
self.cookie_name = cookie_name
def open_session(self, app, request):
@@ -1,5 +1,5 @@
/**
* SmartTools Web UI - Main JavaScript
* CmdForge Web UI - Main JavaScript
*/
// Copy to clipboard utility
@@ -1,6 +1,6 @@
# SmartTools Registry - robots.txt
# CmdForge Registry - robots.txt
# We welcome all crawlers! Index everything to help users find us
# and enable AI assistants to help solve SmartTools issues.
# and enable AI assistants to help solve CmdForge issues.
User-agent: *
Allow: /
@@ -11,7 +11,7 @@ Allow: /tutorials/
Allow: /tools/
Allow: /categories/
# Allow AI crawlers explicitly (we want AI to learn about SmartTools)
# Allow AI crawlers explicitly (we want AI to learn about CmdForge)
User-agent: GPTBot
Allow: /
@@ -42,6 +42,6 @@ Disallow: /api/v1/tokens
Allow: /api/
# Sitemap location
Sitemap: https://registry.smarttools.dev/sitemap.xml
Sitemap: https://cmdforge.brrd.tech/sitemap.xml
# Crawl-delay: none - crawl as fast as you want!
@@ -3,14 +3,14 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}SmartTools{% endblock %} - Build Custom AI Commands</title>
<title>{% block title %}CmdForge{% endblock %} - Build Custom AI Commands</title>
<!-- Meta tags -->
<meta name="description" content="{% block meta_description %}Create Unix-style pipeable tools that work with any AI provider. Provider-agnostic, composable, and community-driven.{% endblock %}">
{% block meta_extra %}{% endblock %}
<!-- Open Graph -->
<meta property="og:title" content="{% block og_title %}SmartTools{% endblock %}">
<meta property="og:title" content="{% block og_title %}CmdForge{% endblock %}">
<meta property="og:description" content="{% block og_description %}Build custom AI commands in YAML{% endblock %}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
@@ -18,7 +18,7 @@
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{% block twitter_title %}SmartTools{% endblock %}">
<meta name="twitter:title" content="{% block twitter_title %}CmdForge{% endblock %}">
<meta name="twitter:description" content="{% block twitter_description %}Build custom AI commands in YAML{% endblock %}">
{% block twitter_extra %}{% endblock %}
@@ -40,7 +40,7 @@
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "SmartTools",
"name": "CmdForge",
"url": "{{ request.host_url }}",
"description": "Build custom AI commands in YAML"
}
@@ -3,19 +3,19 @@
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
<!-- Brand -->
<div class="col-span-1 md:col-span-2">
<a href="{{ url_for('web.index') }}" class="text-xl font-bold">SmartTools</a>
<a href="{{ url_for('web.index') }}" class="text-xl font-bold">CmdForge</a>
<p class="mt-2 text-gray-400 text-sm max-w-md">
Build custom AI commands in YAML. Create Unix-style pipeable tools that work with any AI provider.
Provider-agnostic, composable, and community-driven.
</p>
<div class="mt-4 flex space-x-4">
<a href="https://github.com/rob/smarttools" target="_blank" rel="noopener noreferrer"
<a href="https://github.com/rob/cmdforge" target="_blank" rel="noopener noreferrer"
class="text-gray-400 hover:text-white transition-colors" aria-label="GitHub">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/>
</svg>
</a>
<a href="https://twitter.com/smarttools" target="_blank" rel="noopener noreferrer"
<a href="https://twitter.com/cmdforge" target="_blank" rel="noopener noreferrer"
class="text-gray-400 hover:text-white transition-colors" aria-label="Twitter">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84"/>
@@ -50,7 +50,7 @@
<div class="mt-8 pt-8 border-t border-slate-700 flex flex-col sm:flex-row justify-between items-center">
<p class="text-gray-400 text-sm">
&copy; {{ now().year }} SmartTools. Open source under MIT License.
&copy; {{ now().year }} CmdForge. Open source under MIT License.
</p>
<p class="text-gray-300 text-xs mt-2 sm:mt-0">
Made with care for the developer community.
@@ -4,7 +4,7 @@
<!-- Logo -->
<div class="flex-shrink-0">
<a href="{{ url_for('web.index') }}" class="text-xl font-bold hover:text-indigo-400 transition-colors">
SmartTools
CmdForge
</a>
</div>
@@ -54,10 +54,10 @@
<div class="mt-4">
<div class="flex items-center bg-gray-100 rounded px-3 py-2 group">
<code class="text-xs text-gray-700 flex-1 truncate font-mono">
smarttools install {{ tool.owner }}/{{ tool.name }}
cmdforge install {{ tool.owner }}/{{ tool.name }}
</code>
<button type="button"
onclick="copyToClipboard('smarttools install {{ tool.owner }}/{{ tool.name }}')"
onclick="copyToClipboard('cmdforge install {{ tool.owner }}/{{ tool.name }}')"
class="ml-2 p-1 text-gray-400 hover:text-gray-600 opacity-0 group-hover:opacity-100 transition-opacity"
aria-label="Copy install command">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -39,7 +39,7 @@
</a>
</h3>
<p class="mt-2 text-sm text-gray-600 line-clamp-2">
{{ tutorial.description or 'Learn how to use SmartTools effectively.' }}
{{ tutorial.description or 'Learn how to use CmdForge effectively.' }}
</p>
<a href="{{ href or '#' }}"
class="mt-4 inline-flex items-center text-sm font-medium text-indigo-600 hover:text-indigo-800 transition-colors">
@@ -1,7 +1,7 @@
{% extends "dashboard/base.html" %}
{% set active_page = 'overview' %}
{% block title %}Dashboard - SmartTools{% endblock %}
{% block title %}Dashboard - CmdForge{% endblock %}
{% block dashboard_content %}
<!-- Stats Cards -->
@@ -2,7 +2,7 @@
{% from "components/forms.html" import text_input, textarea, button_primary, form_errors, success_alert %}
{% set active_page = 'settings' %}
{% block title %}Settings - SmartTools Dashboard{% endblock %}
{% block title %}Settings - CmdForge Dashboard{% endblock %}
{% block dashboard_header %}
<h1 class="text-2xl font-bold text-gray-900">Settings</h1>
@@ -1,7 +1,7 @@
{% extends "dashboard/base.html" %}
{% set active_page = 'tokens' %}
{% block title %}API Tokens - SmartTools Dashboard{% endblock %}
{% block title %}API Tokens - CmdForge Dashboard{% endblock %}
{% block dashboard_header %}
<div class="flex items-center justify-between">
@@ -30,9 +30,9 @@
<div class="ml-3">
<h4 class="text-sm font-medium text-blue-800">About API Tokens</h4>
<p class="mt-1 text-sm text-blue-700">
API tokens are used to authenticate with the SmartTools registry from the CLI.
Use <code class="px-1 bg-blue-100 rounded">smarttools auth login</code> to authenticate,
or set the <code class="px-1 bg-blue-100 rounded">SMARTTOOLS_TOKEN</code> environment variable.
API tokens are used to authenticate with the CmdForge registry from the CLI.
Use <code class="px-1 bg-blue-100 rounded">cmdforge auth login</code> to authenticate,
or set the <code class="px-1 bg-blue-100 rounded">CMDFORGE_TOKEN</code> environment variable.
</p>
</div>
</div>
@@ -215,7 +215,7 @@
<p class="mt-4 text-sm text-gray-600">
To use this token, run:
</p>
<pre class="mt-2 bg-gray-900 text-gray-100 text-sm p-3 rounded-lg overflow-x-auto"><code>export SMARTTOOLS_TOKEN="<span id="token-in-export"></span>"</code></pre>
<pre class="mt-2 bg-gray-900 text-gray-100 text-sm p-3 rounded-lg overflow-x-auto"><code>export CMDFORGE_TOKEN="<span id="token-in-export"></span>"</code></pre>
</div>
<div class="bg-gray-50 px-6 py-4 rounded-b-lg flex justify-end">
@@ -1,7 +1,7 @@
{% extends "dashboard/base.html" %}
{% set active_page = 'tools' %}
{% block title %}My Tools - SmartTools Dashboard{% endblock %}
{% block title %}My Tools - CmdForge Dashboard{% endblock %}
{% block dashboard_header %}
<div class="flex items-center justify-between">
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Page Not Found - SmartTools{% endblock %}
{% block title %}Page Not Found - CmdForge{% endblock %}
{% block content %}
<div class="min-h-[60vh] flex items-center justify-center px-4">
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Server Error - SmartTools{% endblock %}
{% block title %}Server Error - CmdForge{% endblock %}
{% block content %}
<div class="min-h-[60vh] flex items-center justify-center px-4">
@@ -15,7 +15,7 @@
class="w-full sm:w-auto inline-flex justify-center items-center px-6 py-3 text-base font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700">
Go Home
</a>
<a href="https://github.com/your-org/smarttools/issues"
<a href="https://github.com/your-org/cmdforge/issues"
target="_blank"
rel="noopener noreferrer"
class="w-full sm:w-auto inline-flex justify-center items-center px-6 py-3 text-base font-medium text-gray-700 border border-gray-300 rounded-md hover:bg-gray-50">
@@ -2,7 +2,7 @@
{% block title %}Community Forum{% endblock %}
{% block meta_description %}Join the SmartTools community. Ask questions, share your projects, and connect with other users.{% endblock %}
{% block meta_description %}Join the CmdForge community. Ask questions, share your projects, and connect with other users.{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -11,7 +11,7 @@
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<h1 class="text-3xl font-bold text-gray-900">Community Forum</h1>
<p class="mt-2 text-gray-600">
Ask questions, share your projects, and connect with other SmartTools users.
Ask questions, share your projects, and connect with other CmdForge users.
</p>
<div class="mt-4 flex items-center gap-6 text-sm text-gray-500">
<span>{{ stats.topics }} topics</span>
@@ -119,7 +119,7 @@
</svg>
Browse Tools
</a>
<a href="https://gitea.brrd.tech/rob/SmartTools/issues"
<a href="https://gitea.brrd.tech/rob/CmdForge/issues"
target="_blank" rel="noopener"
class="flex items-center text-sm text-gray-600 hover:text-indigo-600">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -1,14 +1,14 @@
{% extends "base.html" %}
{% block title %}About - SmartTools{% endblock %}
{% block title %}About - CmdForge{% endblock %}
{% block meta_description %}Learn about SmartTools, the open-source platform for building custom AI-powered command-line tools.{% endblock %}
{% block meta_description %}Learn about CmdForge, the open-source platform for building custom AI-powered command-line tools.{% endblock %}
{% block content %}
<div class="bg-white">
<!-- Hero -->
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16 text-center">
<h1 class="text-4xl font-bold text-gray-900">About SmartTools</h1>
<h1 class="text-4xl font-bold text-gray-900">About CmdForge</h1>
<p class="mt-6 text-xl text-gray-600">
An open-source platform for building and sharing AI-powered command-line tools.
</p>
@@ -20,7 +20,7 @@
<h2 class="text-2xl font-bold text-gray-900 mb-6">Our Mission</h2>
<div class="prose prose-lg prose-indigo max-w-none">
<p>
SmartTools was created with a simple belief: powerful AI tools should be accessible to everyone,
CmdForge was created with a simple belief: powerful AI tools should be accessible to everyone,
not just those with extensive programming knowledge or expensive API subscriptions.
</p>
<p>
@@ -29,7 +29,7 @@
</p>
<p>
Our platform follows the Unix philosophy: simple, composable tools that do one thing well.
With SmartTools, you can create custom AI commands using simple YAML configuration,
With CmdForge, you can create custom AI commands using simple YAML configuration,
chain them together, and share them with the community.
</p>
</div>
@@ -49,7 +49,7 @@
</div>
<h3 class="text-lg font-semibold text-gray-900 mb-2">Open Source</h3>
<p class="text-gray-600">
SmartTools is MIT licensed and open source. We believe in transparency and community ownership.
CmdForge is MIT licensed and open source. We believe in transparency and community ownership.
</p>
</div>
@@ -98,7 +98,7 @@
<h2 class="text-2xl font-bold text-gray-900 mb-6">Sustainability</h2>
<div class="prose prose-lg prose-indigo max-w-none">
<p>
SmartTools is committed to long-term sustainability. Revenue from optional ads
CmdForge is committed to long-term sustainability. Revenue from optional ads
and donations supports:
</p>
<ul>
@@ -121,9 +121,9 @@
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 class="text-2xl font-bold text-gray-900 mb-6">Contribute</h2>
<p class="text-lg text-gray-600 mb-8">
SmartTools is open source and welcomes contributions of all kinds.
CmdForge is open source and welcomes contributions of all kinds.
</p>
<a href="https://github.com/your-org/smarttools"
<a href="https://github.com/your-org/cmdforge"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-6 py-3 text-base font-medium text-white bg-gray-900 rounded-md hover:bg-gray-800">
@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Community - SmartTools{% endblock %}
{% block title %}Community - CmdForge{% endblock %}
{% block meta_description %}Connect with SmartTools - report issues, request features, and contribute to the project.{% endblock %}
{% block meta_description %}Connect with CmdForge - report issues, request features, and contribute to the project.{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -11,7 +11,7 @@
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 text-center">
<h1 class="text-3xl font-bold text-gray-900">Community</h1>
<p class="mt-4 text-lg text-gray-600">
SmartTools is open source. Get help, report issues, and contribute.
CmdForge is open source. Get help, report issues, and contribute.
</p>
</div>
</div>
@@ -52,7 +52,7 @@
<p class="mt-2 text-sm text-gray-600">
Browse the source, fork the project, and submit pull requests.
</p>
<a href="https://gitea.brrd.tech/rob/SmartTools"
<a href="https://gitea.brrd.tech/rob/CmdForge"
target="_blank" rel="noopener"
class="mt-4 inline-flex items-center text-sm font-medium text-indigo-600 hover:text-indigo-800">
View Repository
@@ -72,7 +72,7 @@
<p class="mt-2 text-sm text-gray-600">
Found a bug? Have a feature request? Open an issue.
</p>
<a href="https://gitea.brrd.tech/rob/SmartTools/issues"
<a href="https://gitea.brrd.tech/rob/CmdForge/issues"
target="_blank" rel="noopener"
class="mt-4 inline-flex items-center text-sm font-medium text-indigo-600 hover:text-indigo-800">
Open Issue
@@ -137,7 +137,7 @@
<div>
<h3 class="font-semibold text-gray-900">Report Bugs</h3>
<p class="mt-1 text-sm text-gray-600">
Help make SmartTools better by reporting issues with clear reproduction steps.
Help make CmdForge better by reporting issues with clear reproduction steps.
</p>
</div>
</div>
@@ -163,7 +163,7 @@
class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700">
Visit Forum
</a>
<a href="https://gitea.brrd.tech/rob/SmartTools#installation"
<a href="https://gitea.brrd.tech/rob/CmdForge#installation"
target="_blank" rel="noopener"
class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50">
Installation
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}{{ title }} - SmartTools{% endblock %}
{% block title %}{{ title }} - CmdForge{% endblock %}
{% block content %}
<section class="bg-white py-16">
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% from "components/callouts.html" import info, warning, tip %}
{% block title %}{{ page.title }} - SmartTools Docs{% endblock %}
{% block title %}{{ page.title }} - CmdForge Docs{% endblock %}
{% block meta_description %}{{ page.description or page.title }}{% endblock %}
@@ -124,7 +124,7 @@
<!-- Edit on GitHub -->
<div class="mt-6 text-center">
<a href="https://github.com/your-org/smarttools/edit/main/docs/{{ current_path }}.md"
<a href="https://github.com/your-org/cmdforge/edit/main/docs/{{ current_path }}.md"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center text-sm text-gray-500 hover:text-gray-700">
@@ -1,17 +1,17 @@
{% extends "base.html" %}
{% block title %}Support SmartTools{% endblock %}
{% block title %}Support CmdForge{% endblock %}
{% block meta_description %}Support SmartTools by contributing code, tools, or feedback.{% endblock %}
{% block meta_description %}Support CmdForge by contributing code, tools, or feedback.{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
<!-- Hero -->
<div class="bg-white border-b border-gray-200">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 text-center">
<h1 class="text-3xl font-bold text-gray-900">Support SmartTools</h1>
<h1 class="text-3xl font-bold text-gray-900">Support CmdForge</h1>
<p class="mt-4 text-lg text-gray-600">
SmartTools is a passion project. The best way to support it is to use it and share what you build.
CmdForge is a passion project. The best way to support it is to use it and share what you build.
</p>
</div>
</div>
@@ -38,7 +38,7 @@
</div>
<h2 class="text-lg font-semibold text-gray-900">Spread the Word</h2>
<p class="mt-2 text-sm text-gray-600">
Tell a friend or colleague who might find SmartTools useful.
Tell a friend or colleague who might find CmdForge useful.
</p>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-6">
@@ -58,10 +58,10 @@
<section class="bg-white rounded-lg border border-gray-200 p-8 text-center">
<h2 class="text-2xl font-bold text-gray-900">Get Involved</h2>
<p class="mt-3 text-gray-600 max-w-2xl mx-auto">
SmartTools is open source. The code, docs, and registry are all open for contributions.
CmdForge is open source. The code, docs, and registry are all open for contributions.
</p>
<div class="mt-6 flex flex-col sm:flex-row items-center justify-center gap-4">
<a href="https://gitea.brrd.tech/rob/SmartTools"
<a href="https://gitea.brrd.tech/rob/CmdForge"
target="_blank" rel="noopener"
class="inline-flex items-center px-6 py-3 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
@@ -79,7 +79,7 @@
<!-- Thank you -->
<section class="mt-12 text-center">
<p class="text-gray-500">
Thanks for using SmartTools!
Thanks for using CmdForge!
</p>
</section>
</div>
@@ -3,7 +3,7 @@
{% from "components/tutorial_card.html" import tutorial_card %}
{% from "components/contributor_card.html" import contributor_card %}
{% block title %}SmartTools - Build Custom AI Commands in YAML{% endblock %}
{% block title %}CmdForge - Build Custom AI Commands in YAML{% endblock %}
{% block meta_description %}Create Unix-style pipeable AI tools with simple YAML configuration. Provider-agnostic, composable, and community-driven.{% endblock %}
@@ -21,7 +21,7 @@
<!-- Install Link -->
<div class="mt-10">
<a href="https://gitea.brrd.tech/rob/SmartTools#installation"
<a href="https://gitea.brrd.tech/rob/CmdForge#installation"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-2 text-indigo-600 hover:text-indigo-800 font-medium transition-colors">
@@ -50,7 +50,7 @@
<section class="py-16 bg-gray-50">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-3xl font-bold text-gray-900 text-center mb-12">
Why SmartTools?
Why CmdForge?
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
@@ -144,7 +144,7 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
{{ tutorial_card(
title="Basic Setup",
description="Learn how to install SmartTools and configure your first AI provider.",
description="Learn how to install CmdForge and configure your first AI provider.",
href=url_for('web.docs', path='getting-started'),
step_number=1
) }}
@@ -191,7 +191,7 @@
<p class="text-xs text-gray-500 mb-2">Advertisement</p>
<div id="footer-ad-zone" class="min-h-[90px] flex items-center justify-center">
<!-- Ad content loaded dynamically -->
<p class="text-gray-400 text-sm">Support SmartTools Development</p>
<p class="text-gray-400 text-sm">Support CmdForge Development</p>
</div>
</div>
</section>
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% from "components/forms.html" import text_input, button_primary, form_errors %}
{% block title %}Sign In - SmartTools{% endblock %}
{% block title %}Sign In - CmdForge{% endblock %}
{% block content %}
<div class="min-h-[70vh] flex items-center justify-center px-4 py-12">
@@ -12,7 +12,7 @@
<path d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
</a>
<h1 class="mt-4 text-2xl font-bold text-gray-900">Sign in to SmartTools</h1>
<h1 class="mt-4 text-2xl font-bold text-gray-900">Sign in to CmdForge</h1>
<p class="mt-2 text-gray-600">
Access your dashboard and manage your tools
</p>
@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Privacy Policy - SmartTools{% endblock %}
{% block title %}Privacy Policy - CmdForge{% endblock %}
{% block meta_description %}SmartTools privacy policy. Learn how we collect, use, and protect your data.{% endblock %}
{% block meta_description %}CmdForge privacy policy. Learn how we collect, use, and protect your data.{% endblock %}
{% block content %}
<div class="bg-white py-16">
@@ -13,7 +13,7 @@
<div class="prose prose-lg prose-indigo max-w-none">
<h2>Introduction</h2>
<p>
SmartTools ("we", "our", or "us") respects your privacy and is committed to protecting
CmdForge ("we", "our", or "us") respects your privacy and is committed to protecting
your personal data. This privacy policy explains how we collect, use, and safeguard
your information when you use our website and services.
</p>
@@ -121,8 +121,8 @@
contact us at:
</p>
<ul>
<li>Email: privacy@smarttools.dev</li>
<li>GitHub: <a href="https://github.com/your-org/smarttools/issues">Open an issue</a></li>
<li>Email: privacy@cmdforge.dev</li>
<li>GitHub: <a href="https://github.com/your-org/cmdforge/issues">Open an issue</a></li>
</ul>
</div>
</div>
@@ -1,9 +1,9 @@
{% extends "base.html" %}
{% from "components/tool_card.html" import tool_card %}
{% block title %}{{ publisher.display_name }} (@{{ publisher.slug }}) - SmartTools{% endblock %}
{% block title %}{{ publisher.display_name }} (@{{ publisher.slug }}) - CmdForge{% endblock %}
{% block meta_description %}{{ publisher.bio or 'SmartTools publisher profile for ' ~ publisher.display_name }}{% endblock %}
{% block meta_description %}{{ publisher.bio or 'CmdForge publisher profile for ' ~ publisher.display_name }}{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% from "components/forms.html" import text_input, button_primary, form_errors, checkbox %}
{% block title %}Create Account - SmartTools{% endblock %}
{% block title %}Create Account - CmdForge{% endblock %}
{% block content %}
<div class="min-h-[70vh] flex items-center justify-center px-4 py-12">
@@ -1,9 +1,9 @@
{% extends "base.html" %}
{% from "components/tool_card.html" import tool_card %}
{% block title %}Search: {{ query }} - SmartTools Registry{% endblock %}
{% block title %}Search: {{ query }} - CmdForge Registry{% endblock %}
{% block meta_description %}Search results for "{{ query }}" in the SmartTools Registry.{% endblock %}
{% block meta_description %}Search results for "{{ query }}" in the CmdForge Registry.{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Terms of Service - SmartTools{% endblock %}
{% block title %}Terms of Service - CmdForge{% endblock %}
{% block meta_description %}SmartTools terms of service. Read our terms and conditions for using the platform.{% endblock %}
{% block meta_description %}CmdForge terms of service. Read our terms and conditions for using the platform.{% endblock %}
{% block content %}
<div class="bg-white py-16">
@@ -13,19 +13,19 @@
<div class="prose prose-lg prose-indigo max-w-none">
<h2>1. Acceptance of Terms</h2>
<p>
By accessing or using SmartTools ("the Service"), you agree to be bound by these
By accessing or using CmdForge ("the Service"), you agree to be bound by these
Terms of Service ("Terms"). If you do not agree to these Terms, you may not use
the Service.
</p>
<h2>2. Description of Service</h2>
<p>
SmartTools is a platform for creating, publishing, and sharing AI-powered
CmdForge is a platform for creating, publishing, and sharing AI-powered
command-line tools. The Service includes:
</p>
<ul>
<li>The SmartTools CLI application</li>
<li>The SmartTools Registry (tool hosting and discovery)</li>
<li>The CmdForge CLI application</li>
<li>The CmdForge Registry (tool hosting and discovery)</li>
<li>Documentation and tutorials</li>
<li>Community features</li>
</ul>
@@ -46,7 +46,7 @@
<h3>4.1 Your Content</h3>
<p>
You retain ownership of tools and content you publish ("User Content"). By publishing
to the Registry, you grant SmartTools a non-exclusive, worldwide license to host,
to the Registry, you grant CmdForge a non-exclusive, worldwide license to host,
distribute, and display your User Content.
</p>
@@ -80,22 +80,22 @@
<h2>6. API and CLI Usage</h2>
<p>
Access to the SmartTools API and CLI is subject to rate limits. Excessive use
Access to the CmdForge API and CLI is subject to rate limits. Excessive use
that impacts service availability for others may result in temporary or permanent
restrictions.
</p>
<h2>7. Third-Party Services</h2>
<p>
SmartTools is designed to work with various AI providers and external services.
CmdForge is designed to work with various AI providers and external services.
Your use of these third-party services is subject to their respective terms and
conditions. We are not responsible for third-party services.
</p>
<h2>8. Intellectual Property</h2>
<p>
The SmartTools software is open source and licensed under the MIT License.
The SmartTools name, logo, and branding are trademarks of SmartTools.
The CmdForge software is open source and licensed under the MIT License.
The CmdForge name, logo, and branding are trademarks of CmdForge.
</p>
<h2>9. Disclaimer of Warranties</h2>
@@ -104,20 +104,20 @@
WE DO NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE, OR SECURE.
</p>
<p>
Tools published by third parties are not endorsed by SmartTools. You use third-party
Tools published by third parties are not endorsed by CmdForge. You use third-party
tools at your own risk.
</p>
<h2>10. Limitation of Liability</h2>
<p>
TO THE MAXIMUM EXTENT PERMITTED BY LAW, SMARTTOOLS SHALL NOT BE LIABLE FOR ANY
TO THE MAXIMUM EXTENT PERMITTED BY LAW, CMDFORGE SHALL NOT BE LIABLE FOR ANY
INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES ARISING FROM
YOUR USE OF THE SERVICE.
</p>
<h2>11. Indemnification</h2>
<p>
You agree to indemnify and hold harmless SmartTools and its contributors from
You agree to indemnify and hold harmless CmdForge and its contributors from
any claims, damages, or expenses arising from your use of the Service or
violation of these Terms.
</p>
@@ -140,7 +140,7 @@
<h2>14. Governing Law</h2>
<p>
These Terms are governed by the laws of the jurisdiction in which SmartTools
These Terms are governed by the laws of the jurisdiction in which CmdForge
operates, without regard to conflict of law principles.
</p>
@@ -149,8 +149,8 @@
For questions about these Terms, please contact us at:
</p>
<ul>
<li>Email: legal@smarttools.dev</li>
<li>GitHub: <a href="https://github.com/your-org/smarttools/issues">Open an issue</a></li>
<li>Email: legal@cmdforge.dev</li>
<li>GitHub: <a href="https://github.com/your-org/cmdforge/issues">Open an issue</a></li>
</ul>
</div>
</div>
@@ -1,12 +1,12 @@
{% extends "base.html" %}
{% from "components/callouts.html" import warning, info %}
{% block title %}{{ tool.owner }}/{{ tool.name }} - SmartTools Registry{% endblock %}
{% block title %}{{ tool.owner }}/{{ tool.name }} - CmdForge Registry{% endblock %}
{% block meta_description %}{{ tool.description or 'A SmartTools command-line tool' }}{% endblock %}
{% block meta_description %}{{ tool.description or 'A CmdForge command-line tool' }}{% endblock %}
{% block og_title %}{{ tool.owner }}/{{ tool.name }}{% endblock %}
{% block og_description %}{{ tool.description or 'A SmartTools command-line tool' }}{% endblock %}
{% block og_description %}{{ tool.description or 'A CmdForge command-line tool' }}{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -91,7 +91,7 @@
<p>{{ tool.description or 'No additional documentation available.' }}</p>
<h2>Installation</h2>
<pre><code>smarttools install {{ tool.owner }}/{{ tool.name }}</code></pre>
<pre><code>cmdforge install {{ tool.owner }}/{{ tool.name }}</code></pre>
<h2>Usage</h2>
<pre><code>{{ tool.name }} --help</code></pre>
@@ -108,7 +108,7 @@
<h3 class="text-lg font-semibold text-gray-900 mb-4">Install</h3>
<div class="flex items-center bg-gray-100 rounded-lg p-3 group">
<span class="text-gray-400 mr-2 select-none">$</span>
<code id="install-cmd" class="flex-1 text-sm text-gray-800 font-mono overflow-x-auto">smarttools install {{ tool.owner }}/{{ tool.name }}</code>
<code id="install-cmd" class="flex-1 text-sm text-gray-800 font-mono overflow-x-auto">cmdforge install {{ tool.owner }}/{{ tool.name }}</code>
<button type="button"
onclick="copyInstall()"
class="ml-2 p-1.5 text-gray-400 hover:text-gray-600"
@@ -267,7 +267,7 @@
<script>
function copyInstall() {
const cmd = 'smarttools install {{ tool.owner }}/{{ tool.name }}';
const cmd = 'cmdforge install {{ tool.owner }}/{{ tool.name }}';
navigator.clipboard.writeText(cmd).then(() => {
const copyIcon = document.getElementById('copy-icon');
const checkIcon = document.getElementById('check-icon');
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% from "components/tool_card.html" import tool_card %}
{% block title %}Browse Tools - SmartTools Registry{% endblock %}
{% block title %}Browse Tools - CmdForge Registry{% endblock %}
{% block meta_description %}Discover and install community-built AI tools. Browse by category, search by name, or explore the most popular tools.{% endblock %}
@@ -1,9 +1,9 @@
{% extends "base.html" %}
{% from "components/tutorial_card.html" import tutorial_card %}
{% block title %}Tutorials - SmartTools{% endblock %}
{% block title %}Tutorials - CmdForge{% endblock %}
{% block meta_description %}Learn how to use SmartTools with step-by-step tutorials. From basic setup to advanced workflows.{% endblock %}
{% block meta_description %}Learn how to use CmdForge with step-by-step tutorials. From basic setup to advanced workflows.{% endblock %}
{% block content %}
<div class="bg-gray-50 min-h-screen">
@@ -12,7 +12,7 @@
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 text-center">
<h1 class="text-3xl font-bold text-gray-900">Tutorials</h1>
<p class="mt-4 text-lg text-gray-600">
Learn SmartTools from the ground up with step-by-step guides.
Learn CmdForge from the ground up with step-by-step guides.
</p>
</div>
</div>
@@ -22,13 +22,13 @@
<section class="mb-16">
<h2 class="text-2xl font-bold text-gray-900 mb-6">Getting Started</h2>
<p class="text-gray-600 mb-8">
New to SmartTools? Start here with the fundamentals.
New to CmdForge? Start here with the fundamentals.
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
{{ tutorial_card(
title="Installation & Setup",
description="Install SmartTools and configure your first AI provider.",
description="Install CmdForge and configure your first AI provider.",
href=url_for('web.tutorials_path', path='installation'),
step_number=1
) }}
@@ -42,7 +42,7 @@
{{ tutorial_card(
title="Understanding YAML Config",
description="Learn the structure of SmartTools configuration files.",
description="Learn the structure of CmdForge configuration files.",
href=url_for('web.tutorials_path', path='yaml-config'),
step_number=3
) }}
@@ -53,7 +53,7 @@
<section class="mb-16">
<h2 class="text-2xl font-bold text-gray-900 mb-6">Core Concepts</h2>
<p class="text-gray-600 mb-8">
Understand the key concepts that power SmartTools.
Understand the key concepts that power CmdForge.
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
-3
View File
@@ -1,3 +0,0 @@
"""SmartTools - A lightweight personal tool builder for AI-powered CLI commands."""
__version__ = "0.1.0"
-5
View File
@@ -1,5 +0,0 @@
"""Forum blueprint for SmartTools community discussions."""
from .routes import forum_bp
__all__ = ["forum_bp"]