kopipasta 0.15.0__py3-none-any.whl → 0.17.0__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.

Potentially problematic release.


This version of kopipasta might be problematic. Click here for more details.

kopipasta/main.py CHANGED
@@ -5,7 +5,7 @@ import json
5
5
  import os
6
6
  import argparse
7
7
  import re
8
- from typing import Dict, List, Optional, Tuple
8
+ from typing import Dict, List, Optional, Set, Tuple
9
9
  import pyperclip
10
10
  import fnmatch
11
11
 
@@ -519,9 +519,9 @@ def select_files_in_directory(directory: str, ignore_patterns: List[str], curren
519
519
  else:
520
520
  print("Invalid choice. Please try again.")
521
521
 
522
- def process_directory(directory, ignore_patterns, current_char_count=0):
522
+ def process_directory(directory: str, ignore_patterns: List[str], current_char_count: int = 0) -> Tuple[List[FileTuple], Set[str], int]:
523
523
  files_to_include: List[FileTuple] = []
524
- processed_dirs = set()
524
+ processed_dirs: Set[str] = set()
525
525
 
526
526
  for root, dirs, files in os.walk(directory):
527
527
  dirs[:] = [d for d in dirs if not is_ignored(os.path.join(root, d), ignore_patterns)]
@@ -535,12 +535,8 @@ def process_directory(directory, ignore_patterns, current_char_count=0):
535
535
  if choice == 'y':
536
536
  selected_files, current_char_count = select_files_in_directory(root, ignore_patterns, current_char_count)
537
537
  for file_tuple in selected_files:
538
- if len(file_tuple) == 3:
539
- f, use_snippet, chunks = file_tuple
540
- files_to_include.append((os.path.join(root, f), use_snippet, chunks))
541
- else:
542
- f, use_snippet = file_tuple
543
- files_to_include.append((os.path.join(root, f), use_snippet))
538
+ full_path = os.path.join(root, file_tuple[0])
539
+ files_to_include.append((full_path, file_tuple[1], file_tuple[2], file_tuple[3]))
544
540
  processed_dirs.add(root)
545
541
  elif choice == 'n':
546
542
  dirs[:] = [] # Skip all subdirectories
@@ -553,20 +549,25 @@ def process_directory(directory, ignore_patterns, current_char_count=0):
553
549
 
554
550
  return files_to_include, processed_dirs, current_char_count
555
551
 
556
- def fetch_web_content(url):
552
+ def fetch_web_content(url: str) -> Tuple[Optional[FileTuple], Optional[str], Optional[str]]:
557
553
  try:
558
554
  response = requests.get(url)
559
555
  response.raise_for_status()
560
556
  content_type = response.headers.get('content-type', '').lower()
557
+ full_content = response.text
558
+ snippet = full_content[:10000] + "..." if len(full_content) > 10000 else full_content
559
+
561
560
  if 'json' in content_type:
562
- return response.json(), 'json'
561
+ content_type = 'json'
563
562
  elif 'csv' in content_type:
564
- return response.text, 'csv'
563
+ content_type = 'csv'
565
564
  else:
566
- return response.text, 'text'
565
+ content_type = 'text'
566
+
567
+ return (url, False, None, content_type), full_content, snippet
567
568
  except requests.RequestException as e:
568
569
  print(f"Error fetching content from {url}: {e}")
569
- return None, None
570
+ return None, None, None
570
571
 
571
572
  def read_file_content(file_path):
572
573
  _, ext = os.path.splitext(file_path)
@@ -670,7 +671,7 @@ def handle_env_variables(content, env_vars):
670
671
 
671
672
  return content
672
673
 
673
- def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str], web_contents: Dict[str, Tuple[str, str]], env_vars: Dict[str, str]) -> str:
674
+ def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str], web_contents: Dict[str, Tuple[FileTuple, str]], env_vars: Dict[str, str]) -> str:
674
675
  prompt = "# Project Overview\n\n"
