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,383 @@
|
|
|
1
|
+
"""Package CLI commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from aiconfigkit.cli.package_create import create_package_command
|
|
11
|
+
from aiconfigkit.cli.package_install import InstallationResult, install_package
|
|
12
|
+
from aiconfigkit.core.models import (
|
|
13
|
+
AIToolType,
|
|
14
|
+
ConflictResolution,
|
|
15
|
+
InstallationScope,
|
|
16
|
+
InstallationStatus,
|
|
17
|
+
)
|
|
18
|
+
from aiconfigkit.storage.package_tracker import PackageTracker
|
|
19
|
+
from aiconfigkit.utils.project import find_project_root
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
22
|
+
package_app = typer.Typer(help="Manage configuration packages")
|
|
23
|
+
|
|
24
|
+
# Register create command
|
|
25
|
+
package_app.command(name="create")(create_package_command)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@package_app.command(name="install")
|
|
29
|
+
def install_package_command(
|
|
30
|
+
package_path: str = typer.Argument(
|
|
31
|
+
...,
|
|
32
|
+
help="Path to package directory containing manifest",
|
|
33
|
+
),
|
|
34
|
+
target_ide: str = typer.Option(
|
|
35
|
+
"claude",
|
|
36
|
+
"--ide",
|
|
37
|
+
"-i",
|
|
38
|
+
help="Target IDE (claude, cursor, windsurf, copilot)",
|
|
39
|
+
),
|
|
40
|
+
project: Optional[str] = typer.Option(
|
|
41
|
+
None,
|
|
42
|
+
"--project",
|
|
43
|
+
"-p",
|
|
44
|
+
help="Project root directory (defaults to current directory)",
|
|
45
|
+
),
|
|
46
|
+
conflict: str = typer.Option(
|
|
47
|
+
"skip",
|
|
48
|
+
"--conflict",
|
|
49
|
+
"-c",
|
|
50
|
+
help="Conflict resolution strategy (skip, overwrite, rename)",
|
|
51
|
+
),
|
|
52
|
+
force: bool = typer.Option(
|
|
53
|
+
False,
|
|
54
|
+
"--force",
|
|
55
|
+
"-f",
|
|
56
|
+
help="Force reinstallation even if already installed",
|
|
57
|
+
),
|
|
58
|
+
quiet: bool = typer.Option(
|
|
59
|
+
False,
|
|
60
|
+
"--quiet",
|
|
61
|
+
"-q",
|
|
62
|
+
help="Minimal output",
|
|
63
|
+
),
|
|
64
|
+
json_output: bool = typer.Option(
|
|
65
|
+
False,
|
|
66
|
+
"--json",
|
|
67
|
+
help="Output results as JSON",
|
|
68
|
+
),
|
|
69
|
+
) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Install a configuration package to a project.
|
|
72
|
+
|
|
73
|
+
Package must contain an ai-config-kit-package.yaml manifest.
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
aiconfig package install ./python-dev-setup --ide claude
|
|
77
|
+
aiconfig package install ~/packages/my-package --ide cursor --conflict overwrite
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
# Parse target IDE
|
|
81
|
+
try:
|
|
82
|
+
ide_type = AIToolType(target_ide.lower())
|
|
83
|
+
except ValueError:
|
|
84
|
+
console.print(
|
|
85
|
+
f"[red]Error: Invalid IDE '{target_ide}'. " f"Valid options: claude, cursor, windsurf, copilot[/red]"
|
|
86
|
+
)
|
|
87
|
+
raise typer.Exit(1)
|
|
88
|
+
|
|
89
|
+
# Parse conflict resolution
|
|
90
|
+
try:
|
|
91
|
+
conflict_resolution = ConflictResolution(conflict.lower())
|
|
92
|
+
except ValueError:
|
|
93
|
+
console.print(
|
|
94
|
+
f"[red]Error: Invalid conflict resolution '{conflict}'. "
|
|
95
|
+
f"Valid options: skip, overwrite, rename[/red]"
|
|
96
|
+
)
|
|
97
|
+
raise typer.Exit(1)
|
|
98
|
+
|
|
99
|
+
# Determine project root
|
|
100
|
+
if project:
|
|
101
|
+
project_root = Path(project).resolve()
|
|
102
|
+
if not project_root.exists():
|
|
103
|
+
console.print(f"[red]Error: Project directory not found: {project}[/red]")
|
|
104
|
+
raise typer.Exit(1)
|
|
105
|
+
else:
|
|
106
|
+
project_root_maybe = find_project_root()
|
|
107
|
+
if not project_root_maybe:
|
|
108
|
+
console.print("[red]Error: Could not find project root. " "Use --project to specify explicitly.[/red]")
|
|
109
|
+
raise typer.Exit(1)
|
|
110
|
+
project_root = project_root_maybe
|
|
111
|
+
|
|
112
|
+
# Resolve package path
|
|
113
|
+
pkg_path = Path(package_path).resolve()
|
|
114
|
+
if not pkg_path.exists():
|
|
115
|
+
console.print(f"[red]Error: Package directory not found: {package_path}[/red]")
|
|
116
|
+
raise typer.Exit(1)
|
|
117
|
+
|
|
118
|
+
if not quiet:
|
|
119
|
+
console.print(f"[cyan]Installing package from {pkg_path}...[/cyan]")
|
|
120
|
+
console.print(f"[cyan]Target IDE: {ide_type.value}[/cyan]")
|
|
121
|
+
console.print(f"[cyan]Project root: {project_root}[/cyan]")
|
|
122
|
+
|
|
123
|
+
# Install package
|
|
124
|
+
result = install_package(
|
|
125
|
+
package_path=pkg_path,
|
|
126
|
+
project_root=project_root,
|
|
127
|
+
target_ide=ide_type,
|
|
128
|
+
scope=InstallationScope.PROJECT,
|
|
129
|
+
conflict_resolution=conflict_resolution,
|
|
130
|
+
force=force,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Output results
|
|
134
|
+
if json_output:
|
|
135
|
+
import json
|
|
136
|
+
|
|
137
|
+
output = {
|
|
138
|
+
"success": result.success,
|
|
139
|
+
"status": result.status.value,
|
|
140
|
+
"package_name": result.package_name,
|
|
141
|
+
"version": result.version,
|
|
142
|
+
"installed_count": result.installed_count,
|
|
143
|
+
"skipped_count": result.skipped_count,
|
|
144
|
+
"failed_count": result.failed_count,
|
|
145
|
+
"components_installed": {k.value: v for k, v in result.components_installed.items()},
|
|
146
|
+
"is_reinstall": result.is_reinstall,
|
|
147
|
+
"error_message": result.error_message,
|
|
148
|
+
}
|
|
149
|
+
console.print(json.dumps(output, indent=2))
|
|
150
|
+
else:
|
|
151
|
+
_display_installation_summary(result, quiet)
|
|
152
|
+
|
|
153
|
+
# Exit with appropriate code
|
|
154
|
+
if not result.success:
|
|
155
|
+
raise typer.Exit(1)
|
|
156
|
+
|
|
157
|
+
except Exception as e:
|
|
158
|
+
console.print(f"[red]Installation failed: {e}[/red]")
|
|
159
|
+
raise typer.Exit(1)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _display_installation_summary(result: InstallationResult, quiet: bool) -> None:
|
|
163
|
+
"""Display installation summary to user."""
|
|
164
|
+
if result.success:
|
|
165
|
+
# Success message
|
|
166
|
+
if result.status == InstallationStatus.COMPLETE:
|
|
167
|
+
console.print(f"\n[green]✓ Successfully installed {result.package_name} v{result.version}[/green]")
|
|
168
|
+
elif result.status == InstallationStatus.PARTIAL:
|
|
169
|
+
console.print(f"\n[yellow]⚠ Partially installed {result.package_name} v{result.version}[/yellow]")
|
|
170
|
+
else:
|
|
171
|
+
console.print(f"\n[red]✗ Installation failed for {result.package_name} v{result.version}[/red]")
|
|
172
|
+
|
|
173
|
+
if result.is_reinstall:
|
|
174
|
+
console.print("[cyan] (Reinstalled existing package)[/cyan]")
|
|
175
|
+
|
|
176
|
+
# Component summary table
|
|
177
|
+
if not quiet:
|
|
178
|
+
table = Table(title="Installation Summary", show_header=True)
|
|
179
|
+
table.add_column("Component Type", style="cyan")
|
|
180
|
+
table.add_column("Count", justify="right", style="green")
|
|
181
|
+
|
|
182
|
+
for component_type, count in result.components_installed.items():
|
|
183
|
+
table.add_row(component_type.value, str(count))
|
|
184
|
+
|
|
185
|
+
console.print()
|
|
186
|
+
console.print(table)
|
|
187
|
+
|
|
188
|
+
# Statistics
|
|
189
|
+
console.print(f"\n Installed: {result.installed_count}")
|
|
190
|
+
if result.skipped_count > 0:
|
|
191
|
+
console.print(f" Skipped: {result.skipped_count}")
|
|
192
|
+
if result.failed_count > 0:
|
|
193
|
+
console.print(f" Failed: {result.failed_count}")
|
|
194
|
+
|
|
195
|
+
else:
|
|
196
|
+
# Failure message
|
|
197
|
+
console.print(f"\n[red]✗ Installation failed for {result.package_name}[/red]")
|
|
198
|
+
if result.error_message:
|
|
199
|
+
console.print(f"[red] Error: {result.error_message}[/red]")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@package_app.command(name="list")
|
|
203
|
+
def list_packages_command(
|
|
204
|
+
project: Optional[str] = typer.Option(
|
|
205
|
+
None,
|
|
206
|
+
"--project",
|
|
207
|
+
"-p",
|
|
208
|
+
help="Project root directory (defaults to current directory)",
|
|
209
|
+
),
|
|
210
|
+
json_output: bool = typer.Option(
|
|
211
|
+
False,
|
|
212
|
+
"--json",
|
|
213
|
+
help="Output results as JSON",
|
|
214
|
+
),
|
|
215
|
+
) -> None:
|
|
216
|
+
"""
|
|
217
|
+
List installed packages in a project.
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
aiconfig package list
|
|
221
|
+
aiconfig package list --project ~/my-project
|
|
222
|
+
"""
|
|
223
|
+
try:
|
|
224
|
+
# Determine project root
|
|
225
|
+
if project:
|
|
226
|
+
project_root = Path(project).resolve()
|
|
227
|
+
if not project_root.exists():
|
|
228
|
+
console.print(f"[red]Error: Project directory not found: {project}[/red]")
|
|
229
|
+
raise typer.Exit(1)
|
|
230
|
+
else:
|
|
231
|
+
project_root_maybe = find_project_root()
|
|
232
|
+
if not project_root_maybe:
|
|
233
|
+
console.print("[red]Error: Could not find project root. " "Use --project to specify explicitly.[/red]")
|
|
234
|
+
raise typer.Exit(1)
|
|
235
|
+
project_root = project_root_maybe
|
|
236
|
+
|
|
237
|
+
# Get tracker
|
|
238
|
+
tracker_file = project_root / ".ai-config-kit" / "packages.json"
|
|
239
|
+
tracker = PackageTracker(tracker_file)
|
|
240
|
+
|
|
241
|
+
# Get installed packages
|
|
242
|
+
packages = tracker.get_installed_packages()
|
|
243
|
+
|
|
244
|
+
if json_output:
|
|
245
|
+
import json
|
|
246
|
+
|
|
247
|
+
output = []
|
|
248
|
+
for pkg in packages:
|
|
249
|
+
output.append(
|
|
250
|
+
{
|
|
251
|
+
"name": pkg.package_name,
|
|
252
|
+
"namespace": pkg.namespace,
|
|
253
|
+
"version": pkg.version,
|
|
254
|
+
"status": pkg.status.value,
|
|
255
|
+
"scope": pkg.scope.value,
|
|
256
|
+
"installed_at": pkg.installed_at.isoformat(),
|
|
257
|
+
"updated_at": pkg.updated_at.isoformat(),
|
|
258
|
+
"component_count": len(pkg.components),
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
console.print(json.dumps(output, indent=2))
|
|
262
|
+
else:
|
|
263
|
+
if not packages:
|
|
264
|
+
console.print("[yellow]No packages installed in this project.[/yellow]")
|
|
265
|
+
return
|
|
266
|
+
|
|
267
|
+
console.print(f"\n[cyan]Installed packages in {project_root}:[/cyan]\n")
|
|
268
|
+
|
|
269
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
270
|
+
table.add_column("Package", style="green")
|
|
271
|
+
table.add_column("Version", style="blue")
|
|
272
|
+
table.add_column("Status", style="yellow")
|
|
273
|
+
table.add_column("Components", justify="right", style="magenta")
|
|
274
|
+
table.add_column("Installed", style="dim")
|
|
275
|
+
|
|
276
|
+
for pkg in packages:
|
|
277
|
+
status_icon = "✓" if pkg.status == InstallationStatus.COMPLETE else "⚠"
|
|
278
|
+
table.add_row(
|
|
279
|
+
f"{pkg.namespace}/{pkg.package_name}",
|
|
280
|
+
pkg.version,
|
|
281
|
+
f"{status_icon} {pkg.status.value}",
|
|
282
|
+
str(len(pkg.components)),
|
|
283
|
+
pkg.installed_at.strftime("%Y-%m-%d %H:%M"),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
console.print(table)
|
|
287
|
+
console.print(f"\n[dim]Total: {len(packages)} package(s)[/dim]\n")
|
|
288
|
+
|
|
289
|
+
except Exception as e:
|
|
290
|
+
console.print(f"[red]Failed to list packages: {e}[/red]")
|
|
291
|
+
raise typer.Exit(1)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
@package_app.command(name="uninstall")
|
|
295
|
+
def uninstall_package_command(
|
|
296
|
+
package_name: str = typer.Argument(
|
|
297
|
+
...,
|
|
298
|
+
help="Package name to uninstall",
|
|
299
|
+
),
|
|
300
|
+
project: Optional[str] = typer.Option(
|
|
301
|
+
None,
|
|
302
|
+
"--project",
|
|
303
|
+
"-p",
|
|
304
|
+
help="Project root directory (defaults to current directory)",
|
|
305
|
+
),
|
|
306
|
+
yes: bool = typer.Option(
|
|
307
|
+
False,
|
|
308
|
+
"--yes",
|
|
309
|
+
"-y",
|
|
310
|
+
help="Skip confirmation prompt",
|
|
311
|
+
),
|
|
312
|
+
) -> None:
|
|
313
|
+
"""
|
|
314
|
+
Uninstall a package from a project.
|
|
315
|
+
|
|
316
|
+
This removes the package's files and tracking record.
|
|
317
|
+
|
|
318
|
+
Example:
|
|
319
|
+
aiconfig package uninstall test-package
|
|
320
|
+
aiconfig package uninstall my-org/my-package --yes
|
|
321
|
+
"""
|
|
322
|
+
try:
|
|
323
|
+
# Determine project root
|
|
324
|
+
if project:
|
|
325
|
+
project_root = Path(project).resolve()
|
|
326
|
+
if not project_root.exists():
|
|
327
|
+
console.print(f"[red]Error: Project directory not found: {project}[/red]")
|
|
328
|
+
raise typer.Exit(1)
|
|
329
|
+
else:
|
|
330
|
+
project_root_maybe = find_project_root()
|
|
331
|
+
if not project_root_maybe:
|
|
332
|
+
console.print("[red]Error: Could not find project root. " "Use --project to specify explicitly.[/red]")
|
|
333
|
+
raise typer.Exit(1)
|
|
334
|
+
project_root = project_root_maybe
|
|
335
|
+
|
|
336
|
+
# Get tracker
|
|
337
|
+
tracker_file = project_root / ".ai-config-kit" / "packages.json"
|
|
338
|
+
tracker = PackageTracker(tracker_file)
|
|
339
|
+
|
|
340
|
+
# Get package
|
|
341
|
+
package = tracker.get_package(package_name, InstallationScope.PROJECT)
|
|
342
|
+
if not package:
|
|
343
|
+
console.print(f"[red]Error: Package '{package_name}' is not installed in this project.[/red]")
|
|
344
|
+
raise typer.Exit(1)
|
|
345
|
+
|
|
346
|
+
# Confirm uninstall
|
|
347
|
+
if not yes:
|
|
348
|
+
console.print("\n[yellow]Package to uninstall:[/yellow]")
|
|
349
|
+
console.print(f" Name: {package.package_name}")
|
|
350
|
+
console.print(f" Version: {package.version}")
|
|
351
|
+
console.print(f" Components: {len(package.components)}")
|
|
352
|
+
|
|
353
|
+
confirm = typer.confirm("\nAre you sure you want to uninstall this package?")
|
|
354
|
+
if not confirm:
|
|
355
|
+
console.print("[yellow]Uninstall cancelled.[/yellow]")
|
|
356
|
+
raise typer.Exit(0)
|
|
357
|
+
|
|
358
|
+
# Remove component files
|
|
359
|
+
removed_count = 0
|
|
360
|
+
failed_count = 0
|
|
361
|
+
for component in package.components:
|
|
362
|
+
try:
|
|
363
|
+
file_path = project_root / component.installed_path
|
|
364
|
+
if file_path.exists():
|
|
365
|
+
file_path.unlink()
|
|
366
|
+
removed_count += 1
|
|
367
|
+
console.print(f"[dim] Removed: {component.installed_path}[/dim]")
|
|
368
|
+
except Exception as e:
|
|
369
|
+
console.print(f"[yellow] Warning: Failed to remove {component.installed_path}: {e}[/yellow]")
|
|
370
|
+
failed_count += 1
|
|
371
|
+
|
|
372
|
+
# Remove from tracker
|
|
373
|
+
tracker.remove_package(package_name, InstallationScope.PROJECT)
|
|
374
|
+
|
|
375
|
+
# Summary
|
|
376
|
+
console.print(f"\n[green]✓ Uninstalled {package.package_name} v{package.version}[/green]")
|
|
377
|
+
console.print(f" Removed {removed_count} file(s)")
|
|
378
|
+
if failed_count > 0:
|
|
379
|
+
console.print(f"[yellow] Failed to remove {failed_count} file(s)[/yellow]")
|
|
380
|
+
|
|
381
|
+
except Exception as e:
|
|
382
|
+
console.print(f"[red]Failed to uninstall package: {e}[/red]")
|
|
383
|
+
raise typer.Exit(1)
|