Files
dss/dss-cli.py
2025-12-11 07:13:06 -03:00

212 lines
8.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
DSS-CLI - A command-line interface for the DSS Engine.
This script provides a direct, scriptable interface to the core functionalities
of the DSS analysis and context engine. It is designed for use in CI/CD
pipelines and other automated workflows.
"""
import argparse
import asyncio
import json
import sys
from pathlib import Path
# Ensure the script can find the 'dss' module
# This adds the parent directory of 'dss-mvp1' to the Python path
# Assuming the script is run from the project root, this will allow `from dss...` imports
sys.path.insert(0, str(Path(__file__).parent.parent))
try:
from dss import StorybookScanner, StoryGenerator, ThemeGenerator
from dss.analyze.project_analyzer import export_project_context, run_project_analysis
from dss.project.manager import ProjectManager
except ImportError as e:
print(
"Error: Could not import DSS modules. Make sure dss-mvp1 is in the PYTHONPATH.",
file=sys.stderr,
)
print(f"Import error: {e}", file=sys.stderr)
sys.exit(1)
def main():
"""Main function to parse arguments and dispatch commands."""
parser = argparse.ArgumentParser(
description="DSS Command Line Interface for project analysis and context management."
)
subparsers = parser.add_subparsers(dest="command", required=True, help="Available commands")
# =========================================================================
# 'analyze' command
# =========================================================================
analyze_parser = subparsers.add_parser(
"analyze",
help="Run a deep analysis of a project and save the results to .dss/analysis_graph.json",
)
analyze_parser.add_argument(
"--project-path",
required=True,
help="The root path to the project directory to be analyzed.",
)
analyze_parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
# =========================================================================
# 'export-context' command
# =========================================================================
export_parser = subparsers.add_parser(
"export-context",
help="Export the comprehensive project context as a JSON object to stdout.",
)
export_parser.add_argument(
"--project-path", required=True, help="The path to the project directory."
)
# =========================================================================
# 'add-figma-file' command
# =========================================================================
add_figma_parser = subparsers.add_parser(
"add-figma-file", help="Link a Figma file to a DSS project."
)
add_figma_parser.add_argument(
"--project-path", required=True, help="The path to the DSS project directory."
)
add_figma_parser.add_argument(
"--file-key", required=True, help="The file key of the Figma file (from the URL)."
)
add_figma_parser.add_argument(
"--file-name", required=True, help="A human-readable name for the Figma file."
)
# =========================================================================
# 'setup-storybook' command
# =========================================================================
storybook_parser = subparsers.add_parser(
"setup-storybook", help="Scan, generate, or configure Storybook for a project."
)
storybook_parser.add_argument(
"--project-path", required=True, help="The path to the DSS project directory."
)
storybook_parser.add_argument(
"--action",
required=True,
choices=["scan", "generate", "configure"],
help="The Storybook action to perform.",
)
# =========================================================================
# 'sync-tokens' command
# =========================================================================
sync_parser = subparsers.add_parser(
"sync-tokens", help="Synchronize design tokens from the linked Figma file(s)."
)
sync_parser.add_argument(
"--project-path", required=True, help="The path to the DSS project directory."
)
sync_parser.add_argument(
"--figma-token",
help="Your Figma personal access token. If not provided, it will try to use the FIGMA_TOKEN environment variable.",
)
sync_parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
sync_parser.add_argument("--force", action="store_true", help="Force sync, ignoring cache")
args = parser.parse_args()
# --- Command Dispatch ---
project_path = Path(args.project_path).resolve()
if not project_path.is_dir():
print(
f"Error: Provided project path is not a valid directory: {project_path}",
file=sys.stderr,
)
sys.exit(1)
try:
if args.command == "analyze":
result = run_project_analysis(str(project_path))
print(
f"Analysis complete. Graph saved to {project_path / '.dss' / 'analysis_graph.json'}"
)
# Optionally print a summary to stdout
summary = {
"status": "success",
"nodes_created": len(result.get("nodes", [])),
"links_created": len(result.get("links", [])),
}
print(json.dumps(summary, indent=2))
elif args.command == "export-context":
result = export_project_context(str(project_path))
# Print the full context to stdout
print(json.dumps(result, indent=2))
elif args.command == "add-figma-file":
manager = ProjectManager()
try:
project = manager.load(project_path)
except FileNotFoundError:
print(
f"Error: No 'ds.config.json' found at {project_path}. Is this a valid DSS project?",
file=sys.stderr,
)
sys.exit(1)
manager.add_figma_file(
project=project, file_key=args.file_key, file_name=args.file_name
)
print(
f"Successfully added Figma file '{args.file_name}' to project '{project.config.name}'."
)
elif args.command == "setup-storybook":
action = args.action
print(f"Running Storybook setup with action: {action}...")
if action == "scan":
scanner = StorybookScanner(project_path)
result = scanner.scan()
print(json.dumps(result, indent=2))
elif action == "generate":
generator = StoryGenerator(project_path)
result = generator.generate()
print(f"Successfully generated {len(result)} new stories.")
elif action == "configure":
theme_gen = ThemeGenerator(project_path)
result = theme_gen.generate()
print(f"Storybook theme configured at {result.get('theme_file')}")
print("Storybook setup complete.")
elif args.command == "sync-tokens":
manager = ProjectManager()
try:
project = manager.load(project_path)
except FileNotFoundError:
print(
f"Error: No 'ds.config.json' found at {project_path}. Is this a valid DSS project?",
file=sys.stderr,
)
sys.exit(1)
print("Synchronizing tokens from Figma...")
# The manager.sync method is now async
asyncio.run(
manager.sync(
project, figma_token=args.figma_token, force=args.force, verbose=args.verbose
)
)
print("Token synchronization complete.")
except Exception as e:
print(json.dumps({"success": False, "error": str(e)}), file=sys.stderr)
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
# The main function now handles both sync and async command dispatches
main()