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,323 @@
1
+ """CLI command for creating configuration packages."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ from aiconfigkit.core.component_detector import ComponentDetector, DetectionResult
12
+ from aiconfigkit.core.package_creator import PackageCreationResult, PackageCreator, PackageMetadata, get_git_author
13
+ from aiconfigkit.utils.project import find_project_root
14
+
15
+ console = Console()
16
+
17
+
18
+ def create_package_command(
19
+ name: Optional[str] = typer.Option(
20
+ None,
21
+ "--name",
22
+ "-n",
23
+ help="Package name (lowercase, hyphens allowed)",
24
+ ),
25
+ version: str = typer.Option(
26
+ "1.0.0",
27
+ "--version",
28
+ "-v",
29
+ help="Package version (semantic versioning)",
30
+ ),
31
+ description: Optional[str] = typer.Option(
32
+ None,
33
+ "--description",
34
+ "-d",
35
+ help="Package description",
36
+ ),
37
+ author: Optional[str] = typer.Option(
38
+ None,
39
+ "--author",
40
+ "-a",
41
+ help="Package author (defaults to git user.name)",
42
+ ),
43
+ license_: str = typer.Option(
44
+ "MIT",
45
+ "--license",
46
+ "-l",
47
+ help="Package license",
48
+ ),
49
+ output: str = typer.Option(
50
+ ".",
51
+ "--output",
52
+ "-o",
53
+ help="Output directory for package",
54
+ ),
55
+ project: Optional[str] = typer.Option(
56
+ None,
57
+ "--project",
58
+ "-p",
59
+ help="Project root directory (defaults to current directory)",
60
+ ),
61
+ interactive: bool = typer.Option(
62
+ True,
63
+ "--interactive/--no-interactive",
64
+ help="Enable interactive mode for component selection",
65
+ ),
66
+ scrub_secrets: bool = typer.Option(
67
+ True,
68
+ "--scrub-secrets/--keep-secrets",
69
+ help="Template secrets in MCP configs",
70
+ ),
71
+ force: bool = typer.Option(
72
+ False,
73
+ "--force",
74
+ "-f",
75
+ help="Overwrite existing package directory",
76
+ ),
77
+ quiet: bool = typer.Option(
78
+ False,
79
+ "--quiet",
80
+ "-q",
81
+ help="Minimal output",
82
+ ),
83
+ json_output: bool = typer.Option(
84
+ False,
85
+ "--json",
86
+ help="Output results as JSON",
87
+ ),
88
+ ) -> None:
89
+ """
90
+ Create a shareable configuration package from project components.
91
+
92
+ Scans the current project for AI coding assistant configurations
93
+ (instructions, MCP servers, hooks, commands, resources) and creates
94
+ a portable package that can be installed in other projects.
95
+
96
+ Example:
97
+ aiconfig package create --name my-package
98
+ aiconfig package create --name dev-setup --no-interactive
99
+ aiconfig package create --name my-pkg --output ~/packages
100
+ """
101
+ try:
102
+ if project:
103
+ project_root = Path(project).resolve()
104
+ if not project_root.exists():
105
+ console.print(f"[red]Error: Project directory not found: {project}[/red]")
106
+ raise typer.Exit(1)
107
+ else:
108
+ project_root_maybe = find_project_root()
109
+ if not project_root_maybe:
110
+ console.print("[red]Error: Could not find project root. " "Use --project to specify explicitly.[/red]")
111
+ raise typer.Exit(1)
112
+ project_root = project_root_maybe
113
+
114
+ output_dir = Path(output).resolve()
115
+ if not output_dir.exists():
116
+ console.print(f"[red]Error: Output directory not found: {output}[/red]")
117
+ raise typer.Exit(1)
118
+
119
+ if not quiet:
120
+ console.print(f"[cyan]Scanning project: {project_root}[/cyan]")
121
+
122
+ detector = ComponentDetector(project_root)
123
+ detection_result = detector.detect_all()
124
+
125
+ if detection_result.total_count == 0:
126
+ console.print("[yellow]No packageable components found in this project.[/yellow]")
127
+ console.print("\n[dim]Components are detected from:[/dim]")
128
+ console.print("[dim] - Instructions: .claude/rules/, .cursor/rules/, etc.[/dim]")
129
+ console.print("[dim] - MCP servers: .claude/settings.local.json[/dim]")
130
+ console.print("[dim] - Hooks: .claude/hooks/[/dim]")
131
+ console.print("[dim] - Commands: .claude/commands/[/dim]")
132
+ console.print("[dim] - Resources: .ai-config-kit/resources/[/dim]")
133
+ raise typer.Exit(1)
134
+
135
+ if not quiet:
136
+ _display_detected_components(detection_result)
137
+
138
+ if not name:
139
+ if interactive:
140
+ name = typer.prompt("Package name", default=project_root.name.lower().replace(" ", "-"))
141
+ else:
142
+ console.print("[red]Error: --name is required in non-interactive mode[/red]")
143
+ raise typer.Exit(1)
144
+
145
+ # At this point name is guaranteed to be a string (either from option or prompt)
146
+ assert name is not None
147
+ package_name: str = name.lower().replace(" ", "-")
148
+ if not package_name.replace("-", "").replace("_", "").isalnum():
149
+ console.print(
150
+ f"[red]Error: Invalid package name '{package_name}'. "
151
+ f"Use only lowercase letters, numbers, hyphens.[/red]"
152
+ )
153
+ raise typer.Exit(1)
154
+
155
+ package_description: str
156
+ if not description:
157
+ if interactive:
158
+ package_description = typer.prompt(
159
+ "Package description",
160
+ default=f"Configuration package for {project_root.name}",
161
+ )
162
+ else:
163
+ package_description = f"Configuration package for {project_root.name}"
164
+ else:
165
+ package_description = description
166
+
167
+ package_author: str
168
+ if not author:
169
+ git_author = get_git_author()
170
+ if not git_author and interactive:
171
+ package_author = typer.prompt("Author", default="Unknown")
172
+ elif not git_author:
173
+ package_author = "Unknown"
174
+ else:
175
+ package_author = git_author
176
+ else:
177
+ package_author = author
178
+
179
+ package_dir = output_dir / f"package-{package_name}"
180
+ if package_dir.exists():
181
+ if force:
182
+ if not quiet:
183
+ console.print(f"[yellow]Removing existing package directory: {package_dir}[/yellow]")
184
+ import shutil
185
+
186
+ shutil.rmtree(package_dir)
187
+ else:
188
+ console.print(f"[red]Error: Package directory already exists: {package_dir}[/red]")
189
+ console.print("[dim]Use --force to overwrite[/dim]")
190
+ raise typer.Exit(1)
191
+
192
+ if interactive:
193
+ console.print(f"\n[cyan]Creating package with {detection_result.total_count} components[/cyan]")
194
+ if not typer.confirm("Proceed?", default=True):
195
+ console.print("[yellow]Package creation cancelled.[/yellow]")
196
+ raise typer.Exit(0)
197
+
198
+ metadata = PackageMetadata(
199
+ name=package_name,
200
+ version=version,
201
+ description=package_description,
202
+ author=package_author,
203
+ license=license_,
204
+ namespace="local/local",
205
+ )
206
+
207
+ creator = PackageCreator(
208
+ project_root=project_root,
209
+ output_dir=output_dir,
210
+ metadata=metadata,
211
+ scrub_secrets=scrub_secrets,
212
+ )
213
+
214
+ result = creator.create(detection_result=detection_result)
215
+
216
+ if json_output:
217
+ output_data = {
218
+ "success": result.success,
219
+ "package_path": str(result.package_path) if result.package_path else None,
220
+ "manifest_path": str(result.manifest_path) if result.manifest_path else None,
221
+ "components_included": result.components_included,
222
+ "secrets_templated": result.secrets_templated,
223
+ "warnings": result.warnings,
224
+ "error_message": result.error_message,
225
+ }
226
+ console.print(json.dumps(output_data, indent=2))
227
+ else:
228
+ _display_creation_result(result, quiet)
229
+
230
+ if not result.success:
231
+ raise typer.Exit(1)
232
+
233
+ except typer.Exit:
234
+ raise
235
+ except Exception as e:
236
+ console.print(f"[red]Package creation failed: {e}[/red]")
237
+ raise typer.Exit(1)
238
+
239
+
240
+ def _display_detected_components(detection_result: "DetectionResult") -> None:
241
+ """Display summary of detected components."""
242
+ console.print("\n[cyan]Detected components:[/cyan]")
243
+
244
+ table = Table(show_header=True, header_style="bold cyan")
245
+ table.add_column("Type", style="green")
246
+ table.add_column("Count", justify="right", style="blue")
247
+ table.add_column("Details", style="dim")
248
+
249
+ if detection_result.instructions:
250
+ names = ", ".join(i.name for i in detection_result.instructions[:3])
251
+ if len(detection_result.instructions) > 3:
252
+ names += f", +{len(detection_result.instructions) - 3} more"
253
+ table.add_row("Instructions", str(len(detection_result.instructions)), names)
254
+
255
+ if detection_result.mcp_servers:
256
+ names = ", ".join(m.name for m in detection_result.mcp_servers[:3])
257
+ if len(detection_result.mcp_servers) > 3:
258
+ names += f", +{len(detection_result.mcp_servers) - 3} more"
259
+ table.add_row("MCP Servers", str(len(detection_result.mcp_servers)), names)
260
+
261
+ if detection_result.hooks:
262
+ names = ", ".join(h.name for h in detection_result.hooks[:3])
263
+ if len(detection_result.hooks) > 3:
264
+ names += f", +{len(detection_result.hooks) - 3} more"
265
+ table.add_row("Hooks", str(len(detection_result.hooks)), names)
266
+
267
+ if detection_result.commands:
268
+ names = ", ".join(c.name for c in detection_result.commands[:3])
269
+ if len(detection_result.commands) > 3:
270
+ names += f", +{len(detection_result.commands) - 3} more"
271
+ table.add_row("Commands", str(len(detection_result.commands)), names)
272
+
273
+ if detection_result.resources:
274
+ names = ", ".join(r.name for r in detection_result.resources[:3])
275
+ if len(detection_result.resources) > 3:
276
+ names += f", +{len(detection_result.resources) - 3} more"
277
+ table.add_row("Resources", str(len(detection_result.resources)), names)
278
+
279
+ if detection_result.skills:
280
+ names = ", ".join(s.name for s in detection_result.skills[:3])
281
+ if len(detection_result.skills) > 3:
282
+ names += f", +{len(detection_result.skills) - 3} more"
283
+ table.add_row("Skills", str(len(detection_result.skills)), names)
284
+
285
+ if detection_result.workflows:
286
+ names = ", ".join(w.name for w in detection_result.workflows[:3])
287
+ if len(detection_result.workflows) > 3:
288
+ names += f", +{len(detection_result.workflows) - 3} more"
289
+ table.add_row("Workflows", str(len(detection_result.workflows)), names)
290
+
291
+ if detection_result.memory_files:
292
+ names = ", ".join(m.name for m in detection_result.memory_files[:3])
293
+ if len(detection_result.memory_files) > 3:
294
+ names += f", +{len(detection_result.memory_files) - 3} more"
295
+ table.add_row("Memory Files", str(len(detection_result.memory_files)), names)
296
+
297
+ console.print(table)
298
+ console.print(f"\n[dim]Total: {detection_result.total_count} component(s)[/dim]")
299
+
300
+
301
+ def _display_creation_result(result: PackageCreationResult, quiet: bool) -> None:
302
+ """Display package creation result."""
303
+ if result.success:
304
+ console.print("\n[green]✓ Package created successfully![/green]")
305
+ console.print(f" Location: {result.package_path}")
306
+
307
+ if not quiet:
308
+ console.print(f" Components: {result.components_included}")
309
+ if result.secrets_templated > 0:
310
+ console.print(f" Secrets templated: {result.secrets_templated}")
311
+
312
+ if result.warnings:
313
+ console.print(f"\n[yellow]Warnings ({len(result.warnings)}):[/yellow]")
314
+ for warning in result.warnings:
315
+ console.print(f" - {warning}")
316
+
317
+ console.print("\n[cyan]To install this package:[/cyan]")
318
+ console.print(f" aiconfig package install {result.package_path} --ide claude")
319
+
320
+ else:
321
+ console.print("\n[red]✗ Package creation failed[/red]")
322
+ if result.error_message:
323
+ console.print(f" Error: {result.error_message}")