675
676
  prompt += "## Project Structure\n\n"
676
677
  prompt += "```\n"
@@ -696,7 +697,8 @@ def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str
696
697
 
697
698
  if web_contents:
698
699
  prompt += "## Web Content\n\n"
699
- for url, (content, is_snippet, content_type) in web_contents.items():
700
+ for url, (file_tuple, content) in web_contents.items():
701
+ _, is_snippet, _, content_type = file_tuple
700
702
  content = handle_env_variables(content, env_vars)
701
703
  language = content_type if content_type in ['json', 'csv'] else ''
702
704
  prompt += f"### {url}{' (snippet)' if is_snippet else ''}\n\n```{language}\n{content}\n```\n\n"
@@ -704,15 +706,36 @@ def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str
704
706
  prompt += "## Task Instructions\n\n"
705
707
  task_instructions = input("Enter the task instructions: ")
706
708
  prompt += f"{task_instructions}\n\n"
707
- prompt += "## Task Analysis and Planning\n\n"
709
+ prompt += "## Instructions for Achieving the Task\n\n"
708
710
  analysis_text = (
709
- "Before starting, explain the task back to me in your own words. "
710
- "Ask for any clarifications if needed. Once you're clear, ask to proceed.\n\n"
711
- "Then, outline a plan for the task. Finally, use your plan to complete the task."
711
+ "1. **Confirm and Understand the Task**:\n"
712
+ " - Rephrase the task in your own words to ensure understanding.\n"
713
+ " - Ask for any necessary clarifications.\n"
714
+ " - Once everything is clear, ask to proceed.\n\n"
715
+ "2. **Outline a Plan**:\n"
716
+ " - Provide a brief plan on how to approach the task.\n"
717
+ " - Make minimal incremental changes to maintain a working codebase at each step.\n"
718
+ " - This is an iterative process aimed at achieving the task step by step.\n\n"
719
+ "3. **Implement Changes Iteratively**:\n"
720
+ " - Apply changes in small, manageable increments.\n"
721
+ " - Ensure the codebase remains functional after each change.\n"
722
+ " - After each increment, verify stability before proceeding to the next step.\n\n"
723
+ "4. **Present Code Changes Clearly**:\n"
724
+ " - Specify the file being modified at the beginning of each code block.\n"
725
+ " - Format changes for clarity:\n"
726
+ " - For small changes: Show only the changed lines with clear comments.\n"
727
+ " - For larger changes: Provide the full new implementation of changed parts, using placeholders like `'// ... (rest of the function)'` for unchanged code.\n"
728
+ " - Provide context by including important unchanged parts as needed.\n"
729
+ " - Use clear comments to explain the changes and reference old code if helpful.\n\n"
730
+ "5. **Encourage User Testing and Collaboration**:\n"
731
+ " - Ask the user to test the code on their machine after each change.\n"
732
+ " - If debugging is needed, include debugging messages in the code.\n"
733
+ " - Request the user to share any error messages or outputs from debugging to assist further.\n"
712
734
  )
713
735
  prompt += analysis_text
714
736
  return prompt
715
737
 
738
+
716
739
  def main():
717
740
  parser = argparse.ArgumentParser(description="Generate a prompt with project structure, file contents, and web content.")
718
741
  parser.add_argument('inputs', nargs='+', help='Files, directories, or URLs to include in the prompt')
@@ -721,18 +744,45 @@ def main():
721
744
  ignore_patterns = read_gitignore()
722
745
  env_vars = read_env_file()
723
746
 
724
- files_to_include:List[FileTuple] = []
747
+ files_to_include: List[FileTuple] = []
725
748
  processed_dirs = set()
726
- web_contents = {}
749
+ web_contents: Dict[str, Tuple[FileTuple, str]] = {}
727
750
  current_char_count = 0
728
751
 
729
752
  for input_path in args.inputs:
730
753
  if input_path.startswith(('http://', 'https://')):
