cliops 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cliops-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 CliOps Development Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include requirements.txt
3
+ include LICENSE
4
+ recursive-include core *.py
5
+ recursive-include tests *.py
6
+ global-exclude *.pyc
7
+ global-exclude __pycache__
cliops-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: cliops
3
+ Version: 1.0.0
4
+ Summary: Advanced CLI tool for structured, pattern-based prompt optimization and state management
5
+ Home-page: https://github.com/cliops/cliops
6
+ Author: CliOps Development Team
7
+ Author-email: contact@cliops.dev
8
+ Project-URL: Bug Reports, https://github.com/cliops/cliops/issues
9
+ Project-URL: Source, https://github.com/cliops/cliops
10
+ Project-URL: Documentation, https://cliops.readthedocs.io
11
+ Keywords: cli prompt optimization ai llm prompt-engineering patterns state-management
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Software Development :: Build Tools
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Topic :: Utilities
26
+ Classifier: Topic :: Text Processing :: Linguistic
27
+ Classifier: Environment :: Console
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: rich>=13.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
35
+ Requires-Dist: black>=22.0.0; extra == "dev"
36
+ Requires-Dist: flake8>=5.0.0; extra == "dev"
37
+ Provides-Extra: test
38
+ Requires-Dist: pytest>=7.0.0; extra == "test"
39
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
40
+ Dynamic: author
41
+ Dynamic: author-email
42
+ Dynamic: classifier
43
+ Dynamic: description
44
+ Dynamic: description-content-type
45
+ Dynamic: home-page
46
+ Dynamic: keywords
47
+ Dynamic: license-file
48
+ Dynamic: project-url
49
+ Dynamic: provides-extra
50
+ Dynamic: requires-dist
51
+ Dynamic: requires-python
52
+ Dynamic: summary
53
+
54
+ # CliOps - Command Line Interface for Prompt Optimization
55
+
56
+ A powerful CLI tool for structured, pattern-based prompt optimization and state management.
57
+
58
+ ## Features
59
+
60
+ - **Pattern-based optimization**: Apply proven prompt engineering patterns
61
+ - **State management**: Persistent CLI state for project context
62
+ - **Rich terminal UI**: Beautiful output with syntax highlighting
63
+ - **Extensible**: Add custom patterns and presets
64
+ - **Cross-platform**: Works on Windows, macOS, and Linux
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ pip install -e .
70
+ ```
71
+
72
+ ## Quick Start
73
+
74
+ ```bash
75
+ # Initialize configuration
76
+ cliops init
77
+
78
+ # Set project context
79
+ cliops state set ARCHITECTURE "React + Node.js"
80
+ cliops state set FOCUS "API development"
81
+
82
+ # Optimize a prompt
83
+ cliops "Create a user authentication endpoint"
84
+
85
+ # Analyze a prompt
86
+ cliops analyze "Make this code better"
87
+
88
+ # List available patterns
89
+ cliops patterns
90
+ ```
91
+
92
+ ## Usage
93
+
94
+ ### Basic Commands
95
+
96
+ - `cliops optimize <prompt>` - Optimize a prompt using patterns
97
+ - `cliops analyze <prompt>` - Analyze prompt for improvements
98
+ - `cliops patterns` - List available optimization patterns
99
+ - `cliops state set <key> <value>` - Set persistent state
100
+ - `cliops init` - Initialize configuration
101
+
102
+ ### Examples
103
+
104
+ ```bash
105
+ # Direct prompt optimization
106
+ cliops "Fix this bug in my React component"
107
+
108
+ # With specific pattern
109
+ cliops optimize "Refactor this function" --pattern surgical_refactor
110
+
111
+ # With overrides
112
+ cliops optimize "Create API" --context "Express.js backend" --constraints "RESTful design"
113
+
114
+ # Dry run to see what would be generated
115
+ cliops optimize "Test prompt" --dry-run
116
+ ```
117
+
118
+ ## Testing
119
+
120
+ ```bash
121
+ python run_tests.py
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT License
cliops-1.0.0/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # CliOps - Command Line Interface for Prompt Optimization
2
+
3
+ A powerful CLI tool for structured, pattern-based prompt optimization and state management.
4
+
5
+ ## Features
6
+
7
+ - **Pattern-based optimization**: Apply proven prompt engineering patterns
8
+ - **State management**: Persistent CLI state for project context
9
+ - **Rich terminal UI**: Beautiful output with syntax highlighting
10
+ - **Extensible**: Add custom patterns and presets
11
+ - **Cross-platform**: Works on Windows, macOS, and Linux
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install -e .
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Initialize configuration
23
+ cliops init
24
+
25
+ # Set project context
26
+ cliops state set ARCHITECTURE "React + Node.js"
27
+ cliops state set FOCUS "API development"
28
+
29
+ # Optimize a prompt
30
+ cliops "Create a user authentication endpoint"
31
+
32
+ # Analyze a prompt
33
+ cliops analyze "Make this code better"
34
+
35
+ # List available patterns
36
+ cliops patterns
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### Basic Commands
42
+
43
+ - `cliops optimize <prompt>` - Optimize a prompt using patterns
44
+ - `cliops analyze <prompt>` - Analyze prompt for improvements
45
+ - `cliops patterns` - List available optimization patterns
46
+ - `cliops state set <key> <value>` - Set persistent state
47
+ - `cliops init` - Initialize configuration
48
+
49
+ ### Examples
50
+
51
+ ```bash
52
+ # Direct prompt optimization
53
+ cliops "Fix this bug in my React component"
54
+
55
+ # With specific pattern
56
+ cliops optimize "Refactor this function" --pattern surgical_refactor
57
+
58
+ # With overrides
59
+ cliops optimize "Create API" --context "Express.js backend" --constraints "RESTful design"
60
+
61
+ # Dry run to see what would be generated
62
+ cliops optimize "Test prompt" --dry-run
63
+ ```
64
+
65
+ ## Testing
66
+
67
+ ```bash
68
+ python run_tests.py
69
+ ```
70
+
71
+ ## License
72
+
73
+ MIT License
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: cliops
3
+ Version: 1.0.0
4
+ Summary: Advanced CLI tool for structured, pattern-based prompt optimization and state management
5
+ Home-page: https://github.com/cliops/cliops
6
+ Author: CliOps Development Team
7
+ Author-email: contact@cliops.dev
8
+ Project-URL: Bug Reports, https://github.com/cliops/cliops/issues
9
+ Project-URL: Source, https://github.com/cliops/cliops
10
+ Project-URL: Documentation, https://cliops.readthedocs.io
11
+ Keywords: cli prompt optimization ai llm prompt-engineering patterns state-management
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Software Development :: Build Tools
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Topic :: Utilities
26
+ Classifier: Topic :: Text Processing :: Linguistic
27
+ Classifier: Environment :: Console
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: rich>=13.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
35
+ Requires-Dist: black>=22.0.0; extra == "dev"
36
+ Requires-Dist: flake8>=5.0.0; extra == "dev"
37
+ Provides-Extra: test
38
+ Requires-Dist: pytest>=7.0.0; extra == "test"
39
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
40
+ Dynamic: author
41
+ Dynamic: author-email
42
+ Dynamic: classifier
43
+ Dynamic: description
44
+ Dynamic: description-content-type
45
+ Dynamic: home-page
46
+ Dynamic: keywords
47
+ Dynamic: license-file
48
+ Dynamic: project-url
49
+ Dynamic: provides-extra
50
+ Dynamic: requires-dist
51
+ Dynamic: requires-python
52
+ Dynamic: summary
53
+
54
+ # CliOps - Command Line Interface for Prompt Optimization
55
+
56
+ A powerful CLI tool for structured, pattern-based prompt optimization and state management.
57
+
58
+ ## Features
59
+
60
+ - **Pattern-based optimization**: Apply proven prompt engineering patterns
61
+ - **State management**: Persistent CLI state for project context
62
+ - **Rich terminal UI**: Beautiful output with syntax highlighting
63
+ - **Extensible**: Add custom patterns and presets
64
+ - **Cross-platform**: Works on Windows, macOS, and Linux
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ pip install -e .
70
+ ```
71
+
72
+ ## Quick Start
73
+
74
+ ```bash
75
+ # Initialize configuration
76
+ cliops init
77
+
78
+ # Set project context
79
+ cliops state set ARCHITECTURE "React + Node.js"
80
+ cliops state set FOCUS "API development"
81
+
82
+ # Optimize a prompt
83
+ cliops "Create a user authentication endpoint"
84
+
85
+ # Analyze a prompt
86
+ cliops analyze "Make this code better"
87
+
88
+ # List available patterns
89
+ cliops patterns
90
+ ```
91
+
92
+ ## Usage
93
+
94
+ ### Basic Commands
95
+
96
+ - `cliops optimize <prompt>` - Optimize a prompt using patterns
97
+ - `cliops analyze <prompt>` - Analyze prompt for improvements
98
+ - `cliops patterns` - List available optimization patterns
99
+ - `cliops state set <key> <value>` - Set persistent state
100
+ - `cliops init` - Initialize configuration
101
+
102
+ ### Examples
103
+
104
+ ```bash
105
+ # Direct prompt optimization
106
+ cliops "Fix this bug in my React component"
107
+
108
+ # With specific pattern
109
+ cliops optimize "Refactor this function" --pattern surgical_refactor
110
+
111
+ # With overrides
112
+ cliops optimize "Create API" --context "Express.js backend" --constraints "RESTful design"
113
+
114
+ # Dry run to see what would be generated
115
+ cliops optimize "Test prompt" --dry-run
116
+ ```
117
+
118
+ ## Testing
119
+
120
+ ```bash
121
+ python run_tests.py
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT License
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ requirements.txt
5
+ setup.py
6
+ cliops.egg-info/PKG-INFO
7
+ cliops.egg-info/SOURCES.txt
8
+ cliops.egg-info/dependency_links.txt
9
+ cliops.egg-info/entry_points.txt
10
+ cliops.egg-info/not-zip-safe
11
+ cliops.egg-info/requires.txt
12
+ cliops.egg-info/top_level.txt
13
+ core/__init__.py
14
+ core/analyzer.py
15
+ core/config.py
16
+ core/optimizer.py
17
+ core/patterns.py
18
+ core/state.py
19
+ tests/__init__.py
20
+ tests/test_integration.py
21
+ tests/test_optimizer.py
22
+ tests/test_patterns.py
23
+ tests/test_state.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ cliops = main:main
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,11 @@
1
+ rich>=13.0.0
2
+
3
+ [dev]
4
+ pytest>=7.0.0
5
+ pytest-cov>=4.0.0
6
+ black>=22.0.0
7
+ flake8>=5.0.0
8
+
9
+ [test]
10
+ pytest>=7.0.0
11
+ pytest-cov>=4.0.0
@@ -0,0 +1 @@
1
+ core
@@ -0,0 +1 @@
1
+ # Core module for cliops
@@ -0,0 +1,78 @@
1
+ import re
2
+ import os
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+
6
+ console = Console()
7
+
8
+ class PromptAnalyzer:
9
+ """Analyzes a raw prompt for common issues based on optimization principles."""
10
+ def __init__(self, pattern_registry):
11
+ self.pattern_registry = pattern_registry
12
+ self.principles = {
13
+ "Structure and Clarity": {
14
+ "keywords": ["directive", "scope", "constraints", "output format", "success criteria"],
15
+ "suggestion": "Ensure your prompt has a clear structure with explicit sections like 'DIRECTIVE', 'SCOPE', 'CONSTRAINTS', 'OUTPUT FORMAT', and 'SUCCESS CRITERIA'."
16
+ },
17
+ "Specificity and Detail": {
18
+ "keywords": ["specific", "detailed", "precise", "exact", "example"],
19
+ "suggestion": "Add more specific details about the task, desired output, edge cases, and expected behavior. Consider using few-shot examples."
20
+ },
21
+ "Context-Aware Generation": {
22
+ "keywords": ["context", "background", "system", "environment", "state"],
23
+ "suggestion": "Provide relevant context, system state, or background information the LLM needs to understand the scenario fully. Leverage `cliops state`."
24
+ },
25
+ "Output Format": {
26
+ "keywords": ["json", "xml", "yaml", "markdown", "code block", "format", "structure"],
27
+ "suggestion": "Clearly define the desired output format (e.g., JSON, YAML, Markdown code block, specific class structure)."
28
+ },
29
+ "Error Prevention": {
30
+ "keywords": ["handle errors", "robust", "mitigate", "assumptions", "potential issues", "safeguards"],
31
+ "suggestion": "Instruct the LLM on how to handle potential errors, edge cases, or invalid inputs. Define explicit assumptions."
32
+ }
33
+ }
34
+
35
+ def analyze_prompt(self, prompt_text: str):
36
+ """Analyzes a raw prompt for adherence to prompt engineering principles."""
37
+ console.print(Panel("[bold green]Prompt Analysis[/bold green]", expand=False, border_style="green"))
38
+ issues = []
39
+ recommendations = []
40
+
41
+ # Check for general structure and key fields
42
+ if not re.search(r"DIRECTIVE:", prompt_text, re.IGNORECASE):
43
+ issues.append("Missing or unclear 'DIRECTIVE'.")
44
+ recommendations.append(self.principles["Structure and Clarity"]["suggestion"])
45
+ if not re.search(r"CONSTRAINTS:", prompt_text, re.IGNORECASE):
46
+ issues.append("Missing or unclear 'CONSTRAINTS'.")
47
+ recommendations.append(self.principles["Structure and Clarity"]["suggestion"])
48
+ if not re.search(r"OUTPUT FORMAT:", prompt_text, re.IGNORECASE):
49
+ issues.append("Missing or unclear 'OUTPUT FORMAT'.")
50
+ recommendations.append(self.principles["Output Format"]["suggestion"])
51
+
52
+ # Check for keywords related to other principles
53
+ for principle, data in self.principles.items():
54
+ if principle in ["Structure and Clarity", "Output Format"]:
55
+ continue
56
+
57
+ found_keyword = False
58
+ for keyword in data["keywords"]:
59
+ if re.search(r"\b" + re.escape(keyword) + r"\b", prompt_text, re.IGNORECASE):
60
+ found_keyword = True
61
+ break
62
+ if not found_keyword:
63
+ recommendations.append(f"Consider: {data['suggestion']}")
64
+
65
+ if issues:
66
+ console.print(Panel("[bold red]Identified Issues[/bold red]", expand=False, border_style="red"))
67
+ for issue in sorted(list(set(issues))):
68
+ console.print(f"[red]- {issue}[/red]")
69
+ else:
70
+ console.print("[bold green]No critical issues identified in prompt structure.[/bold green]", style="green")
71
+
72
+ if recommendations:
73
+ console.print(Panel("[bold yellow]Recommendations for Improvement[/bold yellow]", expand=False, border_style="yellow"))
74
+ for rec in sorted(list(set(recommendations))):
75
+ console.print(f"[yellow]- {rec}[/yellow]")
76
+ else:
77
+ console.print("[bold green]Prompt appears well-structured and comprehensive.[/bold green]", style="green")
78
+ console.print(Panel.fit("[dim]Analysis Complete[/dim]", border_style="dim"))
@@ -0,0 +1,35 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ class Config:
5
+ """Manages application configuration, including state file path and pattern definitions."""
6
+ APP_NAME = "cliops"
7
+ STATE_FILE_NAME = "cliops_state.json"
8
+ PATTERNS_FILE_NAME = "patterns.json"
9
+
10
+ @staticmethod
11
+ def get_app_data_dir():
12
+ """Returns the appropriate application data directory for the OS."""
13
+ if os.name == 'nt': # Windows
14
+ return Path(os.environ.get('APPDATA', Path.home() / Config.APP_NAME)) / Config.APP_NAME
15
+ elif os.name == 'posix': # Linux, macOS, etc.
16
+ xdg_data_home = os.environ.get('XDG_DATA_HOME')
17
+ if xdg_data_home:
18
+ return Path(xdg_data_home) / Config.APP_NAME
19
+ return Path.home() / ".local" / "share" / Config.APP_NAME
20
+ else:
21
+ return Path.home() / f".{Config.APP_NAME}"
22
+
23
+ @staticmethod
24
+ def get_state_file_path():
25
+ """Returns the full path to the CLI state file."""
26
+ data_dir = Config.get_app_data_dir()
27
+ data_dir.mkdir(parents=True, exist_ok=True)
28
+ return data_dir / Config.STATE_FILE_NAME
29
+
30
+ @staticmethod
31
+ def get_patterns_file_path():
32
+ """Returns the full path to the user-defined patterns file."""
33
+ data_dir = Config.get_app_data_dir()
34
+ data_dir.mkdir(parents=True, exist_ok=True)
35
+ return data_dir / Config.PATTERNS_FILE_NAME
@@ -0,0 +1,143 @@
1
+ import re
2
+ from rich.console import Console
3
+ from rich.panel import Panel
4
+ from rich.table import Table
5
+ from rich.syntax import Syntax
6
+ from rich.text import Text
7
+ from rich import box
8
+
9
+ console = Console()
10
+
11
+ class PromptOptimizer:
12
+ """Optimizes raw prompts using predefined patterns."""
13
+ def __init__(self, pattern_registry, cli_state, verbose: bool = False):
14
+ self.pattern_registry = pattern_registry
15
+ self.cli_state = cli_state
16
+ self.verbose = verbose
17
+
18
+ def _parse_prompt_into_sections(self, raw_prompt: str) -> dict:
19
+ """Parses a raw prompt into a dictionary of sections based on '## SECTION:' headers and <TAG>...</TAG> blocks."""
20
+ sections = {}
21
+ main_body_content = raw_prompt
22
+ extracted_sections = {}
23
+
24
+ # Extract tagged blocks (e.g., <CODE>, <CONTEXT>)
25
+ tag_block_pattern = re.compile(r"<(\w+)>(.*?)</\1>", re.DOTALL | re.IGNORECASE)
26
+
27
+ matches_to_remove = []
28
+ for match in tag_block_pattern.finditer(main_body_content):
29
+ tag_name = match.group(1).upper()
30
+ content = match.group(2).strip()
31
+ extracted_sections[tag_name] = content
32
+ matches_to_remove.append(match.span())
33
+
34
+ # Remove extracted tag blocks from the main body content
35
+ for start, end in sorted(matches_to_remove, key=lambda x: x[0], reverse=True):
36
+ main_body_content = main_body_content[:start] + main_body_content[end:]
37
+
38
+ # Extract ## sections from the remaining text
39
+ parts = re.split(r'(?m)^(##\s*[\w\s\/]+?:)', main_body_content)
40
+
41
+ current_key = "MAIN_BODY"
42
+ if parts and parts[0].strip():
43
+ extracted_sections[current_key] = parts[0].strip()
44
+
45
+ for i in range(1, len(parts), 2):
46
+ header = parts[i].strip()
47
+ key = header.replace('##', '').replace(':', '').strip().replace(' ', '_').upper()
48
+ content = parts[i+1].strip() if i+1 < len(parts) else ""
49
+ extracted_sections[key] = content
50
+
51
+ # Handle 'code_here' specifically if it's the main body or implied
52
+ if "CODE" in extracted_sections:
53
+ extracted_sections["CODE_HERE"] = extracted_sections.pop("CODE")
54
+
55
+ return extracted_sections
56
+
57
+ def _extract_components(self, raw_prompt: str, pattern) -> dict:
58
+ """Extracts common and pattern-specific components from a raw prompt."""
59
+ parsed_sections = self._parse_prompt_into_sections(raw_prompt)
60
+ extracted_fields = {}
61
+
62
+ # Map common section names to expected template field names
63
+ common_mappings = {
64
+ 'DIRECTIVE': 'directive',
65
+ 'SCOPE': 'scope',
66
+ 'CONSTRAINTS': 'constraints',
67
+ 'OUTPUT_FORMAT': 'output_format',
68
+ 'SUCCESS_CRITERIA': 'success_criteria',
69
+ 'CODE_HERE': 'code_here',
70
+ 'CODE': 'code_here',
71
+ 'CONTEXT': 'context',
72
+ 'CURRENT_FOCUS': 'current_focus',
73
+ 'MINDSET': 'mindset',
74
+ 'MAIN_BODY': 'code_here'
75
+ }
76
+
77
+ for section_key, template_field in common_mappings.items():
78
+ if section_key in parsed_sections and parsed_sections[section_key] != "":
79
+ extracted_fields[template_field] = parsed_sections[section_key]
80
+
81
+ # Apply pattern-specific extraction logic
82
+ if pattern.specific_extract_func:
83
+ specific_extracted = pattern.specific_extract_func(raw_prompt)
84
+ for k,v in specific_extracted.items():
85
+ if v is not None and v != '':
86
+ extracted_fields[k.lower()] = v
87
+
88
+ return {k: v for k, v in extracted_fields.items() if v is not None}
89
+
90
+ def optimize_prompt(self, raw_prompt: str, pattern_name: str, overrides: dict, dry_run: bool = False) -> str:
91
+ """Applies an optimization pattern to a raw prompt."""
92
+ pattern = self.pattern_registry.get_pattern(pattern_name)
93
+ if not pattern:
94
+ raise ValueError(f"Pattern '{pattern_name}' not found.")
95
+
96
+ # Extract components from raw_prompt
97
+ extracted_fields = self._extract_components(raw_prompt, pattern)
98
+
99
+ # Prepare fields for template formatting
100
+ template_fields = {}
101
+ for key in extracted_fields:
102
+ template_fields[key] = extracted_fields[key]
103
+
104
+ # Inject CLI state
105
+ cli_state_values = {key: self.cli_state.get(key) for key in self.cli_state.state.keys()}
106
+ StateObject = type('StateObject', (object,), cli_state_values)
107
+ template_fields['STATE'] = StateObject()
108
+
109
+ # Apply explicit CLI argument overrides
110
+ for key, value in overrides.items():
111
+ if key in template_fields:
112
+ template_fields[key] = value
113
+ elif key.upper() in cli_state_values:
114
+ setattr(template_fields['STATE'], key.upper(), value)
115
+
116
+ # Set defaults if fields are still missing
117
+ default_fields = {
118
+ 'directive': 'Please complete the task.',
119
+ 'scope': 'The entire codebase.',
120
+ 'constraints': 'No specific constraints.',
121
+ 'output_format': 'Clean code/text.',
122
+ 'success_criteria': 'The task is completed as per the directive.',
123
+ 'code_here': 'No code provided.',
124
+ 'context': 'General context.',
125
+ 'current_focus': 'Overall system.',
126
+ 'mindset': 'Standard development mindset.',
127
+ 'examples': 'No examples provided.'
128
+ }
129
+
130
+ for field, default_value in default_fields.items():
131
+ if field not in template_fields or template_fields[field] is None or template_fields[field] == '':
132
+ template_fields[field] = default_value
133
+
134
+ if dry_run:
135
+ console.print(Panel("[bold blue]Dry Run: Prompt Optimization Details[/bold blue]", expand=False, border_style="blue"))
136
+ console.print("Dry run complete. No prompt generated.")
137
+ return "Dry run complete. No prompt generated."
138
+
139
+ try:
140
+ optimized_prompt = pattern.template.format(**template_fields)
141
+ return optimized_prompt
142
+ except KeyError as e:
143
+ raise ValueError(f"Template for pattern '{pattern_name}' missing field {e}.")
@@ -0,0 +1,142 @@
1
+ import json
2
+ import re
3
+ from pathlib import Path
4
+ from rich.console import Console
5
+ from rich.table import Table
6
+ from rich.syntax import Syntax
7
+ from rich import box
8
+ from .config import Config
9
+
10
+ console = Console()
11
+
12
+ class OptimizationPattern:
13
+ """Represents a prompt optimization pattern with its template and extraction logic."""
14
+ def __init__(self, name: str, description: str, template: str, principles: list[str], specific_extract_func=None):
15
+ self.name = name
16
+ self.description = description
17
+ self.template = template
18
+ self.principles = principles
19
+ self.specific_extract_func = specific_extract_func
20
+
21
+ @classmethod
22
+ def from_dict(cls, data: dict):
23
+ """Creates an OptimizationPattern instance from a dictionary."""
24
+ return cls(
25
+ name=data['name'],
26
+ description=data['description'],
27
+ template=data['template'],
28
+ principles=data.get('principles', []),
29
+ specific_extract_func=None
30
+ )
31
+
32
+ def to_dict(self):
33
+ """Converts the pattern to a dictionary for serialization."""
34
+ return {
35
+ 'name': self.name,
36
+ 'description': self.description,
37
+ 'template': self.template,
38
+ 'principles': self.principles
39
+ }
40
+
41
+ class PatternRegistry:
42
+ """Manages available optimization patterns."""
43
+ def __init__(self, cli_state):
44
+ self.patterns: dict[str, OptimizationPattern] = {}
45
+ self.cli_state = cli_state
46
+ self._load_default_patterns()
47
+ self._load_user_patterns()
48
+
49
+ def _load_default_patterns(self):
50
+ """Loads hardcoded default patterns."""
51
+ # Generic extraction helpers
52
+ def extract_colon_value(text, field_name):
53
+ match = re.search(rf"^{re.escape(field_name)}:\s*(.*?)(?:\n##|\n<|\Z)", text, re.MULTILINE | re.DOTALL | re.IGNORECASE)
54
+ if match:
55
+ content = match.group(1).strip()
56
+ next_header_match = re.search(r"##\s*\w+", content, re.DOTALL)
57
+ if next_header_match:
58
+ content = content[:next_header_match.start()].strip()
59
+ next_tag_match = re.search(r"<\w+>", content, re.DOTALL)
60
+ if next_tag_match:
61
+ content = content[:next_tag_match.start()].strip()
62
+ return content
63
+ return None
64
+
65
+ def extract_between_tags(text, start_tag, end_tag):
66
+ match = re.search(rf"{re.escape(start_tag)}(.*?){re.escape(end_tag)}", text, re.DOTALL)
67
+ return match.group(1).strip() if match else None
68
+
69
+ # Pattern-specific extraction functions
70
+ def specific_extract_context_aware(prompt_text):
71
+ extracted = {}
72
+ extracted['CONTEXT'] = extract_between_tags(prompt_text, "<CONTEXT>", "</CONTEXT>")
73
+ extracted['CURRENT_FOCUS'] = extract_colon_value(prompt_text, "Current Focus")
74
+ extracted['MINDSET'] = extract_colon_value(prompt_text, "Mindset")
75
+ return {k: v for k, v in extracted.items() if v is not None}
76
+
77
+ default_patterns_data = [
78
+ {"name": "context_aware_generation",
79
+ "description": "Guides generation based on specific context, mindset, and current focus.",
80
+ "template": "# DIRECTIVE: {directive}\n\n"
81
+ "## CONTEXT:\n"
82
+ "<CONTEXT>{context}</CONTEXT>\n\n"
83
+ "## CURRENT FOCUS:\n"
84
+ "{current_focus}\n\n"
85
+ "## MINDSET:\n"
86
+ "{mindset}\n\n"
87
+ "## CONSTRAINTS:\n"
88
+ "{constraints}\n\n"
89
+ "## OUTPUT FORMAT:\n"
90
+ "{output_format}\n\n"
91
+ "## EXAMPLES:\n"
92
+ "{examples}\n\n"
93
+ "## SUCCESS CRITERIA:\n"
94
+ "{success_criteria}\n\n"
95
+ "## STATE:\n"
96
+ "Project Architecture: {STATE.ARCHITECTURE}\n"
97
+ "Common Patterns: {STATE.PATTERNS}\n"
98
+ "Current Project Focus: {STATE.FOCUS}\n\n"
99
+ "{code_here}",
100
+ "principles": ["Context-Aware Generation", "Adaptive Nuance", "State Anchoring"],
101
+ "specific_extract_func": specific_extract_context_aware}
102
+ ]
103
+
104
+ for p_data in default_patterns_data:
105
+ pattern = OptimizationPattern.from_dict(p_data)
106
+ if pattern.name == "context_aware_generation":
107
+ pattern.specific_extract_func = specific_extract_context_aware
108
+ self.patterns[pattern.name] = pattern
109
+
110
+ def _load_user_patterns(self):
111
+ """Loads user-defined patterns from patterns.json."""
112
+ patterns_file = Config.get_patterns_file_path()
113
+ if patterns_file.exists():
114
+ try:
115
+ with open(patterns_file, 'r') as f:
116
+ user_patterns_data = json.load(f)
117
+ for p_data in user_patterns_data:
118
+ pattern_name = p_data.get('name')
119
+ if pattern_name:
120
+ pattern = OptimizationPattern.from_dict(p_data)
121
+ self.patterns[pattern_name] = pattern
122
+ except json.JSONDecodeError:
123
+ console.print(f"[bold yellow]Warning:[/bold yellow] Could not decode JSON from user patterns file {patterns_file}. Ignoring user patterns.", style="yellow")
124
+ except Exception as e:
125
+ console.print(f"[bold red]Error:[/bold red] loading user patterns from {patterns_file}: {e}", style="red")
126
+
127
+ def get_pattern(self, name: str) -> OptimizationPattern | None:
128
+ """Retrieves a pattern by name."""
129
+ return self.patterns.get(name)
130
+
131
+ def list_patterns(self):
132
+ """Lists all available patterns."""
133
+ table = Table(title="Available Optimization Patterns", box=box.ROUNDED, style="magenta")
134
+ table.add_column("Pattern Name", style="bold cyan", justify="left")
135
+ table.add_column("Description", style="green", justify="left")
136
+ table.add_column("Principles", style="blue", justify="left")
137
+
138
+ for name, pattern in self.patterns.items():
139
+ principles_text = ", ".join(pattern.principles) if pattern.principles else "N/A"
140
+ table.add_row(name, pattern.description, principles_text)
141
+
142
+ console.print(table)
@@ -0,0 +1,60 @@
1
+ import json
2
+ from pathlib import Path
3
+ from rich.console import Console
4
+ from rich.table import Table
5
+ from rich import box
6
+
7
+ console = Console()
8
+
9
+ class CLIState:
10
+ """Manages persistent key-value state for CLI operations."""
11
+ def __init__(self, file_path: Path):
12
+ self.file_path = file_path
13
+ self.state = self._load_state()
14
+
15
+ def _load_state(self) -> dict:
16
+ """Loads state from the JSON file."""
17
+ if self.file_path.exists():
18
+ try:
19
+ with open(self.file_path, 'r') as f:
20
+ return json.load(f)
21
+ except json.JSONDecodeError:
22
+ console.print(f"[bold yellow]Warning:[/bold yellow] Could not decode JSON from {self.file_path}. Starting with empty state.", style="yellow")
23
+ return {}
24
+ return {}
25
+
26
+ def _save_state(self):
27
+ """Saves the current state to the JSON file."""
28
+ with open(self.file_path, 'w') as f:
29
+ json.dump(self.state, f, indent=4)
30
+
31
+ def set(self, key: str, value: str):
32
+ """Sets a key-value pair in the state."""
33
+ self.state[key.upper()] = value
34
+ self._save_state()
35
+ console.print(f"State '[bold green]{key.upper()}[/bold green]' set to '[cyan]{value}[/cyan]'.")
36
+
37
+ def get(self, key: str) -> str | None:
38
+ """Gets a value from the state."""
39
+ return self.state.get(key.upper())
40
+
41
+ def show(self):
42
+ """Displays the current state."""
43
+ if not self.state:
44
+ console.print("No CLI state currently set.", style="italic dim")
45
+ return
46
+
47
+ table = Table(title="Current CLI State", box=box.ROUNDED, style="blue")
48
+ table.add_column("Key", style="bold cyan")
49
+ table.add_column("Value", style="green")
50
+
51
+ for key, value in self.state.items():
52
+ table.add_row(key, value)
53
+
54
+ console.print(table)
55
+
56
+ def clear(self):
57
+ """Clears all entries from the state."""
58
+ self.state = {}
59
+ self._save_state()
60
+ console.print("CLI state cleared.", style="red")
@@ -0,0 +1 @@
1
+ rich>=13.0.0
cliops-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
cliops-1.0.0/setup.py ADDED
@@ -0,0 +1,66 @@
1
+ from setuptools import setup, find_packages
2
+ from pathlib import Path
3
+
4
+ # Read README for long description
5
+ this_directory = Path(__file__).parent
6
+ long_description = (this_directory / "README.md").read_text(encoding='utf-8')
7
+
8
+ # Read requirements
9
+ requirements = (this_directory / "requirements.txt").read_text().strip().split('\n')
10
+
11
+ setup(
12
+ name='cliops',
13
+ version='1.0.0',
14
+ author='CliOps Development Team',
15
+ author_email='contact@cliops.dev',
16
+ description='Advanced CLI tool for structured, pattern-based prompt optimization and state management',
17
+ long_description=long_description,
18
+ long_description_content_type='text/markdown',
19
+ url='https://github.com/cliops/cliops',
20
+ project_urls={
21
+ 'Bug Reports': 'https://github.com/cliops/cliops/issues',
22
+ 'Source': 'https://github.com/cliops/cliops',
23
+ 'Documentation': 'https://cliops.readthedocs.io',
24
+ },
25
+ packages=find_packages(exclude=['tests*']),
26
+ include_package_data=True,
27
+ install_requires=requirements,
28
+ extras_require={
29
+ 'dev': [
30
+ 'pytest>=7.0.0',
31
+ 'pytest-cov>=4.0.0',
32
+ 'black>=22.0.0',
33
+ 'flake8>=5.0.0',
34
+ ],
35
+ 'test': [
36
+ 'pytest>=7.0.0',
37
+ 'pytest-cov>=4.0.0',
38
+ ],
39
+ },
40
+ entry_points={
41
+ 'console_scripts': [
42
+ 'cliops=main:main',
43
+ ],
44
+ },
45
+ classifiers=[
46
+ 'Development Status :: 5 - Production/Stable',
47
+ 'Intended Audience :: Developers',
48
+ 'Intended Audience :: System Administrators',
49
+ 'License :: OSI Approved :: MIT License',
50
+ 'Operating System :: OS Independent',
51
+ 'Programming Language :: Python :: 3.8',
52
+ 'Programming Language :: Python :: 3.9',
53
+ 'Programming Language :: Python :: 3.10',
54
+ 'Programming Language :: Python :: 3.11',
55
+ 'Programming Language :: Python :: 3.12',
56
+ 'Topic :: Software Development :: Libraries :: Python Modules',
57
+ 'Topic :: Software Development :: Build Tools',
58
+ 'Topic :: System :: Systems Administration',
59
+ 'Topic :: Utilities',
60
+ 'Topic :: Text Processing :: Linguistic',
61
+ 'Environment :: Console',
62
+ ],
63
+ keywords='cli prompt optimization ai llm prompt-engineering patterns state-management',
64
+ python_requires='>=3.8',
65
+ zip_safe=False,
66
+ )
@@ -0,0 +1 @@
1
+ # Test module for cliops
@@ -0,0 +1,51 @@
1
+ import unittest
2
+ import subprocess
3
+ import tempfile
4
+ import os
5
+ from pathlib import Path
6
+
7
+ class TestCLIIntegration(unittest.TestCase):
8
+ def setUp(self):
9
+ self.temp_dir = tempfile.mkdtemp()
10
+ self.original_home = os.environ.get('HOME')
11
+ os.environ['HOME'] = self.temp_dir
12
+
13
+ def tearDown(self):
14
+ if self.original_home:
15
+ os.environ['HOME'] = self.original_home
16
+ else:
17
+ os.environ.pop('HOME', None)
18
+
19
+ def run_cliops(self, args):
20
+ """Helper to run cliops command and return result"""
21
+ cmd = ['python', 'main.py'] + args
22
+ result = subprocess.run(cmd, capture_output=True, text=True, cwd=Path(__file__).parent.parent)
23
+ return result
24
+
25
+ def test_init_command(self):
26
+ result = self.run_cliops(['init'])
27
+ self.assertEqual(result.returncode, 0)
28
+ self.assertIn("Initialization complete", result.stdout)
29
+
30
+ def test_state_set_and_show(self):
31
+ # Set state
32
+ result = self.run_cliops(['state', 'set', 'TEST_KEY', 'test_value'])
33
+ self.assertEqual(result.returncode, 0)
34
+
35
+ # Show state
36
+ result = self.run_cliops(['state', 'show'])
37
+ self.assertEqual(result.returncode, 0)
38
+ self.assertIn('TEST_KEY', result.stdout)
39
+
40
+ def test_patterns_list(self):
41
+ result = self.run_cliops(['patterns'])
42
+ self.assertEqual(result.returncode, 0)
43
+ self.assertIn('context_aware_generation', result.stdout)
44
+
45
+ def test_optimize_basic(self):
46
+ result = self.run_cliops(['optimize', 'Create a function', '--dry-run'])
47
+ self.assertEqual(result.returncode, 0)
48
+ self.assertIn('Dry run complete', result.stdout)
49
+
50
+ if __name__ == '__main__':
51
+ unittest.main()
@@ -0,0 +1,49 @@
1
+ import unittest
2
+ from unittest.mock import Mock
3
+ from core.optimizer import PromptOptimizer
4
+ from core.patterns import OptimizationPattern
5
+
6
+ class TestPromptOptimizer(unittest.TestCase):
7
+ def setUp(self):
8
+ self.mock_cli_state = Mock()
9
+ self.mock_cli_state.state = {"ARCHITECTURE": "Test Architecture"}
10
+ self.mock_cli_state.get.return_value = "Test Architecture"
11
+
12
+ self.mock_pattern_registry = Mock()
13
+ self.test_pattern = OptimizationPattern(
14
+ name="test_pattern",
15
+ description="Test pattern",
16
+ template="# DIRECTIVE: {directive}\n## CONTEXT: {context}\n{code_here}",
17
+ principles=["Test"]
18
+ )
19
+ self.mock_pattern_registry.get_pattern.return_value = self.test_pattern
20
+
21
+ self.optimizer = PromptOptimizer(self.mock_pattern_registry, self.mock_cli_state)
22
+
23
+ def test_parse_prompt_into_sections(self):
24
+ prompt = "## DIRECTIVE:\nTest directive\n## CONTEXT:\nTest context\n<CODE>test code</CODE>"
25
+ sections = self.optimizer._parse_prompt_into_sections(prompt)
26
+
27
+ self.assertIn("DIRECTIVE", sections)
28
+ self.assertIn("CONTEXT", sections)
29
+ self.assertIn("CODE_HERE", sections)
30
+ self.assertEqual(sections["DIRECTIVE"], "Test directive")
31
+ self.assertEqual(sections["CONTEXT"], "Test context")
32
+ self.assertEqual(sections["CODE_HERE"], "test code")
33
+
34
+ def test_optimize_prompt_basic(self):
35
+ raw_prompt = "## DIRECTIVE:\nCreate a function\n## CONTEXT:\nPython project"
36
+ result = self.optimizer.optimize_prompt(raw_prompt, "test_pattern", {})
37
+
38
+ self.assertIn("Create a function", result)
39
+ self.assertIn("Python project", result)
40
+
41
+ def test_optimize_prompt_with_overrides(self):
42
+ raw_prompt = "## DIRECTIVE:\nCreate a function"
43
+ overrides = {"context": "Override context"}
44
+ result = self.optimizer.optimize_prompt(raw_prompt, "test_pattern", overrides)
45
+
46
+ self.assertIn("Override context", result)
47
+
48
+ if __name__ == '__main__':
49
+ unittest.main()
@@ -0,0 +1,51 @@
1
+ import unittest
2
+ from unittest.mock import Mock
3
+ from core.patterns import OptimizationPattern, PatternRegistry
4
+
5
+ class TestOptimizationPattern(unittest.TestCase):
6
+ def test_from_dict(self):
7
+ data = {
8
+ "name": "test_pattern",
9
+ "description": "Test pattern",
10
+ "template": "Test template: {field}",
11
+ "principles": ["Test Principle"]
12
+ }
13
+ pattern = OptimizationPattern.from_dict(data)
14
+ self.assertEqual(pattern.name, "test_pattern")
15
+ self.assertEqual(pattern.description, "Test pattern")
16
+ self.assertEqual(pattern.template, "Test template: {field}")
17
+ self.assertEqual(pattern.principles, ["Test Principle"])
18
+
19
+ def test_to_dict(self):
20
+ pattern = OptimizationPattern(
21
+ name="test_pattern",
22
+ description="Test pattern",
23
+ template="Test template: {field}",
24
+ principles=["Test Principle"]
25
+ )
26
+ result = pattern.to_dict()
27
+ expected = {
28
+ "name": "test_pattern",
29
+ "description": "Test pattern",
30
+ "template": "Test template: {field}",
31
+ "principles": ["Test Principle"]
32
+ }
33
+ self.assertEqual(result, expected)
34
+
35
+ class TestPatternRegistry(unittest.TestCase):
36
+ def setUp(self):
37
+ self.mock_cli_state = Mock()
38
+ self.mock_cli_state.state = {}
39
+ self.registry = PatternRegistry(self.mock_cli_state)
40
+
41
+ def test_get_pattern(self):
42
+ pattern = self.registry.get_pattern("context_aware_generation")
43
+ self.assertIsNotNone(pattern)
44
+ self.assertEqual(pattern.name, "context_aware_generation")
45
+
46
+ def test_get_nonexistent_pattern(self):
47
+ pattern = self.registry.get_pattern("nonexistent_pattern")
48
+ self.assertIsNone(pattern)
49
+
50
+ if __name__ == '__main__':
51
+ unittest.main()
@@ -0,0 +1,39 @@
1
+ import unittest
2
+ import tempfile
3
+ import json
4
+ from pathlib import Path
5
+ from core.state import CLIState
6
+
7
+ class TestCLIState(unittest.TestCase):
8
+ def setUp(self):
9
+ self.temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json')
10
+ self.temp_file.close()
11
+ self.state_file = Path(self.temp_file.name)
12
+ self.cli_state = CLIState(self.state_file)
13
+
14
+ def tearDown(self):
15
+ if self.state_file.exists():
16
+ self.state_file.unlink()
17
+
18
+ def test_set_and_get(self):
19
+ self.cli_state.set("TEST_KEY", "test_value")
20
+ self.assertEqual(self.cli_state.get("TEST_KEY"), "test_value")
21
+ self.assertEqual(self.cli_state.get("test_key"), "test_value") # Case insensitive
22
+
23
+ def test_persistence(self):
24
+ self.cli_state.set("PERSIST_KEY", "persist_value")
25
+
26
+ # Create new instance to test persistence
27
+ new_cli_state = CLIState(self.state_file)
28
+ self.assertEqual(new_cli_state.get("PERSIST_KEY"), "persist_value")
29
+
30
+ def test_clear(self):
31
+ self.cli_state.set("CLEAR_KEY", "clear_value")
32
+ self.cli_state.clear()
33
+ self.assertIsNone(self.cli_state.get("CLEAR_KEY"))
34
+
35
+ def test_nonexistent_key(self):
36
+ self.assertIsNone(self.cli_state.get("NONEXISTENT"))
37
+
38
+ if __name__ == '__main__':
39
+ unittest.main()