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/cli/list.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""List command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from aiconfigkit.core.git_operations import GitOperations
|
|
10
|
+
from aiconfigkit.core.models import AIToolType
|
|
11
|
+
from aiconfigkit.core.repository import RepositoryParser
|
|
12
|
+
from aiconfigkit.storage.library import LibraryManager
|
|
13
|
+
from aiconfigkit.storage.tracker import InstallationTracker
|
|
14
|
+
from aiconfigkit.utils.project import find_project_root
|
|
15
|
+
from aiconfigkit.utils.ui import (
|
|
16
|
+
format_installed_table,
|
|
17
|
+
format_instructions_table,
|
|
18
|
+
print_error,
|
|
19
|
+
print_info,
|
|
20
|
+
)
|
|
21
|
+
from aiconfigkit.utils.validation import is_valid_git_url, normalize_repo_url
|
|
22
|
+
|
|
23
|
+
console = Console()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def list_available(
|
|
27
|
+
repo: str,
|
|
28
|
+
tag: Optional[str] = None,
|
|
29
|
+
bundles_only: bool = False,
|
|
30
|
+
instructions_only: bool = False,
|
|
31
|
+
) -> int:
|
|
32
|
+
"""
|
|
33
|
+
List available instructions from a repository.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
repo: Git repository URL
|
|
37
|
+
tag: Filter by tag
|
|
38
|
+
bundles_only: Show only bundles
|
|
39
|
+
instructions_only: Show only instructions
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Exit code (0 for success, 1 for error)
|
|
43
|
+
"""
|
|
44
|
+
# Validate repository URL
|
|
45
|
+
if not is_valid_git_url(repo):
|
|
46
|
+
print_error(f"Invalid Git repository URL: {repo}", console)
|
|
47
|
+
return 1
|
|
48
|
+
|
|
49
|
+
# Check Git is installed
|
|
50
|
+
if not GitOperations.is_git_installed():
|
|
51
|
+
print_error("Git is not installed. Please install Git and try again.", console)
|
|
52
|
+
return 1
|
|
53
|
+
|
|
54
|
+
# Clone repository or use local path
|
|
55
|
+
git_ops = GitOperations()
|
|
56
|
+
is_local = git_ops.is_local_path(repo)
|
|
57
|
+
|
|
58
|
+
if is_local:
|
|
59
|
+
# Use local directory directly
|
|
60
|
+
try:
|
|
61
|
+
repo_path = git_ops.clone_repository(repo)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
print_error(f"Failed to access local directory: {e}", console)
|
|
64
|
+
return 1
|
|
65
|
+
else:
|
|
66
|
+
# Clone remote repository
|
|
67
|
+
with Progress(
|
|
68
|
+
SpinnerColumn(),
|
|
69
|
+
TextColumn("[progress.description]{task.description}"),
|
|
70
|
+
console=console,
|
|
71
|
+
) as progress:
|
|
72
|
+
progress.add_task(description="Fetching repository...", total=None)
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
repo_path = git_ops.clone_repository(repo)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
print_error(f"Failed to clone repository: {e}", console)
|
|
78
|
+
return 1
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
# Parse repository
|
|
82
|
+
parser = RepositoryParser(repo_path)
|
|
83
|
+
repository = parser.parse()
|
|
84
|
+
|
|
85
|
+
# Filter by tag if specified
|
|
86
|
+
instructions = repository.instructions
|
|
87
|
+
bundles = repository.bundles
|
|
88
|
+
|
|
89
|
+
if tag:
|
|
90
|
+
instructions = [i for i in instructions if tag in i.tags]
|
|
91
|
+
bundles = [b for b in bundles if tag in b.tags]
|
|
92
|
+
print_info(f"Filtered by tag: {tag}", console)
|
|
93
|
+
|
|
94
|
+
# Apply filters
|
|
95
|
+
if bundles_only:
|
|
96
|
+
instructions = []
|
|
97
|
+
if instructions_only:
|
|
98
|
+
bundles = []
|
|
99
|
+
|
|
100
|
+
# Check if anything to display
|
|
101
|
+
if not instructions and not bundles:
|
|
102
|
+
if tag:
|
|
103
|
+
console.print(f"[yellow]No instructions or bundles found with tag '{tag}'[/yellow]")
|
|
104
|
+
else:
|
|
105
|
+
console.print("[yellow]No instructions or bundles found in repository[/yellow]")
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
# Display table
|
|
109
|
+
table = format_instructions_table(instructions, bundles, show_bundles=not instructions_only)
|
|
110
|
+
console.print()
|
|
111
|
+
console.print(table)
|
|
112
|
+
console.print()
|
|
113
|
+
|
|
114
|
+
# Summary
|
|
115
|
+
len(instructions) + len(bundles)
|
|
116
|
+
console.print(f"Found {len(instructions)} instruction(s) and {len(bundles)} bundle(s)")
|
|
117
|
+
|
|
118
|
+
return 0
|
|
119
|
+
|
|
120
|
+
finally:
|
|
121
|
+
# Clean up cloned repository (but not local directories)
|
|
122
|
+
GitOperations.cleanup_repository(repo_path, is_temp=not is_local)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def list_installed(
|
|
126
|
+
tool: Optional[str] = None,
|
|
127
|
+
repo: Optional[str] = None,
|
|
128
|
+
) -> int:
|
|
129
|
+
"""
|
|
130
|
+
List installed instructions.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
tool: Filter by AI tool (cursor, copilot, etc.)
|
|
134
|
+
repo: Filter by source repository URL
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Exit code (0 for success, 1 for error)
|
|
138
|
+
"""
|
|
139
|
+
tracker = InstallationTracker()
|
|
140
|
+
|
|
141
|
+
# Detect project root to include project-scoped installations
|
|
142
|
+
project_root = find_project_root()
|
|
143
|
+
|
|
144
|
+
# Get all installed instructions (both global and project)
|
|
145
|
+
if tool:
|
|
146
|
+
# Filter by specific tool
|
|
147
|
+
try:
|
|
148
|
+
ai_tool = AIToolType(tool.lower())
|
|
149
|
+
records = tracker.get_installed_instructions(ai_tool, project_root=project_root)
|
|
150
|
+
except ValueError:
|
|
151
|
+
print_error(f"Invalid AI tool: {tool}. " f"Valid options: cursor, copilot, windsurf, claude", console)
|
|
152
|
+
return 1
|
|
153
|
+
else:
|
|
154
|
+
records = tracker.get_installed_instructions(project_root=project_root)
|
|
155
|
+
|
|
156
|
+
# Filter by repository if specified
|
|
157
|
+
if repo:
|
|
158
|
+
normalized_repo = normalize_repo_url(repo)
|
|
159
|
+
records = [r for r in records if normalize_repo_url(r.source_repo) == normalized_repo]
|
|
160
|
+
|
|
161
|
+
# Check if anything to display
|
|
162
|
+
if not records:
|
|
163
|
+
if tool and repo:
|
|
164
|
+
console.print(f"[yellow]No instructions installed for {tool} from {repo}[/yellow]")
|
|
165
|
+
elif tool:
|
|
166
|
+
console.print(f"[yellow]No instructions installed for {tool}[/yellow]")
|
|
167
|
+
elif repo:
|
|
168
|
+
console.print(f"[yellow]No instructions installed from {repo}[/yellow]")
|
|
169
|
+
else:
|
|
170
|
+
console.print("[yellow]No instructions installed[/yellow]")
|
|
171
|
+
return 0
|
|
172
|
+
|
|
173
|
+
# Display table
|
|
174
|
+
table = format_installed_table(records, group_by_tool=not bool(tool))
|
|
175
|
+
console.print()
|
|
176
|
+
console.print(table)
|
|
177
|
+
console.print()
|
|
178
|
+
|
|
179
|
+
# Summary
|
|
180
|
+
console.print(f"Total: {len(records)} installed instruction(s)")
|
|
181
|
+
|
|
182
|
+
return 0
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def list_library(
|
|
186
|
+
repo_filter: Optional[str] = None,
|
|
187
|
+
show_instructions: bool = False,
|
|
188
|
+
) -> int:
|
|
189
|
+
"""
|
|
190
|
+
List sources and instructions in the local library.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
repo_filter: Filter by source alias or namespace
|
|
194
|
+
show_instructions: Show individual instructions
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Exit code (0 for success)
|
|
198
|
+
"""
|
|
199
|
+
library = LibraryManager()
|
|
200
|
+
repositories = library.list_repositories()
|
|
201
|
+
|
|
202
|
+
if not repositories:
|
|
203
|
+
print_info("Library is empty. Use 'inskit download' to add sources.")
|
|
204
|
+
return 0
|
|
205
|
+
|
|
206
|
+
# Filter if specified (match against alias or namespace)
|
|
207
|
+
if repo_filter:
|
|
208
|
+
repositories = [
|
|
209
|
+
r
|
|
210
|
+
for r in repositories
|
|
211
|
+
if repo_filter.lower() in (r.alias or "").lower() or repo_filter.lower() in r.namespace.lower()
|
|
212
|
+
]
|
|
213
|
+
if not repositories:
|
|
214
|
+
print_error(f"No sources matching: {repo_filter}")
|
|
215
|
+
return 1
|
|
216
|
+
|
|
217
|
+
# Show sources
|
|
218
|
+
if not show_instructions:
|
|
219
|
+
table = Table(title="Library Sources", show_header=True, header_style="bold cyan")
|
|
220
|
+
table.add_column("Alias", style="cyan", no_wrap=True)
|
|
221
|
+
table.add_column("Name", style="green")
|
|
222
|
+
table.add_column("Version", style="yellow")
|
|
223
|
+
table.add_column("Instructions", style="magenta")
|
|
224
|
+
table.add_column("Downloaded", style="blue")
|
|
225
|
+
|
|
226
|
+
for repo in sorted(repositories, key=lambda r: r.alias or r.name):
|
|
227
|
+
table.add_row(
|
|
228
|
+
repo.alias or repo.namespace,
|
|
229
|
+
repo.name,
|
|
230
|
+
repo.version,
|
|
231
|
+
str(len(repo.instructions)),
|
|
232
|
+
repo.downloaded_at.strftime("%Y-%m-%d"),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
console.print()
|
|
236
|
+
console.print(table)
|
|
237
|
+
console.print()
|
|
238
|
+
console.print(f"Total: {len(repositories)} source(s) in library")
|
|
239
|
+
console.print()
|
|
240
|
+
console.print("[dim]Use 'inskit install' to install instructions from library[/dim]")
|
|
241
|
+
|
|
242
|
+
# Show instructions
|
|
243
|
+
else:
|
|
244
|
+
table = Table(title="Library Instructions", show_header=True, header_style="bold cyan")
|
|
245
|
+
table.add_column("Name", style="cyan")
|
|
246
|
+
table.add_column("Description")
|
|
247
|
+
table.add_column("Repository", style="green")
|
|
248
|
+
table.add_column("Version", style="yellow")
|
|
249
|
+
table.add_column("Tags", style="magenta")
|
|
250
|
+
|
|
251
|
+
all_instructions = []
|
|
252
|
+
for repo in repositories:
|
|
253
|
+
all_instructions.extend(repo.instructions)
|
|
254
|
+
|
|
255
|
+
for inst in sorted(all_instructions, key=lambda i: i.name):
|
|
256
|
+
tags_str = ", ".join(inst.tags[:3]) if inst.tags else "-"
|
|
257
|
+
if len(inst.tags) > 3:
|
|
258
|
+
tags_str += f" +{len(inst.tags) - 3}"
|
|
259
|
+
|
|
260
|
+
table.add_row(
|
|
261
|
+
inst.name,
|
|
262
|
+
inst.description[:60] + "..." if len(inst.description) > 60 else inst.description,
|
|
263
|
+
inst.repo_name,
|
|
264
|
+
inst.version,
|
|
265
|
+
tags_str,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
console.print()
|
|
269
|
+
console.print(table)
|
|
270
|
+
console.print()
|
|
271
|
+
console.print(f"Total: {len(all_instructions)} instruction(s) in library")
|
|
272
|
+
console.print()
|
|
273
|
+
console.print("[dim]Use 'inskit install' to install these instructions[/dim]")
|
|
274
|
+
|
|
275
|
+
return 0
|