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
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Cline 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_cline_config_dir
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ClineTool(AITool):
|
|
11
|
+
"""Integration for Cline AI coding tool (VS Code extension).
|
|
12
|
+
|
|
13
|
+
Cline uses .clinerules/ directory at the project root for AI instructions.
|
|
14
|
+
Files are .md (Markdown) and are read recursively. Optional YAML frontmatter
|
|
15
|
+
with `paths:` field enables conditional rule activation based on file globs.
|
|
16
|
+
|
|
17
|
+
Detection is based on the VS Code extension saoudrizwan.claude-dev
|
|
18
|
+
globalStorage directory.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def tool_type(self) -> AIToolType:
|
|
23
|
+
"""Return the AI tool type identifier."""
|
|
24
|
+
return AIToolType.CLINE
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def tool_name(self) -> str:
|
|
28
|
+
"""Return human-readable tool name."""
|
|
29
|
+
return "Cline"
|
|
30
|
+
|
|
31
|
+
def is_installed(self) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
Check if Cline is installed on the system.
|
|
34
|
+
|
|
35
|
+
Checks for existence of the Cline VS Code extension globalStorage directory
|
|
36
|
+
(saoudrizwan.claude-dev).
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
True if Cline is detected
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
config_dir = get_cline_config_dir()
|
|
43
|
+
return config_dir.exists()
|
|
44
|
+
except Exception:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
def get_instructions_directory(self) -> Path:
|
|
48
|
+
"""
|
|
49
|
+
Get the directory where Cline instructions should be installed.
|
|
50
|
+
|
|
51
|
+
Note: Cline global rules live in ~/Documents/Cline/Rules/ but this
|
|
52
|
+
is non-standard. This tool only supports project-level installations.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Path to Cline instructions directory
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
NotImplementedError: Global installation not supported for Cline
|
|
59
|
+
"""
|
|
60
|
+
raise NotImplementedError(
|
|
61
|
+
f"{self.tool_name} global installation is not supported. "
|
|
62
|
+
"Please use project-level installation instead (--scope project)."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def get_instruction_file_extension(self) -> str:
|
|
66
|
+
"""
|
|
67
|
+
Get the file extension for Cline instructions.
|
|
68
|
+
|
|
69
|
+
Cline uses markdown (.md) files in the .clinerules/ directory.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
File extension including the dot
|
|
73
|
+
"""
|
|
74
|
+
return ".md"
|
|
75
|
+
|
|
76
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
77
|
+
"""
|
|
78
|
+
Get the directory for project-specific Cline instructions.
|
|
79
|
+
|
|
80
|
+
Cline stores project-specific rules in .clinerules/ directory at the
|
|
81
|
+
project root. It reads .md files recursively from this directory.
|
|
82
|
+
Numeric prefixes (e.g., 01-coding-standards.md) control load order.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
project_root: Path to the project root directory
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Path to project instructions directory (.clinerules/)
|
|
89
|
+
"""
|
|
90
|
+
instructions_dir = project_root / ".clinerules"
|
|
91
|
+
instructions_dir.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
return instructions_dir
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""GitHub Copilot 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_copilot_config_dir
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CopilotTool(AITool):
|
|
11
|
+
"""Integration for GitHub Copilot (VS Code extension)."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def tool_type(self) -> AIToolType:
|
|
15
|
+
"""Return the AI tool type identifier."""
|
|
16
|
+
return AIToolType.COPILOT
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def tool_name(self) -> str:
|
|
20
|
+
"""Return human-readable tool name."""
|
|
21
|
+
return "GitHub Copilot"
|
|
22
|
+
|
|
23
|
+
def is_installed(self) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if GitHub Copilot is installed on the system.
|
|
26
|
+
|
|
27
|
+
Checks for existence of VS Code and Copilot extension directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if Copilot is detected
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_dir = get_copilot_config_dir()
|
|
34
|
+
# Check if the Copilot extension directory exists
|
|
35
|
+
# VS Code structure: .../Code/User/globalStorage/github.copilot
|
|
36
|
+
return config_dir.parent.exists()
|
|
37
|
+
except Exception:
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def get_instructions_directory(self) -> Path:
|
|
41
|
+
"""
|
|
42
|
+
Get the directory where Copilot instructions should be installed.
|
|
43
|
+
|
|
44
|
+
Note: GitHub Copilot uses .github/copilot-instructions.md as a single file
|
|
45
|
+
for project-level instructions. Global instructions are not officially supported.
|
|
46
|
+
This tool currently only supports project-level installations.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Path to Copilot instructions directory
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
NotImplementedError: Global installation not supported for GitHub Copilot
|
|
53
|
+
"""
|
|
54
|
+
raise NotImplementedError(
|
|
55
|
+
f"{self.tool_name} global installation is not supported. "
|
|
56
|
+
"GitHub Copilot uses project-level instructions only. "
|
|
57
|
+
"Please use project-level installation instead (--scope project)."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def get_instruction_file_extension(self) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Get the file extension for Copilot instructions.
|
|
63
|
+
|
|
64
|
+
GitHub Copilot requires path-specific instructions to end with
|
|
65
|
+
.instructions.md per official documentation:
|
|
66
|
+
https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
File extension including the dot
|
|
70
|
+
"""
|
|
71
|
+
return ".instructions.md"
|
|
72
|
+
|
|
73
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
74
|
+
"""
|
|
75
|
+
Get the directory for project-specific Copilot instructions.
|
|
76
|
+
|
|
77
|
+
GitHub Copilot stores project-specific instructions in .github/instructions/
|
|
78
|
+
directory in the project root. It supports multiple .md files in this directory.
|
|
79
|
+
|
|
80
|
+
Reference:
|
|
81
|
+
- Path-specific: .github/instructions/*.instructions.md (multiple files)
|
|
82
|
+
- Alternative: .github/copilot-instructions.md (single file, not used by this tool)
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
project_root: Path to the project root directory
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Path to project instructions directory (.github/instructions/)
|
|
89
|
+
"""
|
|
90
|
+
instructions_dir = project_root / ".github" / "instructions"
|
|
91
|
+
instructions_dir.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
return instructions_dir
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Cursor 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_cursor_config_dir, get_cursor_mcp_config_path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CursorTool(AITool):
|
|
11
|
+
"""Integration for Cursor AI coding tool."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def tool_type(self) -> AIToolType:
|
|
15
|
+
"""Return the AI tool type identifier."""
|
|
16
|
+
return AIToolType.CURSOR
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def tool_name(self) -> str:
|
|
20
|
+
"""Return human-readable tool name."""
|
|
21
|
+
return "Cursor"
|
|
22
|
+
|
|
23
|
+
def is_installed(self) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if Cursor is installed on the system.
|
|
26
|
+
|
|
27
|
+
Checks for existence of Cursor configuration directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if Cursor is detected
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_dir = get_cursor_config_dir()
|
|
34
|
+
# Check if parent directory exists (not necessarily the full path)
|
|
35
|
+
# Cursor config dir structure: .../Cursor/User/globalStorage
|
|
36
|
+
cursor_base = config_dir.parent.parent
|
|
37
|
+
return cursor_base.exists()
|
|
38
|
+
except Exception:
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
def get_instructions_directory(self) -> Path:
|
|
42
|
+
"""
|
|
43
|
+
Get the directory where Cursor instructions should be installed.
|
|
44
|
+
|
|
45
|
+
Note: Cursor uses .cursorrules as a single file for global rules.
|
|
46
|
+
This tool currently only supports project-level installations.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Path to Cursor instructions directory
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
NotImplementedError: Global installation not supported for Cursor
|
|
53
|
+
"""
|
|
54
|
+
raise NotImplementedError(
|
|
55
|
+
f"{self.tool_name} global installation is not supported. "
|
|
56
|
+
"Cursor uses a single .cursorrules file for global rules. "
|
|
57
|
+
"Please use project-level installation instead (--scope project)."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def get_instruction_file_extension(self) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Get the file extension for Cursor instructions.
|
|
63
|
+
|
|
64
|
+
Cursor uses .mdc files (markdown with metadata) for rules.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
File extension including the dot
|
|
68
|
+
"""
|
|
69
|
+
return ".mdc"
|
|
70
|
+
|
|
71
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
72
|
+
"""
|
|
73
|
+
Get the directory for project-specific Cursor instructions.
|
|
74
|
+
|
|
75
|
+
Cursor stores project-specific rules in .cursor/rules/ directory
|
|
76
|
+
in the project root. It supports multiple .mdc files in this directory.
|
|
77
|
+
|
|
78
|
+
Reference:
|
|
79
|
+
- Recommended: .cursor/rules/*.mdc (multiple files with metadata)
|
|
80
|
+
- Alternative: .cursorrules (single file, not used by this tool)
|
|
81
|
+
|
|
82
|
+
.mdc files can include metadata like:
|
|
83
|
+
---
|
|
84
|
+
description: Rule description
|
|
85
|
+
globs: ["src/**/*.tsx"]
|
|
86
|
+
alwaysApply: true
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
project_root: Path to the project root directory
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Path to project instructions directory (.cursor/rules/)
|
|
94
|
+
"""
|
|
95
|
+
instructions_dir = project_root / ".cursor" / "rules"
|
|
96
|
+
instructions_dir.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
return instructions_dir
|
|
98
|
+
|
|
99
|
+
def get_mcp_config_path(self) -> Path:
|
|
100
|
+
"""
|
|
101
|
+
Get the path to the Cursor MCP configuration file.
|
|
102
|
+
|
|
103
|
+
Note: Cursor doesn't natively support MCP yet, but we provide this
|
|
104
|
+
for future compatibility.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Path to MCP configuration file
|
|
108
|
+
"""
|
|
109
|
+
return get_cursor_mcp_config_path()
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""AI tool detection and auto-discovery."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from aiconfigkit.ai_tools.base import AITool
|
|
6
|
+
from aiconfigkit.ai_tools.claude import ClaudeTool
|
|
7
|
+
from aiconfigkit.ai_tools.cline import ClineTool
|
|
8
|
+
from aiconfigkit.ai_tools.copilot import CopilotTool
|
|
9
|
+
from aiconfigkit.ai_tools.cursor import CursorTool
|
|
10
|
+
from aiconfigkit.ai_tools.kiro import KiroTool
|
|
11
|
+
from aiconfigkit.ai_tools.roo import RooTool
|
|
12
|
+
from aiconfigkit.ai_tools.winsurf import WinsurfTool
|
|
13
|
+
from aiconfigkit.core.models import AIToolType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AIToolDetector:
|
|
17
|
+
"""Detect and manage AI coding tools."""
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
"""Initialize detector with all supported tools."""
|
|
21
|
+
self.tools: dict[AIToolType, AITool] = {
|
|
22
|
+
AIToolType.CURSOR: CursorTool(),
|
|
23
|
+
AIToolType.COPILOT: CopilotTool(),
|
|
24
|
+
AIToolType.WINSURF: WinsurfTool(),
|
|
25
|
+
AIToolType.CLAUDE: ClaudeTool(),
|
|
26
|
+
AIToolType.KIRO: KiroTool(),
|
|
27
|
+
AIToolType.CLINE: ClineTool(),
|
|
28
|
+
AIToolType.ROO: RooTool(),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def detect_installed_tools(self) -> list[AITool]:
|
|
32
|
+
"""
|
|
33
|
+
Detect all installed AI coding tools.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
List of installed AITool instances
|
|
37
|
+
"""
|
|
38
|
+
installed = []
|
|
39
|
+
for tool in self.tools.values():
|
|
40
|
+
if tool.is_installed():
|
|
41
|
+
installed.append(tool)
|
|
42
|
+
return installed
|
|
43
|
+
|
|
44
|
+
def get_tool_by_name(self, name: str) -> Optional[AITool]:
|
|
45
|
+
"""
|
|
46
|
+
Get AI tool instance by name.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
name: Tool name (cursor, copilot, winsurf, claude)
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
AITool instance or None if not found
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
tool_type = AIToolType(name.lower())
|
|
56
|
+
return self.tools.get(tool_type)
|
|
57
|
+
except ValueError:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
def get_tool_by_type(self, tool_type: AIToolType) -> Optional[AITool]:
|
|
61
|
+
"""
|
|
62
|
+
Get AI tool instance by type.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
tool_type: AIToolType enum value
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
AITool instance
|
|
69
|
+
"""
|
|
70
|
+
return self.tools.get(tool_type)
|
|
71
|
+
|
|
72
|
+
def get_primary_tool(self) -> Optional[AITool]:
|
|
73
|
+
"""
|
|
74
|
+
Get the primary (first detected) AI tool.
|
|
75
|
+
|
|
76
|
+
Priority order: Cursor, Copilot, Winsurf, Claude Code
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
First installed AITool or None if none installed
|
|
80
|
+
"""
|
|
81
|
+
# Check in priority order
|
|
82
|
+
priority = [
|
|
83
|
+
AIToolType.CURSOR,
|
|
84
|
+
AIToolType.COPILOT,
|
|
85
|
+
AIToolType.WINSURF,
|
|
86
|
+
AIToolType.CLAUDE,
|
|
87
|
+
AIToolType.KIRO,
|
|
88
|
+
AIToolType.CLINE,
|
|
89
|
+
AIToolType.ROO,
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
for tool_type in priority:
|
|
93
|
+
tool = self.tools[tool_type]
|
|
94
|
+
if tool.is_installed():
|
|
95
|
+
return tool
|
|
96
|
+
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
def is_any_tool_installed(self) -> bool:
|
|
100
|
+
"""
|
|
101
|
+
Check if any AI coding tool is installed.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if at least one tool is detected
|
|
105
|
+
"""
|
|
106
|
+
return len(self.detect_installed_tools()) > 0
|
|
107
|
+
|
|
108
|
+
def get_tool_names(self) -> list[str]:
|
|
109
|
+
"""
|
|
110
|
+
Get list of all supported tool names.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
List of tool name strings
|
|
114
|
+
"""
|
|
115
|
+
return [tool_type.value for tool_type in self.tools.keys()]
|
|
116
|
+
|
|
117
|
+
def validate_tool_name(self, name: str) -> bool:
|
|
118
|
+
"""
|
|
119
|
+
Validate if tool name is supported.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
name: Tool name to validate
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
True if tool is supported
|
|
126
|
+
"""
|
|
127
|
+
return name.lower() in self.get_tool_names()
|
|
128
|
+
|
|
129
|
+
def get_detection_summary(self) -> dict[str, bool]:
|
|
130
|
+
"""
|
|
131
|
+
Get detection summary for all tools.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Dictionary mapping tool names to installation status
|
|
135
|
+
"""
|
|
136
|
+
return {tool_type.value: tool.is_installed() for tool_type, tool in self.tools.items()}
|
|
137
|
+
|
|
138
|
+
def format_detection_summary(self) -> str:
|
|
139
|
+
"""
|
|
140
|
+
Format detection summary as human-readable string.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Formatted summary string
|
|
144
|
+
"""
|
|
145
|
+
summary = self.get_detection_summary()
|
|
146
|
+
lines = ["AI Coding Tools Detection:"]
|
|
147
|
+
|
|
148
|
+
for tool_name, is_installed in summary.items():
|
|
149
|
+
status = "✓ Installed" if is_installed else "✗ Not found"
|
|
150
|
+
lines.append(f" {tool_name.capitalize()}: {status}")
|
|
151
|
+
|
|
152
|
+
return "\n".join(lines)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# Singleton instance for convenience
|
|
156
|
+
_detector_instance: Optional[AIToolDetector] = None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def get_detector() -> AIToolDetector:
|
|
160
|
+
"""
|
|
161
|
+
Get singleton AIToolDetector instance.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
AIToolDetector instance
|
|
165
|
+
"""
|
|
166
|
+
global _detector_instance
|
|
167
|
+
if _detector_instance is None:
|
|
168
|
+
_detector_instance = AIToolDetector()
|
|
169
|
+
return _detector_instance
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Kiro 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_kiro_config_dir
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class KiroTool(AITool):
|
|
11
|
+
"""Integration for Kiro AI coding tool."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def tool_type(self) -> AIToolType:
|
|
15
|
+
"""Return the AI tool type identifier."""
|
|
16
|
+
return AIToolType.KIRO
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def tool_name(self) -> str:
|
|
20
|
+
"""Return human-readable tool name."""
|
|
21
|
+
return "Kiro"
|
|
22
|
+
|
|
23
|
+
def is_installed(self) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if Kiro is installed on the system.
|
|
26
|
+
|
|
27
|
+
Checks for existence of Kiro configuration directory.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if Kiro is detected
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_dir = get_kiro_config_dir()
|
|
34
|
+
# Check if parent directory exists
|
|
35
|
+
# Kiro config dir structure: .../Kiro/User/globalStorage
|
|
36
|
+
kiro_base = config_dir.parent.parent
|
|
37
|
+
return kiro_base.exists()
|
|
38
|
+
except Exception:
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
def get_instructions_directory(self) -> Path:
|
|
42
|
+
"""
|
|
43
|
+
Get the directory where Kiro instructions should be installed.
|
|
44
|
+
|
|
45
|
+
Note: Kiro uses ~/.kiro/steering/ for global steering files.
|
|
46
|
+
This tool currently only supports project-level installations.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Path to Kiro instructions directory
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
NotImplementedError: Global installation not supported for Kiro
|
|
53
|
+
"""
|
|
54
|
+
raise NotImplementedError(
|
|
55
|
+
f"{self.tool_name} global installation is not supported. "
|
|
56
|
+
"Please use project-level installation instead (--scope project)."
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def get_instruction_file_extension(self) -> str:
|
|
60
|
+
"""
|
|
61
|
+
Get the file extension for Kiro instructions.
|
|
62
|
+
|
|
63
|
+
Kiro uses markdown (.md) files for steering.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
File extension including the dot
|
|
67
|
+
"""
|
|
68
|
+
return ".md"
|
|
69
|
+
|
|
70
|
+
def get_project_instructions_directory(self, project_root: Path) -> Path:
|
|
71
|
+
"""
|
|
72
|
+
Get the directory for project-specific Kiro instructions.
|
|
73
|
+
|
|
74
|
+
Kiro stores project-specific steering files in .kiro/steering/ directory
|
|
75
|
+
in the project root. It supports multiple .md files in this directory.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
project_root: Path to the project root directory
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Path to project instructions directory (.kiro/steering/)
|
|
82
|
+
"""
|
|
83
|
+
instructions_dir = project_root / ".kiro" / "steering"
|
|
84
|
+
instructions_dir.mkdir(parents=True, exist_ok=True)
|
|
85
|
+
return instructions_dir
|