xcorecli 2.0.0__tar.gz → 2.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 (80) hide show
  1. xcorecli-2.1.0/PKG-INFO +77 -0
  2. xcorecli-2.1.0/README.md +62 -0
  3. xcorecli-2.1.0/docs/commands/login.md +34 -0
  4. xcorecli-2.1.0/docs/getting-started/auth.md +110 -0
  5. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/migration/index.md +7 -0
  6. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/install.md +11 -0
  7. xcorecli-2.1.0/docs/plugin/marketplace.md +46 -0
  8. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/reference.md +26 -6
  9. xcorecli-2.1.0/docs/service/index.md +69 -0
  10. {xcorecli-2.0.0 → xcorecli-2.1.0}/mkdocs.yml +2 -0
  11. {xcorecli-2.0.0 → xcorecli-2.1.0}/pyproject.toml +7 -1
  12. {xcorecli-2.0.0 → xcorecli-2.1.0}/uv.lock +11 -0
  13. xcorecli-2.1.0/xcli/_login.py +80 -0
  14. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/config/runtime.py +62 -4
  15. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/init/manager.py +3 -2
  16. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/init/upgrade.py +8 -1
  17. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/main.py +21 -1
  18. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/migrations/cli.py +6 -5
  19. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/migrations/runtime.py +121 -5
  20. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/cli.py +2 -2
  21. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/install_commands.py +106 -65
  22. xcorecli-2.1.0/xcli/plugin/marketplace_commands.py +117 -0
  23. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/shared.py +15 -5
  24. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/update_commands.py +34 -47
  25. xcorecli-2.1.0/xcli/service/cli.py +19 -0
  26. xcorecli-2.1.0/xcli/service/install_commands.py +275 -0
  27. xcorecli-2.1.0/xcli/service/marketplace_commands.py +101 -0
  28. xcorecli-2.1.0/xcli/service/shared.py +20 -0
  29. xcorecli-2.0.0/PKG-INFO +0 -12
  30. xcorecli-2.0.0/README.md +0 -0
  31. xcorecli-2.0.0/docs/getting-started/auth.md +0 -43
  32. xcorecli-2.0.0/docs/plugin/marketplace.md +0 -50
  33. xcorecli-2.0.0/xcli/marketplace/cli.py +0 -57
  34. xcorecli-2.0.0/xcli/plugin/marketplace_commands.py +0 -113
  35. {xcorecli-2.0.0 → xcorecli-2.1.0}/.github/workflows/publish.yml +0 -0
  36. {xcorecli-2.0.0 → xcorecli-2.1.0}/.gitignore +0 -0
  37. {xcorecli-2.0.0 → xcorecli-2.1.0}/.python-version +0 -0
  38. {xcorecli-2.0.0 → xcorecli-2.1.0}/.vscode/configurationCache.log +0 -0
  39. {xcorecli-2.0.0 → xcorecli-2.1.0}/.vscode/dryrun.log +0 -0
  40. {xcorecli-2.0.0 → xcorecli-2.1.0}/.vscode/settings.json +0 -0
  41. {xcorecli-2.0.0 → xcorecli-2.1.0}/.vscode/targets.log +0 -0
  42. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/commands/health.md +0 -0
  43. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/commands/init.md +0 -0
  44. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/config/index.md +0 -0
  45. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/getting-started/configuration.md +0 -0
  46. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/getting-started/install.md +0 -0
  47. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/index.md +0 -0
  48. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/manager/index.md +0 -0
  49. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/manager/monitoring.md +0 -0
  50. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/manager/services.md +0 -0
  51. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/index.md +0 -0
  52. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/local.md +0 -0
  53. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/runtime.md +0 -0
  54. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/security.md +0 -0
  55. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/plugin/update.md +0 -0
  56. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/sandbox/index.md +0 -0
  57. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/worker/index.md +0 -0
  58. {xcorecli-2.0.0 → xcorecli-2.1.0}/docs/worker/process.md +0 -0
  59. {xcorecli-2.0.0 → xcorecli-2.1.0}/makefile +0 -0
  60. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/__init__.py +0 -0
  61. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/_credentials.py +0 -0
  62. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/_run.py +0 -0
  63. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/_xcore.py +0 -0
  64. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/config/__init__.py +0 -0
  65. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/config/cli.py +0 -0
  66. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/init/__init__.py +0 -0
  67. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/manager/__init__.py +0 -0
  68. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/manager/cli.py +0 -0
  69. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/migrations/__init__.py +0 -0
  70. {xcorecli-2.0.0/xcli/marketplace → xcorecli-2.1.0/xcli/plugin}/__init__.py +0 -0
  71. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/local_commands.py +0 -0
  72. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/runtime_commands.py +0 -0
  73. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/scaffold.py +0 -0
  74. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/plugin/security_commands.py +0 -0
  75. {xcorecli-2.0.0/xcli/plugin → xcorecli-2.1.0/xcli/sandbox}/__init__.py +0 -0
  76. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/sandbox/cli.py +0 -0
  77. {xcorecli-2.0.0/xcli/sandbox → xcorecli-2.1.0/xcli/service}/__init__.py +0 -0
  78. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/worker/__init__.py +0 -0
  79. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/worker/cli.py +0 -0
  80. {xcorecli-2.0.0 → xcorecli-2.1.0}/xcli/worker/worker.py +0 -0
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.5
2
+ Name: xcorecli
3
+ Version: 2.1.0
4
+ Summary: CLI for xcore — configuration, plugins, monitoring
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: alembic>=1.18.0
7
+ Requires-Dist: httpx>=0.27
8
+ Requires-Dist: psutil>=5.9
9
+ Requires-Dist: python-dotenv>=1.0.0
10
+ Requires-Dist: pyyaml>=6.0.1
11
+ Requires-Dist: rich>=14.3.4
12
+ Requires-Dist: sqlalchemy>=2.0.0
13
+ Requires-Dist: typer>=0.25.1
14
+ Description-Content-Type: text/markdown
15
+
16
+ # xcli — xcore project manager
17
+
18
+ Official CLI for the `xcore` framework: scaffold a project, manage
19
+ plugins (local dev, marketplace install, runtime control, signing), run
20
+ migrations, control the Celery worker, and monitor a running deployment.
21
+
22
+ ```bash
23
+ pip install xcorecli
24
+ xcli --help
25
+ ```
26
+
27
+ Full docs: https://docs.xcorehub.dev (built from `docs/` with
28
+ `mkdocs-material` — `mkdocs serve` locally).
29
+
30
+ ## Quick start
31
+
32
+ ```bash
33
+ xcli init my-app # scaffold a new xcore project
34
+ cd my-app
35
+ pip install -r requirements.txt
36
+ xcli manager start --reload # run it
37
+ ```
38
+
39
+ ## Installing plugins from the marketplace
40
+
41
+ Browsing is public, no credentials needed:
42
+
43
+ ```bash
44
+ xcli plugin marketplace browse
45
+ xcli plugin marketplace search "auth"
46
+ xcli plugin marketplace info xlicense
47
+ ```
48
+
49
+ Installing needs two credentials — see
50
+ [docs/getting-started/auth.md](docs/getting-started/auth.md):
51
+
52
+ ```bash
53
+ xcli config set api-key xdk_...
54
+ xcli config set signing-key <your-signing-secret>
55
+ xcli plugin install xlicense
56
+ ```
57
+
58
+ ## Command groups
59
+
60
+ | Group | Purpose |
61
+ |-------|---------|
62
+ | `xcli init` / `xcli upgrade` | Scaffold a project / migrate `integration.yaml` to the latest schema |
63
+ | `xcli health` / `xcli services` | Health-check and status of all configured services |
64
+ | `xcli config` | Store local credentials (`api-key`, `signing-key`) |
65
+ | `xcli plugin` | Local dev, marketplace browse/install, runtime control, signing, updates — see `xcli plugin --help` |
66
+ | `xcli deploy` | Deploy plugins to remote servers |
67
+ | `xcli sandbox` | Inspect the plugin sandbox |
68
+ | `xcli worker` | Manage Celery workers |
69
+ | `xcli manager` | Runtime monitoring of a running instance |
70
+ | `xcli migration` | Alembic migrations for plugins |
71
+
72
+ Short hidden aliases exist for the busiest groups: `p` (plugin), `sb`
73
+ (sandbox), `w` (worker), `m` (manager), `mig` (migration).
74
+
75
+ `xcli` expects to run **inside** an xcore project directory (it reads that
76
+ project's `integration.yaml` and needs `xcore` importable in the current
77
+ environment) — it's a project-management tool, not a standalone service.
@@ -0,0 +1,62 @@
1
+ # xcli — xcore project manager
2
+
3
+ Official CLI for the `xcore` framework: scaffold a project, manage
4
+ plugins (local dev, marketplace install, runtime control, signing), run
5
+ migrations, control the Celery worker, and monitor a running deployment.
6
+
7
+ ```bash
8
+ pip install xcorecli
9
+ xcli --help
10
+ ```
11
+
12
+ Full docs: https://docs.xcorehub.dev (built from `docs/` with
13
+ `mkdocs-material` — `mkdocs serve` locally).
14
+
15
+ ## Quick start
16
+
17
+ ```bash
18
+ xcli init my-app # scaffold a new xcore project
19
+ cd my-app
20
+ pip install -r requirements.txt
21
+ xcli manager start --reload # run it
22
+ ```
23
+
24
+ ## Installing plugins from the marketplace
25
+
26
+ Browsing is public, no credentials needed:
27
+
28
+ ```bash
29
+ xcli plugin marketplace browse
30
+ xcli plugin marketplace search "auth"
31
+ xcli plugin marketplace info xlicense
32
+ ```
33
+
34
+ Installing needs two credentials — see
35
+ [docs/getting-started/auth.md](docs/getting-started/auth.md):
36
+
37
+ ```bash
38
+ xcli config set api-key xdk_...
39
+ xcli config set signing-key <your-signing-secret>
40
+ xcli plugin install xlicense
41
+ ```
42
+
43
+ ## Command groups
44
+
45
+ | Group | Purpose |
46
+ |-------|---------|
47
+ | `xcli init` / `xcli upgrade` | Scaffold a project / migrate `integration.yaml` to the latest schema |
48
+ | `xcli health` / `xcli services` | Health-check and status of all configured services |
49
+ | `xcli config` | Store local credentials (`api-key`, `signing-key`) |
50
+ | `xcli plugin` | Local dev, marketplace browse/install, runtime control, signing, updates — see `xcli plugin --help` |
51
+ | `xcli deploy` | Deploy plugins to remote servers |
52
+ | `xcli sandbox` | Inspect the plugin sandbox |
53
+ | `xcli worker` | Manage Celery workers |
54
+ | `xcli manager` | Runtime monitoring of a running instance |
55
+ | `xcli migration` | Alembic migrations for plugins |
56
+
57
+ Short hidden aliases exist for the busiest groups: `p` (plugin), `sb`
58
+ (sandbox), `w` (worker), `m` (manager), `mig` (migration).
59
+
60
+ `xcli` expects to run **inside** an xcore project directory (it reads that
61
+ project's `integration.yaml` and needs `xcore` importable in the current
62
+ environment) — it's a project-management tool, not a standalone service.
@@ -0,0 +1,34 @@
1
+ # Login & Install Shortcut
2
+
3
+ Two small top-level commands, both really about the marketplace rather
4
+ than the local xcore runtime.
5
+
6
+ ## `xcli login`
7
+
8
+ Authorizes this machine with the marketplace via a device-code flow —
9
+ opens a browser, you confirm a 6-digit code, `xcli` saves the resulting
10
+ credentials on its own. Full walkthrough:
11
+ [Authentication → Quick Start](../getting-started/auth.md#quick-start-xcli-login).
12
+
13
+ ```bash
14
+ xcli login
15
+ ```
16
+
17
+ !!! tip "For CI, not this"
18
+ `xcli login` mints a **personal** credential meant for a human running
19
+ it interactively. CI pipelines should use a project-scoped key and the
20
+ `XCLI_API_KEY`/`XCLI_SIGNING_KEY` environment variables instead — see
21
+ [Environment variables](../getting-started/auth.md#environment-variables).
22
+
23
+ ## `xcli install`
24
+
25
+ A shortcut for [`xcli plugin install`](../plugin/install.md) — same
26
+ command, same options, one less word to type:
27
+
28
+ ```bash
29
+ xcli install name-of-plugin
30
+ xcli install name-of-plugin@1.2.3
31
+ ```
32
+
33
+ There's no equivalent top-level shortcut for service extensions — use
34
+ [`xcli service install`](../service/index.md) directly.
@@ -0,0 +1,110 @@
1
+ # Authentication
2
+
3
+ To interact with the **xcore marketplace** and install plugins, you need
4
+ two separate credentials — they protect different things and neither
5
+ substitutes for the other:
6
+
7
+ ## Quick Start: `xcli login`
8
+
9
+ The fastest way to get both credentials — no copy-pasting required.
10
+
11
+ ```bash title="Device-code login"
12
+ xcli login
13
+ ```
14
+
15
+ This opens the marketplace in your browser with a 6-digit code pre-filled,
16
+ and waits. Once you confirm it there (you must already be logged into the
17
+ marketplace website, and the confirmation is an explicit click — it never
18
+ happens automatically just by opening the link), `xcli` retrieves both
19
+ credentials on its own and saves them to `~/.xcli/config.json` — the exact
20
+ same file `xcli config set` writes to, just without the manual steps.
21
+
22
+ ```text
23
+ To authorize this device, visit: https://marketplace.xcorehub.dev/cli/confirm
24
+ And enter code: 042817
25
+
26
+ ✓ Logged in — credentials saved to ~/.xcli/config.json
27
+ ```
28
+
29
+ If the browser can't be opened automatically (headless environment, remote
30
+ shell), the URL and code are printed regardless — open it manually.
31
+
32
+ !!! info "What kind of key does this create?"
33
+ `xcli login` mints a **personal** API key — unlike a key created
34
+ through the marketplace's project UI (which is scoped to exactly one
35
+ plugin or service), a personal key works for installing **any public**
36
+ plugin or service, and any private one you own or have team access to.
37
+ It's meant for day-to-day `xcli install`/`xcli service install` usage,
38
+ not for CI — see [Environment variables](#environment-variables) below
39
+ for the project-scoped alternative CI pipelines should use instead.
40
+
41
+ The device-code request expires after a few minutes if left unconfirmed;
42
+ just run `xcli login` again.
43
+
44
+ ## Manual Setup
45
+
46
+ Prefer to configure credentials by hand, or need a **project-scoped** key
47
+ (tied to one specific plugin/service — the right choice for CI/CD, see
48
+ below) instead of a personal one? Both credentials can also be set directly:
49
+
50
+ | Credential | What it's for | Where to get it |
51
+ |------------|----------------|------------------|
52
+ | **API key** (`xdk_...`) | Authorizes the download itself (`X-API-Key` header on `GET /plugins/{slug}/install`) — tied to one project (`kind=plugin`, matching the target plugin's slug) | XCoreHub → Déploiements → Projets & clés |
53
+ | **Signing key** | An HMAC-SHA256 secret used to verify the `X-Signature` header on the downloaded ZIP — installation is refused if it doesn't match | XCoreHub → Déploiements → Clé de signature |
54
+
55
+ `browse`/`search`/`info` (read-only discovery) need **neither** — the
56
+ marketplace listing is public.
57
+
58
+ ## Configuration Commands
59
+
60
+ `xcorecli` provides a `config` command group to manage your local settings.
61
+
62
+ ### Store your credentials
63
+
64
+ ```bash title="Configuration"
65
+ xcli config set api-key xdk_...
66
+ xcli config set signing-key <your-signing-secret>
67
+ ```
68
+
69
+ Both are required before `xcli plugin install <name>` will succeed —
70
+ `install` checks for each explicitly and tells you exactly which one is
71
+ missing.
72
+
73
+ !!! warning "Security First"
74
+ Never share your API key or signing key, or commit them to version
75
+ control. They're stored in `~/.xcli/config.json` (mode `0600`), never in
76
+ your project's `integration.yaml`.
77
+
78
+ ### View current configuration
79
+
80
+ To check your current configuration (with sensitive data masked):
81
+
82
+ ```bash
83
+ xcli config show
84
+ ```
85
+
86
+ ## Credential storage
87
+
88
+ Managed by `xcli/_credentials.py` — a flat `~/.xcli/config.json`, keyed
89
+ `api-key` / `signing-key`. Only these two keys are valid; anything else
90
+ passed to `xcli config set` is rejected.
91
+
92
+ !!! info "Marketplace URL"
93
+ By default, `xcorecli` connects to `https://marketplace.xcorehub.dev`.
94
+ Override it via `marketplace.url` in the project's `integration.yaml`
95
+ (the same value the project's own backend uses) — always include the
96
+ `https://` scheme, a bare domain will fail to resolve as a URL.
97
+
98
+ ## Environment variables
99
+
100
+ For CI/CD environments, both credentials can be supplied via environment
101
+ variables instead of `xcli config set` — these take priority over
102
+ `~/.xcli/config.json` when present. Use a **project-scoped** key here (one
103
+ plugin/service, created from the marketplace's project page), not a
104
+ personal one from `xcli login` — a CI pipeline should only ever be able to
105
+ touch the one target it's meant to deploy:
106
+
107
+ ```bash title=".env"
108
+ XCLI_API_KEY=xdk_...
109
+ XCLI_SIGNING_KEY=your-signing-secret
110
+ ```
@@ -2,6 +2,13 @@
2
2
 
3
3
  `xcorecli` provides a streamlined wrapper around **Alembic** to manage your database schema migrations, with added safety features like automated backups.
4
4
 
5
+ !!! info "Async database support"
6
+ `upgrade`/`downgrade`/`revision`/`current`/`stamp` all transparently
7
+ bridge to an async engine first when your `integration.yaml` database
8
+ URL uses an async driver (`sqlite+aiosqlite`, `postgresql+asyncpg`,
9
+ ...) — the normal case for an xcore project. No configuration needed;
10
+ it's detected from the URL itself.
11
+
5
12
  ## Getting Started
6
13
 
7
14
  Migrations are managed via the `migration` command group.
@@ -6,10 +6,21 @@ Plugins can be installed from the official **xcore Marketplace** or from externa
6
6
 
7
7
  The easiest way to add features. `xcorecli` handles downloads and HMAC signature verification.
8
8
 
9
+ !!! warning "Two credentials required"
10
+ Marketplace installs need **both** an API key and a signing key
11
+ configured first — see [Authentication](../getting-started/auth.md).
12
+ Missing either one fails fast with a clear message telling you which
13
+ one and how to set it; nothing is extracted until the signature checks
14
+ out.
15
+
9
16
  ```bash title="Marketplace Install"
10
17
  xcli plugin install name-of-plugin
11
18
  ```
12
19
 
20
+ !!! tip "Shortcut"
21
+ `xcli install name-of-plugin` works too — a top-level alias for
22
+ `xcli plugin install`, same command underneath.
23
+
13
24
  ### Installing a Specific Version
14
25
 
15
26
  ```bash
@@ -0,0 +1,46 @@
1
+ # Plugin Marketplace
2
+
3
+ Discover plugins available on the marketplace before installing them — all
4
+ three commands here are read-only and public, no credentials required.
5
+
6
+ ## Browse All
7
+
8
+ List published plugins, sorted `newest` (default), `downloads`, or `rating`.
9
+
10
+ ```bash
11
+ xcli plugin marketplace browse
12
+ xcli plugin marketplace browse --sort downloads --limit 50
13
+ ```
14
+
15
+ ## Search
16
+
17
+ Find plugins by name or description.
18
+
19
+ ```bash title="Search"
20
+ xcli plugin marketplace search "monitoring"
21
+ ```
22
+
23
+ ## Plugin Details
24
+
25
+ Get in-depth information about a specific marketplace plugin before
26
+ installing it — description, rating, download count, repository, and
27
+ published versions.
28
+
29
+ ```bash title="Plugin Info"
30
+ xcli plugin marketplace info name-of-plugin
31
+ ```
32
+
33
+ ## What's not here
34
+
35
+ Rating a plugin (`POST /plugins/{slug}/ratings`) requires a full user
36
+ session (Bearer JWT), not the API key `xcli` stores — that's a web-app
37
+ action, not a CLI one; rate plugins from the XCoreHub dashboard instead.
38
+ There's also no dedicated "trending" endpoint server-side — use
39
+ `browse --sort downloads` or `--sort rating` for the same effect.
40
+
41
+ ## Installing
42
+
43
+ Once you've found a plugin, see [Installing Plugins](install.md) — it
44
+ needs the API key and signing key described in
45
+ [Authentication](../getting-started/auth.md), which discovery commands on
46
+ this page don't.
@@ -6,8 +6,11 @@ A comprehensive list of all commands available in `xcorecli`.
6
6
 
7
7
  - `xcli init`: Initialize a new xcore project.
8
8
  - `xcli upgrade`: Migrate `integration.yaml` to the latest schema.
9
+ - `xcli login`: Authorize this machine with the marketplace (device-code flow).
10
+ - `xcli install`: Shortcut for `xcli plugin install`.
9
11
  - `xcli health`: Global health check of all configured services.
10
- - `xcli services`: Show status and details of all system services.
12
+ - `xcli services`: Show status and details of all system services (local
13
+ runtime — not the marketplace catalog, see `xcli service` below).
11
14
 
12
15
  ## `manager` Administration
13
16
 
@@ -44,11 +47,12 @@ A comprehensive list of all commands available in `xcorecli`.
44
47
  - `local list`: List all plugins with link type.
45
48
 
46
49
  ### `plugin marketplace` Discovery
47
- - `marketplace browse`: List all available plugins.
48
- - `marketplace search`: Search by keyword.
49
- - `marketplace info`: Pre-install details.
50
- - `marketplace trending`: Show popular plugins.
51
- - `marketplace rate`: Rate 15 stars.
50
+ - `marketplace browse`: List published plugins (`--sort newest|downloads|rating`).
51
+ - `marketplace search`: Search by name or description.
52
+ - `marketplace info`: Pre-install details, including published versions.
53
+
54
+ No `rate` command — rating requires a full user session (JWT), not an API
55
+ key; rate plugins from the XCoreHub dashboard.
52
56
 
53
57
  ### `plugin update` Maintenance
54
58
  - `update check`: Check for new versions.
@@ -60,6 +64,22 @@ A comprehensive list of all commands available in `xcorecli`.
60
64
  - `runtime reload`: Restart a plugin.
61
65
  - `runtime status`: Show active plugins.
62
66
 
67
+ ## `service` Marketplace Extensions
68
+
69
+ Mirror of `plugin` for the separate `xservices` catalog — not to be
70
+ confused with `xcli services`/`xcli manager services` (local runtime).
71
+
72
+ - `service info`: Detailed local extension report.
73
+ - `service health`: Health check of all installed extensions.
74
+ - `service remove`: Uninstall an extension.
75
+ - `service install`: Install from marketplace.
76
+ - `service versions`: List marketplace versions.
77
+
78
+ ### `service marketplace` Discovery
79
+ - `marketplace browse`: List published extensions (`--sort newest|installs|rating`).
80
+ - `marketplace search`: Search by name or description.
81
+ - `marketplace info`: Pre-install details, including published versions.
82
+
63
83
  ## `worker` Background Tasks
64
84
 
65
85
  - `worker start`: Start a Celery worker.
@@ -0,0 +1,69 @@
1
+ # Service Extensions
2
+
3
+ The marketplace also hosts **service extensions** (`xservices`) — a
4
+ separate catalog from plugins, for reusable service-shaped dependencies a
5
+ plugin might need (databases, caches, message queues...). The `service`
6
+ command group mirrors `plugin` one-for-one, just pointed at that other
7
+ catalog.
8
+
9
+ !!! warning "Not `xcli services`"
10
+ `xcli service` (singular, this page) is the marketplace catalog.
11
+ `xcli services` and `xcli manager services` (plural) show your
12
+ **local** xcore runtime's own service status — an unrelated command
13
+ that happens to share a similar name. If a command errors with
14
+ something about your local `ServiceContainer`, you probably typed the
15
+ plural by mistake.
16
+
17
+ ## Discovery
18
+
19
+ Read-only, public, no credentials required — same shape as
20
+ [Plugin Marketplace](../plugin/marketplace.md):
21
+
22
+ ```bash
23
+ xcli service marketplace browse
24
+ xcli service marketplace browse --sort installs --limit 50
25
+ xcli service marketplace search "cache"
26
+ xcli service marketplace info name-of-service
27
+ ```
28
+
29
+ `--sort` accepts `newest` (default), `installs`, or `rating` — note
30
+ `installs`, not `downloads`; the service catalog counts installs, not
31
+ downloads.
32
+
33
+ ## Installing
34
+
35
+ Same two credentials as plugins — see [Authentication](../getting-started/auth.md)
36
+ (`xcli login` covers both catalogs at once; a project-scoped key is
37
+ per-catalog, so make sure the project you created it for has
38
+ `kind=service`).
39
+
40
+ ```bash title="Install"
41
+ xcli service install name-of-service
42
+ xcli service install name-of-service@1.2.3
43
+ ```
44
+
45
+ Installed extensions land in the directory configured under
46
+ `marketplace_services.directory` in `integration.yaml` (defaults to
47
+ `./services`) — deliberately a separate key from `plugins.directory` and
48
+ from `services.databases.*` (xcore's own internal service container
49
+ config), which already both use `services`/`plugins` for something else.
50
+
51
+ ```bash
52
+ xcli service versions name-of-service
53
+ ```
54
+
55
+ ## Management Commands
56
+
57
+ Identical shape to `plugin`:
58
+
59
+ ```bash
60
+ xcli service info name-of-service # manifest, permissions, signature status
61
+ xcli service health # signature + AST + manifest check, all installed
62
+ xcli service remove name-of-service # uninstall
63
+ ```
64
+
65
+ !!! info "Smaller surface than `plugin`"
66
+ There's no `service local`/`service runtime`/`service security`/
67
+ `service update` today — service extensions don't have the same
68
+ local-dev-scaffolding or hot-reload workflow plugins do. Everything
69
+ that exists lives directly under `xcli service`.
@@ -58,6 +58,7 @@ nav:
58
58
  - Global Commands:
59
59
  - init & upgrade: commands/init.md
60
60
  - health & services: commands/health.md
61
+ - login & install: commands/login.md
61
62
  - Config: config/index.md
62
63
  - Plugin:
63
64
  - Overview: plugin/index.md
@@ -67,6 +68,7 @@ nav:
67
68
  - Marketplace: plugin/marketplace.md
68
69
  - Security: plugin/security.md
69
70
  - Updates: plugin/update.md
71
+ - Service: service/index.md
70
72
  - Sandbox: sandbox/index.md
71
73
  - Worker:
72
74
  - Overview: worker/index.md
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "xcorecli"
7
- version = "2.0.0"
7
+ version = "2.1.0"
8
8
  description = "CLI for xcore — configuration, plugins, monitoring"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -16,6 +16,12 @@ dependencies = [
16
16
  "pyyaml>=6.0.1",
17
17
  "psutil>=5.9",
18
18
  "httpx>=0.27",
19
+ # xcli migration needs to resolve ${VAR}-style placeholders in
20
+ # integration.yaml's services.databases.*.url the same way the app
21
+ # itself does at runtime (xcore.configurations.loader.ConfigLoader,
22
+ # same app.dotenv key, same library) — declared directly rather than
23
+ # relying on it being transitively present via an installed `xcore`.
24
+ "python-dotenv>=1.0.0",
19
25
  ]
20
26
 
21
27
  [project.scripts]
@@ -569,6 +569,15 @@ wheels = [
569
569
  { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
570
570
  ]
571
571
 
572
+ [[package]]
573
+ name = "python-dotenv"
574
+ version = "1.2.3"
575
+ source = { registry = "https://pypi.org/simple" }
576
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz", hash = "sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", size = 58945, upload-time = "2026-08-16T16:54:54.067Z" }
577
+ wheels = [
578
+ { url = "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl", hash = "sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", size = 22780, upload-time = "2026-08-16T16:54:52.473Z" },
579
+ ]
580
+
572
581
  [[package]]
573
582
  name = "pyyaml"
574
583
  version = "6.0.3"
@@ -779,6 +788,7 @@ dependencies = [
779
788
  { name = "alembic" },
780
789
  { name = "httpx" },
781
790
  { name = "psutil" },
791
+ { name = "python-dotenv" },
782
792
  { name = "pyyaml" },
783
793
  { name = "rich" },
784
794
  { name = "sqlalchemy" },
@@ -795,6 +805,7 @@ requires-dist = [
795
805
  { name = "alembic", specifier = ">=1.18.0" },
796
806
  { name = "httpx", specifier = ">=0.27" },
797
807
  { name = "psutil", specifier = ">=5.9" },
808
+ { name = "python-dotenv", specifier = ">=1.0.0" },
798
809
  { name = "pyyaml", specifier = ">=6.0.1" },
799
810
  { name = "rich", specifier = ">=14.3.4" },
800
811
  { name = "sqlalchemy", specifier = ">=2.0.0" },
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import webbrowser
5
+
6
+ import httpx
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from xcli._credentials import save_credential
11
+ from xcli.plugin.shared import marketplace_api_base
12
+
13
+ console = Console()
14
+
15
+ _START_PATH = '/app/xdevkeys/device/start'
16
+ _POLL_PATH = '/app/xdevkeys/device/poll'
17
+
18
+
19
+ def _try_open(url: str) -> bool:
20
+ try:
21
+ return webbrowser.open(url)
22
+ except Exception:
23
+ return False
24
+
25
+
26
+ def login() -> None:
27
+ """`xcli login` — device-code flow (RFC 8628): opens the marketplace in a
28
+ browser for the user to confirm a 6-digit code, then polls until the
29
+ marketplace hands back a personal API key + signing key, saved straight
30
+ into ~/.xcli/config.json (same store `xcli config set` writes to — this
31
+ is just that, automated). The raw secrets are never printed."""
32
+ base = marketplace_api_base()
33
+
34
+ try:
35
+ resp = httpx.post(f'{base}{_START_PATH}', timeout=15)
36
+ resp.raise_for_status()
37
+ except httpx.RequestError as e:
38
+ console.print(f'[red]Network error:[/red] {e}')
39
+ raise typer.Exit(1)
40
+ except httpx.HTTPStatusError as e:
41
+ console.print(f'[red]HTTP {e.response.status_code}:[/red] {e.response.text[:200]}')
42
+ raise typer.Exit(1)
43
+
44
+ data = resp.json()
45
+ device_code = data['device_code']
46
+ user_code = data['user_code']
47
+ verification_uri = data['verification_uri']
48
+ expires_in = data['expires_in']
49
+ interval = data['interval']
50
+ complete_url = f'{verification_uri}?code={user_code}'
51
+
52
+ console.print(f"\nTo authorize this device, visit: [cyan]{verification_uri}[/cyan]")
53
+ console.print(f"And enter code: [bold yellow]{user_code}[/bold yellow]\n")
54
+ if not _try_open(complete_url):
55
+ console.print("[dim]Couldn't open a browser automatically — open the URL above manually and enter the code.[/dim]\n")
56
+
57
+ deadline = time.monotonic() + expires_in
58
+ with console.status('Waiting for authorization...'):
59
+ while time.monotonic() < deadline:
60
+ time.sleep(interval)
61
+ try:
62
+ poll_resp = httpx.get(f'{base}{_POLL_PATH}', params={'device_code': device_code}, timeout=15)
63
+ except httpx.RequestError:
64
+ continue
65
+
66
+ if poll_resp.status_code == 404:
67
+ console.print('[red]Login request expired or was already used.[/red] Run [cyan]xcli login[/cyan] again.')
68
+ raise typer.Exit(1)
69
+ if poll_resp.status_code != 200:
70
+ continue
71
+
72
+ payload = poll_resp.json()
73
+ if payload.get('status') == 'confirmed':
74
+ save_credential('api-key', payload['api_key'])
75
+ save_credential('signing-key', payload['signing_key'])
76
+ console.print('[green]✓[/green] Logged in — credentials saved to [dim]~/.xcli/config.json[/dim]')
77
+ return
78
+
79
+ console.print('[red]Login timed out.[/red] Run [cyan]xcli login[/cyan] again.')
80
+ raise typer.Exit(1)