#!/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()