731
- full_content, snippet = fetch_web_content(input_path)
732
- if full_content:
733
- web_contents[input_path] = (full_content, snippet)
734
- current_char_count += len(snippet if len(full_content) > 10000 else full_content)
735
- print(f"Added web content from: {input_path}")
754
+ result = fetch_web_content(input_path)
755
+ if result:
756
+ file_tuple, full_content, snippet = result
757
+ is_large = len(full_content) > 10000
758
+ if is_large:
759
+ print(f"\nContent from {input_path} is large. Here's a snippet:\n")
760
+ print(snippet)
761
+ print("\n" + "-"*40 + "\n")
762
+
763
+ while True:
764
+ choice = input("Use (f)ull content or (s)nippet? ").lower()
765
+ if choice in ['f', 's']:
766
+ break
767
+ print("Invalid choice. Please enter 'f' or 's'.")
768
+
769
+ if choice == 'f':
770
+ content = full_content
771
+ is_snippet = False
772
+ print("Using full content.")
773
+ else:
774
+ content = snippet
775
+ is_snippet = True
776
+ print("Using snippet.")
777
+ else:
778
+ content = full_content
779
+ is_snippet = False
780
+ print(f"Content from {input_path} is not large. Using full content.")
781
+
782
+ file_tuple = (file_tuple[0], is_snippet, file_tuple[2], file_tuple[3])
783
+ web_contents[input_path] = (file_tuple, content)
784
+ current_char_count += len(content)
785
+ print(f"Added {'snippet of ' if is_snippet else ''}web content from: {input_path}")
736
786
  elif os.path.isfile(input_path):
737
787
  if not is_ignored(input_path, ignore_patterns) and not is_binary(input_path):
738
788
  while True:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kopipasta
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Summary: A CLI tool to generate prompts with project structure and file contents
5
5
  Home-page: https://github.com/mkorpela/kopipasta
6
6
  Author: Mikko Korpela
@@ -0,0 +1,8 @@
1
+ kopipasta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ kopipasta/main.py,sha256=jDcsdCYE3u2EuMKZbcpkyayxgj5soLLm7XWbhG46Poo,34657
3
+ kopipasta-0.17.0.dist-info/LICENSE,sha256=xw4C9TAU7LFu4r_MwSbky90uzkzNtRwAo3c51IWR8lk,1091
4
+ kopipasta-0.17.0.dist-info/METADATA,sha256=4JjrjvjRucGOIlIEP3PvPDLefJ-Dq7JTDGd1HIbiraA,5646
5
+ kopipasta-0.17.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
6
+ kopipasta-0.17.0.dist-info/entry_points.txt,sha256=but54qDNz1-F8fVvGstq_QID5tHjczP7bO7rWLFkc6Y,50
7
+ kopipasta-0.17.0.dist-info/top_level.txt,sha256=iXohixMuCdw8UjGDUp0ouICLYBDrx207sgZIJ9lxn0o,10
8
+ kopipasta-0.17.0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- kopipasta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- kopipasta/main.py,sha256=51k6jZXChwZY_CYVnqCqeY_hoHCAj3flN8qnr0vEVQI,31652
3
- kopipasta-0.15.0.dist-info/LICENSE,sha256=xw4C9TAU7LFu4r_MwSbky90uzkzNtRwAo3c51IWR8lk,1091
4
- kopipasta-0.15.0.dist-info/METADATA,sha256=ehTVHvX8IWh7hISa0O3bxJqj4a7gBqX9H0JtU1xU2ys,5646
5
- kopipasta-0.15.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
6
- kopipasta-0.15.0.dist-info/entry_points.txt,sha256=but54qDNz1-F8fVvGstq_QID5tHjczP7bO7rWLFkc6Y,50
7
- kopipasta-0.15.0.dist-info/top_level.txt,sha256=iXohixMuCdw8UjGDUp0ouICLYBDrx207sgZIJ9lxn0o,10
8
- kopipasta-0.15.0.dist-info/RECORD,,