llm-ide-rules 0.7.0__py3-none-any.whl → 0.8.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.
- llm_ide_rules/__init__.py +20 -1
- llm_ide_rules/agents/__init__.py +4 -0
- llm_ide_rules/agents/agents.py +124 -0
- llm_ide_rules/agents/base.py +11 -0
- llm_ide_rules/agents/claude.py +15 -4
- llm_ide_rules/agents/cursor.py +36 -7
- llm_ide_rules/agents/gemini.py +28 -4
- llm_ide_rules/agents/github.py +34 -3
- llm_ide_rules/agents/opencode.py +6 -0
- llm_ide_rules/agents/vscode.py +88 -0
- llm_ide_rules/commands/config.py +46 -0
- llm_ide_rules/commands/delete.py +111 -5
- llm_ide_rules/commands/download.py +33 -14
- llm_ide_rules/commands/explode.py +67 -16
- llm_ide_rules/commands/implode.py +18 -18
- llm_ide_rules/commands/mcp.py +1 -1
- llm_ide_rules/constants.py +1 -1
- llm_ide_rules/utils.py +118 -0
- {llm_ide_rules-0.7.0.dist-info → llm_ide_rules-0.8.0.dist-info}/METADATA +3 -3
- llm_ide_rules-0.8.0.dist-info/RECORD +27 -0
- llm_ide_rules-0.7.0.dist-info/RECORD +0 -23
- {llm_ide_rules-0.7.0.dist-info → llm_ide_rules-0.8.0.dist-info}/WHEEL +0 -0
- {llm_ide_rules-0.7.0.dist-info → llm_ide_rules-0.8.0.dist-info}/entry_points.txt +0 -0
llm_ide_rules/utils.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Utility functions for LLM IDE rules."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def modify_json_file(file_path: Path, updates: dict[str, Any]) -> bool:
|
|
9
|
+
"""Modify a JSON/JSONC file by adding MISSING keys using string manipulation to preserve comments.
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
bool: True if changes were written to the file, False otherwise.
|
|
13
|
+
"""
|
|
14
|
+
if not file_path.exists():
|
|
15
|
+
# Create new file with standard JSON if it doesn't exist
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
file_path.write_text(json.dumps(updates, indent=2))
|
|
20
|
+
return True
|
|
21
|
+
|
|
22
|
+
original_content = file_path.read_text()
|
|
23
|
+
content = original_content
|
|
24
|
+
|
|
25
|
+
for key, value in updates.items():
|
|
26
|
+
# Prepare the value representation (basic JSON serialization)
|
|
27
|
+
if isinstance(value, bool):
|
|
28
|
+
val_str = "true" if value else "false"
|
|
29
|
+
elif isinstance(value, (int, float)):
|
|
30
|
+
val_str = str(value)
|
|
31
|
+
elif isinstance(value, str):
|
|
32
|
+
val_str = f'"{value}"'
|
|
33
|
+
else:
|
|
34
|
+
import json
|
|
35
|
+
|
|
36
|
+
val_str = json.dumps(value)
|
|
37
|
+
|
|
38
|
+
# Updated pattern:
|
|
39
|
+
# 1. Match key part: (["']?key["']?\s* : \s*)
|
|
40
|
+
# 2. Match value part: ([^,\n\r}]+?)
|
|
41
|
+
# 3. Lookahead to stop before a comma, newline, closing brace, or start of a comment
|
|
42
|
+
escaped_key = re.escape(key)
|
|
43
|
+
pattern_str = (
|
|
44
|
+
rf'(["\\]?{escaped_key}["\\]?\s*:\s*)([^,\n\r}}]+?)'
|
|
45
|
+
r"(?=\s*(?:,|\n|\r|\}|\/\/|\/\*))"
|
|
46
|
+
)
|
|
47
|
+
pattern = re.compile(pattern_str, re.MULTILINE)
|
|
48
|
+
|
|
49
|
+
match = pattern.search(content)
|
|
50
|
+
if match:
|
|
51
|
+
# Key exists, replace the value part
|
|
52
|
+
# full_match = match.group(0)
|
|
53
|
+
key_part = match.group(1)
|
|
54
|
+
# Replace the value part (group 2) with new value
|
|
55
|
+
new_entry = f"{key_part}{val_str}"
|
|
56
|
+
content = content[: match.start()] + new_entry + content[match.end() :]
|
|
57
|
+
else:
|
|
58
|
+
# Insert new key
|
|
59
|
+
last_brace_idx = content.rfind("}")
|
|
60
|
+
if last_brace_idx != -1:
|
|
61
|
+
insertion_point = last_brace_idx
|
|
62
|
+
|
|
63
|
+
# Look backwards for the first non-whitespace character before the brace
|
|
64
|
+
prev_char_idx = insertion_point - 1
|
|
65
|
+
while prev_char_idx >= 0 and content[prev_char_idx].isspace():
|
|
66
|
+
prev_char_idx -= 1
|
|
67
|
+
|
|
68
|
+
# Detect indentation from the previous line if possible
|
|
69
|
+
line_start = content.rfind("\n", 0, insertion_point)
|
|
70
|
+
if line_start != -1:
|
|
71
|
+
indent_match = re.match(r"^(\s*)", content[line_start + 1 :])
|
|
72
|
+
indent = indent_match.group(1) if indent_match else " "
|
|
73
|
+
else:
|
|
74
|
+
indent = " "
|
|
75
|
+
|
|
76
|
+
if prev_char_idx >= 0:
|
|
77
|
+
prev_char = content[prev_char_idx]
|
|
78
|
+
# If the last thing wasn't a comma or opening brace, we need a comma
|
|
79
|
+
if prev_char not in ["{", ","]:
|
|
80
|
+
new_entry = f',\n{indent}"{key}": {val_str}'
|
|
81
|
+
else:
|
|
82
|
+
new_entry = f'\n{indent}"{key}": {val_str}'
|
|
83
|
+
|
|
84
|
+
content = (
|
|
85
|
+
content[:insertion_point]
|
|
86
|
+
+ new_entry
|
|
87
|
+
+ content[insertion_point:]
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if content != original_content:
|
|
91
|
+
file_path.write_text(content)
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def find_project_root(start_path: Path | None = None) -> Path:
|
|
98
|
+
"""Find the project root by looking for common markers."""
|
|
99
|
+
if start_path is None:
|
|
100
|
+
start_path = Path.cwd()
|
|
101
|
+
|
|
102
|
+
path = start_path.resolve()
|
|
103
|
+
# Check current directory and parents
|
|
104
|
+
for parent in [path] + list(path.parents):
|
|
105
|
+
if (parent / ".git").exists():
|
|
106
|
+
return parent
|
|
107
|
+
if (parent / "pyproject.toml").exists():
|
|
108
|
+
return parent
|
|
109
|
+
if (parent / ".cursor").exists():
|
|
110
|
+
return parent
|
|
111
|
+
if (parent / ".claude").exists():
|
|
112
|
+
return parent
|
|
113
|
+
if (parent / ".gemini").exists():
|
|
114
|
+
return parent
|
|
115
|
+
if (parent / ".github").exists():
|
|
116
|
+
return parent
|
|
117
|
+
|
|
118
|
+
return start_path # Fallback to current directory
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: llm-ide-rules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
|
|
19
19
|
# Copilot, Cursor, Claude, Gemini, etc LLM Instructions
|
|
20
20
|
|
|
21
|
-
This project makes it easy to download prompts and implode/explode them so they can be used by various providers.
|
|
21
|
+
This project makes it easy to download prompts and implode/explode them so they can be used by various providers. It's completely vibe coded, but it works.
|
|
22
22
|
|
|
23
23
|
I don't want to be tied to a specific IDE and it's a pain to have to edit instructions for various languages across a ton of different files.
|
|
24
24
|
|
|
@@ -40,7 +40,7 @@ Different AI coding assistants use different formats for instructions and comman
|
|
|
40
40
|
| **GitHub Copilot** | instructions | `.github/copilot-instructions.md` | Single markdown file |
|
|
41
41
|
| **GitHub Copilot** | instructions | `.github/instructions/*.instructions.md` | Multiple instruction files |
|
|
42
42
|
| **GitHub Copilot** | prompts | `.github/prompts/*.prompt.md` | YAML frontmatter with `mode: 'agent'` |
|
|
43
|
-
| **Gemini CLI** | instructions | `
|
|
43
|
+
| **Gemini CLI** | instructions | `AGENTS.md` | Single markdown file at root |
|
|
44
44
|
| **Gemini CLI** | commands | `.gemini/commands/*.toml` | TOML format, supports `{{args}}` and shell commands |
|
|
45
45
|
| **OpenCode** | commands | `.opencode/commands/*.md` | Plain markdown, no frontmatter |
|
|
46
46
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
llm_ide_rules/__init__.py,sha256=azpwor_AmypcI7JkDSgoOf-gyUJ66q2rPQ_WEzdJvVo,2746
|
|
2
|
+
llm_ide_rules/__main__.py,sha256=8maIDGnEcSUBs9lXg7YEevCXPC0fisYPC2gAEXHfHGM,145
|
|
3
|
+
llm_ide_rules/agents/__init__.py,sha256=pJ9sifirxbFGbajyFM6ZAnuE0kQAWiNw_bWanA4ujOY,1063
|
|
4
|
+
llm_ide_rules/agents/agents.py,sha256=QxXwlneARcPyKrsoQIlDhBMwmEKAXZDulkxZGJo6xNw,4296
|
|
5
|
+
llm_ide_rules/agents/base.py,sha256=WdzFBp_IUcOmh34joAu4FIyysZIFHbamT_4NH4IzIso,10843
|
|
6
|
+
llm_ide_rules/agents/claude.py,sha256=21D8s0FEMuD3_hAV8m_vK_zlA5BD15sPd1V_RhXRzPs,3647
|
|
7
|
+
llm_ide_rules/agents/cursor.py,sha256=QOrroQK3vHmJhpg1QsdIwfcvxjMkCNwcwwiGtxa2TNA,6890
|
|
8
|
+
llm_ide_rules/agents/gemini.py,sha256=bkigB1eUOpB6qz3N61IEF7kVH5TNZpSs0a2pqABkssE,6427
|
|
9
|
+
llm_ide_rules/agents/github.py,sha256=NZse_v5bogIyiUq0eBozZUrP0tzyYCcgiUfRpURmfNE,8196
|
|
10
|
+
llm_ide_rules/agents/opencode.py,sha256=GRtuJf8LU75KY9By4g0-Cr5e212rFeO4VnA64gnhdEk,4241
|
|
11
|
+
llm_ide_rules/agents/vscode.py,sha256=Xlte0I1TXTMV_F57hOY-6hROnh8L7arAOYXYRveAP6I,2764
|
|
12
|
+
llm_ide_rules/commands/config.py,sha256=_aVbQ4L39rYi5sQAQvK7Nd_AaMFHxn3ardNf_283mW0,1377
|
|
13
|
+
llm_ide_rules/commands/delete.py,sha256=8x0x6Hl0x-tKGy6X9yDggwREEKPUfNJ6NIanoxF05lM,9819
|
|
14
|
+
llm_ide_rules/commands/download.py,sha256=H0NX116aK1PahGTON8Ei5zysViAEIjDy_QF72OPXp4k,15189
|
|
15
|
+
llm_ide_rules/commands/explode.py,sha256=m8QUKzfX3-yRjMO4Rxwv_DPpZwBhumcaggarem99IH0,10989
|
|
16
|
+
llm_ide_rules/commands/implode.py,sha256=CEFcQkUCD8F1X3gpUscKr769qwCU8Lirg4Pp1-bPM7w,7126
|
|
17
|
+
llm_ide_rules/commands/mcp.py,sha256=KDG5RBVay6zK81RV9Msk4JJmQOpBKRsxA1JuKydzrRQ,3688
|
|
18
|
+
llm_ide_rules/constants.py,sha256=i1fWk39ZmtMgsf71xwWNCn-2U_2zOfJyVxCZ4JXJ_Ow,437
|
|
19
|
+
llm_ide_rules/log.py,sha256=hfkCLaTf2juQ7n67BYNREUrFxXDh6hqNcN2Pt9YTOo8,322
|
|
20
|
+
llm_ide_rules/markdown_parser.py,sha256=-S3sxrfFe1DRkNdu0dgUId1SMhUnfCZFMm9P7CZagUs,3418
|
|
21
|
+
llm_ide_rules/mcp/__init__.py,sha256=g73PAMhN7jDqmTBGskWJg2atpPj_-tiVY9ww7YqO2Yw,118
|
|
22
|
+
llm_ide_rules/mcp/models.py,sha256=gYzhgdWQwhH3pmj6OWVFWNNKRgxcblXeE3car2Tv8O4,440
|
|
23
|
+
llm_ide_rules/utils.py,sha256=n4gS-97pE1BE1ImypEvLUNbdAhxxHvtbZDvaIdciCgY,4288
|
|
24
|
+
llm_ide_rules-0.8.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
25
|
+
llm_ide_rules-0.8.0.dist-info/entry_points.txt,sha256=xsALXWBwSEifz-2Mike7s2SwqNu1taLs_-EcmGrONeM,54
|
|
26
|
+
llm_ide_rules-0.8.0.dist-info/METADATA,sha256=bse_eIJTkQ0-YoNSY7V2NSS-ARvMurpMEXcSkPKs7_k,5397
|
|
27
|
+
llm_ide_rules-0.8.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
llm_ide_rules/__init__.py,sha256=jr4i_EenGGu4xPpuAdZYEA3oOQZCBau5v65uFJr8YsM,2201
|
|
2
|
-
llm_ide_rules/__main__.py,sha256=8maIDGnEcSUBs9lXg7YEevCXPC0fisYPC2gAEXHfHGM,145
|
|
3
|
-
llm_ide_rules/agents/__init__.py,sha256=-KfKLr_qG26t2OXi1dA-gCesPDqS1ARGa6hELdoyCo0,905
|
|
4
|
-
llm_ide_rules/agents/base.py,sha256=BZCW-Ikmj-YsZzqzE5GOsWg68uOlSeCztENmqOZOYLo,10434
|
|
5
|
-
llm_ide_rules/agents/claude.py,sha256=07qKYmrX1ScWhLATK3sRClhddbb8iaJd9ZiaUdhb8aA,3176
|
|
6
|
-
llm_ide_rules/agents/cursor.py,sha256=3nfbagRtAMXhyPVY6rpOe-XnEJVHOZiVIW9hKeTmSPg,5939
|
|
7
|
-
llm_ide_rules/agents/gemini.py,sha256=sALl6NuX9wNL0cQ5UYclDQOBt-MlF1TUpPnW5Bk9i4g,5518
|
|
8
|
-
llm_ide_rules/agents/github.py,sha256=aEilEXCiRmRLtCpArhzRO12ZyqL6-sGKczvmQbGzlLE,6950
|
|
9
|
-
llm_ide_rules/agents/opencode.py,sha256=6aOwfns2DvynvWNSpidjyK3erxEahfa7bUJeml_APhg,3993
|
|
10
|
-
llm_ide_rules/commands/delete.py,sha256=m8hSDD5jruj6QN0w8zuRmrmX-SfscXjuEWwrGy3v0fs,5490
|
|
11
|
-
llm_ide_rules/commands/download.py,sha256=X6RAPXXXX5aseTWZHFTzHTrbzGP6GMofsZAC4iyO-oQ,14384
|
|
12
|
-
llm_ide_rules/commands/explode.py,sha256=auCx-LqRee93zHv7CqISDp_uiCK_xrEJWlrMBuKD4Dg,9384
|
|
13
|
-
llm_ide_rules/commands/implode.py,sha256=KHaOkkpz4vqAXhQh-iE5ftvrtDtFuSz0itXNQpKigls,6971
|
|
14
|
-
llm_ide_rules/commands/mcp.py,sha256=61juJyWe7BQrOisWH67-ynTBe3xjBPGq-s-HAzPWVrU,3680
|
|
15
|
-
llm_ide_rules/constants.py,sha256=WDz1_LFKzQe3m2pM8nCrDS47a16OMKFMZo2VK3rkX7E,427
|
|
16
|
-
llm_ide_rules/log.py,sha256=hfkCLaTf2juQ7n67BYNREUrFxXDh6hqNcN2Pt9YTOo8,322
|
|
17
|
-
llm_ide_rules/markdown_parser.py,sha256=-S3sxrfFe1DRkNdu0dgUId1SMhUnfCZFMm9P7CZagUs,3418
|
|
18
|
-
llm_ide_rules/mcp/__init__.py,sha256=g73PAMhN7jDqmTBGskWJg2atpPj_-tiVY9ww7YqO2Yw,118
|
|
19
|
-
llm_ide_rules/mcp/models.py,sha256=gYzhgdWQwhH3pmj6OWVFWNNKRgxcblXeE3car2Tv8O4,440
|
|
20
|
-
llm_ide_rules-0.7.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
|
|
21
|
-
llm_ide_rules-0.7.0.dist-info/entry_points.txt,sha256=xsALXWBwSEifz-2Mike7s2SwqNu1taLs_-EcmGrONeM,54
|
|
22
|
-
llm_ide_rules-0.7.0.dist-info/METADATA,sha256=uuHchmwl2QlV-V_CXT76NgVD7vqvBeo3MDKWjDt7qX4,5355
|
|
23
|
-
llm_ide_rules-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|