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,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}")
|