djux 0.1.0__tar.gz

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 (39) hide show
  1. djux-0.1.0/PKG-INFO +172 -0
  2. djux-0.1.0/README.md +145 -0
  3. djux-0.1.0/djux/__init__.py +1 -0
  4. djux-0.1.0/djux/cli.py +30 -0
  5. djux-0.1.0/djux/commands/__init__.py +0 -0
  6. djux-0.1.0/djux/commands/add.py +207 -0
  7. djux-0.1.0/djux/commands/list.py +45 -0
  8. djux-0.1.0/djux/commands/new.py +51 -0
  9. djux-0.1.0/djux/commands/publish.py +64 -0
  10. djux-0.1.0/djux/commands/remove.py +94 -0
  11. djux-0.1.0/djux/core/__init__.py +0 -0
  12. djux-0.1.0/djux/core/downloader.py +32 -0
  13. djux-0.1.0/djux/core/manifest.py +40 -0
  14. djux-0.1.0/djux/core/patcher.py +83 -0
  15. djux-0.1.0/djux/core/registry.py +67 -0
  16. djux-0.1.0/djux/templates/project_template/.env.example +3 -0
  17. djux-0.1.0/djux/templates/project_template/.gitignore +11 -0
  18. djux-0.1.0/djux/templates/project_template/apps/.gitkeep +0 -0
  19. djux-0.1.0/djux/templates/project_template/config/__init__.py +0 -0
  20. djux-0.1.0/djux/templates/project_template/config/asgi.py +7 -0
  21. djux-0.1.0/djux/templates/project_template/config/settings.py +85 -0
  22. djux-0.1.0/djux/templates/project_template/config/urls.py +7 -0
  23. djux-0.1.0/djux/templates/project_template/config/wsgi.py +7 -0
  24. djux-0.1.0/djux/templates/project_template/djux.project.json +5 -0
  25. djux-0.1.0/djux/templates/project_template/manage.py +20 -0
  26. djux-0.1.0/djux/templates/project_template/requirements.txt +2 -0
  27. djux-0.1.0/djux/templates/project_template/static/.gitkeep +0 -0
  28. djux-0.1.0/djux/templates/project_template/templates/.gitkeep +0 -0
  29. djux-0.1.0/djux.egg-info/PKG-INFO +172 -0
  30. djux-0.1.0/djux.egg-info/SOURCES.txt +37 -0
  31. djux-0.1.0/djux.egg-info/dependency_links.txt +1 -0
  32. djux-0.1.0/djux.egg-info/entry_points.txt +2 -0
  33. djux-0.1.0/djux.egg-info/requires.txt +3 -0
  34. djux-0.1.0/djux.egg-info/top_level.txt +1 -0
  35. djux-0.1.0/pyproject.toml +48 -0
  36. djux-0.1.0/setup.cfg +4 -0
  37. djux-0.1.0/tests/test_add.py +209 -0
  38. djux-0.1.0/tests/test_new.py +69 -0
  39. djux-0.1.0/tests/test_patcher.py +117 -0
