llm-ide-rules 0.6.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.
@@ -1,29 +1,23 @@
1
1
  """Implode command: Bundle rule files into a single instruction file."""
2
2
 
3
- from pathlib import Path
4
3
  from typing_extensions import Annotated
5
4
 
6
5
  import typer
7
6
 
8
7
  from llm_ide_rules.agents import get_agent
9
- from llm_ide_rules.constants import load_section_globs
10
8
  from llm_ide_rules.log import log
9
+ from llm_ide_rules.utils import find_project_root
11
10
 
12
11
 
13
12
  def cursor(
14
13
  output: Annotated[
15
14
  str, typer.Argument(help="Output file for rules")
16
15
  ] = "instructions.md",
17
- config: Annotated[
18
- str | None,
19
- typer.Option("--config", "-c", help="Custom configuration file path"),
20
- ] = None,
21
16
  ) -> None:
22
17
  """Bundle Cursor rules into instructions.md and commands into commands.md."""
23
18
 
24
- section_globs = load_section_globs(config)
25
19
  agent = get_agent("cursor")
26
- cwd = Path.cwd()
20
+ base_dir = find_project_root()
27
21
 
28
22
  rules_dir = agent.rules_dir
29
23
  if not rules_dir:
@@ -34,18 +28,17 @@ def cursor(
34
28
  "bundling cursor rules and commands",
35
29
  rules_dir=rules_dir,
36
30
  commands_dir=agent.commands_dir,
37
- config=config,
38
31
  )
39
32
 
40
- rules_path = cwd / rules_dir
33
+ rules_path = base_dir / rules_dir
41
34
  if not rules_path.exists():
42
35
  log.error("cursor rules directory not found", rules_dir=str(rules_path))
43
36
  error_msg = f"Cursor rules directory not found: {rules_path}"
44
37
  typer.echo(typer.style(error_msg, fg=typer.colors.RED), err=True)
45
38
  raise typer.Exit(1)
46
39
 
47
- output_path = cwd / output
48
- rules_written = agent.bundle_rules(output_path, section_globs)
40
+ output_path = base_dir / output
41
+ rules_written = agent.bundle_rules(output_path)
49
42
  if rules_written:
50
43
  success_msg = f"Bundled cursor rules into {output}"
