xed-cci 0.0.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.
- xed_cci-0.0.1/.gitignore +27 -0
- xed_cci-0.0.1/CHANGELOG.md +29 -0
- xed_cci-0.0.1/LICENSE +21 -0
- xed_cci-0.0.1/PKG-INFO +125 -0
- xed_cci-0.0.1/README.md +90 -0
- xed_cci-0.0.1/pyproject.toml +80 -0
- xed_cci-0.0.1/src/cci/__init__.py +5 -0
- xed_cci-0.0.1/src/cci/_version.py +2 -0
- xed_cci-0.0.1/src/cci/cli.py +73 -0
- xed_cci-0.0.1/src/cci/commands/__init__.py +0 -0
- xed_cci-0.0.1/src/cci/commands/inventory.py +221 -0
- xed_cci-0.0.1/src/cci/system/__init__.py +0 -0
- xed_cci-0.0.1/src/cci/system/audit_log.py +79 -0
- xed_cci-0.0.1/src/cci/system/inventory/__init__.py +0 -0
- xed_cci-0.0.1/src/cci/system/inventory/apps/__init__.py +45 -0
- xed_cci-0.0.1/src/cci/system/inventory/apps/_types.py +14 -0
- xed_cci-0.0.1/src/cci/system/inventory/apps/typo3.py +101 -0
- xed_cci-0.0.1/src/cci/system/inventory/cc_suite.py +78 -0
- xed_cci-0.0.1/src/cci/system/inventory/databases.py +112 -0
- xed_cci-0.0.1/src/cci/system/inventory/os.py +66 -0
- xed_cci-0.0.1/src/cci/system/inventory/stack.py +88 -0
- xed_cci-0.0.1/src/cci/system/safe_run.py +136 -0
xed_cci-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python build/cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
*.egg
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
.eggs/
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
|
|
15
|
+
# pytest
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# IDE / OS
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
23
|
+
.DS_Store
|
|
24
|
+
*.swp
|
|
25
|
+
|
|
26
|
+
# uv
|
|
27
|
+
.uv/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Alle bemerkenswerten Änderungen an `xed-cci` werden hier dokumentiert.
|
|
4
|
+
|
|
5
|
+
Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
|
6
|
+
Versionierung folgt [Semantic Versioning](https://semver.org/lang/de/).
|
|
7
|
+
|
|
8
|
+
## [0.0.1] — UNRELEASED
|
|
9
|
+
|
|
10
|
+
### Hinzugefügt (CCI-SS1 — Skelett-Setup)
|
|
11
|
+
|
|
12
|
+
- **CLI-Skelett** mit Typer-app + `--version`/`-V`-Flag + `--help`-Übersicht
|
|
13
|
+
- **`cci inventory` als Stub-Verb** — Skelett-Form, eigentliche Implementation
|
|
14
|
+
folgt in SS5 (Composition + Rich + JSON-Output + `--section`-Filter)
|
|
15
|
+
- **pyproject.toml** mit hatchling-Backend + dynamic version aus
|
|
16
|
+
`_version.py` + Stack-Konsistenz zu ccc/cca (Typer + Rich + psutil + pytest)
|
|
17
|
+
- **Test-Skelett** mit 3 Smoke-Cases (--version, --help, inventory-Stub)
|
|
18
|
+
|
|
19
|
+
### Architektur-Notizen
|
|
20
|
+
|
|
21
|
+
- Phase 1: Python-CLI Read-Only-Klasse, Drei-Tool-Suite-Symmetrie zu ccc + cca
|
|
22
|
+
- Phase 2 (DeltaChat-Bot) + Phase 3 (cBOX@ /Monitor) sind Vision/Mission,
|
|
23
|
+
NICHT in dieser Version umgesetzt — siehe `WHITEPAPER.md` für vollständige
|
|
24
|
+
Architektur-Entscheidungsfindung
|
|
25
|
+
- Symmetrisches Layout: `docs/firstboot.sh` (Pages-Source), kein `scripts/`-
|
|
26
|
+
Pfad-Mapping (Lehre aus CCC-Layout-Refactor 2026-05-08)
|
|
27
|
+
- Read-Only-Garantie strukturell via `safe_run.py` (kommt SS2)
|
|
28
|
+
|
|
29
|
+
[0.0.1]: https://github.com/XED-dev/CCI/releases/tag/v0.0.1
|
xed_cci-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 XED /Code ❤️ recode@ /DAO
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xed_cci-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xed-cci
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: cBOX@ /Container Inventur — Read-Only-Tool für lokale Box-Inventur (OS, CC-Suite, Stack, Datenbanken, Server-Apps). Drittes Mitglied der XED /CC-Suite neben ccc + cca. cBOX.at/YOU by XED.dev Tools via Collective Context (CC).
|
|
5
|
+
Project-URL: Homepage, https://cci.xed.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/XED-dev/CCI
|
|
7
|
+
Project-URL: XED /Suite, https://xed.dev
|
|
8
|
+
Project-URL: Issues, https://github.com/XED-dev/CCI/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/XED-dev/CCI/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Collective Context <code@collective-context.org>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: cbox,cci,cli,container,debian,inventory,kaizen,lxc,monitoring,proxmox,read-only,ubuntu
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: System Administrators
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: System :: Monitoring
|
|
25
|
+
Classifier: Topic :: System :: Systems Administration
|
|
26
|
+
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: psutil>=5.9
|
|
29
|
+
Requires-Dist: rich>=13.7
|
|
30
|
+
Requires-Dist: typer>=0.12
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# XED /CCI — cBOX@ /Container Inventur
|
|
37
|
+
|
|
38
|
+
> Read-Only-Tool für lokale cBOX-Inventur. Drittes Mitglied der XED /CC-Suite
|
|
39
|
+
> neben [ccc](../XED-CCC/) (Control) und [cca](../XED-CCA/) (App-Installation).
|
|
40
|
+
|
|
41
|
+
**100% Read-Only:** cci verändert NIEMALS den Box-Zustand. Strukturelle
|
|
42
|
+
Garantie via subprocess-Whitelist.
|
|
43
|
+
|
|
44
|
+
## Was es macht (Phase 1)
|
|
45
|
+
|
|
46
|
+
`cci inventory` liefert eine vollständige Inventur der lokalen Box als
|
|
47
|
+
Rich-Tabelle (Mensch) oder JSON (AI-Agent).
|
|
48
|
+
|
|
49
|
+
**Sektionen:**
|
|
50
|
+
- **OS** — `/etc/os-release` + Kernel
|
|
51
|
+
- **CC-Suite** — installed `xed-ccc` / `xed-cca` / `xed-cci`-Versionen
|
|
52
|
+
- **Stack** — `python3` / `php` / `node` Versionen (wenn installiert)
|
|
53
|
+
- **Databases** — `mysql` / `mariadb` / `postgres` Versionen + Service-Status
|
|
54
|
+
- **Apps** — Server-Apps mit Pfaden + Versionen (v0.0.1: Typo3-Detection)
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
**Empfohlen** — auf einer cBOX (LXC) via firstboot.sh:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bash <(curl -s https://cci.xed.dev/firstboot.sh)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Das Script installiert Python-Stack + pipx und holt `xed-cci` von PyPI.
|
|
65
|
+
|
|
66
|
+
**Manuell** — wenn pipx schon vorhanden:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pipx install xed-cci
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Verwendung
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Komplette Inventur als Rich-Tabelle
|
|
76
|
+
cci inventory
|
|
77
|
+
|
|
78
|
+
# JSON für AI-Agent-Konsumtion
|
|
79
|
+
cci inventory --format json
|
|
80
|
+
|
|
81
|
+
# Gefilterte Sektion
|
|
82
|
+
cci inventory --section os
|
|
83
|
+
cci inventory --section apps
|
|
84
|
+
cci inventory --section stack
|
|
85
|
+
cci inventory --section databases
|
|
86
|
+
cci inventory --section cc-suite
|
|
87
|
+
|
|
88
|
+
# Verb-Übersicht
|
|
89
|
+
cci --help
|
|
90
|
+
|
|
91
|
+
# Tool-Version
|
|
92
|
+
cci --version
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Use-Case: AI-Agent-Konsultation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cci inventory --format json > /tmp/box.json
|
|
99
|
+
|
|
100
|
+
# Dann an AI-Agent (Claude Code, ChatGPT, etc.):
|
|
101
|
+
# "Hier ist meine Box-Inventur. Passt diese Konfiguration für Typo3 v13?
|
|
102
|
+
# Welche Anpassungen sind nötig?"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Der AI-Agent sieht in einem strukturierten JSON-Block alle relevanten
|
|
106
|
+
Box-Daten und kann fundierte Migrations-/Update-Empfehlungen geben.
|
|
107
|
+
|
|
108
|
+
## Roadmap
|
|
109
|
+
|
|
110
|
+
- **Phase 1 (jetzt):** Python-CLI mit `cci inventory`-Verb (read-only,
|
|
111
|
+
pipx-Distribution, ccc/cca-Pattern-Symmetrie). Erste App-Detection für
|
|
112
|
+
Typo3.
|
|
113
|
+
- **Phase 2 (Vision):** DeltaChat-Bot-Daemon für dezentrale Box-Steuerung
|
|
114
|
+
ohne offene Ports + TLS-Cert-Management. Siehe
|
|
115
|
+
[WHITEPAPER.md §Phase 2](./WHITEPAPER.md#phase-2--deltachat-bot-daemon-visionmission-nicht-für-phase-1-umsetzen).
|
|
116
|
+
- **Phase 3 (Vision):** cBOX@ /Monitor Master-Programm für Inventur-
|
|
117
|
+
Aggregation über tausende cBOX@ /CUBE-Boxen. Siehe
|
|
118
|
+
[WHITEPAPER.md §Phase 3](./WHITEPAPER.md#phase-3--cbox-monitor-visionmission-nicht-für-phase-12-umsetzen).
|
|
119
|
+
|
|
120
|
+
Volle Architektur-Entscheidungsfindung + Vision/Mission siehe
|
|
121
|
+
[WHITEPAPER.md](./WHITEPAPER.md).
|
|
122
|
+
|
|
123
|
+
## Lizenz
|
|
124
|
+
|
|
125
|
+
MIT
|
xed_cci-0.0.1/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# XED /CCI — cBOX@ /Container Inventur
|
|
2
|
+
|
|
3
|
+
> Read-Only-Tool für lokale cBOX-Inventur. Drittes Mitglied der XED /CC-Suite
|
|
4
|
+
> neben [ccc](../XED-CCC/) (Control) und [cca](../XED-CCA/) (App-Installation).
|
|
5
|
+
|
|
6
|
+
**100% Read-Only:** cci verändert NIEMALS den Box-Zustand. Strukturelle
|
|
7
|
+
Garantie via subprocess-Whitelist.
|
|
8
|
+
|
|
9
|
+
## Was es macht (Phase 1)
|
|
10
|
+
|
|
11
|
+
`cci inventory` liefert eine vollständige Inventur der lokalen Box als
|
|
12
|
+
Rich-Tabelle (Mensch) oder JSON (AI-Agent).
|
|
13
|
+
|
|
14
|
+
**Sektionen:**
|
|
15
|
+
- **OS** — `/etc/os-release` + Kernel
|
|
16
|
+
- **CC-Suite** — installed `xed-ccc` / `xed-cca` / `xed-cci`-Versionen
|
|
17
|
+
- **Stack** — `python3` / `php` / `node` Versionen (wenn installiert)
|
|
18
|
+
- **Databases** — `mysql` / `mariadb` / `postgres` Versionen + Service-Status
|
|
19
|
+
- **Apps** — Server-Apps mit Pfaden + Versionen (v0.0.1: Typo3-Detection)
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
**Empfohlen** — auf einer cBOX (LXC) via firstboot.sh:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bash <(curl -s https://cci.xed.dev/firstboot.sh)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Das Script installiert Python-Stack + pipx und holt `xed-cci` von PyPI.
|
|
30
|
+
|
|
31
|
+
**Manuell** — wenn pipx schon vorhanden:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pipx install xed-cci
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Verwendung
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Komplette Inventur als Rich-Tabelle
|
|
41
|
+
cci inventory
|
|
42
|
+
|
|
43
|
+
# JSON für AI-Agent-Konsumtion
|
|
44
|
+
cci inventory --format json
|
|
45
|
+
|
|
46
|
+
# Gefilterte Sektion
|
|
47
|
+
cci inventory --section os
|
|
48
|
+
cci inventory --section apps
|
|
49
|
+
cci inventory --section stack
|
|
50
|
+
cci inventory --section databases
|
|
51
|
+
cci inventory --section cc-suite
|
|
52
|
+
|
|
53
|
+
# Verb-Übersicht
|
|
54
|
+
cci --help
|
|
55
|
+
|
|
56
|
+
# Tool-Version
|
|
57
|
+
cci --version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Use-Case: AI-Agent-Konsultation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cci inventory --format json > /tmp/box.json
|
|
64
|
+
|
|
65
|
+
# Dann an AI-Agent (Claude Code, ChatGPT, etc.):
|
|
66
|
+
# "Hier ist meine Box-Inventur. Passt diese Konfiguration für Typo3 v13?
|
|
67
|
+
# Welche Anpassungen sind nötig?"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Der AI-Agent sieht in einem strukturierten JSON-Block alle relevanten
|
|
71
|
+
Box-Daten und kann fundierte Migrations-/Update-Empfehlungen geben.
|
|
72
|
+
|
|
73
|
+
## Roadmap
|
|
74
|
+
|
|
75
|
+
- **Phase 1 (jetzt):** Python-CLI mit `cci inventory`-Verb (read-only,
|
|
76
|
+
pipx-Distribution, ccc/cca-Pattern-Symmetrie). Erste App-Detection für
|
|
77
|
+
Typo3.
|
|
78
|
+
- **Phase 2 (Vision):** DeltaChat-Bot-Daemon für dezentrale Box-Steuerung
|
|
79
|
+
ohne offene Ports + TLS-Cert-Management. Siehe
|
|
80
|
+
[WHITEPAPER.md §Phase 2](./WHITEPAPER.md#phase-2--deltachat-bot-daemon-visionmission-nicht-für-phase-1-umsetzen).
|
|
81
|
+
- **Phase 3 (Vision):** cBOX@ /Monitor Master-Programm für Inventur-
|
|
82
|
+
Aggregation über tausende cBOX@ /CUBE-Boxen. Siehe
|
|
83
|
+
[WHITEPAPER.md §Phase 3](./WHITEPAPER.md#phase-3--cbox-monitor-visionmission-nicht-für-phase-12-umsetzen).
|
|
84
|
+
|
|
85
|
+
Volle Architektur-Entscheidungsfindung + Vision/Mission siehe
|
|
86
|
+
[WHITEPAPER.md](./WHITEPAPER.md).
|
|
87
|
+
|
|
88
|
+
## Lizenz
|
|
89
|
+
|
|
90
|
+
MIT
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xed-cci"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "cBOX@ /Container Inventur — Read-Only-Tool für lokale Box-Inventur (OS, CC-Suite, Stack, Datenbanken, Server-Apps). Drittes Mitglied der XED /CC-Suite neben ccc + cca. cBOX.at/YOU by XED.dev Tools via Collective Context (CC)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Collective Context", email = "code@collective-context.org" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"lxc",
|
|
17
|
+
"proxmox",
|
|
18
|
+
"container",
|
|
19
|
+
"inventory",
|
|
20
|
+
"read-only",
|
|
21
|
+
"cli",
|
|
22
|
+
"cci",
|
|
23
|
+
"cbox",
|
|
24
|
+
"debian",
|
|
25
|
+
"ubuntu",
|
|
26
|
+
"monitoring",
|
|
27
|
+
"kaizen",
|
|
28
|
+
]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 3 - Alpha",
|
|
31
|
+
"Environment :: Console",
|
|
32
|
+
"Intended Audience :: System Administrators",
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
"Operating System :: POSIX :: Linux",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.10",
|
|
37
|
+
"Programming Language :: Python :: 3.11",
|
|
38
|
+
"Programming Language :: Python :: 3.12",
|
|
39
|
+
"Programming Language :: Python :: 3.13",
|
|
40
|
+
"Topic :: System :: Monitoring",
|
|
41
|
+
"Topic :: System :: Systems Administration",
|
|
42
|
+
"Topic :: Utilities",
|
|
43
|
+
]
|
|
44
|
+
dependencies = [
|
|
45
|
+
"typer>=0.12",
|
|
46
|
+
"rich>=13.7",
|
|
47
|
+
"psutil>=5.9",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
dev = [
|
|
52
|
+
"pytest>=8.0",
|
|
53
|
+
"pytest-cov>=5.0",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
cci = "cci.cli:main"
|
|
58
|
+
|
|
59
|
+
[project.urls]
|
|
60
|
+
Homepage = "https://cci.xed.dev"
|
|
61
|
+
Repository = "https://github.com/XED-dev/CCI"
|
|
62
|
+
"XED /Suite" = "https://xed.dev"
|
|
63
|
+
Issues = "https://github.com/XED-dev/CCI/issues"
|
|
64
|
+
Changelog = "https://github.com/XED-dev/CCI/blob/main/CHANGELOG.md"
|
|
65
|
+
|
|
66
|
+
[tool.hatch.version]
|
|
67
|
+
path = "src/cci/_version.py"
|
|
68
|
+
pattern = '__version__ = "(?P<version>[^"]+)"'
|
|
69
|
+
|
|
70
|
+
[tool.hatch.build.targets.wheel]
|
|
71
|
+
packages = ["src/cci"]
|
|
72
|
+
|
|
73
|
+
[tool.hatch.build.targets.sdist]
|
|
74
|
+
include = [
|
|
75
|
+
"src/cci",
|
|
76
|
+
"README.md",
|
|
77
|
+
"LICENSE",
|
|
78
|
+
"CHANGELOG.md",
|
|
79
|
+
"pyproject.toml",
|
|
80
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""xed-cci CLI — Typer-basiertes Read-Only-Inventur-Tool.
|
|
2
|
+
|
|
3
|
+
Designprinzipien (siehe WHITEPAPER §Vision + §Mission Statement):
|
|
4
|
+
- 100% Read-Only: cci verändert NIEMALS den Box-Zustand
|
|
5
|
+
- Stack-Konsistenz mit ccc + cca (Typer + Rich + pytest + pipx)
|
|
6
|
+
- AI-Agent-Konsumtion via JSON-Output
|
|
7
|
+
|
|
8
|
+
Phase-1-Verben (v0.0.1+):
|
|
9
|
+
- inventory: komplette Box-Inventur (Rich-Tabelle oder JSON)
|
|
10
|
+
|
|
11
|
+
Phase 2 (DeltaChat-Bot) + Phase 3 (cBOX@ /Monitor) sind Vision/Mission,
|
|
12
|
+
NICHT in Phase 1 umgesetzt.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import sys
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
import typer
|
|
21
|
+
from rich.console import Console
|
|
22
|
+
|
|
23
|
+
from cci._version import __version__
|
|
24
|
+
from cci.commands.inventory import inventory_command
|
|
25
|
+
|
|
26
|
+
app = typer.Typer(
|
|
27
|
+
name="cci",
|
|
28
|
+
help="cBOX@ /Container Inventur — Read-Only-Tool für lokale Box-Inventur.\n\n"
|
|
29
|
+
"Liefert OS, CC-Suite-Versionen, Stacks, Datenbanken und Server-Apps\n"
|
|
30
|
+
"als Rich-Tabelle (Mensch) oder JSON (AI-Agent-Konsumtion).\n\n"
|
|
31
|
+
"100% Read-Only: cci verändert NIEMALS den Box-Zustand.\n\n"
|
|
32
|
+
"cBOX.at/YOU by XED.dev Tools via Collective Context (CC).",
|
|
33
|
+
no_args_is_help=True,
|
|
34
|
+
add_completion=False,
|
|
35
|
+
)
|
|
36
|
+
console = Console()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def version_callback(value: bool) -> None:
|
|
40
|
+
if value:
|
|
41
|
+
console.print(f"xed-cci [bold]v{__version__}[/bold]")
|
|
42
|
+
raise typer.Exit()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.callback()
|
|
46
|
+
def main_callback(
|
|
47
|
+
version: Optional[bool] = typer.Option(
|
|
48
|
+
None,
|
|
49
|
+
"--version",
|
|
50
|
+
"-V",
|
|
51
|
+
help="Zeige Version und beende.",
|
|
52
|
+
callback=version_callback,
|
|
53
|
+
is_eager=True,
|
|
54
|
+
),
|
|
55
|
+
) -> None:
|
|
56
|
+
"""xed-cci Top-Level-Callback. Lädt globale Optionen wie --version."""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# inventory-Verb (SS5: Composition + Rich + JSON-Output + --section-Filter)
|
|
60
|
+
app.command("inventory")(inventory_command)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def main() -> None:
|
|
64
|
+
"""Entry point für das `cci`-Script (siehe pyproject.toml [project.scripts])."""
|
|
65
|
+
try:
|
|
66
|
+
app()
|
|
67
|
+
except KeyboardInterrupt:
|
|
68
|
+
console.print("\n[red]Abgebrochen.[/red]")
|
|
69
|
+
sys.exit(130)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""inventory — cci inventory-Verb (Composition + Rich + JSON + --section).
|
|
2
|
+
|
|
3
|
+
Composition über die fünf Inventur-Sektionen (os/cc-suite/stack/databases/
|
|
4
|
+
apps). Output entweder Rich-Tabelle (Mensch) oder JSON (AI-Agent-Konsumtion).
|
|
5
|
+
|
|
6
|
+
Senior-Pre-Hints H6-H11 (AI039 SS5 2026-05-08):
|
|
7
|
+
- H6: InventoryReport TypedDict matcht WHITEPAPER §JSON-Schema 1:1
|
|
8
|
+
- H7: Rich für Mensch / json.dumps für AI-Agent
|
|
9
|
+
- H8: --section-Filter mit enum-Choices (os/cc-suite/stack/databases/apps/all)
|
|
10
|
+
- H9: datetime.now(timezone.utc).isoformat — KEIN deprecated utcnow()
|
|
11
|
+
- H10: socket.gethostname() — KEIN subprocess hostname
|
|
12
|
+
- H11: _SCHEMA_VERSION als Konstante (Single-Source-of-Truth)
|
|
13
|
+
|
|
14
|
+
Stdlib-Reflex maximiert: keine subprocess-Aufrufe in dieser Datei
|
|
15
|
+
(Composition + Output-Rendering nur).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import socket
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
|
+
from enum import Enum
|
|
24
|
+
from typing import TypedDict
|
|
25
|
+
|
|
26
|
+
import typer
|
|
27
|
+
from rich.console import Console
|
|
28
|
+
from rich.table import Table
|
|
29
|
+
|
|
30
|
+
from cci.system.inventory.apps import AppInfo, collect_apps_info
|
|
31
|
+
from cci.system.inventory.cc_suite import CCSuiteInfo, collect_cc_suite_info
|
|
32
|
+
from cci.system.inventory.databases import DatabaseInfo, collect_databases_info
|
|
33
|
+
from cci.system.inventory.os import OSInfo, collect_os_info
|
|
34
|
+
from cci.system.inventory.stack import StackInfo, collect_stack_info
|
|
35
|
+
|
|
36
|
+
_SCHEMA_VERSION = "0.0.1"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class InventoryReport(TypedDict):
|
|
40
|
+
"""Vollständige Inventur-Composition matching WHITEPAPER §JSON-Schema."""
|
|
41
|
+
|
|
42
|
+
schema_version: str
|
|
43
|
+
timestamp: str
|
|
44
|
+
host: str
|
|
45
|
+
os: OSInfo
|
|
46
|
+
cc_suite: CCSuiteInfo
|
|
47
|
+
stack: StackInfo
|
|
48
|
+
databases: list[DatabaseInfo]
|
|
49
|
+
apps: list[AppInfo]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Section(str, Enum):
|
|
53
|
+
"""Erlaubte --section-Werte (Typer-Choices)."""
|
|
54
|
+
|
|
55
|
+
ALL = "all"
|
|
56
|
+
OS = "os"
|
|
57
|
+
CC_SUITE = "cc-suite"
|
|
58
|
+
STACK = "stack"
|
|
59
|
+
DATABASES = "databases"
|
|
60
|
+
APPS = "apps"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _utc_timestamp() -> str:
|
|
64
|
+
"""ISO-UTC-Zeitstempel mit 'Z'-Suffix (kompatibel zu audit_log-Format)."""
|
|
65
|
+
return (
|
|
66
|
+
datetime.now(timezone.utc)
|
|
67
|
+
.isoformat(timespec="seconds")
|
|
68
|
+
.replace("+00:00", "Z")
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _build_report() -> InventoryReport:
|
|
73
|
+
"""Baue komplette InventoryReport via Composition aller collect_X_info()."""
|
|
74
|
+
return InventoryReport(
|
|
75
|
+
schema_version=_SCHEMA_VERSION,
|
|
76
|
+
timestamp=_utc_timestamp(),
|
|
77
|
+
host=socket.gethostname(),
|
|
78
|
+
os=collect_os_info(),
|
|
79
|
+
cc_suite=collect_cc_suite_info(),
|
|
80
|
+
stack=collect_stack_info(),
|
|
81
|
+
databases=collect_databases_info(),
|
|
82
|
+
apps=collect_apps_info(),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _filter_report(report: InventoryReport, section: Section) -> dict:
|
|
87
|
+
"""Filtere Report auf gewählte Sektion (alle wenn Section.ALL).
|
|
88
|
+
|
|
89
|
+
Returns dict statt InventoryReport weil bei Section-Filter die
|
|
90
|
+
TypedDict-Struktur verändert wird (nur Subkey).
|
|
91
|
+
"""
|
|
92
|
+
if section is Section.ALL:
|
|
93
|
+
return dict(report)
|
|
94
|
+
|
|
95
|
+
# Schema-Header bleibt immer drin für Kontext, plus die gewählte Sektion
|
|
96
|
+
base = {
|
|
97
|
+
"schema_version": report["schema_version"],
|
|
98
|
+
"timestamp": report["timestamp"],
|
|
99
|
+
"host": report["host"],
|
|
100
|
+
}
|
|
101
|
+
section_key = section.value.replace("-", "_") # 'cc-suite' -> 'cc_suite'
|
|
102
|
+
base[section_key] = report[section_key] # type: ignore[literal-required]
|
|
103
|
+
return base
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _render_rich(console: Console, report: InventoryReport, section: Section) -> None:
|
|
107
|
+
"""Rich-Tabellen-Output für gewählte Sektion(en)."""
|
|
108
|
+
if section in (Section.ALL, Section.OS):
|
|
109
|
+
_render_os(console, report["os"])
|
|
110
|
+
if section in (Section.ALL, Section.CC_SUITE):
|
|
111
|
+
_render_cc_suite(console, report["cc_suite"])
|
|
112
|
+
if section in (Section.ALL, Section.STACK):
|
|
113
|
+
_render_stack(console, report["stack"])
|
|
114
|
+
if section in (Section.ALL, Section.DATABASES):
|
|
115
|
+
_render_databases(console, report["databases"])
|
|
116
|
+
if section in (Section.ALL, Section.APPS):
|
|
117
|
+
_render_apps(console, report["apps"])
|
|
118
|
+
|
|
119
|
+
if section is Section.ALL:
|
|
120
|
+
console.print(
|
|
121
|
+
f"[dim]Schema {report['schema_version']} · "
|
|
122
|
+
f"{report['timestamp']} · {report['host']}[/dim]"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _render_os(console: Console, os_info: OSInfo) -> None:
|
|
127
|
+
table = Table(title="OS", show_header=True, header_style="bold cyan")
|
|
128
|
+
table.add_column("Field")
|
|
129
|
+
table.add_column("Value")
|
|
130
|
+
for key in ("id", "version_id", "pretty_name", "kernel"):
|
|
131
|
+
table.add_row(key, os_info[key]) # type: ignore[literal-required]
|
|
132
|
+
console.print(table)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _render_cc_suite(console: Console, cc: CCSuiteInfo) -> None:
|
|
136
|
+
table = Table(title="CC-Suite", show_header=True, header_style="bold cyan")
|
|
137
|
+
table.add_column("Tool")
|
|
138
|
+
table.add_column("Version")
|
|
139
|
+
for tool in ("xed-ccc", "xed-cca", "xed-cci"):
|
|
140
|
+
table.add_row(tool, cc[tool]) # type: ignore[literal-required]
|
|
141
|
+
console.print(table)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _render_stack(console: Console, stack: StackInfo) -> None:
|
|
145
|
+
table = Table(title="Stack", show_header=True, header_style="bold cyan")
|
|
146
|
+
table.add_column("Language")
|
|
147
|
+
table.add_column("Version")
|
|
148
|
+
table.add_row("python3", stack["python3"])
|
|
149
|
+
table.add_row("php", stack["php"] or "[dim]not installed[/dim]")
|
|
150
|
+
table.add_row("node", stack["node"] or "[dim]not installed[/dim]")
|
|
151
|
+
console.print(table)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _render_databases(console: Console, dbs: list[DatabaseInfo]) -> None:
|
|
155
|
+
table = Table(title="Databases", show_header=True, header_style="bold cyan")
|
|
156
|
+
table.add_column("Engine")
|
|
157
|
+
table.add_column("Version")
|
|
158
|
+
table.add_column("Service Active", justify="center")
|
|
159
|
+
if not dbs:
|
|
160
|
+
table.add_row("[dim](none)[/dim]", "", "")
|
|
161
|
+
for db in dbs:
|
|
162
|
+
active = "[green]✓[/green]" if db["service_active"] else "[red]✗[/red]"
|
|
163
|
+
table.add_row(db["engine"], db["version"], active)
|
|
164
|
+
console.print(table)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _render_apps(console: Console, apps: list[AppInfo]) -> None:
|
|
168
|
+
table = Table(title="Server-Apps", show_header=True, header_style="bold cyan")
|
|
169
|
+
table.add_column("Name")
|
|
170
|
+
table.add_column("Version")
|
|
171
|
+
table.add_column("Path")
|
|
172
|
+
if not apps:
|
|
173
|
+
table.add_row("[dim](none)[/dim]", "", "")
|
|
174
|
+
for app in apps:
|
|
175
|
+
table.add_row(app["name"], app["version"], app["path"])
|
|
176
|
+
console.print(table)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def inventory_command(
|
|
180
|
+
section: Section = typer.Option(
|
|
181
|
+
Section.ALL,
|
|
182
|
+
"--section",
|
|
183
|
+
case_sensitive=False,
|
|
184
|
+
help="Welche Sektion ausgeben (Default: alle).",
|
|
185
|
+
),
|
|
186
|
+
output_format: str = typer.Option(
|
|
187
|
+
"rich",
|
|
188
|
+
"--format",
|
|
189
|
+
case_sensitive=False,
|
|
190
|
+
help="Output-Format: 'rich' (Tabellen für Mensch) oder 'json' (AI-Agent).",
|
|
191
|
+
),
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Box-Inventur als Rich-Tabelle oder JSON.
|
|
194
|
+
|
|
195
|
+
Sektionen: os, cc-suite, stack, databases, apps, all (Default).
|
|
196
|
+
|
|
197
|
+
Beispiele:
|
|
198
|
+
cci inventory
|
|
199
|
+
cci inventory --section os
|
|
200
|
+
cci inventory --format json > /tmp/box.json
|
|
201
|
+
"""
|
|
202
|
+
report = _build_report()
|
|
203
|
+
|
|
204
|
+
fmt = output_format.lower()
|
|
205
|
+
if fmt == "json":
|
|
206
|
+
# JSON-Output via stdout, Rich-Console-Output deaktiviert um
|
|
207
|
+
# Format-Kontamination zu vermeiden (Senior-Pre-Hint H7/H8 STOPP-
|
|
208
|
+
# Kriterium: bei --format json darf KEIN Rich-Output dazwischen
|
|
209
|
+
# rutschen).
|
|
210
|
+
filtered = _filter_report(report, section)
|
|
211
|
+
print(json.dumps(filtered, indent=2))
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
if fmt == "rich":
|
|
215
|
+
console = Console()
|
|
216
|
+
_render_rich(console, report, section)
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
raise typer.BadParameter(
|
|
220
|
+
f"Unbekanntes Format: {output_format!r}. Erlaubt: 'rich' oder 'json'."
|
|
221
|
+
)
|
|
File without changes
|