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.
Files changed (84) hide show
  1. aiconfigkit/__init__.py +0 -0
  2. aiconfigkit/__main__.py +6 -0
  3. aiconfigkit/ai_tools/__init__.py +0 -0
  4. aiconfigkit/ai_tools/base.py +236 -0
  5. aiconfigkit/ai_tools/capability_registry.py +262 -0
  6. aiconfigkit/ai_tools/claude.py +91 -0
  7. aiconfigkit/ai_tools/claude_desktop.py +97 -0
  8. aiconfigkit/ai_tools/cline.py +92 -0
  9. aiconfigkit/ai_tools/copilot.py +92 -0
  10. aiconfigkit/ai_tools/cursor.py +109 -0
  11. aiconfigkit/ai_tools/detector.py +169 -0
  12. aiconfigkit/ai_tools/kiro.py +85 -0
  13. aiconfigkit/ai_tools/mcp_syncer.py +291 -0
  14. aiconfigkit/ai_tools/roo.py +110 -0
  15. aiconfigkit/ai_tools/translator.py +390 -0
  16. aiconfigkit/ai_tools/winsurf.py +102 -0
  17. aiconfigkit/cli/__init__.py +0 -0
  18. aiconfigkit/cli/delete.py +118 -0
  19. aiconfigkit/cli/download.py +274 -0
  20. aiconfigkit/cli/install.py +237 -0
  21. aiconfigkit/cli/install_new.py +937 -0
  22. aiconfigkit/cli/list.py +275 -0
  23. aiconfigkit/cli/main.py +454 -0
  24. aiconfigkit/cli/mcp_configure.py +232 -0
  25. aiconfigkit/cli/mcp_install.py +166 -0
  26. aiconfigkit/cli/mcp_sync.py +165 -0
  27. aiconfigkit/cli/package.py +383 -0
  28. aiconfigkit/cli/package_create.py +323 -0
  29. aiconfigkit/cli/package_install.py +472 -0
  30. aiconfigkit/cli/template.py +19 -0
  31. aiconfigkit/cli/template_backup.py +261 -0
  32. aiconfigkit/cli/template_init.py +499 -0
  33. aiconfigkit/cli/template_install.py +261 -0
  34. aiconfigkit/cli/template_list.py +172 -0
  35. aiconfigkit/cli/template_uninstall.py +146 -0
  36. aiconfigkit/cli/template_update.py +225 -0
  37. aiconfigkit/cli/template_validate.py +234 -0
  38. aiconfigkit/cli/tools.py +47 -0
  39. aiconfigkit/cli/uninstall.py +125 -0
  40. aiconfigkit/cli/update.py +309 -0
  41. aiconfigkit/core/__init__.py +0 -0
  42. aiconfigkit/core/checksum.py +211 -0
  43. aiconfigkit/core/component_detector.py +905 -0
  44. aiconfigkit/core/conflict_resolution.py +329 -0
  45. aiconfigkit/core/git_operations.py +539 -0
  46. aiconfigkit/core/mcp/__init__.py +1 -0
  47. aiconfigkit/core/mcp/credentials.py +279 -0
  48. aiconfigkit/core/mcp/manager.py +308 -0
  49. aiconfigkit/core/mcp/set_manager.py +1 -0
  50. aiconfigkit/core/mcp/validator.py +1 -0
  51. aiconfigkit/core/models.py +1661 -0
  52. aiconfigkit/core/package_creator.py +743 -0
  53. aiconfigkit/core/package_manifest.py +248 -0
  54. aiconfigkit/core/repository.py +298 -0
  55. aiconfigkit/core/secret_detector.py +438 -0
  56. aiconfigkit/core/template_manifest.py +283 -0
  57. aiconfigkit/core/version.py +201 -0
  58. aiconfigkit/storage/__init__.py +0 -0
  59. aiconfigkit/storage/library.py +429 -0
  60. aiconfigkit/storage/mcp_tracker.py +1 -0
  61. aiconfigkit/storage/package_tracker.py +234 -0
  62. aiconfigkit/storage/template_library.py +229 -0
  63. aiconfigkit/storage/template_tracker.py +296 -0
  64. aiconfigkit/storage/tracker.py +416 -0
  65. aiconfigkit/tui/__init__.py +5 -0
  66. aiconfigkit/tui/installer.py +511 -0
  67. aiconfigkit/utils/__init__.py +0 -0
  68. aiconfigkit/utils/atomic_write.py +90 -0
  69. aiconfigkit/utils/backup.py +169 -0
  70. aiconfigkit/utils/dotenv.py +128 -0
  71. aiconfigkit/utils/git_helpers.py +187 -0
  72. aiconfigkit/utils/logging.py +60 -0
  73. aiconfigkit/utils/namespace.py +134 -0
  74. aiconfigkit/utils/paths.py +205 -0
  75. aiconfigkit/utils/project.py +109 -0
  76. aiconfigkit/utils/streaming.py +216 -0
  77. aiconfigkit/utils/ui.py +194 -0
  78. aiconfigkit/utils/validation.py +187 -0
  79. devsync-0.5.5.dist-info/LICENSE +21 -0
  80. devsync-0.5.5.dist-info/METADATA +477 -0
  81. devsync-0.5.5.dist-info/RECORD +84 -0
  82. devsync-0.5.5.dist-info/WHEEL +5 -0
  83. devsync-0.5.5.dist-info/entry_points.txt +2 -0
  84. devsync-0.5.5.dist-info/top_level.txt +1 -0
@@ -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