IncludeCPP 3.3.11__py3-none-any.whl → 3.3.20__py3-none-any.whl
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.
- includecpp/__init__.py +1 -1
- includecpp/cli/commands.py +265 -41
- includecpp/core/ai_integration.py +69 -34
- includecpp/core/cppy_converter.py +430 -16
- includecpp/core/error_formatter.py +50 -19
- includecpp/core/project_ui.py +2720 -0
- includecpp/core/settings_ui.py +127 -48
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/METADATA +116 -18
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/RECORD +13 -12
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/WHEEL +0 -0
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/entry_points.txt +0 -0
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.3.11.dist-info → includecpp-3.3.20.dist-info}/top_level.txt +0 -0
includecpp/__init__.py
CHANGED
includecpp/cli/commands.py
CHANGED
|
@@ -10,6 +10,22 @@ import urllib.error
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from .config_parser import CppProjectConfig
|
|
12
12
|
|
|
13
|
+
|
|
14
|
+
def _is_experimental_enabled() -> bool:
|
|
15
|
+
"""Check if experimental features (cppy, ai) are enabled."""
|
|
16
|
+
config_path = Path.home() / '.includecpp' / '.secret'
|
|
17
|
+
if config_path.exists():
|
|
18
|
+
try:
|
|
19
|
+
config = json.loads(config_path.read_text())
|
|
20
|
+
return config.get('experimental_features', False)
|
|
21
|
+
except:
|
|
22
|
+
pass
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Check once at module load time
|
|
27
|
+
_EXPERIMENTAL_ENABLED = _is_experimental_enabled()
|
|
28
|
+
|
|
13
29
|
# Unicode fallback for Windows terminals with limited encoding
|
|
14
30
|
def _supports_unicode():
|
|
15
31
|
"""Check if terminal supports Unicode output."""
|
|
@@ -4816,7 +4832,8 @@ def fix(module_name, all_modules, exclude, undo, auto_fix, verbose, use_ai):
|
|
|
4816
4832
|
click.echo(f"{'='*60}")
|
|
4817
4833
|
|
|
4818
4834
|
|
|
4819
|
-
|
|
4835
|
+
# AI group - conditionally registered based on experimental_features setting
|
|
4836
|
+
@click.group(invoke_without_command=True)
|
|
4820
4837
|
@click.option('--info', is_flag=True, help='Show AI status and usage')
|
|
4821
4838
|
@click.pass_context
|
|
4822
4839
|
def ai(ctx, info):
|
|
@@ -5306,7 +5323,7 @@ def ai_edit(task, module_name, files, all_modules, exclude, think_mode, think_tw
|
|
|
5306
5323
|
question = None # Continuation doesn't ask more questions
|
|
5307
5324
|
|
|
5308
5325
|
if not changes:
|
|
5309
|
-
verbose.status("No changes needed",
|
|
5326
|
+
verbose.status("No changes needed", phase='complete')
|
|
5310
5327
|
verbose.end(success=True, message="No changes required")
|
|
5311
5328
|
return
|
|
5312
5329
|
|
|
@@ -5520,7 +5537,7 @@ def ai_generate(task, files, think_mode, think_twice, think_three, use_websearch
|
|
|
5520
5537
|
verbose.api_call(endpoint='chat/completions', tokens_out=len(str(changes)) // 4 if changes else len(response) // 4)
|
|
5521
5538
|
|
|
5522
5539
|
if not changes:
|
|
5523
|
-
verbose.status("No file changes needed",
|
|
5540
|
+
verbose.status("No file changes needed", phase='complete')
|
|
5524
5541
|
# Show response if any
|
|
5525
5542
|
if response:
|
|
5526
5543
|
_safe_echo(f"\n{response[:2000]}")
|
|
@@ -5598,7 +5615,7 @@ def ai_generate(task, files, think_mode, think_twice, think_three, use_websearch
|
|
|
5598
5615
|
shell=True, capture_output=True, text=True, cwd=project_root
|
|
5599
5616
|
)
|
|
5600
5617
|
if result.returncode == 0:
|
|
5601
|
-
verbose.status("Plugin generated",
|
|
5618
|
+
verbose.status("Plugin generated", phase='complete')
|
|
5602
5619
|
else:
|
|
5603
5620
|
verbose.error(f"Plugin error: {result.stderr[:100]}")
|
|
5604
5621
|
verbose.end(success=False, message="Plugin generation failed")
|
|
@@ -5611,7 +5628,7 @@ def ai_generate(task, files, think_mode, think_twice, think_three, use_websearch
|
|
|
5611
5628
|
shell=True, capture_output=True, text=True, cwd=project_root
|
|
5612
5629
|
)
|
|
5613
5630
|
if result.returncode == 0:
|
|
5614
|
-
verbose.status("Build successful",
|
|
5631
|
+
verbose.status("Build successful", phase='complete')
|
|
5615
5632
|
else:
|
|
5616
5633
|
verbose.error(f"Build error: {result.stderr[:100]}")
|
|
5617
5634
|
|
|
@@ -5719,7 +5736,7 @@ def ai_optimize(module_name, files, agent_task, auto_confirm, no_verbose):
|
|
|
5719
5736
|
|
|
5720
5737
|
verbose.phase('analyzing', 'Analyzing code for optimization opportunities')
|
|
5721
5738
|
for fp in files_to_optimize.keys():
|
|
5722
|
-
verbose.status(f"Scanning {Path(fp).name}",
|
|
5739
|
+
verbose.status(f"Scanning {Path(fp).name}", phase='analyzing')
|
|
5723
5740
|
|
|
5724
5741
|
verbose.phase('thinking', 'AI is analyzing and planning optimizations')
|
|
5725
5742
|
verbose.api_call(endpoint='chat/completions', tokens_in=total_lines * 4)
|
|
@@ -5734,7 +5751,7 @@ def ai_optimize(module_name, files, agent_task, auto_confirm, no_verbose):
|
|
|
5734
5751
|
verbose.api_call(endpoint='chat/completions', tokens_out=len(str(changes)) // 4 if changes else 0)
|
|
5735
5752
|
|
|
5736
5753
|
if not changes:
|
|
5737
|
-
verbose.status("No optimizations needed",
|
|
5754
|
+
verbose.status("No optimizations needed", phase='complete')
|
|
5738
5755
|
verbose.end(success=True, message="Code is already optimal")
|
|
5739
5756
|
return
|
|
5740
5757
|
|
|
@@ -5787,7 +5804,7 @@ def ai_optimize(module_name, files, agent_task, auto_confirm, no_verbose):
|
|
|
5787
5804
|
click.secho("CONFIRM REQUIRED:", fg='yellow', bold=True)
|
|
5788
5805
|
click.echo(f"\n{confirm}\n")
|
|
5789
5806
|
if not click.confirm("Apply this change?"):
|
|
5790
|
-
verbose.status(f"Skipped: {change['file']}",
|
|
5807
|
+
verbose.status(f"Skipped: {change['file']}", phase='warning')
|
|
5791
5808
|
changes = [c for c in changes if c != change]
|
|
5792
5809
|
if not click.confirm("Apply all changes?"):
|
|
5793
5810
|
verbose.warning("Changes aborted by user")
|
|
@@ -5848,11 +5865,59 @@ def settings():
|
|
|
5848
5865
|
click.echo(" includecpp ai key <YOUR_KEY>")
|
|
5849
5866
|
|
|
5850
5867
|
|
|
5868
|
+
@click.command()
|
|
5869
|
+
@click.option('--path', '-p', type=click.Path(), default=None,
|
|
5870
|
+
help='Path to project directory (default: current directory)')
|
|
5871
|
+
def project(path):
|
|
5872
|
+
"""Open the Project Interface with CodeMaker.
|
|
5873
|
+
|
|
5874
|
+
Opens a professional visual mindmap tool for planning and designing
|
|
5875
|
+
your C++ project structure.
|
|
5876
|
+
|
|
5877
|
+
Features:
|
|
5878
|
+
- Visual node-based system design
|
|
5879
|
+
- Class, Function, Object, and Definition nodes
|
|
5880
|
+
- Connectable nodes with bezier curves
|
|
5881
|
+
- Pan/zoom navigation (middle mouse button)
|
|
5882
|
+
- Auto-save functionality
|
|
5883
|
+
- .ma map file management
|
|
5884
|
+
|
|
5885
|
+
Controls:
|
|
5886
|
+
- Right-click canvas: Create new nodes
|
|
5887
|
+
- Right-click node: Edit/Connect/Delete
|
|
5888
|
+
- Middle mouse + drag: Pan view
|
|
5889
|
+
- Middle mouse + scroll: Zoom in/out
|
|
5890
|
+
- ESC: Cancel connection mode
|
|
5891
|
+
- DELETE: Remove selected nodes
|
|
5892
|
+
|
|
5893
|
+
Requires: pip install PyQt6
|
|
5894
|
+
"""
|
|
5895
|
+
from pathlib import Path as PathLib
|
|
5896
|
+
project_path = PathLib(path) if path else PathLib.cwd()
|
|
5897
|
+
|
|
5898
|
+
if not project_path.exists():
|
|
5899
|
+
click.secho(f"Path does not exist: {project_path}", fg='red', err=True)
|
|
5900
|
+
return
|
|
5901
|
+
|
|
5902
|
+
try:
|
|
5903
|
+
from ..core.project_ui import show_project, PYQT_AVAILABLE
|
|
5904
|
+
if not PYQT_AVAILABLE:
|
|
5905
|
+
click.secho("PyQt6 not installed.", fg='red', err=True)
|
|
5906
|
+
click.echo("Install with: pip install PyQt6")
|
|
5907
|
+
return
|
|
5908
|
+
success, msg = show_project(str(project_path))
|
|
5909
|
+
if not success:
|
|
5910
|
+
click.secho(msg, fg='red', err=True)
|
|
5911
|
+
except Exception as e:
|
|
5912
|
+
click.secho(f"Error opening project interface: {e}", fg='red', err=True)
|
|
5913
|
+
|
|
5914
|
+
|
|
5851
5915
|
# ============================================================================
|
|
5852
|
-
# CPPY - Code Conversion Tools
|
|
5916
|
+
# CPPY - Code Conversion Tools (Experimental)
|
|
5853
5917
|
# ============================================================================
|
|
5854
5918
|
|
|
5855
|
-
|
|
5919
|
+
# CPPY group - conditionally registered based on experimental_features setting
|
|
5920
|
+
@click.group(invoke_without_command=True)
|
|
5856
5921
|
@click.pass_context
|
|
5857
5922
|
def cppy(ctx):
|
|
5858
5923
|
"""Code conversion tools for Python <-> C++.
|
|
@@ -6358,6 +6423,38 @@ def _convert_with_ai(content: str, module_name: str, source_file,
|
|
|
6358
6423
|
return _convert_to_python(content, module_name, source_file, output_dir, verbose)
|
|
6359
6424
|
|
|
6360
6425
|
ai_verbose.api_call(endpoint='chat/completions', tokens_out=len(response) // 4)
|
|
6426
|
+
|
|
6427
|
+
# Check if AI needs clarification on unconvertible modules
|
|
6428
|
+
if 'CLARIFICATION_NEEDED:' in response:
|
|
6429
|
+
ai_verbose.phase('clarification', 'AI needs clarification')
|
|
6430
|
+
clarification_match = re.search(r'CLARIFICATION_NEEDED:\n((?:- .+\n?)+)', response)
|
|
6431
|
+
if clarification_match:
|
|
6432
|
+
questions = clarification_match.group(1).strip()
|
|
6433
|
+
click.echo("\n" + "=" * 60)
|
|
6434
|
+
click.secho("AI NEEDS CLARIFICATION:", fg='yellow', bold=True)
|
|
6435
|
+
click.echo(questions)
|
|
6436
|
+
click.echo("=" * 60)
|
|
6437
|
+
user_input = click.prompt("Your response (or 'skip' to use defaults)")
|
|
6438
|
+
if user_input.lower() != 'skip':
|
|
6439
|
+
# Re-run AI with user's clarification
|
|
6440
|
+
clarified_prompt = ai_prompt + f"\n\nUSER CLARIFICATION:\n{user_input}\n\nNow convert with this clarification:"
|
|
6441
|
+
success, response, _ = ai_manager.generate(
|
|
6442
|
+
task=clarified_prompt,
|
|
6443
|
+
files={str(source_file): content},
|
|
6444
|
+
project_root=project_root,
|
|
6445
|
+
think=think,
|
|
6446
|
+
think_twice=think_twice,
|
|
6447
|
+
think_three=think_three,
|
|
6448
|
+
use_websearch=use_websearch,
|
|
6449
|
+
skip_tool_execution=True
|
|
6450
|
+
)
|
|
6451
|
+
if not success:
|
|
6452
|
+
ai_verbose.warning("Clarified conversion failed, using standard converter")
|
|
6453
|
+
if to_cpp:
|
|
6454
|
+
return _convert_to_cpp(content, module_name, source_file, output_dir, no_header, namespace, verbose)
|
|
6455
|
+
else:
|
|
6456
|
+
return _convert_to_python(content, module_name, source_file, output_dir, verbose)
|
|
6457
|
+
|
|
6361
6458
|
ai_verbose.phase('parsing', 'Extracting converted code from AI response')
|
|
6362
6459
|
|
|
6363
6460
|
# Parse AI response
|
|
@@ -6367,7 +6464,7 @@ def _convert_with_ai(content: str, module_name: str, source_file,
|
|
|
6367
6464
|
converted_code = _extract_ai_converted_code(response, to_cpp, module_name, namespace)
|
|
6368
6465
|
|
|
6369
6466
|
if not converted_code:
|
|
6370
|
-
ai_verbose.status("Using hybrid conversion (AI + standard)",
|
|
6467
|
+
ai_verbose.status("Using hybrid conversion (AI + standard)", phase='complete')
|
|
6371
6468
|
# Fall back to standard conversion with AI enhancements
|
|
6372
6469
|
if to_cpp:
|
|
6373
6470
|
converter = PythonToCppConverter()
|
|
@@ -6460,22 +6557,95 @@ def _convert_with_ai(content: str, module_name: str, source_file,
|
|
|
6460
6557
|
return result
|
|
6461
6558
|
|
|
6462
6559
|
|
|
6560
|
+
def _get_includecpp_readme() -> str:
|
|
6561
|
+
"""Load IncludeCPP README.md for AI context."""
|
|
6562
|
+
try:
|
|
6563
|
+
import importlib.resources
|
|
6564
|
+
import includecpp
|
|
6565
|
+
readme_path = Path(includecpp.__file__).parent.parent / 'README.md'
|
|
6566
|
+
if readme_path.exists():
|
|
6567
|
+
readme = readme_path.read_text(encoding='utf-8')
|
|
6568
|
+
# Truncate to first sections (keep it focused)
|
|
6569
|
+
sections = readme.split('# Changelog')[0] # Everything before changelog
|
|
6570
|
+
return sections[:8000] # Limit to ~8k chars
|
|
6571
|
+
except Exception:
|
|
6572
|
+
pass
|
|
6573
|
+
return ""
|
|
6574
|
+
|
|
6463
6575
|
def _build_cppy_ai_prompt(source: str, mode: str, module_name: str, namespace: str, analysis: dict, no_header: bool = False) -> str:
|
|
6464
6576
|
"""Build AI prompt with IncludeCPP-specific instructions."""
|
|
6465
6577
|
|
|
6578
|
+
# Load README for AI context (dynamically, not hardcoded)
|
|
6579
|
+
readme_context = _get_includecpp_readme()
|
|
6580
|
+
includecpp_docs = ""
|
|
6581
|
+
if readme_context:
|
|
6582
|
+
includecpp_docs = f'''
|
|
6583
|
+
=== INCLUDECPP DOCUMENTATION (from README.md) ===
|
|
6584
|
+
{readme_context}
|
|
6585
|
+
=== END DOCUMENTATION ===
|
|
6586
|
+
'''
|
|
6587
|
+
|
|
6588
|
+
# Critical file extension rules
|
|
6589
|
+
file_rules = f'''
|
|
6590
|
+
CRITICAL FILE EXTENSION RULES:
|
|
6591
|
+
- C++ implementation file MUST be: {module_name}.cpp (NOT .cp, NOT .cc, NOT .cxx)
|
|
6592
|
+
- C++ header file MUST be: {module_name}.h (NOT .hpp, NOT .hh)
|
|
6593
|
+
- Python file MUST be: {module_name}.py
|
|
6594
|
+
FOLLOW THESE EXTENSIONS EXACTLY.
|
|
6595
|
+
'''
|
|
6596
|
+
|
|
6597
|
+
# Unconvertible module handling
|
|
6598
|
+
unconvertible_info = ""
|
|
6599
|
+
for item, reason, line in getattr(analysis.get('converter', None), 'unconvertible', []) if isinstance(analysis, dict) else []:
|
|
6600
|
+
unconvertible_info += f"- Line {line}: {item} ({reason})\n"
|
|
6601
|
+
|
|
6602
|
+
unconvertible_guidance = ""
|
|
6603
|
+
if unconvertible_info:
|
|
6604
|
+
unconvertible_guidance = f'''
|
|
6605
|
+
UNCONVERTIBLE MODULES DETECTED:
|
|
6606
|
+
{unconvertible_info}
|
|
6607
|
+
|
|
6608
|
+
For unconvertible modules (tkinter, pygame, ursina, etc.):
|
|
6609
|
+
1. COMMENT OUT: Add /* UNCONVERTIBLE: tkinter */ comment
|
|
6610
|
+
2. ALTERNATIVE: Suggest C++ alternatives (Qt for GUI, SDL2 for games, etc.)
|
|
6611
|
+
3. SKIP: Remove the code with explanation comment
|
|
6612
|
+
|
|
6613
|
+
If you need clarification, output:
|
|
6614
|
+
CLARIFICATION_NEEDED:
|
|
6615
|
+
- <what you need clarified>
|
|
6616
|
+
'''
|
|
6617
|
+
|
|
6466
6618
|
if mode == 'py_to_cpp':
|
|
6467
6619
|
direction = "Python to C++"
|
|
6468
6620
|
source_lang = "python"
|
|
6469
6621
|
target_lang = "cpp"
|
|
6470
6622
|
|
|
6623
|
+
# CRITICAL: No pybind11 - IncludeCPP handles bindings automatically
|
|
6624
|
+
includecpp_note = '''
|
|
6625
|
+
**CRITICAL - IncludeCPP HANDLES BINDINGS AUTOMATICALLY:**
|
|
6626
|
+
- DO NOT include pybind11 headers
|
|
6627
|
+
- DO NOT write PYBIND11_MODULE macros
|
|
6628
|
+
- DO NOT use py:: namespace or py::object
|
|
6629
|
+
- Just write CLEAN C++ code in namespace includecpp
|
|
6630
|
+
- IncludeCPP will auto-generate Python bindings via: includecpp plugin <name> <file.cpp>
|
|
6631
|
+
|
|
6632
|
+
The user runs:
|
|
6633
|
+
1. includecpp cppy convert file.py --cpp (generates .cpp)
|
|
6634
|
+
2. includecpp plugin mymod file.cpp (auto-generates pybind11 bindings)
|
|
6635
|
+
3. includecpp rebuild (compiles to Python module)
|
|
6636
|
+
'''
|
|
6637
|
+
|
|
6471
6638
|
if no_header:
|
|
6472
6639
|
# No header mode - put everything in .cpp
|
|
6473
6640
|
specific_rules = f'''
|
|
6474
6641
|
INCLUDECPP-SPECIFIC REQUIREMENTS:
|
|
6475
6642
|
1. ALL code MUST be wrapped in: namespace {namespace} {{ ... }}
|
|
6476
|
-
2. DO NOT create a header file -
|
|
6477
|
-
3.
|
|
6478
|
-
4.
|
|
6643
|
+
2. **CRITICAL: DO NOT create a header file** - --no-h flag is set
|
|
6644
|
+
3. Put ALL declarations AND implementations in the .cpp file only
|
|
6645
|
+
4. NO separate .h file should be created
|
|
6646
|
+
{includecpp_note}
|
|
6647
|
+
|
|
6648
|
+
{file_rules}
|
|
6479
6649
|
|
|
6480
6650
|
TYPE CONVERSIONS:
|
|
6481
6651
|
- int -> int
|
|
@@ -6487,8 +6657,14 @@ TYPE CONVERSIONS:
|
|
|
6487
6657
|
- Set[T] -> std::unordered_set<T>
|
|
6488
6658
|
- Optional[T] -> std::optional<T>
|
|
6489
6659
|
- Callable -> std::function<R(Args...)>
|
|
6490
|
-
-
|
|
6491
|
-
|
|
6660
|
+
- bytes -> std::vector<uint8_t>
|
|
6661
|
+
|
|
6662
|
+
GENERIC/TEMPLATE FUNCTIONS:
|
|
6663
|
+
- For functions that accept any type (like choices), use C++ templates:
|
|
6664
|
+
template<typename T> T getRandomChoice(const std::vector<T>& choices);
|
|
6665
|
+
- NOT: auto getRandomChoice(const std::vector<auto>& choices) // INVALID!
|
|
6666
|
+
|
|
6667
|
+
{unconvertible_guidance}'''
|
|
6492
6668
|
else:
|
|
6493
6669
|
# Normal mode with header
|
|
6494
6670
|
specific_rules = f'''
|
|
@@ -6497,22 +6673,30 @@ INCLUDECPP-SPECIFIC REQUIREMENTS:
|
|
|
6497
6673
|
2. Create BOTH .cpp implementation AND .h header file
|
|
6498
6674
|
3. Use #include "{module_name}.h" at top of .cpp file
|
|
6499
6675
|
4. Header guard: #ifndef {module_name.upper()}_H / #define / #endif
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
- Context managers: Use RAII pattern
|
|
6504
|
-
- Duck typing: Use templates with concepts
|
|
6676
|
+
{includecpp_note}
|
|
6677
|
+
|
|
6678
|
+
{file_rules}
|
|
6505
6679
|
|
|
6506
|
-
|
|
6680
|
+
GENERIC/TEMPLATE FUNCTIONS:
|
|
6681
|
+
- For functions that accept any type, use C++ templates:
|
|
6682
|
+
template<typename T> T getRandomChoice(const std::vector<T>& choices);
|
|
6683
|
+
- NOT: auto getRandomChoice(const std::vector<auto>& choices) // INVALID!
|
|
6684
|
+
|
|
6685
|
+
TEMPLATE EXAMPLE (for generic functions):
|
|
6507
6686
|
```cpp
|
|
6508
|
-
|
|
6509
|
-
|
|
6687
|
+
// In header (.h):
|
|
6688
|
+
template<typename T>
|
|
6689
|
+
T getRandomChoice(const std::vector<T>& choices);
|
|
6510
6690
|
|
|
6511
|
-
//
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6691
|
+
// In implementation (.cpp):
|
|
6692
|
+
template<typename T>
|
|
6693
|
+
T Manager::getRandomChoice(const std::vector<T>& choices) {{
|
|
6694
|
+
// implementation
|
|
6515
6695
|
}}
|
|
6696
|
+
// Explicit instantiations for common types:
|
|
6697
|
+
template int Manager::getRandomChoice<int>(const std::vector<int>&);
|
|
6698
|
+
template double Manager::getRandomChoice<double>(const std::vector<double>&);
|
|
6699
|
+
template std::string Manager::getRandomChoice<std::string>(const std::vector<std::string>&);
|
|
6516
6700
|
```
|
|
6517
6701
|
|
|
6518
6702
|
TYPE CONVERSIONS:
|
|
@@ -6520,13 +6704,14 @@ TYPE CONVERSIONS:
|
|
|
6520
6704
|
- float -> double
|
|
6521
6705
|
- str -> std::string
|
|
6522
6706
|
- bool -> bool
|
|
6707
|
+
- bytes -> std::vector<uint8_t>
|
|
6523
6708
|
- List[T] -> std::vector<T>
|
|
6524
6709
|
- Dict[K,V] -> std::unordered_map<K,V>
|
|
6525
6710
|
- Set[T] -> std::unordered_set<T>
|
|
6526
6711
|
- Optional[T] -> std::optional<T>
|
|
6527
6712
|
- Callable -> std::function<R(Args...)>
|
|
6528
|
-
|
|
6529
|
-
'''
|
|
6713
|
+
|
|
6714
|
+
{unconvertible_guidance}'''
|
|
6530
6715
|
else:
|
|
6531
6716
|
direction = "C++ to Python"
|
|
6532
6717
|
source_lang = "cpp"
|
|
@@ -6559,37 +6744,60 @@ TYPE CONVERSIONS:
|
|
|
6559
6744
|
# Build output format based on mode and no_header flag
|
|
6560
6745
|
if mode == 'py_to_cpp':
|
|
6561
6746
|
if no_header:
|
|
6562
|
-
output_format = f'''OUTPUT FORMAT (NO HEADER
|
|
6563
|
-
|
|
6747
|
+
output_format = f'''OUTPUT FORMAT (--no-h flag is set, NO HEADER FILE):
|
|
6748
|
+
**CRITICAL**: Output ONLY a single .cpp file. NO .h file allowed.
|
|
6749
|
+
|
|
6750
|
+
Output the implementation file (extension MUST be .cpp):
|
|
6564
6751
|
```cpp
|
|
6565
6752
|
// {module_name}.cpp
|
|
6566
|
-
<
|
|
6753
|
+
#include <string>
|
|
6754
|
+
#include <vector>
|
|
6755
|
+
// ... other includes ...
|
|
6756
|
+
|
|
6757
|
+
namespace {namespace} {{
|
|
6758
|
+
|
|
6759
|
+
// All declarations AND implementations go here
|
|
6760
|
+
// No forward declarations needed since everything is in one file
|
|
6761
|
+
|
|
6762
|
+
}} // namespace {namespace}
|
|
6567
6763
|
```
|
|
6568
6764
|
|
|
6569
|
-
|
|
6765
|
+
REMEMBER:
|
|
6766
|
+
- File extension is .cpp (NOT .cp, NOT .cc)
|
|
6767
|
+
- DO NOT create a .h header file
|
|
6768
|
+
- Put ALL code in the single .cpp file'''
|
|
6570
6769
|
else:
|
|
6571
6770
|
output_format = f'''OUTPUT FORMAT (with header):
|
|
6572
|
-
1. First output the
|
|
6771
|
+
1. First output the implementation file (extension MUST be .cpp):
|
|
6573
6772
|
```cpp
|
|
6574
6773
|
// {module_name}.cpp
|
|
6575
|
-
|
|
6774
|
+
#include "{module_name}.h"
|
|
6775
|
+
// ... implementations ...
|
|
6576
6776
|
```
|
|
6577
6777
|
|
|
6578
|
-
2. Then the header file (
|
|
6778
|
+
2. Then output the header file (extension MUST be .h):
|
|
6579
6779
|
```cpp
|
|
6580
6780
|
// {module_name}.h
|
|
6581
|
-
|
|
6582
|
-
|
|
6781
|
+
#ifndef {module_name.upper()}_H
|
|
6782
|
+
#define {module_name.upper()}_H
|
|
6783
|
+
// ... declarations ...
|
|
6784
|
+
#endif // {module_name.upper()}_H
|
|
6785
|
+
```
|
|
6786
|
+
|
|
6787
|
+
REMEMBER:
|
|
6788
|
+
- Implementation file extension is .cpp (NOT .cp, NOT .cc)
|
|
6789
|
+
- Header file extension is .h (NOT .hpp, NOT .hh)'''
|
|
6583
6790
|
else:
|
|
6584
6791
|
output_format = f'''OUTPUT FORMAT:
|
|
6585
|
-
Output the Python file:
|
|
6792
|
+
Output the Python file (extension MUST be .py):
|
|
6586
6793
|
```python
|
|
6587
6794
|
# {module_name}.py
|
|
6588
6795
|
<full python content>
|
|
6589
6796
|
```'''
|
|
6590
6797
|
|
|
6591
6798
|
prompt = f'''Convert the following {direction}.
|
|
6592
|
-
|
|
6799
|
+
You are IncludeCPP's AI code converter. Follow all requirements precisely.
|
|
6800
|
+
{includecpp_docs}
|
|
6593
6801
|
MODULE NAME: {module_name}
|
|
6594
6802
|
NAMESPACE: {namespace}
|
|
6595
6803
|
{specific_rules}
|
|
@@ -6602,6 +6810,10 @@ SOURCE CODE ({source_lang}):
|
|
|
6602
6810
|
|
|
6603
6811
|
{output_format}
|
|
6604
6812
|
|
|
6813
|
+
If you need clarification about how to convert specific modules or patterns:
|
|
6814
|
+
CLARIFICATION_NEEDED:
|
|
6815
|
+
- <specific question about conversion approach>
|
|
6816
|
+
|
|
6605
6817
|
At the end, list any API changes:
|
|
6606
6818
|
API_CHANGES:
|
|
6607
6819
|
- <change description>
|
|
@@ -6921,5 +7133,17 @@ def cppy_types():
|
|
|
6921
7133
|
click.echo("=" * 60)
|
|
6922
7134
|
|
|
6923
7135
|
|
|
7136
|
+
# ============================================================================
|
|
7137
|
+
# Conditional Registration of Experimental Commands
|
|
7138
|
+
# ============================================================================
|
|
7139
|
+
# AI and CPPY commands are only available when experimental features are enabled
|
|
7140
|
+
# Enable via: includecpp settings -> "Enable Experimental Features" checkbox
|
|
7141
|
+
|
|
7142
|
+
if _EXPERIMENTAL_ENABLED:
|
|
7143
|
+
cli.add_command(ai)
|
|
7144
|
+
cli.add_command(cppy)
|
|
7145
|
+
cli.add_command(project)
|
|
7146
|
+
|
|
7147
|
+
|
|
6924
7148
|
if __name__ == '__main__':
|
|
6925
7149
|
cli()
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
import sys
|
|
3
4
|
import stat
|
|
4
5
|
import requests
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from datetime import datetime
|
|
7
8
|
from typing import Optional, Dict, List, Tuple, Any
|
|
8
9
|
|
|
10
|
+
|
|
11
|
+
def _supports_unicode():
|
|
12
|
+
"""Check if terminal supports Unicode output."""
|
|
13
|
+
if sys.platform == 'win32':
|
|
14
|
+
try:
|
|
15
|
+
'✓✗❌'.encode(sys.stdout.encoding or 'utf-8')
|
|
16
|
+
return True
|
|
17
|
+
except (UnicodeEncodeError, LookupError, AttributeError):
|
|
18
|
+
return False
|
|
19
|
+
return True
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_UNICODE_OK = _supports_unicode()
|
|
23
|
+
|
|
24
|
+
# Unicode symbols with ASCII fallbacks
|
|
25
|
+
SYM_CHECK = '✓' if _UNICODE_OK else '[OK]'
|
|
26
|
+
SYM_CROSS = '✗' if _UNICODE_OK else '[X]'
|
|
27
|
+
SYM_ERROR = '❌' if _UNICODE_OK else '[ERR]'
|
|
28
|
+
SYM_ARROW = '→' if _UNICODE_OK else '->'
|
|
29
|
+
SYM_BULLET = '•' if _UNICODE_OK else '*'
|
|
30
|
+
|
|
9
31
|
MODELS = {
|
|
10
32
|
'gpt-3.5-turbo': {'context': 16385, 'endpoint': 'gpt-3.5-turbo'},
|
|
11
33
|
'gpt-4-turbo': {'context': 128000, 'endpoint': 'gpt-4-turbo'},
|
|
@@ -1759,29 +1781,29 @@ class AIVerboseOutput:
|
|
|
1759
1781
|
'white': '\033[37m',
|
|
1760
1782
|
}
|
|
1761
1783
|
|
|
1762
|
-
# Status icons and messages
|
|
1784
|
+
# Status icons and messages - with ASCII fallbacks for Windows
|
|
1763
1785
|
PHASES = {
|
|
1764
|
-
'init': ('⚙', 'cyan', 'Initializing'),
|
|
1765
|
-
'context': ('📋', 'blue', 'Building context'),
|
|
1766
|
-
'thinking': ('🧠', 'magenta', 'Thinking'),
|
|
1767
|
-
'planning': ('📝', 'yellow', 'Planning'),
|
|
1768
|
-
'analyzing': ('🔍', 'cyan', 'Analyzing'),
|
|
1769
|
-
'generating': ('✨', 'green', 'Generating'),
|
|
1770
|
-
'writing': ('📄', 'blue', 'Writing'),
|
|
1771
|
-
'editing': ('✏️', 'yellow', 'Editing'),
|
|
1772
|
-
'reading': ('👁', 'cyan', 'Reading'),
|
|
1773
|
-
'searching': ('🔎', 'blue', 'Searching'),
|
|
1774
|
-
'executing': ('⚡', 'magenta', 'Executing'),
|
|
1775
|
-
'converting': ('🔄', 'cyan', 'Converting'),
|
|
1776
|
-
'optimizing': ('⚡', 'green', 'Optimizing'),
|
|
1777
|
-
'websearch': ('🌐', 'blue', 'Web searching'),
|
|
1778
|
-
'parsing': ('📊', 'cyan', 'Parsing response'),
|
|
1779
|
-
'applying': ('💾', 'green', 'Applying changes'),
|
|
1780
|
-
'complete': ('✅', 'green', 'Complete'),
|
|
1781
|
-
'error': ('❌', 'red', 'Error'),
|
|
1782
|
-
'warning': ('⚠️', 'yellow', 'Warning'),
|
|
1783
|
-
'waiting': ('⏳', 'dim', 'Waiting for API'),
|
|
1784
|
-
'tool': ('🔧', 'cyan', 'Running tool'),
|
|
1786
|
+
'init': ('*' if not _UNICODE_OK else '⚙', 'cyan', 'Initializing'),
|
|
1787
|
+
'context': ('*' if not _UNICODE_OK else '📋', 'blue', 'Building context'),
|
|
1788
|
+
'thinking': ('*' if not _UNICODE_OK else '🧠', 'magenta', 'Thinking'),
|
|
1789
|
+
'planning': ('*' if not _UNICODE_OK else '📝', 'yellow', 'Planning'),
|
|
1790
|
+
'analyzing': ('>' if not _UNICODE_OK else '🔍', 'cyan', 'Analyzing'),
|
|
1791
|
+
'generating': ('+' if not _UNICODE_OK else '✨', 'green', 'Generating'),
|
|
1792
|
+
'writing': ('>' if not _UNICODE_OK else '📄', 'blue', 'Writing'),
|
|
1793
|
+
'editing': ('>' if not _UNICODE_OK else '✏️', 'yellow', 'Editing'),
|
|
1794
|
+
'reading': ('>' if not _UNICODE_OK else '👁', 'cyan', 'Reading'),
|
|
1795
|
+
'searching': ('>' if not _UNICODE_OK else '🔎', 'blue', 'Searching'),
|
|
1796
|
+
'executing': ('!' if not _UNICODE_OK else '⚡', 'magenta', 'Executing'),
|
|
1797
|
+
'converting': ('~' if not _UNICODE_OK else '🔄', 'cyan', 'Converting'),
|
|
1798
|
+
'optimizing': ('!' if not _UNICODE_OK else '⚡', 'green', 'Optimizing'),
|
|
1799
|
+
'websearch': ('@' if not _UNICODE_OK else '🌐', 'blue', 'Web searching'),
|
|
1800
|
+
'parsing': ('>' if not _UNICODE_OK else '📊', 'cyan', 'Parsing response'),
|
|
1801
|
+
'applying': ('+' if not _UNICODE_OK else '💾', 'green', 'Applying changes'),
|
|
1802
|
+
'complete': ('[OK]' if not _UNICODE_OK else '✅', 'green', 'Complete'),
|
|
1803
|
+
'error': ('[ERR]' if not _UNICODE_OK else '❌', 'red', 'Error'),
|
|
1804
|
+
'warning': ('[!]' if not _UNICODE_OK else '⚠️', 'yellow', 'Warning'),
|
|
1805
|
+
'waiting': ('...' if not _UNICODE_OK else '⏳', 'dim', 'Waiting for API'),
|
|
1806
|
+
'tool': ('#' if not _UNICODE_OK else '🔧', 'cyan', 'Running tool'),
|
|
1785
1807
|
}
|
|
1786
1808
|
|
|
1787
1809
|
def __init__(self, enabled: bool = True, use_colors: bool = True):
|
|
@@ -1893,7 +1915,9 @@ class AIVerboseOutput:
|
|
|
1893
1915
|
pct = int((current / total) * 100) if total > 0 else 0
|
|
1894
1916
|
bar_width = 30
|
|
1895
1917
|
filled = int(bar_width * current / total) if total > 0 else 0
|
|
1896
|
-
|
|
1918
|
+
fill_char = '#' if not _UNICODE_OK else '█'
|
|
1919
|
+
empty_char = '-' if not _UNICODE_OK else '░'
|
|
1920
|
+
bar = fill_char * filled + empty_char * (bar_width - filled)
|
|
1897
1921
|
label_str = f" {label}" if label else ""
|
|
1898
1922
|
print(f"\r{indent} [{self._color(bar, 'cyan')}] {pct}%{label_str}", end='', flush=True)
|
|
1899
1923
|
if current >= total:
|
|
@@ -1917,10 +1941,10 @@ class AIVerboseOutput:
|
|
|
1917
1941
|
return
|
|
1918
1942
|
indent = self._get_indent()
|
|
1919
1943
|
if success:
|
|
1920
|
-
icon =
|
|
1944
|
+
icon = SYM_CHECK
|
|
1921
1945
|
color = 'green'
|
|
1922
1946
|
else:
|
|
1923
|
-
icon =
|
|
1947
|
+
icon = SYM_CROSS
|
|
1924
1948
|
color = 'red'
|
|
1925
1949
|
msg = message[:60] + "..." if message and len(message) > 60 else (message or "")
|
|
1926
1950
|
print(f"{indent} {self._color(icon, color)} {msg}")
|
|
@@ -2064,15 +2088,26 @@ class AIVerboseOutput:
|
|
|
2064
2088
|
if not self.enabled:
|
|
2065
2089
|
return
|
|
2066
2090
|
indent = self._get_indent()
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2091
|
+
if _UNICODE_OK:
|
|
2092
|
+
ops = {
|
|
2093
|
+
'read': ('👁', 'Reading'),
|
|
2094
|
+
'write': ('📝', 'Writing'),
|
|
2095
|
+
'edit': ('✏️', 'Editing'),
|
|
2096
|
+
'delete': ('🗑', 'Deleting'),
|
|
2097
|
+
'create': ('📁', 'Creating'),
|
|
2098
|
+
}
|
|
2099
|
+
default_icon = '📄'
|
|
2100
|
+
else:
|
|
2101
|
+
ops = {
|
|
2102
|
+
'read': ('>', 'Reading'),
|
|
2103
|
+
'write': ('>', 'Writing'),
|
|
2104
|
+
'edit': ('>', 'Editing'),
|
|
2105
|
+
'delete': ('x', 'Deleting'),
|
|
2106
|
+
'create': ('+', 'Creating'),
|
|
2107
|
+
}
|
|
2108
|
+
default_icon = '>'
|
|
2109
|
+
icon, label = ops.get(operation, (default_icon, operation))
|
|
2110
|
+
status = self._color(SYM_CHECK, 'green') if success else self._color(SYM_CROSS, 'red')
|
|
2076
2111
|
# Truncate path if too long
|
|
2077
2112
|
display_path = path if len(path) <= 40 else "..." + path[-37:]
|
|
2078
2113
|
print(f"{indent} {icon} {label}: {display_path} {status}")
|