djux-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: djux
3
+ Version: 0.1.0
4
+ Summary: Django app installer and registry CLI
5
+ Author: Djux contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/djuxhq/djux
8
+ Project-URL: Repository, https://github.com/djuxhq/djux
9
+ Project-URL: Issues, https://github.com/djuxhq/djux/issues
10
+ Project-URL: Roadmap, https://github.com/djuxhq/djux/blob/main/APP_ROADMAP.md
11
+ Keywords: django,cli,scaffold,templates,registry
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Framework :: Django
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Code Generators
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: click>=8.1
25
+ Requires-Dist: requests>=2.31
26
+ Requires-Dist: rich>=13.0
27
+
28
+ # djux
29
+
30
+ **djux** is a CLI and registry for adding production-ready Django app templates to a project in one command. It handles the repetitive setup work: app files, Django settings, URL wiring, pip dependencies, and migrations.
31
+
32
+ ```bash
33
+ pip install djux
34
+
35
+ djux new myproject
36
+ cd myproject
37
+
38
+ djux add auth
39
+ ```
40
+
41
+ Think of it as a Django app installer where the installed code is copied into your project so you can own it, edit it, and ship it like normal Django code.
42
+
43
+ ## Vision
44
+
45
+ Djux aims to make reusable Django app templates easier to discover, install, inspect, and customize. The project is intentionally open to community feedback: the registry should grow around apps Django developers actually want, with a safe update story for vendored app code.
46
+
47
+ Current focus:
48
+
49
+ - Core app templates such as `auth`, `users`, `api-keys`, and `files`.
50
+ - AI-ready templates such as `ai-models`, `ai-prompts`, `ai-chat`, `ai-usage`, and `ai-rag`.
51
+ - A safer update workflow for copied app code: `djux outdated` and `djux update <app>`.
52
+
53
+ See [APP_ROADMAP.md](APP_ROADMAP.md) for the full roadmap.
54
+
55
+ ## Installation
56
+
57
+ Requires Python 3.10+.
58
+
59
+ ```bash
60
+ pip install djux
61
+ ```
62
+
63
+ Verify:
64
+
65
+ ```bash
66
+ djux --version
67
+ ```
68
+
69
+ ## Quick start
70
+
71
+ ```bash
72
+ # 1. Create a new project
73
+ djux new myproject
74
+ cd myproject
75
+
76
+ # 2. Set up your environment
77
+ python -m venv .venv
78
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
79
+ pip install -r requirements.txt
80
+ cp .env.example .env
81
+
82
+ # 3. Run initial migrations and start the server
83
+ python manage.py migrate
84
+ python manage.py runserver
85
+
86
+ # 4. Add apps
87
+ djux add auth
88
+ ```
89
+
90
+ See [docs/getting-started.md](docs/getting-started.md) for a full walkthrough.
91
+
92
+ ## Available apps
93
+
94
+ | Name | Description | Tags |
95
+ |---|---|---|
96
+ | `auth` | JWT authentication: register, login, logout, refresh, me | `auth` `jwt` `api` |
97
+ | `users` | User profiles, avatars, preferences | planned |
98
+ | `api-keys` | API keys, scopes, rotation, revocation | planned |
99
+ | `ai-chat` | Basic chat API with conversation history | planned `ai` |
100
+ | `ai-models` | Provider/model registry and model selection | planned `ai` |
101
+
102
+ ```bash
103
+ djux list
104
+ ```
105
+
106
+ ## How it works
107
+
108
+ `djux add <app>` currently:
109
+
110
+ 1. Looks up the app in the registry.
111
+ 2. Downloads and extracts the app zip from GitHub.
112
+ 3. Validates the `djux.json` manifest.
113
+ 4. Copies the `app/` folder into your project's `apps/` directory.
114
+ 5. Patches `config/settings.py` with `INSTALLED_APPS` entries and settings blocks.
115
+ 6. Patches `config/urls.py` with the route include.
116
+ 7. Runs `pip install` for declared dependencies.
117
+ 8. Runs `python manage.py migrate` if the app has migrations.
118
+ 9. Records the installed app in `djux.project.json`.
119
+
120
+ Installed apps are vendored into the project. That means developers fully own the copied code after install.
121
+
122
+ ## Project layout
123
+
124
+ ```text
125
+ myproject/
126
+ |-- config/
127
+ | |-- settings.py # djux patches INSTALLED_APPS here
128
+ | `-- urls.py # djux adds URL includes here
129
+ |-- apps/ # all Django apps land here
130
+ |-- templates/
131
+ |-- static/
132
+ |-- manage.py
133
+ |-- djux.project.json # tracks installed apps
134
+ `-- requirements.txt
135
+ ```
136
+
137
+ ## Documentation
138
+
139
+ | Document | Contents |
140
+ |---|---|
141
+ | [Getting started](docs/getting-started.md) | Install, scaffold, first app, what changed |
142
+ | [CLI reference](docs/cli-reference.md) | Commands, options, errors |
143
+ | [Creating apps](docs/creating-apps.md) | Build and publish a djux app |
144
+ | [Manifest spec](docs/manifest-spec.md) | `djux.json` contract and versioning rules |
145
+ | [App conventions](docs/app-conventions.md) | Naming, layout, settings, migrations |
146
+ | [Update design](docs/update-design.md) | Planned `djux outdated` and `djux update <app>` flow |
147
+ | [Smoke test checklist](docs/smoke-test-checklist.md) | Quality checklist for official apps |
148
+ | [Registry](docs/registry.md) | Registry format, caching, custom registries |
149
+
150
+ ## Repositories
151
+
152
+ | Repo | Purpose |
153
+ |---|---|
154
+ | [djuxhq/djux](https://github.com/djuxhq/djux) | CLI and project template |
155
+ | [djuxhq/djux-registry](https://github.com/djuxhq/djux-registry) | Registry index |
156
+ | [djuxhq/djux-app-auth](https://github.com/djuxhq/djux-app-auth) | Official auth app |
157
+
158
+ ## Contributing
159
+
160
+ Contributors and testers are welcome. Useful ways to help:
161
+
162
+ - Build official app templates.
163
+ - Test Djux in real Django projects.
164
+ - Improve the CLI and update workflow.
165
+ - Review app manifests and registry entries.
166
+ - Improve documentation.
167
+
168
+ Start with [CONTRIBUTING.md](CONTRIBUTING.md), then check the roadmap and open issues.
169
+
170
+ ## License
171
+
172
+ MIT
djux-0.1.0/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # djux
2
+
3
+ **djux** is a CLI and registry for adding production-ready Django app templates to a project in one command. It handles the repetitive setup work: app files, Django settings, URL wiring, pip dependencies, and migrations.
4
+
5
+ ```bash
6
+ pip install djux
7
+
8
+ djux new myproject
9
+ cd myproject
10
+
11
+ djux add auth
12
+ ```
13
+
14
+ Think of it as a Django app installer where the installed code is copied into your project so you can own it, edit it, and ship it like normal Django code.
15
+
16
+ ## Vision
17
+
18
+ Djux aims to make reusable Django app templates easier to discover, install, inspect, and customize. The project is intentionally open to community feedback: the registry should grow around apps Django developers actually want, with a safe update story for vendored app code.
19
+
20
+ Current focus:
21
+
22
+ - Core app templates such as `auth`, `users`, `api-keys`, and `files`.
23
+ - AI-ready templates such as `ai-models`, `ai-prompts`, `ai-chat`, `ai-usage`, and `ai-rag`.
24
+ - A safer update workflow for copied app code: `djux outdated` and `djux update <app>`.
25
+
26
+ See [APP_ROADMAP.md](APP_ROADMAP.md) for the full roadmap.
27
+
28
+ ## Installation
29
+
30
+ Requires Python 3.10+.
31
+
32
+ ```bash
33
+ pip install djux
34
+ ```
35
+
36
+ Verify:
37
+
38
+ ```bash
39
+ djux --version
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```bash
45
+ # 1. Create a new project
46
+ djux new myproject
47
+ cd myproject
48
+
49
+ # 2. Set up your environment
50
+ python -m venv .venv
51
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
52
+ pip install -r requirements.txt
53
+ cp .env.example .env
54
+
55
+ # 3. Run initial migrations and start the server
56
+ python manage.py migrate
57
+ python manage.py runserver
58
+
59
+ # 4. Add apps
60
+ djux add auth
61
+ ```
62
+
63
+ See [docs/getting-started.md](docs/getting-started.md) for a full walkthrough.
64
+
65
+ ## Available apps
66
+
67
+ | Name | Description | Tags |
68
+ |---|---|---|
69
+ | `auth` | JWT authentication: register, login, logout, refresh, me | `auth` `jwt` `api` |
70
+ | `users` | User profiles, avatars, preferences | planned |
71
+ | `api-keys` | API keys, scopes, rotation, revocation | planned |
72
+ | `ai-chat` | Basic chat API with conversation history | planned `ai` |
73
+ | `ai-models` | Provider/model registry and model selection | planned `ai` |
74
+
75
+ ```bash
76
+ djux list
77
+ ```
78
+
79
+ ## How it works
80
+
81
+ `djux add <app>` currently:
82
+
83
+ 1. Looks up the app in the registry.
84
+ 2. Downloads and extracts the app zip from GitHub.
85
+ 3. Validates the `djux.json` manifest.
86
+ 4. Copies the `app/` folder into your project's `apps/` directory.
87
+ 5. Patches `config/settings.py` with `INSTALLED_APPS` entries and settings blocks.
88
+ 6. Patches `config/urls.py` with the route include.
89
+ 7. Runs `pip install` for declared dependencies.
90
+ 8. Runs `python manage.py migrate` if the app has migrations.
91
+ 9. Records the installed app in `djux.project.json`.
92
+
93
+ Installed apps are vendored into the project. That means developers fully own the copied code after install.
94
+
95
+ ## Project layout
96
+
97
+ ```text
98
+ myproject/
99
+ |-- config/
100
+ | |-- settings.py # djux patches INSTALLED_APPS here
101
+ | `-- urls.py # djux adds URL includes here
102
+ |-- apps/ # all Django apps land here
103
+ |-- templates/
104
+ |-- static/
105
+ |-- manage.py
106
+ |-- djux.project.json # tracks installed apps
107
+ `-- requirements.txt
108
+ ```
109
+
110
+ ## Documentation
111
+
112
+ | Document | Contents |
113
+ |---|---|
114
+ | [Getting started](docs/getting-started.md) | Install, scaffold, first app, what changed |
115
+ | [CLI reference](docs/cli-reference.md) | Commands, options, errors |
116
+ | [Creating apps](docs/creating-apps.md) | Build and publish a djux app |
117
+ | [Manifest spec](docs/manifest-spec.md) | `djux.json` contract and versioning rules |
118
+ | [App conventions](docs/app-conventions.md) | Naming, layout, settings, migrations |
119
+ | [Update design](docs/update-design.md) | Planned `djux outdated` and `djux update <app>` flow |
120
+ | [Smoke test checklist](docs/smoke-test-checklist.md) | Quality checklist for official apps |
121
+ | [Registry](docs/registry.md) | Registry format, caching, custom registries |
122
+
123
+ ## Repositories
124
+
125
+ | Repo | Purpose |
126
+ |---|---|
127
+ | [djuxhq/djux](https://github.com/djuxhq/djux) | CLI and project template |
128
+ | [djuxhq/djux-registry](https://github.com/djuxhq/djux-registry) | Registry index |
129
+ | [djuxhq/djux-app-auth](https://github.com/djuxhq/djux-app-auth) | Official auth app |
130
+
131
+ ## Contributing
132
+
133
+ Contributors and testers are welcome. Useful ways to help:
134
+
135
+ - Build official app templates.
136
+ - Test Djux in real Django projects.
137
+ - Improve the CLI and update workflow.
138
+ - Review app manifests and registry entries.
139
+ - Improve documentation.
140
+
141
+ Start with [CONTRIBUTING.md](CONTRIBUTING.md), then check the roadmap and open issues.
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
djux-0.1.0/djux/cli.py ADDED
@@ -0,0 +1,30 @@
1
+ import os
2
+ import sys
3
+
4
+ # Ensure UTF-8 output on Windows (required for Rich/Unicode characters)
5
+ if sys.platform == "win32":
6
+ os.environ.setdefault("PYTHONUTF8", "1")
7
+ if hasattr(sys.stdout, "reconfigure"):
8
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
9
+ if hasattr(sys.stderr, "reconfigure"):
10
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
11
+
12
+ import click
13
+ from djux.commands.new import new
14
+ from djux.commands.add import add
15
+ from djux.commands.remove import remove
16
+ from djux.commands.list import list_apps
17
+ from djux.commands.publish import publish
18
+
19
+
20
+ @click.group()
21
+ @click.version_option(package_name="djux")
22
+ def main():
23
+ """djux — add production-ready Django apps in one command."""
24
+
25
+
26
+ main.add_command(new)
27
+ main.add_command(add)
28
+ main.add_command(remove)
29
+ main.add_command(list_apps, name="list")
30
+ main.add_command(publish)
File without changes
@@ -0,0 +1,207 @@
1
+ import json
2
+ import shutil
3
+ import subprocess
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ import click
8
+ from rich.console import Console
9
+
10
+ from djux.core.downloader import download_and_extract
11
+ from djux.core.manifest import InvalidManifestError, parse_manifest
12
+ from djux.core.patcher import (
13
+ patch_installed_apps,
14
+ patch_settings_block,
15
+ patch_urls,
16
+ )
17
+ from djux.core.registry import REGISTRY_URL, fetch_registry, get_app
18
+
19
+ console = Console()
20
+
21
+
22
+ def _find_project_root() -> Path | None:
23
+ current = Path.cwd()
24
+ for parent in [current, *current.parents]:
25
+ if (parent / "djux.project.json").exists():
26
+ return parent
27
+ return None
28
+
29
+
30
+ def _read_project_json(root: Path) -> dict:
31
+ return json.loads((root / "djux.project.json").read_text(encoding="utf-8"))
32
+
33
+
34
+ def _write_project_json(root: Path, data: dict) -> None:
35
+ (root / "djux.project.json").write_text(
36
+ json.dumps(data, indent=2), encoding="utf-8"
37
+ )
38
+
39
+
40
+ @click.command()
41
+ @click.argument("app_name")
42
+ @click.option("--registry", "registry_url", default=REGISTRY_URL, help="Custom registry URL.")
43
+ def add(app_name: str, registry_url: str):
44
+ """Download and install a djux app into the current project."""
45
+
46
+ # 1. Find project root
47
+ root = _find_project_root()
48
+ if root is None:
49
+ console.print("✗ No djux project found. Run this inside a djx project.")
50
+ raise SystemExit(1)
51
+
52
+ # 2. Check if already installed
53
+ project_data = _read_project_json(root)
54
+ if app_name in project_data.get("installed_apps", []):
55
+ console.print(f"⚠ App '[bold]{app_name}[/bold]' is already installed.")
56
+ raise SystemExit(0)
57
+
58
+ # 3. Fetch registry
59
+ with console.status("Fetching registry..."):
60
+ try:
61
+ registry = fetch_registry(registry_url)
62
+ except RuntimeError as e:
63
+ console.print(f"✗ {e}")
64
+ raise SystemExit(1)
65
+
66
+ app_entry = get_app(registry, app_name)
67
+ if app_entry is None:
68
+ console.print(
69
+ f"✗ App '[bold]{app_name}[/bold]' not found in registry.\n"
70
+ " Run [cyan]djux list[/cyan] to see available apps."
71
+ )
72
+ raise SystemExit(1)
73
+
74
+ console.print(f"✓ Found [bold]{app_name}[/bold] v{app_entry.get('version', '?')}")
75
+
76
+ # 4-5. Download and extract
77
+ with console.status("Downloading..."):
78
+ try:
79
+ extracted = download_and_extract(app_entry["download"], app_name)
80
+ except Exception as e:
81
+ console.print(f"✗ Download failed: {e}")
82
+ raise SystemExit(1)
83
+
84
+ console.print("✓ Downloaded")
85
+
86
+ # 6. Validate manifest
87
+ try:
88
+ manifest = parse_manifest(extracted)
89
+ except InvalidManifestError as e:
90
+ console.print(f"✗ {e}")
91
+ raise SystemExit(1)
92
+
93
+ # 7. Check required apps
94
+ requires = manifest.get("requires_apps", [])
95
+ installed = project_data.get("installed_apps", [])
96
+ for dep in requires:
97
+ if dep not in installed:
98
+ console.print(
99
+ f"✗ App '[bold]{app_name}[/bold]' requires "
100
+ f"'[bold]{dep}[/bold]' to be installed first.\n"
101
+ f" Run: [cyan]djux add {dep}[/cyan]"
102
+ )
103
+ raise SystemExit(1)
104
+
105
+ # 8. Copy app code
106
+ app_src = extracted / "app"
107
+ if not app_src.exists():
108
+ console.print("✗ App package is missing the 'app/' directory.")
109
+ raise SystemExit(1)
110
+
111
+ install_name = app_name
112
+ app_dest = root / "apps" / install_name
113
+
114
+ if app_dest.exists():
115
+ console.print(
116
+ f"\n[yellow]Warning:[/yellow] Directory 'apps/{install_name}' already exists."
117
+ )
118
+ while True:
119
+ new_name = click.prompt(
120
+ " Enter a new name to install as (or leave empty to cancel)",
121
+ default="",
122
+ show_default=False,
123
+ ).strip()
124
+
125
+ if not new_name:
126
+ console.print("Cancelled.")
127
+ raise SystemExit(0)
128
+
129
+ import re as _re
130
+ if not _re.match(r"^[a-z][a-z0-9_]*$", new_name):
131
+ console.print(
132
+ " [red]Invalid name.[/red] Use lowercase letters, digits, and underscores only."
133
+ )
134
+ continue
135
+
136
+ app_dest = root / "apps" / new_name
137
+ if app_dest.exists():
138
+ console.print(f" [red]Directory 'apps/{new_name}' also exists.[/red] Try another name.")
139
+ continue
140
+
141
+ install_name = new_name
142
+ console.print(f" Installing as '[bold]{install_name}[/bold]'")
143
+ break
144
+
145
+ shutil.copytree(app_src, app_dest)
146
+ console.print(f"✓ App files copied to apps/{install_name}/")
147
+
148
+ # 9. Patch settings.py
149
+ settings_path = root / "config" / "settings.py"
150
+ patch_installed_apps(settings_path, manifest["installed_apps"])
151
+
152
+ settings_patch = manifest.get("settings_patch")
153
+ if settings_patch:
154
+ patch_settings_block(settings_path, settings_patch)
155
+
156
+ console.print("✓ settings.py updated")
157
+
158
+ # 10. Patch urls.py — use install_name so the URL include matches the folder
159
+ urls_path = root / "config" / "urls.py"
160
+ patch_urls(urls_path, install_name, manifest["url_prefix"])
161
+ console.print("✓ urls.py updated")
162
+
163
+ # 11. Install pip dependencies
164
+ deps = manifest.get("dependencies", [])
165
+ if deps:
166
+ with console.status("Installing dependencies..."):
167
+ result = subprocess.run(
168
+ [sys.executable, "-m", "pip", "install", *deps],
169
+ capture_output=True,
170
+ text=True,
171
+ )
172
+ if result.returncode != 0:
173
+ console.print(f"✗ pip install failed:\n{result.stderr}")
174
+ raise SystemExit(1)
175
+ console.print("✓ Dependencies installed")
176
+
177
+ # 12. Run migrations
178
+ if manifest.get("migrations", False):
179
+ with console.status("Running migrations..."):
180
+ result = subprocess.run(
181
+ [sys.executable, "manage.py", "migrate"],
182
+ cwd=root,
183
+ capture_output=True,
184
+ text=True,
185
+ )
186
+ if result.returncode != 0:
187
+ console.print(f"✗ migrate failed:\n{result.stderr}")
188
+ raise SystemExit(1)
189
+ console.print("✓ Migrations applied")
190
+
191
+ # 13. Update djux.project.json
192
+ project_data.setdefault("installed_apps", []).append(install_name)
193
+ _write_project_json(root, project_data)
194
+
195
+ # 14. Print success
196
+ label = f"{app_name}" if install_name == app_name else f"{app_name} (as '{install_name}')"
197
+ console.print(f"\n[green]✓ {label} added successfully![/green]")
198
+
199
+ env_vars = manifest.get("env_vars", [])
200
+ if env_vars:
201
+ console.print("\nRequired environment variables:")
202
+ for var in env_vars:
203
+ console.print(f" • [yellow]{var}[/yellow]")
204
+
205
+ notes = manifest.get("notes")
206
+ if notes:
207
+ console.print(f"\nNotes: {notes}")
@@ -0,0 +1,45 @@
1
+ import click
2
+ from rich.console import Console
3
+ from rich.table import Table
4
+
5
+ from djux.core.registry import REGISTRY_URL, fetch_registry
6
+
7
+ console = Console()
8
+
9
+
10
+ @click.command()
11
+ @click.option("--registry", "registry_url", default=REGISTRY_URL, help="Custom registry URL.")
12
+ @click.option("--refresh", is_flag=True, help="Bypass cache and fetch fresh registry.")
13
+ def list_apps(registry_url: str, refresh: bool):
14
+ """Show all apps available in the djux registry."""
15
+ with console.status("Fetching registry..."):
16
+ try:
17
+ registry = fetch_registry(registry_url, force_refresh=refresh)
18
+ except RuntimeError as e:
19
+ console.print(f"✗ {e}")
20
+ raise SystemExit(1)
21
+
22
+ apps = registry.get("apps", {})
23
+ if not apps:
24
+ console.print("No apps found in registry.")
25
+ return
26
+
27
+ table = Table(title="Available djux Apps", border_style="blue")
28
+ table.add_column("Name", style="bold cyan", no_wrap=True)
29
+ table.add_column("Version", style="green")
30
+ table.add_column("Description")
31
+ table.add_column("Tags", style="dim")
32
+
33
+ for name, info in apps.items():
34
+ tags = ", ".join(info.get("tags", []))
35
+ official = " [yellow]★[/yellow]" if info.get("official") else ""
36
+ table.add_row(
37
+ f"{name}{official}",
38
+ info.get("version", "?"),
39
+ info.get("description", ""),
40
+ tags,
41
+ )
42
+
43
+ console.print(table)
44
+ console.print("\n Install any app: [bold cyan]djux add <name>[/bold cyan]")
45
+ console.print(" [yellow]★[/yellow] = official djux app")
@@ -0,0 +1,51 @@
1
+ import shutil
2
+ from pathlib import Path
3
+
4
+ import click
5
+ from rich.console import Console
6
+ from rich.panel import Panel
7
+
8
+ console = Console()
9
+
10
+ TEMPLATE_DIR = Path(__file__).parent.parent / "templates" / "project_template"
11
+
12
+
13
+ def _replace_in_file(path: Path, project_name: str) -> None:
14
+ try:
15
+ text = path.read_text(encoding="utf-8")
16
+ path.write_text(text.replace("{{project_name}}", project_name), encoding="utf-8")
17
+ except (UnicodeDecodeError, PermissionError):
18
+ pass # skip binary files
19
+
20
+
21
+ @click.command()
22
+ @click.argument("project_name")
23
+ def new(project_name: str):
24
+ """Scaffold a new djux Django project."""
25
+ target = Path.cwd() / project_name
26
+
27
+ if target.exists():
28
+ console.print(f"✗ Directory '[bold]{project_name}[/bold]' already exists.")
29
+ raise SystemExit(1)
30
+
31
+ console.print(f"Creating project: [bold]{project_name}[/bold]\n")
32
+
33
+ shutil.copytree(TEMPLATE_DIR, target)
34
+
35
+ for file_path in target.rglob("*"):
36
+ if file_path.is_file():
37
+ _replace_in_file(file_path, project_name)
38
+
39
+ panel_content = (
40
+ f"[green]✓[/green] Project created: [bold]{project_name}/[/bold]\n\n"
41
+ f" [cyan]cd {project_name}[/cyan]\n"
42
+ f" [cyan]python -m venv .venv[/cyan]\n"
43
+ f" [cyan]source .venv/bin/activate[/cyan] [dim]# Windows: .venv\\Scripts\\activate[/dim]\n"
44
+ f" [cyan]pip install -r requirements.txt[/cyan]\n"
45
+ f" [cyan]cp .env.example .env[/cyan]\n"
46
+ f" [cyan]python manage.py migrate[/cyan]\n"
47
+ f" [cyan]python manage.py runserver[/cyan]\n\n"
48
+ f" Then add apps: [bold cyan]djux add auth[/bold cyan]"
49
+ )
50
+
51
+ console.print(Panel(panel_content, title="Ready", border_style="green"))