51
44
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -53,8 +46,8 @@ def cursor(
53
46
  output_path.unlink(missing_ok=True)
54
47
  log.info("no cursor rules to bundle")
55
48
 
56
- commands_output_path = cwd / "commands.md"
57
- commands_written = agent.bundle_commands(commands_output_path, section_globs)
49
+ commands_output_path = base_dir / "commands.md"
50
+ commands_written = agent.bundle_commands(commands_output_path)
58
51
  if commands_written:
59
52
  success_msg = "Bundled cursor commands into commands.md"
60
53
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -66,16 +59,11 @@ def github(
66
59
  output: Annotated[
67
60
  str, typer.Argument(help="Output file for instructions")
68
61
  ] = "instructions.md",
69
- config: Annotated[
70
- str | None,
71
- typer.Option("--config", "-c", help="Custom configuration file path"),
72
- ] = None,
73
62
  ) -> None:
74
63
  """Bundle GitHub instructions into instructions.md and prompts into commands.md."""
75
64
 
76
- section_globs = load_section_globs(config)
77
65
  agent = get_agent("github")
78
- cwd = Path.cwd()
66
+ base_dir = find_project_root()
79
67
 
80
68
  rules_dir = agent.rules_dir
81
69
  if not rules_dir:
@@ -86,10 +74,9 @@ def github(
86
74
  "bundling github instructions and prompts",
87
75
  instructions_dir=rules_dir,
88
76
  prompts_dir=agent.commands_dir,
89
- config=config,
90
77
  )
91
78
 
92
- rules_path = cwd / rules_dir
79
+ rules_path = base_dir / rules_dir
93
80
  if not rules_path.exists():
94
81
  log.error(
95
82
  "github instructions directory not found", instructions_dir=str(rules_path)
@@ -98,8 +85,8 @@ def github(
98
85
  typer.echo(typer.style(error_msg, fg=typer.colors.RED), err=True)
99
86
  raise typer.Exit(1)
100
87
 
101
- output_path = cwd / output
102
- instructions_written = agent.bundle_rules(output_path, section_globs)
88
+ output_path = base_dir / output
89
+ instructions_written = agent.bundle_rules(output_path)
103
90
  if instructions_written:
104
91
  success_msg = f"Bundled github instructions into {output}"
105
92
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -107,8 +94,8 @@ def github(
107
94
  output_path.unlink(missing_ok=True)
108
95
  log.info("no github instructions to bundle")
109
96
 
110
- commands_output_path = cwd / "commands.md"
111
- prompts_written = agent.bundle_commands(commands_output_path, section_globs)
97
+ commands_output_path = base_dir / "commands.md"
98
+ prompts_written = agent.bundle_commands(commands_output_path)
112
99
  if prompts_written:
113
100
  success_msg = "Bundled github prompts into commands.md"
114
101
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -118,16 +105,11 @@ def github(
118
105
 
119
106
  def claude(
120
107
  output: Annotated[str, typer.Argument(help="Output file")] = "commands.md",
121
- config: Annotated[
122
- str | None,
123
- typer.Option("--config", "-c", help="Custom configuration file path"),
124
- ] = None,
125
108
  ) -> None:
126
109
  """Bundle Claude Code commands into commands.md."""
127
110
 
128
- section_globs = load_section_globs(config)
129
111
  agent = get_agent("claude")
130
- cwd = Path.cwd()
112
+ base_dir = find_project_root()
131
113
 
132
114
  commands_dir = agent.commands_dir
133
115
  if not commands_dir:
@@ -137,10 +119,9 @@ def claude(
137
119
  log.info(
138
120
  "bundling claude code commands",
139
121
  commands_dir=commands_dir,
140
- config=config,
141
122
  )
142
123
 
143
- commands_path = cwd / commands_dir
124
+ commands_path = base_dir / commands_dir
144
125
  if not commands_path.exists():
145
126
  log.error(
146
127
  "claude code commands directory not found", commands_dir=str(commands_path)
@@ -149,8 +130,8 @@ def claude(
149
130
  typer.echo(typer.style(error_msg, fg=typer.colors.RED), err=True)
150
131
  raise typer.Exit(1)
151
132
 
152
- output_path = cwd / output
153
- commands_written = agent.bundle_commands(output_path, section_globs)
133
+ output_path = base_dir / output
134
+ commands_written = agent.bundle_commands(output_path)
154
135
  if commands_written:
155
136
  success_msg = f"Bundled claude commands into {output}"
156
137
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -161,16 +142,11 @@ def claude(
161
142
 
162
143
  def gemini(
163
144
  output: Annotated[str, typer.Argument(help="Output file")] = "commands.md",
164
- config: Annotated[
165
- str | None,
166
- typer.Option("--config", "-c", help="Custom configuration file path"),
167
- ] = None,
168
145
  ) -> None:
169
146
  """Bundle Gemini CLI commands into commands.md."""
170
147
 
171
- section_globs = load_section_globs(config)
172
148
  agent = get_agent("gemini")
173
- cwd = Path.cwd()
149
+ base_dir = find_project_root()
174
150
 
175
151
  commands_dir = agent.commands_dir
176
152
  if not commands_dir:
@@ -180,10 +156,9 @@ def gemini(
180
156
  log.info(
181
157
  "bundling gemini cli commands",
182
158
  commands_dir=commands_dir,
183
- config=config,
184
159
  )
185
160
 
186
- commands_path = cwd / commands_dir
161
+ commands_path = base_dir / commands_dir
187
162
  if not commands_path.exists():
188
163
  log.error(
189
164
  "gemini cli commands directory not found", commands_dir=str(commands_path)
@@ -192,8 +167,8 @@ def gemini(
192
167
  typer.echo(typer.style(error_msg, fg=typer.colors.RED), err=True)
193
168
  raise typer.Exit(1)
194
169
 
195
- output_path = cwd / output
196
- commands_written = agent.bundle_commands(output_path, section_globs)
170
+ output_path = base_dir / output
171
+ commands_written = agent.bundle_commands(output_path)
197
172
  if commands_written:
198
173
  success_msg = f"Bundled gemini commands into {output}"
199
174
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -204,16 +179,11 @@ def gemini(
204
179
 
205
180
  def opencode(
206
181
  output: Annotated[str, typer.Argument(help="Output file")] = "commands.md",
207
- config: Annotated[
208
- str | None,
209
- typer.Option("--config", "-c", help="Custom configuration file path"),
210
- ] = None,
211
182
  ) -> None:
212
183
  """Bundle OpenCode commands into commands.md."""
213
184
 
214
- section_globs = load_section_globs(config)
215
185
  agent = get_agent("opencode")
216
- cwd = Path.cwd()
186
+ base_dir = find_project_root()
217
187
 
218
188
  commands_dir = agent.commands_dir
219
189
  if not commands_dir:
@@ -223,10 +193,9 @@ def opencode(
223
193
  log.info(
224
194
  "bundling opencode commands",
225
195
  commands_dir=commands_dir,
226
- config=config,
227
196
  )
228
197
 
229
- commands_path = cwd / commands_dir
198
+ commands_path = base_dir / commands_dir
230
199
  if not commands_path.exists():
231
200
  log.error(
232
201
  "opencode commands directory not found", commands_dir=str(commands_path)
@@ -235,8 +204,8 @@ def opencode(
235
204
  typer.echo(typer.style(error_msg, fg=typer.colors.RED), err=True)
236
205
  raise typer.Exit(1)
237
206
 
238
- output_path = cwd / output
239
- commands_written = agent.bundle_commands(output_path, section_globs)
207
+ output_path = base_dir / output
208
+ commands_written = agent.bundle_commands(output_path)
240
209
  if commands_written:
241
210
  success_msg = f"Bundled opencode commands into {output}"
242
211
  typer.echo(typer.style(success_msg, fg=typer.colors.GREEN))
@@ -23,7 +23,7 @@ def explode(
23
23
  "all",
24
24
  "--agent",
25
25
  "-a",
26
- help="Agent: claude, cursor, gemini, opencode, copilot, or all",
26
+ help="Agent: claude, cursor, gemini, opencode, copilot, vscode, or all",
27
27
  ),
28
28
  ) -> None:
29
29
  """Convert unified mcp.json to platform-specific configs."""
@@ -1,32 +1,6 @@
1
1
  """Shared constants for explode and implode functionality."""
2
2
 
3
- import json
4
- from pathlib import Path
5
-
6
- VALID_AGENTS = ["cursor", "github", "claude", "gemini", "opencode", "all"]
7
-
8
-
9
- def load_section_globs(custom_config_path: str | None = None) -> dict[str, str | None]:
10
- """Load section globs from JSON config file.
11
-
12
- Args:
13
- custom_config_path: Path to custom configuration file to override defaults
14
-
15
- Returns:
16
- Dictionary mapping section headers to their file globs or None for prompts
17
- """
18
- if custom_config_path and Path(custom_config_path).exists():
19
- config_path = Path(custom_config_path)
20
- else:
21
- config_path = Path(__file__).parent / "sections.json"
22
-
23
- config = json.loads(config_path.read_text())
24
-
25
- return config["section_globs"]
26
-
27
-
28
- # Default section globs - loaded from bundled JSON
29
- SECTION_GLOBS = load_section_globs()
3
+ VALID_AGENTS = ["cursor", "github", "claude", "gemini", "opencode", "agents", "all"]
30
4
 
31
5
 
32
6
  def header_to_filename(header: str) -> str:
@@ -0,0 +1,108 @@
1
+ """Markdown parsing utilities using markdown-it-py."""
2
+
3
+ from typing import NamedTuple
4
+
5
+ from markdown_it import MarkdownIt
6
+
7
+
8
+ class SectionData(NamedTuple):
9
+ """Data for a parsed section."""
10
+
11
+ content: list[str]
12
+ glob_pattern: str | None
13
+
14
+
15
+ def extract_glob_directive(
16
+ content_lines: list[str],
17
+ ) -> tuple[list[str], str | None]:
18
+ """Extract glob directive from section content if present.
19
+
20
+ Checks the first non-empty line after the header for 'globs: PATTERN'.
21
+
22
+ Args:
23
+ content_lines: Lines including the header
24
+
25
+ Returns:
26
+ Tuple of (content_without_directive, glob_pattern)
27
+ - glob_pattern is None if no directive found (means alwaysApply)
28
+ - glob_pattern is "manual" for manual-only sections
29
+ """
30
+ if not content_lines:
31
+ return content_lines, None
32
+
33
+ header_idx = None
34
+ for i, line in enumerate(content_lines):
35
+ if line.startswith("## "):
36
+ header_idx = i
37
+ break
38
+
39
+ if header_idx is None:
40
+ return content_lines, None
41
+
42
+ for i in range(header_idx + 1, len(content_lines)):
43
+ line = content_lines[i].strip()
44
+ if not line:
45
+ continue
46
+
47
+ if line.lower().startswith("globs: "):
48
+ glob_value = line[7:].strip()
49
+ filtered_content = content_lines[:i] + content_lines[i + 1 :]
50
+ return filtered_content, glob_value
51
+
52
+ break
53
+
54
+ return content_lines, None
55
+
56
+
57
+ def parse_sections(text: str) -> tuple[list[str], dict[str, SectionData]]:
58
+ """Parse markdown text into general section and named sections.
59
+
60
+ Returns:
61
+ Tuple of (general_lines, sections_dict) where:
62
+ - general_lines: Lines before the first H2 header
63
+ - sections_dict: Dict mapping section names to SectionData (content + glob_pattern)
64
+ """
65
+ md = MarkdownIt()
66
+ tokens = md.parse(text)
67
+ lines = text.splitlines(keepends=True)
68
+
69
+ # Find all H2 headers
70
+ section_starts = []
71
+ for i, token in enumerate(tokens):
72
+ if token.type == "heading_open" and token.tag == "h2":
73
+ # Get the content of the header
74
+ # The next token is usually inline, which contains the text
75
+ if i + 1 < len(tokens) and tokens[i + 1].type == "inline":
76
+ header_content = tokens[i + 1].content.strip()
77
+ # token.map contains [start_line, end_line] (0-based)
78
+ if token.map:
79
+ start_line = token.map[0]
80
+ section_starts.append((start_line, header_content))
81
+
82
+ if not section_starts:
83
+ return lines, {}
84
+
85
+ # Extract general content (everything before first H2)
86
+ first_section_start = section_starts[0][0]
87
+ general_lines = lines[:first_section_start]
88
+
89
+ # Extract named sections
90
+ sections = {}
91
+ for i, (start_line, header_name) in enumerate(section_starts):
92
+ # End line is the start of the next section, or end of file
93
+ if i + 1 < len(section_starts):
94
+ end_line = section_starts[i + 1][0]
95
+ else:
96
+ end_line = len(lines)
97
+
98
+ # Extract all lines for this section
99
+ section_content = lines[start_line:end_line]
100
+
101
+ # Extract glob directive if present
102
+ filtered_content, glob_pattern = extract_glob_directive(section_content)
103
+
104
+ sections[header_name] = SectionData(
105
+ content=filtered_content, glob_pattern=glob_pattern
106
+ )
107
+
108
+ return general_lines, sections
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.6.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
@@ -11,13 +11,14 @@ Requires-Dist: requests>=2.25.0
11
11
  Requires-Dist: pydantic>=2.0.0
12
12
  Requires-Dist: json5>=0.9.0
13
13
  Requires-Dist: tomli-w>=1.0.0
14
+ Requires-Dist: markdown-it-py>=4.0.0
14
15
  Requires-Python: >=3.11
15
16
  Project-URL: Repository, https://github.com/iloveitaly/llm-ide-rules
16
17
  Description-Content-Type: text/markdown
17
18
 
18
19
  # Copilot, Cursor, Claude, Gemini, etc LLM Instructions
19
20
 
20
- 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.
21
22
 
22
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.
23
24
 
@@ -39,7 +40,7 @@ Different AI coding assistants use different formats for instructions and comman
39
40
  | **GitHub Copilot** | instructions | `.github/copilot-instructions.md` | Single markdown file |
40
41
  | **GitHub Copilot** | instructions | `.github/instructions/*.instructions.md` | Multiple instruction files |
41
42
  | **GitHub Copilot** | prompts | `.github/prompts/*.prompt.md` | YAML frontmatter with `mode: 'agent'` |
42
- | **Gemini CLI** | instructions | `GEMINI.md` | Single markdown file at root |
43
+ | **Gemini CLI** | instructions | `AGENTS.md` | Single markdown file at root |
43
44
  | **Gemini CLI** | commands | `.gemini/commands/*.toml` | TOML format, supports `{{args}}` and shell commands |
44
45
  | **OpenCode** | commands | `.opencode/commands/*.md` | Plain markdown, no frontmatter |
45
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,17 +0,0 @@
1
- {
2
- "section_globs": {
3
- "Python": "**/*.py,pyproject.toml",
4
- "Python App": "**/*.py",
5
- "Pytest Integration Tests": "tests/integration/**/*.py",
6
- "Pytest Tests": "tests/**/*.py",
7
- "Python Route Tests": "tests/routes/**/*.py",
8
- "Alembic Migrations": "migrations/versions/*.py",
9
- "FastAPI": "app/routes/**/*.py",
10
- "React": "**/*.tsx",
11
- "React Router": "web/app/routes/**/*.tsx",
12
- "Shell": "**/*.sh",
13
- "TypeScript": "**/*.ts,**/*.tsx",
14
- "Secrets": "env/*.sh,.envrc",
15
- "Stripe Backend": "manual"
16
- }
17
- }
@@ -1,23 +0,0 @@
1
- llm_ide_rules/__init__.py,sha256=HiB0P4fycSvvJvVeCQYH3WuoJ3jB8NvJV3Cc3k5U2CA,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=dp7Z3YJtbpQCtEBRdsFedNmljJuqe-C5Vyi8c91vQ2U,8915
5
- llm_ide_rules/agents/claude.py,sha256=MpdrbhudiD54-EakCb2YPQEKKCd0P2R9c7Gp4umkA2E,2624
6
- llm_ide_rules/agents/cursor.py,sha256=CDdarb9_SRDmwAVpQWPqX6NoyTyuuWVB_fr-lzxWSGU,5195
7
- llm_ide_rules/agents/gemini.py,sha256=NnXlOlt4NLzoASjpmNBo079UCGdRR94-2DSC2VxKr7Y,4966
8
- llm_ide_rules/agents/github.py,sha256=fhM3KpS3TP0LIA0TM6waOuuEsKRsCj3xZRwTetaOImI,6739
9
- llm_ide_rules/agents/opencode.py,sha256=fNvN91_GCs9b_hFIBhmSdEiky6u7o4Rn5kqQlnj2PXw,3861
10
- llm_ide_rules/commands/delete.py,sha256=m8hSDD5jruj6QN0w8zuRmrmX-SfscXjuEWwrGy3v0fs,5490
11
- llm_ide_rules/commands/download.py,sha256=3ipuZwYDKVDtl82Yxyv-VgjFZa8ZCTIxbXGAu0HV6Qc,10792
12
- llm_ide_rules/commands/explode.py,sha256=M12pXyo5dGKqsgTFWfJC7xNGuXeBqV5ZIp6kHaipjwM,11761
13
- llm_ide_rules/commands/implode.py,sha256=nVsK3PB9hGYukA7iPEGP5cRwQn3Ma79nC8txf-ES8m8,8161
14
- llm_ide_rules/commands/mcp.py,sha256=61juJyWe7BQrOisWH67-ynTBe3xjBPGq-s-HAzPWVrU,3680
15
- llm_ide_rules/constants.py,sha256=2m4yYcWOcLw82P8VF6py7LXDtwfBywOrJK4SHFfyPOY,1163
16
- llm_ide_rules/log.py,sha256=hfkCLaTf2juQ7n67BYNREUrFxXDh6hqNcN2Pt9YTOo8,322
17
- llm_ide_rules/mcp/__init__.py,sha256=g73PAMhN7jDqmTBGskWJg2atpPj_-tiVY9ww7YqO2Yw,118
18
- llm_ide_rules/mcp/models.py,sha256=gYzhgdWQwhH3pmj6OWVFWNNKRgxcblXeE3car2Tv8O4,440
19
- llm_ide_rules/sections.json,sha256=fY5dY7hIMfHAiLT7OHMj-_iV83LYv5-BL6o9iOXSmOE,536
20
- llm_ide_rules-0.6.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
21
- llm_ide_rules-0.6.0.dist-info/entry_points.txt,sha256=xsALXWBwSEifz-2Mike7s2SwqNu1taLs_-EcmGrONeM,54
22
- llm_ide_rules-0.6.0.dist-info/METADATA,sha256=WHPO5PBdkCh1g6diZjOBmDzTGnsI8P621LUvCuJbxTk,5318
23
- llm_ide_rules-0.6.0.dist-info/RECORD,,