xgic-dev-cli 0.2.0__tar.gz → 0.2.1__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.
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/.gitignore +4 -0
- xgic_dev_cli-0.2.1/PKG-INFO +200 -0
- xgic_dev_cli-0.2.1/README.md +166 -0
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/pyproject.toml +2 -2
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/__init__.py +1 -1
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/commands/check.py +16 -6
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/commands/env_cmd.py +15 -6
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/commands/lifecycle.py +27 -1
- xgic_dev_cli-0.2.1/src/xgic/cli/dev/context.py +105 -0
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/docker.py +12 -4
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/plugin.py +7 -7
- xgic_dev_cli-0.2.0/PKG-INFO +0 -114
- xgic_dev_cli-0.2.0/README.md +0 -80
- xgic_dev_cli-0.2.0/src/xgic/cli/dev/context.py +0 -54
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/LICENSE +0 -0
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/NOTICE +0 -0
- {xgic_dev_cli-0.2.0 → xgic_dev_cli-0.2.1}/src/xgic/cli/dev/commands/__init__.py +0 -0
|
@@ -26,5 +26,9 @@ venv/
|
|
|
26
26
|
.DS_Store
|
|
27
27
|
Thumbs.db
|
|
28
28
|
|
|
29
|
+
# Lockfile: this repo is a PyPI library/CLI module, not an application.
|
|
30
|
+
# Applications should commit uv.lock; libraries gitignore it.
|
|
31
|
+
uv.lock
|
|
32
|
+
|
|
29
33
|
# .xgic/ directory for temporary Grok Build status reports (mandatory per new standard). All reports are temporary working artifacts only and must never be committed. This is required for the mandatory session status report functionality.
|
|
30
34
|
.xgic/
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: xgic-dev-cli
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: XGIC CLI Dev Container module - Docker Compose orchestration and xgic lifecycle commands (xgic.cli.dev).
|
|
5
|
+
Project-URL: Homepage, https://github.com/xgic/dev-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/xgic/dev-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/xgic/dev-cli/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/xgic/dev-cli#readme
|
|
9
|
+
Project-URL: Changelog, https://github.com/xgic/dev-cli/releases
|
|
10
|
+
Author: XGIC
|
|
11
|
+
License: Apache-2.0
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
License-File: NOTICE
|
|
14
|
+
Keywords: cli,dev-containers,docker-compose,orchestration,xgic
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.14
|
|
25
|
+
Requires-Dist: rich>=13.7
|
|
26
|
+
Requires-Dist: xgic-cli>=0.2.1
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# XGIC Dev Container CLI
|
|
36
|
+
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](https://pypi.org/project/xgic-dev-cli/)
|
|
39
|
+
[](https://pypi.org/project/xgic-dev-cli/)
|
|
40
|
+
[](https://github.com/xgic/dev-cli/actions/workflows/ci.yml)
|
|
41
|
+
[](https://github.com/xgic/dev-cli/releases)
|
|
42
|
+
|
|
43
|
+
**Product-agnostic Docker Compose and Dev Container lifecycle for the modular [XGIC CLI](https://github.com/xgic/cli).**
|
|
44
|
+
|
|
45
|
+
Namespace: **`xgic.cli.dev`** · Console entry: **`xgic`** (plugins via entry points) · Brand: **XGIC CLI only** ([ADR-0005](https://github.com/xgic/ai/blob/main/docs/adr/0005-modular-xgic-cli-and-retirement-of-xde.md))
|
|
46
|
+
|
|
47
|
+
Standards hub: [xgic/ai](https://github.com/xgic/ai)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Vision
|
|
52
|
+
|
|
53
|
+
Environment orchestration should be **predictable, documented, and AI-operable**. This package owns the **generic** lifecycle that every XGIC Dev Container product needs—`up`, `down`, `check`, logs, shell—without embedding Payload-specific or other product logic.
|
|
54
|
+
|
|
55
|
+
Humans get a stable command map. AI agents get the same map in [AGENTS.md](AGENTS.md) instead of inventing Make targets or host-global installs.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Why this module exists
|
|
60
|
+
|
|
61
|
+
| Benefit | Detail |
|
|
62
|
+
|---------|--------|
|
|
63
|
+
| **Separation of concerns** | Core CLI stays thin; product commands live in domain modules |
|
|
64
|
+
| **Reuse across products** | Same lifecycle for Payload, GitLab tooling, and future stacks |
|
|
65
|
+
| **Configuration over hard-coding** | Compose file, project, service, and profile via flags or env |
|
|
66
|
+
| **Safe defaults for agents** | Destructive actions require explicit confirmation (`--yes`) |
|
|
67
|
+
| **Open-source rigor** | Apache-2.0, Python 3.14+, PyPI release discipline |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Ecosystem
|
|
72
|
+
|
|
73
|
+
| Package | Role |
|
|
74
|
+
|---------|------|
|
|
75
|
+
| [xgic/cli](https://github.com/xgic/cli) | Thin core framework (`xgic`) |
|
|
76
|
+
| **This repo** | Dev Container / Docker Compose lifecycle (`xgic.cli.dev`) |
|
|
77
|
+
| [xgic/payload-cms-cli](https://github.com/xgic/payload-cms-cli) | Payload product commands (`xgic payload …`) |
|
|
78
|
+
| [xgic/payload-cms-dev](https://github.com/xgic/payload-cms-dev) | Payload Dev Container **image producer** |
|
|
79
|
+
| [xgic/payload-cms](https://github.com/xgic/payload-cms) | Payload **end-user template** (consumes GHCR image) |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
### Install (PyPI)
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv pip install "xgic-dev-cli>=0.2.1"
|
|
89
|
+
xgic --help
|
|
90
|
+
xgic up --help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Development (editable monorepo layout)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
uv pip install -e ../cli
|
|
97
|
+
uv pip install -e ".[dev]"
|
|
98
|
+
xgic --help
|
|
99
|
+
xgic up --help
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Typical session
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
export XGIC_COMPOSE_FILE=.devcontainer/docker-compose.yml
|
|
106
|
+
export XGIC_COMPOSE_PROJECT=my-project
|
|
107
|
+
export XGIC_PRIMARY_SERVICE=app
|
|
108
|
+
|
|
109
|
+
xgic up --profile postgres
|
|
110
|
+
xgic check
|
|
111
|
+
xgic logs
|
|
112
|
+
xgic down
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Console commands
|
|
118
|
+
|
|
119
|
+
Registered on the core `xgic` entrypoint:
|
|
120
|
+
|
|
121
|
+
| Command | Purpose |
|
|
122
|
+
|---------|---------|
|
|
123
|
+
| `xgic up` | Start Compose services (detached) |
|
|
124
|
+
| `xgic down` | Stop services (volumes preserved) |
|
|
125
|
+
| `xgic build [--no-cache]` | Build or rebuild images |
|
|
126
|
+
| `xgic logs` | Follow service logs |
|
|
127
|
+
| `xgic shell` | Shell in primary service (`--service` if unset) |
|
|
128
|
+
| `xgic clean --yes` | Destructive: volumes + `.devcontainer/.env` |
|
|
129
|
+
| `xgic check [--json]` | Services + environment diagnostic |
|
|
130
|
+
| `xgic env [--json]` | Environment status (no secret regeneration) |
|
|
131
|
+
|
|
132
|
+
### Common flags / environment
|
|
133
|
+
|
|
134
|
+
| Flag | Env var | Default |
|
|
135
|
+
|------|---------|---------|
|
|
136
|
+
| `--compose-file` | `XGIC_COMPOSE_FILE` | `.devcontainer/docker-compose.yml` |
|
|
137
|
+
| `--project` | `XGIC_COMPOSE_PROJECT` | Compose file `name:` (else `xgic-dev`) |
|
|
138
|
+
| `--service` | `XGIC_PRIMARY_SERVICE` | `devcontainer.json` `service` (else none) |
|
|
139
|
+
| `--profile` | `XGIC_COMPOSE_PROFILE` | (none; used by `up`) |
|
|
140
|
+
|
|
141
|
+
**Note:** Payload-specific env regenerate / setup lives in **[payload-cms-cli](https://github.com/xgic/payload-cms-cli)** (`xgic payload env`, `xgic payload setup`, …).
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Library API
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from xgic.cli.core import EnvironmentContext
|
|
149
|
+
from xgic.cli.dev import DockerComposeController
|
|
150
|
+
|
|
151
|
+
env = EnvironmentContext.detect()
|
|
152
|
+
docker = DockerComposeController(
|
|
153
|
+
env=env,
|
|
154
|
+
compose_file=".devcontainer/docker-compose.yml",
|
|
155
|
+
project_name="my-project",
|
|
156
|
+
primary_service="app",
|
|
157
|
+
)
|
|
158
|
+
docker.up(profile="postgres")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Requirements
|
|
164
|
+
|
|
165
|
+
- Python **3.14+**
|
|
166
|
+
- `xgic-cli` ≥ 0.2.1
|
|
167
|
+
- Docker / Docker Compose on the host when running lifecycle commands
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Publishing
|
|
172
|
+
|
|
173
|
+
Follow [python-package-release.md](https://github.com/xgic/ai/blob/main/docs/python-package-release.md).
|
|
174
|
+
|
|
175
|
+
Publish **after** `xgic-cli` for stack releases. Tags: `vX.Y.ZrcN` → TestPyPI; `vX.Y.Z` → PyPI.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Working with AI assistants
|
|
180
|
+
|
|
181
|
+
- Prefer documented `xgic` lifecycle commands over ad-hoc `docker compose` one-liners in agent prompts.
|
|
182
|
+
- Point agents at [AGENTS.md](AGENTS.md) and the hub [catalog](https://github.com/xgic/ai/blob/main/docs/ecosystem/catalog.md).
|
|
183
|
+
- Public issues/PRs: [BASE-STANDARDS public-safe gate](https://github.com/xgic/ai/blob/main/docs/BASE-STANDARDS-FOR-ORCHESTRATED-REPOS.md).
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Contributing
|
|
188
|
+
|
|
189
|
+
PRs with human UI review only. Conventional Commits; labels required. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
196
|
+
Copyright form: `Copyright 2026 XGIC`.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
**XGIC** — Modular CLI architecture for open-source developer platforms: thin core, domain modules, AI-operable commands.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# XGIC Dev Container CLI
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://pypi.org/project/xgic-dev-cli/)
|
|
5
|
+
[](https://pypi.org/project/xgic-dev-cli/)
|
|
6
|
+
[](https://github.com/xgic/dev-cli/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/xgic/dev-cli/releases)
|
|
8
|
+
|
|
9
|
+
**Product-agnostic Docker Compose and Dev Container lifecycle for the modular [XGIC CLI](https://github.com/xgic/cli).**
|
|
10
|
+
|
|
11
|
+
Namespace: **`xgic.cli.dev`** · Console entry: **`xgic`** (plugins via entry points) · Brand: **XGIC CLI only** ([ADR-0005](https://github.com/xgic/ai/blob/main/docs/adr/0005-modular-xgic-cli-and-retirement-of-xde.md))
|
|
12
|
+
|
|
13
|
+
Standards hub: [xgic/ai](https://github.com/xgic/ai)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Vision
|
|
18
|
+
|
|
19
|
+
Environment orchestration should be **predictable, documented, and AI-operable**. This package owns the **generic** lifecycle that every XGIC Dev Container product needs—`up`, `down`, `check`, logs, shell—without embedding Payload-specific or other product logic.
|
|
20
|
+
|
|
21
|
+
Humans get a stable command map. AI agents get the same map in [AGENTS.md](AGENTS.md) instead of inventing Make targets or host-global installs.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Why this module exists
|
|
26
|
+
|
|
27
|
+
| Benefit | Detail |
|
|
28
|
+
|---------|--------|
|
|
29
|
+
| **Separation of concerns** | Core CLI stays thin; product commands live in domain modules |
|
|
30
|
+
| **Reuse across products** | Same lifecycle for Payload, GitLab tooling, and future stacks |
|
|
31
|
+
| **Configuration over hard-coding** | Compose file, project, service, and profile via flags or env |
|
|
32
|
+
| **Safe defaults for agents** | Destructive actions require explicit confirmation (`--yes`) |
|
|
33
|
+
| **Open-source rigor** | Apache-2.0, Python 3.14+, PyPI release discipline |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Ecosystem
|
|
38
|
+
|
|
39
|
+
| Package | Role |
|
|
40
|
+
|---------|------|
|
|
41
|
+
| [xgic/cli](https://github.com/xgic/cli) | Thin core framework (`xgic`) |
|
|
42
|
+
| **This repo** | Dev Container / Docker Compose lifecycle (`xgic.cli.dev`) |
|
|
43
|
+
| [xgic/payload-cms-cli](https://github.com/xgic/payload-cms-cli) | Payload product commands (`xgic payload …`) |
|
|
44
|
+
| [xgic/payload-cms-dev](https://github.com/xgic/payload-cms-dev) | Payload Dev Container **image producer** |
|
|
45
|
+
| [xgic/payload-cms](https://github.com/xgic/payload-cms) | Payload **end-user template** (consumes GHCR image) |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
### Install (PyPI)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv pip install "xgic-dev-cli>=0.2.1"
|
|
55
|
+
xgic --help
|
|
56
|
+
xgic up --help
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Development (editable monorepo layout)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv pip install -e ../cli
|
|
63
|
+
uv pip install -e ".[dev]"
|
|
64
|
+
xgic --help
|
|
65
|
+
xgic up --help
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Typical session
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
export XGIC_COMPOSE_FILE=.devcontainer/docker-compose.yml
|
|
72
|
+
export XGIC_COMPOSE_PROJECT=my-project
|
|
73
|
+
export XGIC_PRIMARY_SERVICE=app
|
|
74
|
+
|
|
75
|
+
xgic up --profile postgres
|
|
76
|
+
xgic check
|
|
77
|
+
xgic logs
|
|
78
|
+
xgic down
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Console commands
|
|
84
|
+
|
|
85
|
+
Registered on the core `xgic` entrypoint:
|
|
86
|
+
|
|
87
|
+
| Command | Purpose |
|
|
88
|
+
|---------|---------|
|
|
89
|
+
| `xgic up` | Start Compose services (detached) |
|
|
90
|
+
| `xgic down` | Stop services (volumes preserved) |
|
|
91
|
+
| `xgic build [--no-cache]` | Build or rebuild images |
|
|
92
|
+
| `xgic logs` | Follow service logs |
|
|
93
|
+
| `xgic shell` | Shell in primary service (`--service` if unset) |
|
|
94
|
+
| `xgic clean --yes` | Destructive: volumes + `.devcontainer/.env` |
|
|
95
|
+
| `xgic check [--json]` | Services + environment diagnostic |
|
|
96
|
+
| `xgic env [--json]` | Environment status (no secret regeneration) |
|
|
97
|
+
|
|
98
|
+
### Common flags / environment
|
|
99
|
+
|
|
100
|
+
| Flag | Env var | Default |
|
|
101
|
+
|------|---------|---------|
|
|
102
|
+
| `--compose-file` | `XGIC_COMPOSE_FILE` | `.devcontainer/docker-compose.yml` |
|
|
103
|
+
| `--project` | `XGIC_COMPOSE_PROJECT` | Compose file `name:` (else `xgic-dev`) |
|
|
104
|
+
| `--service` | `XGIC_PRIMARY_SERVICE` | `devcontainer.json` `service` (else none) |
|
|
105
|
+
| `--profile` | `XGIC_COMPOSE_PROFILE` | (none; used by `up`) |
|
|
106
|
+
|
|
107
|
+
**Note:** Payload-specific env regenerate / setup lives in **[payload-cms-cli](https://github.com/xgic/payload-cms-cli)** (`xgic payload env`, `xgic payload setup`, …).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Library API
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from xgic.cli.core import EnvironmentContext
|
|
115
|
+
from xgic.cli.dev import DockerComposeController
|
|
116
|
+
|
|
117
|
+
env = EnvironmentContext.detect()
|
|
118
|
+
docker = DockerComposeController(
|
|
119
|
+
env=env,
|
|
120
|
+
compose_file=".devcontainer/docker-compose.yml",
|
|
121
|
+
project_name="my-project",
|
|
122
|
+
primary_service="app",
|
|
123
|
+
)
|
|
124
|
+
docker.up(profile="postgres")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Requirements
|
|
130
|
+
|
|
131
|
+
- Python **3.14+**
|
|
132
|
+
- `xgic-cli` ≥ 0.2.1
|
|
133
|
+
- Docker / Docker Compose on the host when running lifecycle commands
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Publishing
|
|
138
|
+
|
|
139
|
+
Follow [python-package-release.md](https://github.com/xgic/ai/blob/main/docs/python-package-release.md).
|
|
140
|
+
|
|
141
|
+
Publish **after** `xgic-cli` for stack releases. Tags: `vX.Y.ZrcN` → TestPyPI; `vX.Y.Z` → PyPI.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Working with AI assistants
|
|
146
|
+
|
|
147
|
+
- Prefer documented `xgic` lifecycle commands over ad-hoc `docker compose` one-liners in agent prompts.
|
|
148
|
+
- Point agents at [AGENTS.md](AGENTS.md) and the hub [catalog](https://github.com/xgic/ai/blob/main/docs/ecosystem/catalog.md).
|
|
149
|
+
- Public issues/PRs: [BASE-STANDARDS public-safe gate](https://github.com/xgic/ai/blob/main/docs/BASE-STANDARDS-FOR-ORCHESTRATED-REPOS.md).
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Contributing
|
|
154
|
+
|
|
155
|
+
PRs with human UI review only. Conventional Commits; labels required. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
162
|
+
Copyright form: `Copyright 2026 XGIC`.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
**XGIC** — Modular CLI architecture for open-source developer platforms: thin core, domain modules, AI-operable commands.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xgic-dev-cli"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "XGIC CLI Dev Container module - Docker Compose orchestration and xgic lifecycle commands (xgic.cli.dev)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -13,7 +13,7 @@ authors = [
|
|
|
13
13
|
]
|
|
14
14
|
requires-python = ">=3.14"
|
|
15
15
|
dependencies = [
|
|
16
|
-
"xgic-cli>=0.2.
|
|
16
|
+
"xgic-cli>=0.2.1",
|
|
17
17
|
"rich>=13.7",
|
|
18
18
|
]
|
|
19
19
|
keywords = [
|
|
@@ -12,24 +12,34 @@ from xgic.cli.utils.output import print_info, print_success, print_warning
|
|
|
12
12
|
def run_check(ctx: CommandContext) -> int:
|
|
13
13
|
"""Lightweight compose + environment health check."""
|
|
14
14
|
docker = make_docker(ctx.env, ctx.args)
|
|
15
|
-
|
|
15
|
+
cli_ok = docker.docker_cli_available()
|
|
16
|
+
services_ok = docker.services_running() if cli_ok else False
|
|
16
17
|
use_json = bool(getattr(ctx.args, "json", False))
|
|
17
18
|
|
|
18
19
|
if use_json:
|
|
19
20
|
result = {
|
|
21
|
+
"docker_cli_available": cli_ok,
|
|
20
22
|
"services_running": services_ok,
|
|
21
23
|
"compose_file": docker.compose_file,
|
|
22
24
|
"project_name": docker.project_name,
|
|
23
25
|
"primary_service": docker.primary_service,
|
|
24
26
|
"environment": ctx.env.describe(),
|
|
25
|
-
"overall_ok": services_ok,
|
|
27
|
+
"overall_ok": cli_ok and services_ok,
|
|
26
28
|
}
|
|
27
29
|
print(json.dumps(result, indent=2))
|
|
28
|
-
return 0 if
|
|
30
|
+
return 0 if result["overall_ok"] else 1
|
|
29
31
|
|
|
30
32
|
print_info("Running environment health checks...")
|
|
31
33
|
|
|
32
|
-
if
|
|
34
|
+
if not cli_ok:
|
|
35
|
+
print_warning(
|
|
36
|
+
"Docker CLI not found on PATH. Cannot query Compose services."
|
|
37
|
+
)
|
|
38
|
+
print_info(
|
|
39
|
+
"Install a Docker client (Docker-outside-of-Docker) or run "
|
|
40
|
+
"lifecycle commands where `docker` is on PATH."
|
|
41
|
+
)
|
|
42
|
+
elif services_ok:
|
|
33
43
|
print_success("Docker Compose services: running")
|
|
34
44
|
else:
|
|
35
45
|
print_warning(
|
|
@@ -37,13 +47,13 @@ def run_check(ctx: CommandContext) -> int:
|
|
|
37
47
|
)
|
|
38
48
|
print_info("Suggestion: Run `xgic up` to start services.")
|
|
39
49
|
|
|
40
|
-
print_info(f"Compose file: {docker.compose_file}")
|
|
50
|
+
print_info(f"Docker Compose file: {docker.compose_file}")
|
|
41
51
|
print_info(f"Project: {docker.project_name}")
|
|
42
52
|
if docker.primary_service:
|
|
43
53
|
print_info(f"Primary service: {docker.primary_service}")
|
|
44
54
|
print_info("Environment context: " + ctx.env.describe())
|
|
45
55
|
|
|
46
|
-
if services_ok:
|
|
56
|
+
if cli_ok and services_ok:
|
|
47
57
|
print_success("Basic environment check passed")
|
|
48
58
|
return 0
|
|
49
59
|
return 1
|
|
@@ -16,7 +16,8 @@ def run_env(ctx: CommandContext) -> int:
|
|
|
16
16
|
"""Inspect development environment status (no regenerate in this module)."""
|
|
17
17
|
docker = make_docker(ctx.env, ctx.args)
|
|
18
18
|
env_file_exists = ENV_FILE.exists()
|
|
19
|
-
|
|
19
|
+
cli_ok = docker.docker_cli_available()
|
|
20
|
+
services_ok = docker.services_running() if cli_ok else False
|
|
20
21
|
use_json = bool(getattr(ctx.args, "json", False))
|
|
21
22
|
|
|
22
23
|
if use_json:
|
|
@@ -25,6 +26,7 @@ def run_env(ctx: CommandContext) -> int:
|
|
|
25
26
|
{
|
|
26
27
|
"env_file_exists": env_file_exists,
|
|
27
28
|
"env_file": str(ENV_FILE),
|
|
29
|
+
"docker_cli_available": cli_ok,
|
|
28
30
|
"services_running": services_ok,
|
|
29
31
|
"compose_file": docker.compose_file,
|
|
30
32
|
"project_name": docker.project_name,
|
|
@@ -40,14 +42,21 @@ def run_env(ctx: CommandContext) -> int:
|
|
|
40
42
|
if env_file_exists:
|
|
41
43
|
print_success(f".env file exists at {ENV_FILE}")
|
|
42
44
|
else:
|
|
43
|
-
print_info(
|
|
45
|
+
print_info(
|
|
46
|
+
f".env file not found at {ENV_FILE} "
|
|
47
|
+
"(expected before first product setup)"
|
|
48
|
+
)
|
|
44
49
|
|
|
45
|
-
if
|
|
46
|
-
|
|
50
|
+
if not cli_ok:
|
|
51
|
+
print_info(
|
|
52
|
+
"Docker CLI not found on PATH; Compose services were not queried"
|
|
53
|
+
)
|
|
54
|
+
elif services_ok:
|
|
55
|
+
print_success("Docker Compose services: appear to be running")
|
|
47
56
|
else:
|
|
48
|
-
print_info("Compose services: not detected as running")
|
|
57
|
+
print_info("Docker Compose services: not detected as running")
|
|
49
58
|
|
|
50
|
-
print_info(f"Compose file: {docker.compose_file}")
|
|
59
|
+
print_info(f"Docker Compose file: {docker.compose_file}")
|
|
51
60
|
print_info(f"Project: {docker.project_name}")
|
|
52
61
|
print_info("Environment context: " + ctx.env.describe())
|
|
53
62
|
return 0
|
|
@@ -7,14 +7,30 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
from xgic.cli.app import CommandContext
|
|
9
9
|
from xgic.cli.dev.context import make_docker, resolve_profile
|
|
10
|
-
from xgic.cli.
|
|
10
|
+
from xgic.cli.dev.docker import DockerComposeController
|
|
11
|
+
from xgic.cli.utils.output import print_error, print_info, print_success, print_warning
|
|
11
12
|
|
|
12
13
|
ENV_FILE = Path(".devcontainer/.env")
|
|
13
14
|
|
|
15
|
+
_NO_DOCKER_CLI = (
|
|
16
|
+
"Docker CLI not found on PATH. Compose lifecycle commands need a Docker "
|
|
17
|
+
"client talking to the host engine (Docker-outside-of-Docker). This image "
|
|
18
|
+
"must install docker-ce-cli; do not enable Docker-in-Docker."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _require_docker(docker: DockerComposeController) -> int | None:
|
|
23
|
+
if docker.docker_cli_available():
|
|
24
|
+
return None
|
|
25
|
+
print_error(_NO_DOCKER_CLI)
|
|
26
|
+
return 2
|
|
27
|
+
|
|
14
28
|
|
|
15
29
|
def run_up(ctx: CommandContext) -> int:
|
|
16
30
|
"""Start compose services in detached mode."""
|
|
17
31
|
docker = make_docker(ctx.env, ctx.args)
|
|
32
|
+
if (rc := _require_docker(docker)) is not None:
|
|
33
|
+
return rc
|
|
18
34
|
profile = resolve_profile(ctx.args)
|
|
19
35
|
print_info("Starting services...")
|
|
20
36
|
docker.up(profile=profile)
|
|
@@ -25,6 +41,8 @@ def run_up(ctx: CommandContext) -> int:
|
|
|
25
41
|
def run_down(ctx: CommandContext) -> int:
|
|
26
42
|
"""Stop services (volumes preserved)."""
|
|
27
43
|
docker = make_docker(ctx.env, ctx.args)
|
|
44
|
+
if (rc := _require_docker(docker)) is not None:
|
|
45
|
+
return rc
|
|
28
46
|
print_info("Stopping services...")
|
|
29
47
|
docker.down()
|
|
30
48
|
print_success("Services stopped (volumes preserved)")
|
|
@@ -34,6 +52,8 @@ def run_down(ctx: CommandContext) -> int:
|
|
|
34
52
|
def run_build(ctx: CommandContext) -> int:
|
|
35
53
|
"""Build compose images."""
|
|
36
54
|
docker = make_docker(ctx.env, ctx.args)
|
|
55
|
+
if (rc := _require_docker(docker)) is not None:
|
|
56
|
+
return rc
|
|
37
57
|
no_cache = bool(getattr(ctx.args, "no_cache", False))
|
|
38
58
|
print_info("Building services" + (" (no cache)" if no_cache else "") + "...")
|
|
39
59
|
docker.build(no_cache=no_cache)
|
|
@@ -44,6 +64,8 @@ def run_build(ctx: CommandContext) -> int:
|
|
|
44
64
|
def run_logs(ctx: CommandContext) -> int:
|
|
45
65
|
"""Follow logs for all services (blocks until interrupted)."""
|
|
46
66
|
docker = make_docker(ctx.env, ctx.args)
|
|
67
|
+
if (rc := _require_docker(docker)) is not None:
|
|
68
|
+
return rc
|
|
47
69
|
print_info("Following logs (press Ctrl+C to exit)...")
|
|
48
70
|
docker.logs(follow=True)
|
|
49
71
|
return 0
|
|
@@ -52,6 +74,8 @@ def run_logs(ctx: CommandContext) -> int:
|
|
|
52
74
|
def run_shell(ctx: CommandContext) -> int:
|
|
53
75
|
"""Open an interactive shell in the primary service."""
|
|
54
76
|
docker = make_docker(ctx.env, ctx.args)
|
|
77
|
+
if (rc := _require_docker(docker)) is not None:
|
|
78
|
+
return rc
|
|
55
79
|
service = docker.primary_service
|
|
56
80
|
if not service:
|
|
57
81
|
print_warning(
|
|
@@ -70,6 +94,8 @@ def run_shell(ctx: CommandContext) -> int:
|
|
|
70
94
|
def run_clean(ctx: CommandContext) -> int:
|
|
71
95
|
"""Full environment cleanup (volumes + .env). Extremely destructive."""
|
|
72
96
|
docker = make_docker(ctx.env, ctx.args)
|
|
97
|
+
if (rc := _require_docker(docker)) is not None:
|
|
98
|
+
return rc
|
|
73
99
|
yes = bool(getattr(ctx.args, "yes", False))
|
|
74
100
|
|
|
75
101
|
print_warning(
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Build a DockerComposeController from CLI args / environment."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from xgic.cli.core.environment import EnvironmentContext
|
|
12
|
+
from xgic.cli.dev.docker import (
|
|
13
|
+
DEFAULT_COMPOSE_FILE,
|
|
14
|
+
DEFAULT_PROJECT_NAME,
|
|
15
|
+
DockerComposeController,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
ENV_COMPOSE_FILE = "XGIC_COMPOSE_FILE"
|
|
19
|
+
ENV_COMPOSE_PROJECT = "XGIC_COMPOSE_PROJECT"
|
|
20
|
+
ENV_PRIMARY_SERVICE = "XGIC_PRIMARY_SERVICE"
|
|
21
|
+
ENV_COMPOSE_PROFILE = "XGIC_COMPOSE_PROFILE"
|
|
22
|
+
|
|
23
|
+
DEFAULT_DEVCONTAINER_JSON = Path(".devcontainer/devcontainer.json")
|
|
24
|
+
_SAFE_NAME = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_-]{0,62}$")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def resolve_compose_file(args: argparse.Namespace) -> str:
|
|
28
|
+
return (
|
|
29
|
+
getattr(args, "compose_file", None)
|
|
30
|
+
or os.environ.get(ENV_COMPOSE_FILE)
|
|
31
|
+
or DEFAULT_COMPOSE_FILE
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _is_compose_safe_name(name: str) -> bool:
|
|
36
|
+
return bool(name and _SAFE_NAME.fullmatch(name))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def compose_name_from_file(compose_path: Path) -> str | None:
|
|
40
|
+
"""Parse top-level ``name:`` from a Compose file (best-effort)."""
|
|
41
|
+
if not compose_path.is_file():
|
|
42
|
+
return None
|
|
43
|
+
try:
|
|
44
|
+
for line in compose_path.read_text(encoding="utf-8").splitlines():
|
|
45
|
+
stripped = line.strip()
|
|
46
|
+
if stripped.startswith("#") or not stripped.startswith("name:"):
|
|
47
|
+
continue
|
|
48
|
+
raw = stripped.split(":", 1)[1].strip().strip("\"'")
|
|
49
|
+
if raw and _is_compose_safe_name(raw):
|
|
50
|
+
return raw
|
|
51
|
+
except OSError:
|
|
52
|
+
return None
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def primary_service_from_devcontainer(
|
|
57
|
+
path: Path = DEFAULT_DEVCONTAINER_JSON,
|
|
58
|
+
) -> str | None:
|
|
59
|
+
"""Read ``service`` from ``.devcontainer/devcontainer.json`` if present."""
|
|
60
|
+
if not path.is_file():
|
|
61
|
+
return None
|
|
62
|
+
try:
|
|
63
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
64
|
+
except (OSError, json.JSONDecodeError):
|
|
65
|
+
return None
|
|
66
|
+
if not isinstance(data, dict):
|
|
67
|
+
return None
|
|
68
|
+
raw = data.get("service")
|
|
69
|
+
if isinstance(raw, str) and raw.strip() and _is_compose_safe_name(raw.strip()):
|
|
70
|
+
return raw.strip()
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def resolve_project_name(args: argparse.Namespace) -> str:
|
|
75
|
+
named = getattr(args, "project", None) or os.environ.get(ENV_COMPOSE_PROJECT)
|
|
76
|
+
if isinstance(named, str) and named.strip() and _is_compose_safe_name(named.strip()):
|
|
77
|
+
return named.strip()
|
|
78
|
+
compose_file = resolve_compose_file(args)
|
|
79
|
+
from_file = compose_name_from_file(Path(compose_file))
|
|
80
|
+
if from_file:
|
|
81
|
+
return from_file
|
|
82
|
+
return DEFAULT_PROJECT_NAME
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def resolve_primary_service(args: argparse.Namespace) -> str | None:
|
|
86
|
+
named = getattr(args, "service", None) or os.environ.get(ENV_PRIMARY_SERVICE)
|
|
87
|
+
if isinstance(named, str) and named.strip():
|
|
88
|
+
return named.strip()
|
|
89
|
+
return primary_service_from_devcontainer()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def resolve_profile(args: argparse.Namespace) -> str | None:
|
|
93
|
+
return getattr(args, "profile", None) or os.environ.get(ENV_COMPOSE_PROFILE)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def make_docker(
|
|
97
|
+
env: EnvironmentContext, args: argparse.Namespace
|
|
98
|
+
) -> DockerComposeController:
|
|
99
|
+
"""Construct a controller from CommandContext-compatible args."""
|
|
100
|
+
return DockerComposeController(
|
|
101
|
+
env=env,
|
|
102
|
+
compose_file=resolve_compose_file(args),
|
|
103
|
+
project_name=resolve_project_name(args),
|
|
104
|
+
primary_service=resolve_primary_service(args),
|
|
105
|
+
)
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""Docker Compose orchestration for Dev Container environments.
|
|
2
2
|
|
|
3
|
-
Product-agnostic Compose controller. Callers inject compose file,
|
|
4
|
-
name, primary service, and optional profile. Payload CMS–specific
|
|
5
|
-
and config readers live in ``xgic.cli.payload``
|
|
3
|
+
Product-agnostic Docker Compose controller. Callers inject compose file,
|
|
4
|
+
project name, primary service, and optional profile. Payload CMS–specific
|
|
5
|
+
defaults and config readers live in ``xgic.cli.payload``
|
|
6
|
+
(xgic/payload-cms-cli).
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
11
|
+
import shutil
|
|
10
12
|
import subprocess
|
|
11
13
|
from dataclasses import dataclass
|
|
12
14
|
|
|
@@ -25,6 +27,10 @@ class DockerComposeController:
|
|
|
25
27
|
project_name: str = DEFAULT_PROJECT_NAME
|
|
26
28
|
primary_service: str | None = None
|
|
27
29
|
|
|
30
|
+
def docker_cli_available(self) -> bool:
|
|
31
|
+
"""Return True if a ``docker`` executable is on PATH."""
|
|
32
|
+
return shutil.which("docker") is not None
|
|
33
|
+
|
|
28
34
|
def _run_compose(
|
|
29
35
|
self,
|
|
30
36
|
*args: str,
|
|
@@ -65,7 +71,9 @@ class DockerComposeController:
|
|
|
65
71
|
if target is None:
|
|
66
72
|
return True
|
|
67
73
|
return target in running
|
|
68
|
-
except
|
|
74
|
+
except FileNotFoundError:
|
|
75
|
+
return False
|
|
76
|
+
except subprocess.CalledProcessError:
|
|
69
77
|
return False
|
|
70
78
|
|
|
71
79
|
def up(
|
|
@@ -21,22 +21,22 @@ def _common_parent() -> argparse.ArgumentParser:
|
|
|
21
21
|
parent.add_argument(
|
|
22
22
|
"--compose-file",
|
|
23
23
|
metavar="PATH",
|
|
24
|
-
help="Compose file path (or XGIC_COMPOSE_FILE)",
|
|
24
|
+
help="Docker Compose file path (or XGIC_COMPOSE_FILE)",
|
|
25
25
|
)
|
|
26
26
|
parent.add_argument(
|
|
27
27
|
"--project",
|
|
28
28
|
metavar="NAME",
|
|
29
|
-
help="Compose project name (or XGIC_COMPOSE_PROJECT)",
|
|
29
|
+
help="Docker Compose project name (or XGIC_COMPOSE_PROJECT)",
|
|
30
30
|
)
|
|
31
31
|
parent.add_argument(
|
|
32
32
|
"--service",
|
|
33
33
|
metavar="NAME",
|
|
34
|
-
help="Primary
|
|
34
|
+
help="Primary Docker Compose service (or XGIC_PRIMARY_SERVICE)",
|
|
35
35
|
)
|
|
36
36
|
parent.add_argument(
|
|
37
37
|
"--profile",
|
|
38
38
|
metavar="NAME",
|
|
39
|
-
help="Compose profile for up (or XGIC_COMPOSE_PROFILE)",
|
|
39
|
+
help="Docker Compose profile for up (or XGIC_COMPOSE_PROFILE)",
|
|
40
40
|
)
|
|
41
41
|
return parent
|
|
42
42
|
|
|
@@ -64,7 +64,7 @@ def register(
|
|
|
64
64
|
build = subparsers.add_parser(
|
|
65
65
|
"build",
|
|
66
66
|
parents=[parent],
|
|
67
|
-
help="Build or rebuild
|
|
67
|
+
help="Build or rebuild Docker Compose services",
|
|
68
68
|
)
|
|
69
69
|
build.add_argument(
|
|
70
70
|
"--no-cache",
|
|
@@ -76,7 +76,7 @@ def register(
|
|
|
76
76
|
logs = subparsers.add_parser(
|
|
77
77
|
"logs",
|
|
78
78
|
parents=[parent],
|
|
79
|
-
help="Follow logs for
|
|
79
|
+
help="Follow logs for Docker Compose services",
|
|
80
80
|
)
|
|
81
81
|
logs.set_defaults(func=run_logs)
|
|
82
82
|
|
|
@@ -102,7 +102,7 @@ def register(
|
|
|
102
102
|
check = subparsers.add_parser(
|
|
103
103
|
"check",
|
|
104
104
|
parents=[parent],
|
|
105
|
-
help="Diagnostic:
|
|
105
|
+
help="Diagnostic: Docker Compose services + environment context",
|
|
106
106
|
)
|
|
107
107
|
check.add_argument(
|
|
108
108
|
"--json",
|
xgic_dev_cli-0.2.0/PKG-INFO
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: xgic-dev-cli
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: XGIC CLI Dev Container module - Docker Compose orchestration and xgic lifecycle commands (xgic.cli.dev).
|
|
5
|
-
Project-URL: Homepage, https://github.com/xgic/dev-cli
|
|
6
|
-
Project-URL: Repository, https://github.com/xgic/dev-cli
|
|
7
|
-
Project-URL: Issues, https://github.com/xgic/dev-cli/issues
|
|
8
|
-
Project-URL: Documentation, https://github.com/xgic/dev-cli#readme
|
|
9
|
-
Project-URL: Changelog, https://github.com/xgic/dev-cli/releases
|
|
10
|
-
Author: XGIC
|
|
11
|
-
License: Apache-2.0
|
|
12
|
-
License-File: LICENSE
|
|
13
|
-
License-File: NOTICE
|
|
14
|
-
Keywords: cli,dev-containers,docker-compose,orchestration,xgic
|
|
15
|
-
Classifier: Development Status :: 3 - Alpha
|
|
16
|
-
Classifier: Environment :: Console
|
|
17
|
-
Classifier: Intended Audience :: Developers
|
|
18
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
|
-
Classifier: Operating System :: OS Independent
|
|
20
|
-
Classifier: Programming Language :: Python :: 3
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
-
Classifier: Typing :: Typed
|
|
24
|
-
Requires-Python: >=3.14
|
|
25
|
-
Requires-Dist: rich>=13.7
|
|
26
|
-
Requires-Dist: xgic-cli>=0.2.0
|
|
27
|
-
Provides-Extra: dev
|
|
28
|
-
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
29
|
-
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
30
|
-
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
31
|
-
Provides-Extra: test
|
|
32
|
-
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
33
|
-
Description-Content-Type: text/markdown
|
|
34
|
-
|
|
35
|
-
# XGIC Dev Container CLI
|
|
36
|
-
|
|
37
|
-
[](https://opensource.org/licenses/Apache-2.0)
|
|
38
|
-
|
|
39
|
-
**XGIC Dev Container CLI** (`xgic.cli.dev`) provides Docker Compose orchestration and Dev Container–oriented **`xgic` subcommands** for the modular [XGIC CLI](https://github.com/xgic/cli).
|
|
40
|
-
|
|
41
|
-
Architecture: [ADR-0005](https://github.com/xgic/ai/blob/main/docs/adr/0005-modular-xgic-cli-and-retirement-of-xde.md).
|
|
42
|
-
|
|
43
|
-
**Publishing to PyPI:** [python-package-release.md](https://github.com/xgic/ai/blob/main/docs/python-package-release.md)
|
|
44
|
-
(publish **after** `xgic-cli` for stack releases). Tags: `vX.Y.ZrcN` → TestPyPI; `vX.Y.Z` → PyPI.
|
|
45
|
-
|
|
46
|
-
| Package | Role |
|
|
47
|
-
|---------|------|
|
|
48
|
-
| [xgic/cli](https://github.com/xgic/cli) | Thin core framework (`xgic`) |
|
|
49
|
-
| **This repo** | Dev Container / Compose + lifecycle commands (`xgic.cli.dev`) |
|
|
50
|
-
| [xgic/payload-cms-cli](https://github.com/xgic/payload-cms-cli) | Payload CMS product module |
|
|
51
|
-
|
|
52
|
-
## Status
|
|
53
|
-
|
|
54
|
-
**0.2.0 — B3 lifecycle commands.** Product-agnostic Compose library + registered `xgic` subcommands. Payload CMS–specific env regenerate / setup remains in **payload-cms-cli**.
|
|
55
|
-
|
|
56
|
-
## Requirements
|
|
57
|
-
|
|
58
|
-
- Python **3.14+**
|
|
59
|
-
- `xgic-cli` ≥ 0.2.0
|
|
60
|
-
- Docker / Docker Compose on the host when running lifecycle commands
|
|
61
|
-
|
|
62
|
-
## Install (development)
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
python -m pip install -e ../cli
|
|
66
|
-
python -m pip install -e ".[dev]"
|
|
67
|
-
xgic --help
|
|
68
|
-
xgic up --help
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Console commands (via entry point)
|
|
72
|
-
|
|
73
|
-
Installed with this package, registered on the core `xgic` entrypoint:
|
|
74
|
-
|
|
75
|
-
| Command | Purpose |
|
|
76
|
-
|---------|---------|
|
|
77
|
-
| `xgic up` | Start compose services (detached) |
|
|
78
|
-
| `xgic down` | Stop services (volumes preserved) |
|
|
79
|
-
| `xgic build [--no-cache]` | Build images |
|
|
80
|
-
| `xgic logs` | Follow logs |
|
|
81
|
-
| `xgic shell` | Shell in primary service (`--service` required if not set) |
|
|
82
|
-
| `xgic clean --yes` | Destructive: volumes + `.devcontainer/.env` |
|
|
83
|
-
| `xgic check [--json]` | Services + environment diagnostic |
|
|
84
|
-
| `xgic env [--json]` | Environment status (no secret regeneration) |
|
|
85
|
-
|
|
86
|
-
Common flags (or env vars):
|
|
87
|
-
|
|
88
|
-
| Flag | Env var | Default |
|
|
89
|
-
|------|---------|---------|
|
|
90
|
-
| `--compose-file` | `XGIC_COMPOSE_FILE` | `.devcontainer/docker-compose.yml` |
|
|
91
|
-
| `--project` | `XGIC_COMPOSE_PROJECT` | `xgic-dev` |
|
|
92
|
-
| `--service` | `XGIC_PRIMARY_SERVICE` | (none) |
|
|
93
|
-
| `--profile` | `XGIC_COMPOSE_PROFILE` | (none; used by `up`) |
|
|
94
|
-
|
|
95
|
-
## Library API
|
|
96
|
-
|
|
97
|
-
```python
|
|
98
|
-
from xgic.cli.core import EnvironmentContext
|
|
99
|
-
from xgic.cli.dev import DockerComposeController
|
|
100
|
-
|
|
101
|
-
env = EnvironmentContext.detect()
|
|
102
|
-
docker = DockerComposeController(
|
|
103
|
-
env=env,
|
|
104
|
-
compose_file=".devcontainer/docker-compose.yml",
|
|
105
|
-
project_name="my-project",
|
|
106
|
-
primary_service="app",
|
|
107
|
-
)
|
|
108
|
-
docker.up(profile="postgres")
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## License
|
|
112
|
-
|
|
113
|
-
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
114
|
-
Copyright form: `Copyright 2026 XGIC`.
|
xgic_dev_cli-0.2.0/README.md
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# XGIC Dev Container CLI
|
|
2
|
-
|
|
3
|
-
[](https://opensource.org/licenses/Apache-2.0)
|
|
4
|
-
|
|
5
|
-
**XGIC Dev Container CLI** (`xgic.cli.dev`) provides Docker Compose orchestration and Dev Container–oriented **`xgic` subcommands** for the modular [XGIC CLI](https://github.com/xgic/cli).
|
|
6
|
-
|
|
7
|
-
Architecture: [ADR-0005](https://github.com/xgic/ai/blob/main/docs/adr/0005-modular-xgic-cli-and-retirement-of-xde.md).
|
|
8
|
-
|
|
9
|
-
**Publishing to PyPI:** [python-package-release.md](https://github.com/xgic/ai/blob/main/docs/python-package-release.md)
|
|
10
|
-
(publish **after** `xgic-cli` for stack releases). Tags: `vX.Y.ZrcN` → TestPyPI; `vX.Y.Z` → PyPI.
|
|
11
|
-
|
|
12
|
-
| Package | Role |
|
|
13
|
-
|---------|------|
|
|
14
|
-
| [xgic/cli](https://github.com/xgic/cli) | Thin core framework (`xgic`) |
|
|
15
|
-
| **This repo** | Dev Container / Compose + lifecycle commands (`xgic.cli.dev`) |
|
|
16
|
-
| [xgic/payload-cms-cli](https://github.com/xgic/payload-cms-cli) | Payload CMS product module |
|
|
17
|
-
|
|
18
|
-
## Status
|
|
19
|
-
|
|
20
|
-
**0.2.0 — B3 lifecycle commands.** Product-agnostic Compose library + registered `xgic` subcommands. Payload CMS–specific env regenerate / setup remains in **payload-cms-cli**.
|
|
21
|
-
|
|
22
|
-
## Requirements
|
|
23
|
-
|
|
24
|
-
- Python **3.14+**
|
|
25
|
-
- `xgic-cli` ≥ 0.2.0
|
|
26
|
-
- Docker / Docker Compose on the host when running lifecycle commands
|
|
27
|
-
|
|
28
|
-
## Install (development)
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
python -m pip install -e ../cli
|
|
32
|
-
python -m pip install -e ".[dev]"
|
|
33
|
-
xgic --help
|
|
34
|
-
xgic up --help
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Console commands (via entry point)
|
|
38
|
-
|
|
39
|
-
Installed with this package, registered on the core `xgic` entrypoint:
|
|
40
|
-
|
|
41
|
-
| Command | Purpose |
|
|
42
|
-
|---------|---------|
|
|
43
|
-
| `xgic up` | Start compose services (detached) |
|
|
44
|
-
| `xgic down` | Stop services (volumes preserved) |
|
|
45
|
-
| `xgic build [--no-cache]` | Build images |
|
|
46
|
-
| `xgic logs` | Follow logs |
|
|
47
|
-
| `xgic shell` | Shell in primary service (`--service` required if not set) |
|
|
48
|
-
| `xgic clean --yes` | Destructive: volumes + `.devcontainer/.env` |
|
|
49
|
-
| `xgic check [--json]` | Services + environment diagnostic |
|
|
50
|
-
| `xgic env [--json]` | Environment status (no secret regeneration) |
|
|
51
|
-
|
|
52
|
-
Common flags (or env vars):
|
|
53
|
-
|
|
54
|
-
| Flag | Env var | Default |
|
|
55
|
-
|------|---------|---------|
|
|
56
|
-
| `--compose-file` | `XGIC_COMPOSE_FILE` | `.devcontainer/docker-compose.yml` |
|
|
57
|
-
| `--project` | `XGIC_COMPOSE_PROJECT` | `xgic-dev` |
|
|
58
|
-
| `--service` | `XGIC_PRIMARY_SERVICE` | (none) |
|
|
59
|
-
| `--profile` | `XGIC_COMPOSE_PROFILE` | (none; used by `up`) |
|
|
60
|
-
|
|
61
|
-
## Library API
|
|
62
|
-
|
|
63
|
-
```python
|
|
64
|
-
from xgic.cli.core import EnvironmentContext
|
|
65
|
-
from xgic.cli.dev import DockerComposeController
|
|
66
|
-
|
|
67
|
-
env = EnvironmentContext.detect()
|
|
68
|
-
docker = DockerComposeController(
|
|
69
|
-
env=env,
|
|
70
|
-
compose_file=".devcontainer/docker-compose.yml",
|
|
71
|
-
project_name="my-project",
|
|
72
|
-
primary_service="app",
|
|
73
|
-
)
|
|
74
|
-
docker.up(profile="postgres")
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## License
|
|
78
|
-
|
|
79
|
-
Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
80
|
-
Copyright form: `Copyright 2026 XGIC`.
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"""Build a DockerComposeController from CLI args / environment."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import argparse
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
from xgic.cli.core.environment import EnvironmentContext
|
|
9
|
-
from xgic.cli.dev.docker import (
|
|
10
|
-
DEFAULT_COMPOSE_FILE,
|
|
11
|
-
DEFAULT_PROJECT_NAME,
|
|
12
|
-
DockerComposeController,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
ENV_COMPOSE_FILE = "XGIC_COMPOSE_FILE"
|
|
16
|
-
ENV_COMPOSE_PROJECT = "XGIC_COMPOSE_PROJECT"
|
|
17
|
-
ENV_PRIMARY_SERVICE = "XGIC_PRIMARY_SERVICE"
|
|
18
|
-
ENV_COMPOSE_PROFILE = "XGIC_COMPOSE_PROFILE"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def resolve_compose_file(args: argparse.Namespace) -> str:
|
|
22
|
-
return (
|
|
23
|
-
getattr(args, "compose_file", None)
|
|
24
|
-
or os.environ.get(ENV_COMPOSE_FILE)
|
|
25
|
-
or DEFAULT_COMPOSE_FILE
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def resolve_project_name(args: argparse.Namespace) -> str:
|
|
30
|
-
return (
|
|
31
|
-
getattr(args, "project", None)
|
|
32
|
-
or os.environ.get(ENV_COMPOSE_PROJECT)
|
|
33
|
-
or DEFAULT_PROJECT_NAME
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def resolve_primary_service(args: argparse.Namespace) -> str | None:
|
|
38
|
-
return getattr(args, "service", None) or os.environ.get(ENV_PRIMARY_SERVICE)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def resolve_profile(args: argparse.Namespace) -> str | None:
|
|
42
|
-
return getattr(args, "profile", None) or os.environ.get(ENV_COMPOSE_PROFILE)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def make_docker(
|
|
46
|
-
env: EnvironmentContext, args: argparse.Namespace
|
|
47
|
-
) -> DockerComposeController:
|
|
48
|
-
"""Construct a controller from CommandContext-compatible args."""
|
|
49
|
-
return DockerComposeController(
|
|
50
|
-
env=env,
|
|
51
|
-
compose_file=resolve_compose_file(args),
|
|
52
|
-
project_name=resolve_project_name(args),
|
|
53
|
-
primary_service=resolve_primary_service(args),
|
|
54
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|