llm-ide-rules 0.2.0__tar.gz → 0.3.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.
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/PKG-INFO +2 -2
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/README.md +1 -1
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/pyproject.toml +2 -2
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/__init__.py +1 -1
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/commands/download.py +83 -4
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/__main__.py +0 -0
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/commands/explode.py +0 -0
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/commands/implode.py +0 -0
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/constants.py +0 -0
- {llm_ide_rules-0.2.0 → llm_ide_rules-0.3.0}/src/llm_ide_rules/sections.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: llm-ide-rules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CLI tool for managing LLM IDE prompts and rules
|
|
5
5
|
Keywords: llm,ide,prompts,cursor,copilot
|
|
6
6
|
Author: Michael Bianco
|
|
@@ -12,7 +12,7 @@ Requires-Python: >=3.9
|
|
|
12
12
|
Project-URL: Repository, https://github.com/iloveitaly/llm-ide-rules
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
|
|
15
|
-
# Copilot
|
|
15
|
+
# Copilot, Cursor, Claude, Gemini, etc LLM Instructions
|
|
16
16
|
|
|
17
17
|
Going to try to centralize all my prompts in a single place and create some scripts to help convert from copilot to cursor, etc.
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "llm-ide-rules"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "CLI tool for managing LLM IDE prompts and rules"
|
|
5
5
|
keywords = ["llm", "ide", "prompts", "cursor", "copilot"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -11,7 +11,7 @@ urls = { "Repository" = "https://github.com/iloveitaly/llm-ide-rules" }
|
|
|
11
11
|
|
|
12
12
|
# additional packaging information: https://packaging.python.org/en/latest/specifications/core-metadata/#license
|
|
13
13
|
[project.scripts]
|
|
14
|
-
|
|
14
|
+
llm-ide-rules = "llm_ide_rules:main"
|
|
15
15
|
|
|
16
16
|
[build-system]
|
|
17
17
|
requires = ["uv_build>=0.8.11,<0.9.0"]
|
|
@@ -7,7 +7,7 @@ from llm_ide_rules.commands.explode import explode_main
|
|
|
7
7
|
from llm_ide_rules.commands.implode import cursor, github
|
|
8
8
|
from llm_ide_rules.commands.download import download_main
|
|
9
9
|
|
|
10
|
-
__version__ = "0.
|
|
10
|
+
__version__ = "0.3.0"
|
|
11
11
|
|
|
12
12
|
app = typer.Typer(
|
|
13
13
|
name="llm_ide_rules",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Download command: Download LLM instruction files from GitHub repositories."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import re
|
|
4
5
|
import tempfile
|
|
5
6
|
import zipfile
|
|
6
7
|
from pathlib import Path
|
|
@@ -13,9 +14,31 @@ from typing_extensions import Annotated
|
|
|
13
14
|
|
|
14
15
|
logger = structlog.get_logger()
|
|
15
16
|
|
|
16
|
-
DEFAULT_REPO = "iloveitaly/
|
|
17
|
+
DEFAULT_REPO = "iloveitaly/llm-ide-rules"
|
|
17
18
|
DEFAULT_BRANCH = "master"
|
|
18
19
|
|
|
20
|
+
|
|
21
|
+
def normalize_repo(repo: str) -> str:
|
|
22
|
+
"""Normalize repository input to user/repo format.
|
|
23
|
+
|
|
24
|
+
Handles both formats:
|
|
25
|
+
- user/repo (unchanged)
|
|
26
|
+
- https://github.com/user/repo/ (extracts user/repo)
|
|
27
|
+
"""
|
|
28
|
+
# If it's already in user/repo format, return as-is
|
|
29
|
+
if "/" in repo and not repo.startswith("http"):
|
|
30
|
+
return repo
|
|
31
|
+
|
|
32
|
+
# Extract user/repo from GitHub URL
|
|
33
|
+
github_pattern = r"https?://github\.com/([^/]+/[^/]+)/?.*"
|
|
34
|
+
match = re.match(github_pattern, repo)
|
|
35
|
+
|
|
36
|
+
if match:
|
|
37
|
+
return match.group(1)
|
|
38
|
+
|
|
39
|
+
# If no pattern matches, assume it's already in the correct format
|
|
40
|
+
return repo
|
|
41
|
+
|
|
19
42
|
# Define what files/directories each instruction type includes
|
|
20
43
|
INSTRUCTION_TYPES = {
|
|
21
44
|
"cursor": {"directories": [".cursor"], "files": []},
|
|
@@ -27,6 +50,7 @@ INSTRUCTION_TYPES = {
|
|
|
27
50
|
"gemini": {"directories": [], "files": ["GEMINI.md"]},
|
|
28
51
|
"claude": {"directories": [], "files": ["CLAUDE.md"]},
|
|
29
52
|
"agent": {"directories": [], "files": ["AGENT.md"]},
|
|
53
|
+
"agents": {"directories": [], "files": [], "recursive_files": ["AGENTS.md"]},
|
|
30
54
|
}
|
|
31
55
|
|
|
32
56
|
# Default types to download when no specific types are specified
|
|
@@ -35,9 +59,10 @@ DEFAULT_TYPES = list(INSTRUCTION_TYPES.keys())
|
|
|
35
59
|
|
|
36
60
|
def download_and_extract_repo(repo: str, branch: str = DEFAULT_BRANCH) -> Path:
|
|
37
61
|
"""Download a GitHub repository as a ZIP and extract it to a temporary directory."""
|
|
38
|
-
|
|
62
|
+
normalized_repo = normalize_repo(repo)
|
|
63
|
+
zip_url = f"https://github.com/{normalized_repo}/archive/{branch}.zip"
|
|
39
64
|
|
|
40
|
-
logger.info("Downloading repository", repo=repo, branch=branch, url=zip_url)
|
|
65
|
+
logger.info("Downloading repository", repo=repo, normalized_repo=normalized_repo, branch=branch, url=zip_url)
|
|
41
66
|
|
|
42
67
|
try:
|
|
43
68
|
response = requests.get(zip_url, timeout=30)
|
|
@@ -123,6 +148,60 @@ def copy_instruction_files(
|
|
|
123
148
|
target_file.write_bytes(source_file.read_bytes())
|
|
124
149
|
copied_items.append(file_name)
|
|
125
150
|
|
|
151
|
+
# Copy recursive files (search throughout repository)
|
|
152
|
+
for file_pattern in config.get("recursive_files", []):
|
|
153
|
+
copied_recursive = copy_recursive_files(repo_dir, target_dir, file_pattern)
|
|
154
|
+
copied_items.extend(copied_recursive)
|
|
155
|
+
|
|
156
|
+
return copied_items
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def copy_recursive_files(
|
|
160
|
+
repo_dir: Path, target_dir: Path, file_pattern: str
|
|
161
|
+
) -> List[str]:
|
|
162
|
+
"""Recursively copy files matching pattern, preserving directory structure.
|
|
163
|
+
|
|
164
|
+
Only copies files to locations where the target directory already exists.
|
|
165
|
+
Warns and skips files where target directories don't exist.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
repo_dir: Source repository directory
|
|
169
|
+
target_dir: Target directory to copy to
|
|
170
|
+
file_pattern: File pattern to search for (e.g., "AGENTS.md")
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
List of copied file paths relative to target_dir
|
|
174
|
+
"""
|
|
175
|
+
copied_items = []
|
|
176
|
+
|
|
177
|
+
# Find all matching files recursively
|
|
178
|
+
matching_files = list(repo_dir.rglob(file_pattern))
|
|
179
|
+
|
|
180
|
+
for source_file in matching_files:
|
|
181
|
+
# Calculate relative path from repo root
|
|
182
|
+
relative_path = source_file.relative_to(repo_dir)
|
|
183
|
+
target_file = target_dir / relative_path
|
|
184
|
+
|
|
185
|
+
# Check if target directory already exists
|
|
186
|
+
target_parent = target_file.parent
|
|
187
|
+
if not target_parent.exists():
|
|
188
|
+
logger.warning(
|
|
189
|
+
"Target directory does not exist, skipping file copy",
|
|
190
|
+
target_directory=str(target_parent),
|
|
191
|
+
file=str(relative_path)
|
|
192
|
+
)
|
|
193
|
+
continue
|
|
194
|
+
|
|
195
|
+
logger.info(
|
|
196
|
+
"Copying recursive file",
|
|
197
|
+
source=str(source_file),
|
|
198
|
+
target=str(target_file)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Copy file (parent directory already exists)
|
|
202
|
+
target_file.write_bytes(source_file.read_bytes())
|
|
203
|
+
copied_items.append(str(relative_path))
|
|
204
|
+
|
|
126
205
|
return copied_items
|
|
127
206
|
|
|
128
207
|
|
|
@@ -161,7 +240,7 @@ def download_main(
|
|
|
161
240
|
instruction_types: Annotated[
|
|
162
241
|
List[str],
|
|
163
242
|
typer.Argument(
|
|
164
|
-
help="Types of instructions to download (cursor, github, gemini, claude, agent). Downloads everything by default."
|
|
243
|
+
help="Types of instructions to download (cursor, github, gemini, claude, agent, agents). Downloads everything by default."
|
|
165
244
|
),
|
|
166
245
|
] = None,
|
|
167
246
|
repo: Annotated[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|