devsync 0.5.5__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.
- aiconfigkit/__init__.py +0 -0
- aiconfigkit/__main__.py +6 -0
- aiconfigkit/ai_tools/__init__.py +0 -0
- aiconfigkit/ai_tools/base.py +236 -0
- aiconfigkit/ai_tools/capability_registry.py +262 -0
- aiconfigkit/ai_tools/claude.py +91 -0
- aiconfigkit/ai_tools/claude_desktop.py +97 -0
- aiconfigkit/ai_tools/cline.py +92 -0
- aiconfigkit/ai_tools/copilot.py +92 -0
- aiconfigkit/ai_tools/cursor.py +109 -0
- aiconfigkit/ai_tools/detector.py +169 -0
- aiconfigkit/ai_tools/kiro.py +85 -0
- aiconfigkit/ai_tools/mcp_syncer.py +291 -0
- aiconfigkit/ai_tools/roo.py +110 -0
- aiconfigkit/ai_tools/translator.py +390 -0
- aiconfigkit/ai_tools/winsurf.py +102 -0
- aiconfigkit/cli/__init__.py +0 -0
- aiconfigkit/cli/delete.py +118 -0
- aiconfigkit/cli/download.py +274 -0
- aiconfigkit/cli/install.py +237 -0
- aiconfigkit/cli/install_new.py +937 -0
- aiconfigkit/cli/list.py +275 -0
- aiconfigkit/cli/main.py +454 -0
- aiconfigkit/cli/mcp_configure.py +232 -0
- aiconfigkit/cli/mcp_install.py +166 -0
- aiconfigkit/cli/mcp_sync.py +165 -0
- aiconfigkit/cli/package.py +383 -0
- aiconfigkit/cli/package_create.py +323 -0
- aiconfigkit/cli/package_install.py +472 -0
- aiconfigkit/cli/template.py +19 -0
- aiconfigkit/cli/template_backup.py +261 -0
- aiconfigkit/cli/template_init.py +499 -0
- aiconfigkit/cli/template_install.py +261 -0
- aiconfigkit/cli/template_list.py +172 -0
- aiconfigkit/cli/template_uninstall.py +146 -0
- aiconfigkit/cli/template_update.py +225 -0
- aiconfigkit/cli/template_validate.py +234 -0
- aiconfigkit/cli/tools.py +47 -0
- aiconfigkit/cli/uninstall.py +125 -0
- aiconfigkit/cli/update.py +309 -0
- aiconfigkit/core/__init__.py +0 -0
- aiconfigkit/core/checksum.py +211 -0
- aiconfigkit/core/component_detector.py +905 -0
- aiconfigkit/core/conflict_resolution.py +329 -0
- aiconfigkit/core/git_operations.py +539 -0
- aiconfigkit/core/mcp/__init__.py +1 -0
- aiconfigkit/core/mcp/credentials.py +279 -0
- aiconfigkit/core/mcp/manager.py +308 -0
- aiconfigkit/core/mcp/set_manager.py +1 -0
- aiconfigkit/core/mcp/validator.py +1 -0
- aiconfigkit/core/models.py +1661 -0
- aiconfigkit/core/package_creator.py +743 -0
- aiconfigkit/core/package_manifest.py +248 -0
- aiconfigkit/core/repository.py +298 -0
- aiconfigkit/core/secret_detector.py +438 -0
- aiconfigkit/core/template_manifest.py +283 -0
- aiconfigkit/core/version.py +201 -0
- aiconfigkit/storage/__init__.py +0 -0
- aiconfigkit/storage/library.py +429 -0
- aiconfigkit/storage/mcp_tracker.py +1 -0
- aiconfigkit/storage/package_tracker.py +234 -0
- aiconfigkit/storage/template_library.py +229 -0
- aiconfigkit/storage/template_tracker.py +296 -0
- aiconfigkit/storage/tracker.py +416 -0
- aiconfigkit/tui/__init__.py +5 -0
- aiconfigkit/tui/installer.py +511 -0
- aiconfigkit/utils/__init__.py +0 -0
- aiconfigkit/utils/atomic_write.py +90 -0
- aiconfigkit/utils/backup.py +169 -0
- aiconfigkit/utils/dotenv.py +128 -0
- aiconfigkit/utils/git_helpers.py +187 -0
- aiconfigkit/utils/logging.py +60 -0
- aiconfigkit/utils/namespace.py +134 -0
- aiconfigkit/utils/paths.py +205 -0
- aiconfigkit/utils/project.py +109 -0
- aiconfigkit/utils/streaming.py +216 -0
- aiconfigkit/utils/ui.py +194 -0
- aiconfigkit/utils/validation.py +187 -0
- devsync-0.5.5.dist-info/LICENSE +21 -0
- devsync-0.5.5.dist-info/METADATA +477 -0
- devsync-0.5.5.dist-info/RECORD +84 -0
- devsync-0.5.5.dist-info/WHEEL +5 -0
- devsync-0.5.5.dist-info/entry_points.txt +2 -0
- devsync-0.5.5.dist-info/top_level.txt +1 -0
aiconfigkit/__init__.py
ADDED
|
File without changes
|
aiconfigkit/__main__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""Base interface for AI coding tool integrations."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from aiconfigkit.core.models import AIToolType, InstallationScope, Instruction
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AITool(ABC):
|
|
12
|
+
"""
|
|
13
|
+
Abstract base class for AI coding tool integrations.
|
|
14
|
+
|
|
15
|
+
Each AI tool (Cline, Cursor, Copilot, Kiro, Roo Code, Winsurf, Claude) implements this interface
|
|
16
|
+
to provide tool-specific installation logic.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def tool_type(self) -> AIToolType:
|
|
22
|
+
"""Return the AI tool type identifier."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def tool_name(self) -> str:
|
|
28
|
+
"""Return human-readable tool name."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def is_installed(self) -> bool:
|
|
33
|
+
"""
|
|
34
|
+
Check if this AI tool is installed on the system.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
True if tool is detected, False otherwise
|
|
38
|
+
"""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def get_instructions_directory(self) -> Path:
|
|
43
|
+
"""
|
|
44
|
+
Get the directory where instructions should be installed.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Path to instructions directory
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
FileNotFoundError: If tool is not installed
|
|
51
|
+
"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def get_instruction_file_extension(self) -> str:
|
|
56
|
+
"""
|
|
57
|
+
Get the file extension for instructions (e.g., '.md', '.txt').
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
File extension including the dot
|
|
61
|
+
"""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
66
|
+
"""
|
|
67
|
+
Get the directory where project-specific instructions should be installed.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
project_root: Path to the project root directory
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Path to project instructions directory
|
|
74
|
+
"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def get_mcp_config_path(self) -> Path:
|
|
78
|
+
"""
|
|
79
|
+
Get the path to the MCP configuration file for this AI tool.
|
|
80
|
+
|
|
81
|
+
This is an optional method - tools that support MCP server configuration
|
|
82
|
+
should override this method.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Path to MCP configuration file
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
NotImplementedError: If tool doesn't support MCP configuration
|
|
89
|
+
"""
|
|
90
|
+
raise NotImplementedError(f"{self.tool_name} does not support MCP server configuration")
|
|
91
|
+
|
|
92
|
+
def get_instruction_path(
|
|
93
|
+
self,
|
|
94
|
+
instruction_name: str,
|
|
95
|
+
scope: InstallationScope = InstallationScope.GLOBAL,
|
|
96
|
+
project_root: Optional[Path] = None,
|
|
97
|
+
) -> Path:
|
|
98
|
+
"""
|
|
99
|
+
Get the full path where an instruction file should be installed.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
instruction_name: Name of the instruction
|
|
103
|
+
scope: Installation scope (global or project)
|
|
104
|
+
project_root: Project root path (required if scope is PROJECT)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Full path to instruction file
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
ValueError: If scope is PROJECT but project_root is None
|
|
111
|
+
"""
|
|
112
|
+
if scope == InstallationScope.PROJECT:
|
|
113
|
+
if project_root is None:
|
|
114
|
+
raise ValueError("project_root is required for PROJECT scope")
|
|
115
|
+
directory = self.get_project_instructions_directory(project_root)
|
|
116
|
+
else:
|
|
117
|
+
directory = self.get_instructions_directory()
|
|
118
|
+
|
|
119
|
+
extension = self.get_instruction_file_extension()
|
|
120
|
+
filename = f"{instruction_name}{extension}"
|
|
121
|
+
return directory / filename
|
|
122
|
+
|
|
123
|
+
def instruction_exists(
|
|
124
|
+
self,
|
|
125
|
+
instruction_name: str,
|
|
126
|
+
scope: InstallationScope = InstallationScope.GLOBAL,
|
|
127
|
+
project_root: Optional[Path] = None,
|
|
128
|
+
) -> bool:
|
|
129
|
+
"""
|
|
130
|
+
Check if an instruction is already installed.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
instruction_name: Name of the instruction
|
|
134
|
+
scope: Installation scope (global or project)
|
|
135
|
+
project_root: Project root path (required if scope is PROJECT)
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
True if instruction file exists
|
|
139
|
+
"""
|
|
140
|
+
try:
|
|
141
|
+
path = self.get_instruction_path(instruction_name, scope, project_root)
|
|
142
|
+
return path.exists()
|
|
143
|
+
except (FileNotFoundError, ValueError):
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
def install_instruction(
|
|
147
|
+
self,
|
|
148
|
+
instruction: Instruction,
|
|
149
|
+
overwrite: bool = False,
|
|
150
|
+
scope: InstallationScope = InstallationScope.GLOBAL,
|
|
151
|
+
project_root: Optional[Path] = None,
|
|
152
|
+
) -> Path:
|
|
153
|
+
"""
|
|
154
|
+
Install an instruction to this AI tool.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
instruction: Instruction to install
|
|
158
|
+
overwrite: Whether to overwrite existing file
|
|
159
|
+
scope: Installation scope (global or project)
|
|
160
|
+
project_root: Project root path (required if scope is PROJECT)
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Path where instruction was installed
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
FileExistsError: If instruction exists and overwrite=False
|
|
167
|
+
FileNotFoundError: If tool is not installed
|
|
168
|
+
ValueError: If scope is PROJECT but project_root is None
|
|
169
|
+
"""
|
|
170
|
+
path = self.get_instruction_path(instruction.name, scope, project_root)
|
|
171
|
+
|
|
172
|
+
if path.exists() and not overwrite:
|
|
173
|
+
raise FileExistsError(f"Instruction already exists: {path}")
|
|
174
|
+
|
|
175
|
+
# Ensure directory exists
|
|
176
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
177
|
+
|
|
178
|
+
# Write instruction content
|
|
179
|
+
path.write_text(instruction.content, encoding="utf-8")
|
|
180
|
+
|
|
181
|
+
return path
|
|
182
|
+
|
|
183
|
+
def uninstall_instruction(
|
|
184
|
+
self,
|
|
185
|
+
instruction_name: str,
|
|
186
|
+
scope: InstallationScope = InstallationScope.GLOBAL,
|
|
187
|
+
project_root: Optional[Path] = None,
|
|
188
|
+
) -> bool:
|
|
189
|
+
"""
|
|
190
|
+
Uninstall an instruction from this AI tool.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
instruction_name: Name of instruction to remove
|
|
194
|
+
scope: Installation scope (global or project)
|
|
195
|
+
project_root: Project root path (required if scope is PROJECT)
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
True if file was removed, False if it didn't exist
|
|
199
|
+
"""
|
|
200
|
+
try:
|
|
201
|
+
path = self.get_instruction_path(instruction_name, scope, project_root)
|
|
202
|
+
if path.exists():
|
|
203
|
+
path.unlink()
|
|
204
|
+
return True
|
|
205
|
+
return False
|
|
206
|
+
except (FileNotFoundError, ValueError):
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
def validate_installation(self) -> Optional[str]:
|
|
210
|
+
"""
|
|
211
|
+
Validate that tool installation is correct and accessible.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
None if valid, error message if invalid
|
|
215
|
+
"""
|
|
216
|
+
if not self.is_installed():
|
|
217
|
+
return f"{self.tool_name} is not installed or not found"
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
directory = self.get_instructions_directory()
|
|
221
|
+
if not directory.exists():
|
|
222
|
+
# Try to create it
|
|
223
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
224
|
+
|
|
225
|
+
# Check write permissions
|
|
226
|
+
if not os.access(directory, os.W_OK):
|
|
227
|
+
return f"No write permission for {directory}"
|
|
228
|
+
|
|
229
|
+
except Exception as e:
|
|
230
|
+
return f"Error accessing {self.tool_name} directory: {str(e)}"
|
|
231
|
+
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
def __repr__(self) -> str:
|
|
235
|
+
"""String representation."""
|
|
236
|
+
return f"<{self.__class__.__name__} tool_type={self.tool_type.value}>"
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""IDE capability registry for package component support."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from aiconfigkit.core.models import AIToolType, ComponentType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class IDECapability:
|
|
10
|
+
"""
|
|
11
|
+
Defines what component types an IDE supports.
|
|
12
|
+
|
|
13
|
+
Tracks which package components (instructions, MCP servers, hooks, etc.)
|
|
14
|
+
can be installed to each AI coding tool.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
tool_type: AIToolType
|
|
18
|
+
tool_name: str
|
|
19
|
+
supported_components: set[ComponentType]
|
|
20
|
+
instructions_directory: str
|
|
21
|
+
instruction_file_extension: str
|
|
22
|
+
supports_project_scope: bool = True
|
|
23
|
+
supports_global_scope: bool = False
|
|
24
|
+
mcp_config_path: str | None = None
|
|
25
|
+
mcp_project_config_path: str | None = None # Project-level MCP config
|
|
26
|
+
hooks_directory: str | None = None
|
|
27
|
+
commands_directory: str | None = None
|
|
28
|
+
skills_directory: str | None = None # Claude skills
|
|
29
|
+
workflows_directory: str | None = None # Windsurf workflows
|
|
30
|
+
memory_file_name: str | None = None # CLAUDE.md
|
|
31
|
+
notes: str = ""
|
|
32
|
+
|
|
33
|
+
def supports_component(self, component_type: ComponentType) -> bool:
|
|
34
|
+
"""
|
|
35
|
+
Check if IDE supports a specific component type.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
component_type: Component type to check
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
True if supported, False otherwise
|
|
42
|
+
"""
|
|
43
|
+
return component_type in self.supported_components
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# IDE Capability Registry
|
|
47
|
+
# Maps each AI tool to its supported component types and installation paths
|
|
48
|
+
|
|
49
|
+
CAPABILITY_REGISTRY: dict[AIToolType, IDECapability] = {
|
|
50
|
+
AIToolType.CURSOR: IDECapability(
|
|
51
|
+
tool_type=AIToolType.CURSOR,
|
|
52
|
+
tool_name="Cursor",
|
|
53
|
+
supported_components={
|
|
54
|
+
ComponentType.INSTRUCTION,
|
|
55
|
+
ComponentType.MCP_SERVER,
|
|
56
|
+
ComponentType.RESOURCE,
|
|
57
|
+
},
|
|
58
|
+
instructions_directory=".cursor/rules/",
|
|
59
|
+
instruction_file_extension=".mdc",
|
|
60
|
+
supports_project_scope=True,
|
|
61
|
+
supports_global_scope=True,
|
|
62
|
+
mcp_config_path="~/.cursor/mcp.json",
|
|
63
|
+
mcp_project_config_path=".cursor/mcp.json",
|
|
64
|
+
hooks_directory=None, # Hooks not supported
|
|
65
|
+
commands_directory=None, # Commands not supported
|
|
66
|
+
notes=(
|
|
67
|
+
"Cursor uses .mdc (markdown with metadata) files in .cursor/rules/. "
|
|
68
|
+
"MCP servers configured via ~/.cursor/mcp.json (global) or .cursor/mcp.json (project). "
|
|
69
|
+
"Supports up to 40 MCP tools. Resources not yet supported in MCP."
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
AIToolType.CLAUDE: IDECapability(
|
|
73
|
+
tool_type=AIToolType.CLAUDE,
|
|
74
|
+
tool_name="Claude Code",
|
|
75
|
+
supported_components={
|
|
76
|
+
ComponentType.INSTRUCTION,
|
|
77
|
+
ComponentType.MCP_SERVER,
|
|
78
|
+
ComponentType.HOOK,
|
|
79
|
+
ComponentType.COMMAND,
|
|
80
|
+
ComponentType.SKILL,
|
|
81
|
+
ComponentType.MEMORY_FILE,
|
|
82
|
+
ComponentType.RESOURCE,
|
|
83
|
+
},
|
|
84
|
+
instructions_directory=".claude/rules/",
|
|
85
|
+
instruction_file_extension=".md",
|
|
86
|
+
supports_project_scope=True,
|
|
87
|
+
supports_global_scope=False,
|
|
88
|
+
mcp_config_path="~/.claude/settings.json",
|
|
89
|
+
mcp_project_config_path=".claude/settings.local.json",
|
|
90
|
+
hooks_directory=".claude/hooks/",
|
|
91
|
+
commands_directory=".claude/commands/",
|
|
92
|
+
skills_directory=".claude/skills/",
|
|
93
|
+
memory_file_name="CLAUDE.md",
|
|
94
|
+
notes=(
|
|
95
|
+
"Claude Code uses .md files in .claude/rules/. "
|
|
96
|
+
"Full support for MCP servers, hooks, slash commands, and skills. "
|
|
97
|
+
"CLAUDE.md files persist context across sessions."
|
|
98
|
+
),
|
|
99
|
+
),
|
|
100
|
+
AIToolType.WINSURF: IDECapability(
|
|
101
|
+
tool_type=AIToolType.WINSURF,
|
|
102
|
+
tool_name="Windsurf",
|
|
103
|
+
supported_components={
|
|
104
|
+
ComponentType.INSTRUCTION,
|
|
105
|
+
ComponentType.MCP_SERVER,
|
|
106
|
+
ComponentType.WORKFLOW,
|
|
107
|
+
ComponentType.RESOURCE,
|
|
108
|
+
},
|
|
109
|
+
instructions_directory=".windsurf/rules/",
|
|
110
|
+
instruction_file_extension=".md",
|
|
111
|
+
supports_project_scope=True,
|
|
112
|
+
supports_global_scope=True,
|
|
113
|
+
mcp_config_path="~/.codeium/windsurf/mcp_config.json",
|
|
114
|
+
mcp_project_config_path=None, # Windsurf uses global MCP config only
|
|
115
|
+
hooks_directory=None, # Hooks not supported
|
|
116
|
+
commands_directory=None, # Commands not supported
|
|
117
|
+
workflows_directory=".windsurf/workflows/",
|
|
118
|
+
notes=(
|
|
119
|
+
"Windsurf uses .md files in .windsurf/rules/ with 4 activation modes. "
|
|
120
|
+
"MCP servers configured via ~/.codeium/windsurf/mcp_config.json. "
|
|
121
|
+
"Supports workflows in .windsurf/workflows/. Limit of 100 MCP tools."
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
AIToolType.KIRO: IDECapability(
|
|
125
|
+
tool_type=AIToolType.KIRO,
|
|
126
|
+
tool_name="Kiro",
|
|
127
|
+
supported_components={
|
|
128
|
+
ComponentType.INSTRUCTION,
|
|
129
|
+
ComponentType.RESOURCE,
|
|
130
|
+
},
|
|
131
|
+
instructions_directory=".kiro/steering/",
|
|
132
|
+
instruction_file_extension=".md",
|
|
133
|
+
supports_project_scope=True,
|
|
134
|
+
supports_global_scope=False,
|
|
135
|
+
mcp_config_path=None, # Kiro uses .kiro/settings/mcp.json but not yet supported
|
|
136
|
+
mcp_project_config_path=None,
|
|
137
|
+
hooks_directory=None, # Kiro hooks use .kiro.hook JSON format, not yet supported
|
|
138
|
+
commands_directory=None,
|
|
139
|
+
notes=(
|
|
140
|
+
"Kiro uses .md files in .kiro/steering/ with optional YAML front matter "
|
|
141
|
+
"for inclusion modes (always, fileMatch, manual, auto). "
|
|
142
|
+
"MCP and hooks support deferred to future release."
|
|
143
|
+
),
|
|
144
|
+
),
|
|
145
|
+
AIToolType.CLINE: IDECapability(
|
|
146
|
+
tool_type=AIToolType.CLINE,
|
|
147
|
+
tool_name="Cline",
|
|
148
|
+
supported_components={
|
|
149
|
+
ComponentType.INSTRUCTION,
|
|
150
|
+
ComponentType.RESOURCE,
|
|
151
|
+
},
|
|
152
|
+
instructions_directory=".clinerules/",
|
|
153
|
+
instruction_file_extension=".md",
|
|
154
|
+
supports_project_scope=True,
|
|
155
|
+
supports_global_scope=False,
|
|
156
|
+
mcp_config_path=None, # Cline MCP is global-only via cline_mcp_settings.json in VS Code globalStorage
|
|
157
|
+
mcp_project_config_path=None,
|
|
158
|
+
hooks_directory=None,
|
|
159
|
+
commands_directory=None,
|
|
160
|
+
notes=(
|
|
161
|
+
"Cline uses .md files in .clinerules/ directory (recursive). "
|
|
162
|
+
"Supports optional YAML frontmatter with paths: for conditional activation. "
|
|
163
|
+
"MCP configured globally via cline_mcp_settings.json, no project-level MCP support."
|
|
164
|
+
),
|
|
165
|
+
),
|
|
166
|
+
AIToolType.ROO: IDECapability(
|
|
167
|
+
tool_type=AIToolType.ROO,
|
|
168
|
+
tool_name="Roo Code",
|
|
169
|
+
supported_components={
|
|
170
|
+
ComponentType.INSTRUCTION,
|
|
171
|
+
ComponentType.MCP_SERVER,
|
|
172
|
+
ComponentType.COMMAND,
|
|
173
|
+
ComponentType.RESOURCE,
|
|
174
|
+
},
|
|
175
|
+
instructions_directory=".roo/rules/",
|
|
176
|
+
instruction_file_extension=".md",
|
|
177
|
+
supports_project_scope=True,
|
|
178
|
+
supports_global_scope=True,
|
|
179
|
+
mcp_config_path=None, # Global MCP via globalStorage cline_mcp_settings.json
|
|
180
|
+
mcp_project_config_path=".roo/mcp.json",
|
|
181
|
+
hooks_directory=None, # Hooks not supported
|
|
182
|
+
commands_directory=".roo/commands/",
|
|
183
|
+
notes=(
|
|
184
|
+
"Roo Code uses .md files in .roo/rules/ directory (recursive). "
|
|
185
|
+
"Mode-specific rules in .roo/rules-{mode-slug}/. "
|
|
186
|
+
"MCP configured via .roo/mcp.json (project) or globalStorage (global). "
|
|
187
|
+
"Slash commands in .roo/commands/. Global rules at ~/.roo/rules/."
|
|
188
|
+
),
|
|
189
|
+
),
|
|
190
|
+
AIToolType.COPILOT: IDECapability(
|
|
191
|
+
tool_type=AIToolType.COPILOT,
|
|
192
|
+
tool_name="GitHub Copilot",
|
|
193
|
+
supported_components={
|
|
194
|
+
ComponentType.INSTRUCTION,
|
|
195
|
+
ComponentType.MCP_SERVER,
|
|
196
|
+
},
|
|
197
|
+
instructions_directory=".github/instructions/",
|
|
198
|
+
instruction_file_extension=".instructions.md",
|
|
199
|
+
supports_project_scope=True,
|
|
200
|
+
supports_global_scope=True,
|
|
201
|
+
mcp_config_path="~/.vscode/mcp.json", # User-level MCP config
|
|
202
|
+
mcp_project_config_path=".vscode/mcp.json", # Workspace-level MCP config
|
|
203
|
+
hooks_directory=None, # Hooks not supported
|
|
204
|
+
commands_directory=None, # Commands not supported
|
|
205
|
+
notes=(
|
|
206
|
+
"GitHub Copilot uses .github/copilot-instructions.md (main) and "
|
|
207
|
+
".github/instructions/**/*.instructions.md (file-specific with globs). "
|
|
208
|
+
"MCP servers configured via .vscode/mcp.json. Limit of 128 tools."
|
|
209
|
+
),
|
|
210
|
+
),
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_capability(tool_type: AIToolType) -> IDECapability:
|
|
215
|
+
"""
|
|
216
|
+
Get capability information for an IDE.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
tool_type: AI tool type
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
IDECapability for the tool
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
KeyError: If tool type is not in registry
|
|
226
|
+
"""
|
|
227
|
+
return CAPABILITY_REGISTRY[tool_type]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def get_supported_tools_for_component(component_type: ComponentType) -> list[AIToolType]:
|
|
231
|
+
"""
|
|
232
|
+
Get list of IDEs that support a specific component type.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
component_type: Component type to check
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
List of AI tool types that support this component
|
|
239
|
+
"""
|
|
240
|
+
supported_tools = []
|
|
241
|
+
for tool_type, capability in CAPABILITY_REGISTRY.items():
|
|
242
|
+
if capability.supports_component(component_type):
|
|
243
|
+
supported_tools.append(tool_type)
|
|
244
|
+
return supported_tools
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def validate_component_support(tool_type: AIToolType, component_type: ComponentType) -> bool:
|
|
248
|
+
"""
|
|
249
|
+
Validate that an IDE supports a component type.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
tool_type: AI tool type
|
|
253
|
+
component_type: Component type to validate
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
True if supported, False otherwise
|
|
257
|
+
"""
|
|
258
|
+
try:
|
|
259
|
+
capability = get_capability(tool_type)
|
|
260
|
+
return capability.supports_component(component_type)
|
|
261
|
+
except KeyError:
|
|
262
|
+
return False
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Claude Code AI tool integration."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from aiconfigkit.ai_tools.base import AITool
|
|
6
|
+
from aiconfigkit.core.models import AIToolType
|
|
7
|
+
from aiconfigkit.utils.paths import get_claude_config_dir
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ClaudeTool(AITool):
|
|
11
|
+
"""Integration for Claude Code AI coding tool."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def tool_type(self) -> AIToolType:
|
|
15
|
+
"""Return the AI tool type identifier."""
|
|
16
|
+
return AIToolType.CLAUDE
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def tool_name(self) -> str:
|
|
20
|
+
"""Return human-readable tool name."""
|
|
21
|
+
return "Claude Code"
|
|
22
|
+
|
|
23
|
+
def is_installed(self) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if Claude Code is installed on the system.
|
|
26
|
+
|
|
27
|
+
Checks for existence of Claude configuration directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if Claude Code is detected
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_dir = get_claude_config_dir()
|
|
34
|
+
# Check if parent directory exists
|
|
35
|
+
# Claude Code config dir structure: ~/.claude/rules/
|
|
36
|
+
claude_base = config_dir.parent
|
|
37
|
+
return claude_base.exists()
|
|
38
|
+
except Exception:
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
def get_instructions_directory(self) -> Path:
|
|
42
|
+
"""
|
|
43
|
+
Get the directory where Claude Code instructions should be installed.
|
|
44
|
+
|
|
45
|
+
Note: Global installation is not supported. Claude Code supports both
|
|
46
|
+
single-file (~/.claude/rules.md) and multi-file approaches, but for
|
|
47
|
+
consistency with our multi-file installation pattern, we only support
|
|
48
|
+
project-level installations.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Path to Claude Code instructions directory
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
NotImplementedError: Global installation not supported for Claude Code
|
|
55
|
+
"""
|
|
56
|
+
raise NotImplementedError(
|
|
57
|
+
f"{self.tool_name} global installation is not supported. "
|
|
58
|
+
"Please use project-level installation instead (--scope project)."
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def get_instruction_file_extension(self) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Get the file extension for Claude Code instructions.
|
|
64
|
+
|
|
65
|
+
Claude Code uses markdown (.md) files for rules.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
File extension including the dot
|
|
69
|
+
"""
|
|
70
|
+
return ".md"
|
|
71
|
+
|
|
72
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
73
|
+
"""
|
|
74
|
+
Get the directory for project-specific Claude Code instructions.
|
|
75
|
+
|
|
76
|
+
Claude Code stores project-specific rules in .claude/rules/ directory
|
|
77
|
+
in the project root. It supports multiple .md files in this directory.
|
|
78
|
+
|
|
79
|
+
Reference:
|
|
80
|
+
- Recommended: .claude/rules/*.md (multiple files)
|
|
81
|
+
- Alternative: .claude/rules.md (single file, not used by this tool)
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
project_root: Path to the project root directory
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Path to project instructions directory (.claude/rules/)
|
|
88
|
+
"""
|
|
89
|
+
instructions_dir = project_root / ".claude" / "rules"
|
|
90
|
+
instructions_dir.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
return instructions_dir
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Claude Desktop MCP integration."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from aiconfigkit.ai_tools.base import AITool
|
|
6
|
+
from aiconfigkit.core.models import AIToolType
|
|
7
|
+
from aiconfigkit.utils.paths import get_claude_desktop_config_path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ClaudeDesktopTool(AITool):
|
|
11
|
+
"""Integration for Claude Desktop MCP server configuration."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def tool_type(self) -> AIToolType:
|
|
15
|
+
"""Return the AI tool type identifier."""
|
|
16
|
+
return AIToolType.CLAUDE
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def tool_name(self) -> str:
|
|
20
|
+
"""Return human-readable tool name."""
|
|
21
|
+
return "Claude Desktop"
|
|
22
|
+
|
|
23
|
+
def is_installed(self) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if Claude Desktop is installed on the system.
|
|
26
|
+
|
|
27
|
+
Checks for existence of Claude Desktop config directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if Claude Desktop is detected
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_path = get_claude_desktop_config_path()
|
|
34
|
+
# Check if parent directory exists (Claude Desktop install directory)
|
|
35
|
+
return config_path.parent.exists()
|
|
36
|
+
except Exception:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
def get_instructions_directory(self) -> Path:
|
|
40
|
+
"""
|
|
41
|
+
Get the directory where Claude Desktop instructions should be installed.
|
|
42
|
+
|
|
43
|
+
Note: Claude Desktop doesn't use instruction files like Claude Code.
|
|
44
|
+
This method is not applicable for MCP configuration.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Path to instructions directory
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
NotImplementedError: Claude Desktop uses MCP config, not instruction files
|
|
51
|
+
"""
|
|
52
|
+
raise NotImplementedError(
|
|
53
|
+
f"{self.tool_name} uses MCP configuration instead of instruction files. "
|
|
54
|
+
"Use get_mcp_config_path() instead."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def get_instruction_file_extension(self) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Get the file extension for Claude Desktop instructions.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
File extension including the dot
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
NotImplementedError: Claude Desktop uses MCP config, not instruction files
|
|
66
|
+
"""
|
|
67
|
+
raise NotImplementedError(f"{self.tool_name} uses MCP configuration instead of instruction files.")
|
|
68
|
+
|
|
69
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
70
|
+
"""
|
|
71
|
+
Get the directory for project-specific Claude Desktop instructions.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
project_root: Path to the project root directory
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Path to project instructions directory
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
NotImplementedError: Claude Desktop uses MCP config, not instruction files
|
|
81
|
+
"""
|
|
82
|
+
raise NotImplementedError(f"{self.tool_name} uses MCP configuration instead of instruction files.")
|
|
83
|
+
|
|
84
|
+
def get_mcp_config_path(self) -> Path:
|
|
85
|
+
"""
|
|
86
|
+
Get the path to the Claude Desktop MCP configuration file.
|
|
87
|
+
|
|
88
|
+
Claude Desktop stores MCP server configurations in claude_desktop_config.json.
|
|
89
|
+
The file location is platform-specific:
|
|
90
|
+
- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
91
|
+
- Linux: ~/.config/Claude/claude_desktop_config.json
|
|
92
|
+
- Windows: %APPDATA%\\Claude\\claude_desktop_config.json
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Path to claude_desktop_config.json
|
|
96
|
+
"""
|
|
97
|
+
return get_claude_desktop_config_path()
|