elemctl 0.43.2__tar.gz → 0.45.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. {elemctl-0.43.2 → elemctl-0.45.0}/PKG-INFO +26 -8
  2. {elemctl-0.43.2 → elemctl-0.45.0}/README.md +25 -7
  3. {elemctl-0.43.2 → elemctl-0.45.0}/docs/SPEC.md +92 -18
  4. {elemctl-0.43.2 → elemctl-0.45.0}/docs/SPEC.ru.md +177 -22
  5. {elemctl-0.43.2 → elemctl-0.45.0}/docs/changelog.md +46 -0
  6. {elemctl-0.43.2 → elemctl-0.45.0}/docs/changelog.ru.md +44 -0
  7. {elemctl-0.43.2 → elemctl-0.45.0}/docs/cli.md +32 -5
  8. {elemctl-0.43.2 → elemctl-0.45.0}/docs/cli.ru.md +32 -5
  9. {elemctl-0.43.2 → elemctl-0.45.0}/docs/config.md +19 -3
  10. {elemctl-0.43.2 → elemctl-0.45.0}/docs/config.ru.md +18 -3
  11. {elemctl-0.43.2 → elemctl-0.45.0}/docs/mcp.md +6 -4
  12. {elemctl-0.43.2 → elemctl-0.45.0}/docs/mcp.ru.md +6 -4
  13. {elemctl-0.43.2 → elemctl-0.45.0}/docs/platform.md +7 -1
  14. {elemctl-0.43.2 → elemctl-0.45.0}/docs/platform.ru.md +49 -5
  15. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/__init__.py +1 -1
  16. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/build.py +4 -0
  17. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/cli.py +138 -27
  18. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/client.py +380 -27
  19. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/deploy.py +193 -68
  20. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/errors.py +10 -0
  21. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/i18n.py +350 -16
  22. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/mcp_server.py +81 -10
  23. elemctl-0.45.0/src/elemctl/probe.py +816 -0
  24. elemctl-0.45.0/src/elemctl/registry.py +161 -0
  25. elemctl-0.45.0/src/elemctl/schema.py +489 -0
  26. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/selfupdate.py +181 -35
  27. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/PKG-INFO +26 -8
  28. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/SOURCES.txt +6 -0
  29. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_cli.py +5 -0
  30. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_client.py +32 -10
  31. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_deploy.py +157 -4
  32. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_i18n.py +4 -1
  33. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_mcp.py +10 -1
  34. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_probe.py +168 -1
  35. elemctl-0.45.0/tests/test_probe_cleanup.py +279 -0
  36. elemctl-0.45.0/tests/test_registry.py +364 -0
  37. elemctl-0.45.0/tests/test_schema.py +534 -0
  38. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_selfupdate.py +24 -11
  39. elemctl-0.45.0/tests/test_selfupdate_latest.py +270 -0
  40. elemctl-0.45.0/tests/test_server_starting.py +266 -0
  41. elemctl-0.45.0/tests/test_token_access.py +248 -0
  42. elemctl-0.43.2/src/elemctl/probe.py +0 -398
  43. elemctl-0.43.2/src/elemctl/schema.py +0 -221
  44. elemctl-0.43.2/tests/test_schema.py +0 -247
  45. {elemctl-0.43.2 → elemctl-0.45.0}/.env.example +0 -0
  46. {elemctl-0.43.2 → elemctl-0.45.0}/LICENSE +0 -0
  47. {elemctl-0.43.2 → elemctl-0.45.0}/MANIFEST.in +0 -0
  48. {elemctl-0.43.2 → elemctl-0.45.0}/NOTICE +0 -0
  49. {elemctl-0.43.2 → elemctl-0.45.0}/ORIGIN.md +0 -0
  50. {elemctl-0.43.2 → elemctl-0.45.0}/docs/index.md +0 -0
  51. {elemctl-0.43.2 → elemctl-0.45.0}/docs/index.ru.md +0 -0
  52. {elemctl-0.43.2 → elemctl-0.45.0}/docs/library.md +0 -0
  53. {elemctl-0.43.2 → elemctl-0.45.0}/docs/library.ru.md +0 -0
  54. {elemctl-0.43.2 → elemctl-0.45.0}/pyproject.toml +0 -0
  55. {elemctl-0.43.2 → elemctl-0.45.0}/setup.cfg +0 -0
  56. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/__main__.py +0 -0
  57. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/auth.py +0 -0
  58. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/config.py +0 -0
  59. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/plugins.py +0 -0
  60. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/transport.py +0 -0
  61. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl/versions.py +0 -0
  62. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/dependency_links.txt +0 -0
  63. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/entry_points.txt +0 -0
  64. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/requires.txt +0 -0
  65. {elemctl-0.43.2 → elemctl-0.45.0}/src/elemctl.egg-info/top_level.txt +0 -0
  66. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_build.py +0 -0
  67. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_changelog_link.py +0 -0
  68. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_cli_docs.py +0 -0
  69. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_config.py +0 -0
  70. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_conventions.py +0 -0
  71. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_docs_coverage.py +0 -0
  72. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_extract_adapter.py +0 -0
  73. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_plugins.py +0 -0
  74. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_rebuild_docs.py +0 -0
  75. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_release_notes.py +0 -0
  76. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_transport.py +0 -0
  77. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_user_lists.py +0 -0
  78. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_versions.py +0 -0
  79. {elemctl-0.43.2 → elemctl-0.45.0}/tests/test_workflows.py +0 -0
  80. {elemctl-0.43.2 → elemctl-0.45.0}/tools/extract_adapter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elemctl
3
- Version: 0.43.2
3
+ Version: 0.45.0
4
4
  Summary: CLI, MCP server and library for the Console API v2 of the 1C:Enterprise.Element platform (1cmycloud): applications, builds from source, one-command deploy with verification, a compile probe
5
5
  Author: KeyFire
6
6
  License-Expression: MIT
@@ -205,15 +205,31 @@ for the cache to watch and stays pinned for the life of the process instead.
205
205
 
206
206
  ### Behaviour of the tool
207
207
 
208
- `ELEMCTL_LANG` and `ELEMCTL_NO_PLUGINS` are set through the environment only – a
209
- connection `.env` is not their place. `ELEMCTL_NO_PROXY` is the exception,
210
- explained above: it reads the same file the connection does.
208
+ `ELEMCTL_LANG`, `ELEMCTL_NO_PLUGINS` and `ELEMCTL_DATA_DIR` are set through the
209
+ environment only – a connection `.env` is not their place. `ELEMCTL_NO_PROXY` is the
210
+ exception, explained above: it reads the same file the connection does.
211
211
 
212
212
  | Variable | Purpose |
213
213
  |---|---|
214
214
  | `ELEMCTL_LANG` | language of the messages and the help (`ru`, `en`); the `--lang` flag wins over it |
215
215
  | `ELEMCTL_NO_PROXY` | set it to bypass the environment's proxy for every call (loopback and private addresses are bypassed anyway); also readable from the stand's `.env` |
216
216
  | `ELEMCTL_NO_PLUGINS` | do not look for plugins: work with the core capabilities only |
217
+ | `ELEMCTL_DATA_DIR` | the directory of the local registry of uploads; by default `%LOCALAPPDATA%\elemctl` on Windows and `$XDG_STATE_HOME/elemctl` (`~/.local/state/elemctl`) elsewhere |
218
+
219
+ ### The local registry of uploads
220
+
221
+ The platform keeps the commit of a build uploaded into an existing project and nothing else
222
+ of where the build came from. So every upload elemctl makes – `deploy`, `builds upload`,
223
+ `probe` – also appends a line to `uploads.jsonl` in the data directory above: the build id,
224
+ the project, the version, the branch, the commit, whether the tree had uncommitted changes,
225
+ the directory of the sources, the stand, the command and the time. `builds list --brief`
226
+ and `apps get` fill the branch and the commit the card left empty from it and name the
227
+ source of each value.
228
+
229
+ The registry is local. A build uploaded from another machine, from CI or by an elemctl that
230
+ had no registry yet is not in it, and there the listings show what the platform knows. A
231
+ registry that cannot be written is a warning and never a failed upload; the file can be
232
+ deleted at any time, and only the history of this machine goes with it.
217
233
 
218
234
  ### The CI environment
219
235
 
@@ -308,7 +324,7 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
308
324
  |---|---|
309
325
  | `list_apps` | list of applications; the deleted ones are hidden unless `include_deleted` asks for them, `name` filters by a substring of the name on the client and `status` by the status word; the answer carries the counters and a `summary` line next to `applications`, `brief` (the default) keeps id, name, status, uri and the applied version |
310
326
  | `find_app` | find an application by its exact name: the id and a `found` flag; deleted ones are skipped unless `include_deleted` is set |
311
- | `get_app` | application card: status, uri, the actual project version |
327
+ | `get_app` | application card: status, uri, the actual project version; `applied-build` carries the branch and the commit of the build it runs, from the build card or from the local registry of uploads |
312
328
  | `create_app` | create an application; with only a `project_id` the source is the project's latest build. The answer carries `sign-in` – the way in; `verify` waits for the application and checks the build it really runs |
313
329
  | `ensure_app` | create an application by name only if it does not exist yet; an existing one is not recreated (`created: false`); `verify` checks the build the application really runs |
314
330
  | `start_app` | start the application |
@@ -318,16 +334,18 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
318
334
  | `debug_info` | debug-session data: `debug-token` and `debug-address` (debugging must be enabled on the server) |
319
335
  | `list_spaces` | list of spaces |
320
336
  | `list_projects` | list of projects; `name` filters by a substring of the name on the client, the deleted ones are hidden unless `include_deleted` is set; `brief` (the default) – id, name, project kind, space, application count, deletion flag |
321
- | `list_builds` | a project's builds, newest first; the answer is an object `{total, shown, summary, builds}`; `limit` (default 10, 0 – all), `brief` (the default) keeps id, versions, date, branch and commit |
337
+ | `list_builds` | a project's builds, newest first; the answer is an object `{total, shown, summary, builds}`; `limit` (default 10, 0 – all), `brief` (the default) keeps id, versions, date, branch and commit, and names where the branch and the commit came from: the card or the local registry of uploads |
322
338
  | `get_build` | the whole card of one build; `version` is the build's version (`1.0-42`), an id is accepted too and resolved through the listing |
323
339
  | `build_assembly` | build a `.xasm`/`.xlib` archive from the sources locally (does not talk to the platform) |
324
340
  | `inspect_assembly` | parse a built archive: manifest, project properties, subsystems and global types with qualified names (local) |
325
- | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log` |
326
- | `probe` | check the compilation with the server compiler without touching the working application; errors with file, line and column, cleans up after itself |
341
+ | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log`; a server that is still starting is waited out for up to `server_start_timeout` seconds (900 by default) |
342
+ | `probe` | check the compilation with the server compiler without touching the working application; errors with file, line and column, cleans up after itself; with `keep` the report names the command that removes what was left |
343
+ | `probe_cleanup` | remove a probe left on the stand, by `keep` or by a cleanup that broke off, starting from its application: the application, the probe build in the probe's own project and the project when nothing is left in it; an application that is not a probe's is refused |
327
344
  | `apply_build` | apply an uploaded build to the application by its id |
328
345
  | `verify_deploy` | verify the apply actually took effect: failed tasks, the applied build, the availability of the uri |
329
346
  | `list_user_lists` | user lists; `name` filters by a substring of the presentation |
330
347
  | `configure_user_list` | self-registration and password sign-in; without the flags it only reports the current state |
348
+ | `token_access` | a user's access to the HTTP services of an application by a token, the flag behind a 500 "Token access is denied"; shows it, and with `enabled` switches it and reads it back; an empty `user` means the account elemctl signs in with |
331
349
  | `list_branches` | list of development-environment branches; the `project_id` and `name` filters are optional |
332
350
  | `merge_branch` | accept the changes of a development-environment branch |
333
351
  | `debug_adapter` | the path to the platform debug adapter from a plugin; a missing plugin is an answer (`found: false`), not an error (local) |
@@ -173,15 +173,31 @@ for the cache to watch and stays pinned for the life of the process instead.
173
173
 
174
174
  ### Behaviour of the tool
175
175
 
176
- `ELEMCTL_LANG` and `ELEMCTL_NO_PLUGINS` are set through the environment only – a
177
- connection `.env` is not their place. `ELEMCTL_NO_PROXY` is the exception,
178
- explained above: it reads the same file the connection does.
176
+ `ELEMCTL_LANG`, `ELEMCTL_NO_PLUGINS` and `ELEMCTL_DATA_DIR` are set through the
177
+ environment only – a connection `.env` is not their place. `ELEMCTL_NO_PROXY` is the
178
+ exception, explained above: it reads the same file the connection does.
179
179
 
180
180
  | Variable | Purpose |
181
181
  |---|---|
182
182
  | `ELEMCTL_LANG` | language of the messages and the help (`ru`, `en`); the `--lang` flag wins over it |
183
183
  | `ELEMCTL_NO_PROXY` | set it to bypass the environment's proxy for every call (loopback and private addresses are bypassed anyway); also readable from the stand's `.env` |
184
184
  | `ELEMCTL_NO_PLUGINS` | do not look for plugins: work with the core capabilities only |
185
+ | `ELEMCTL_DATA_DIR` | the directory of the local registry of uploads; by default `%LOCALAPPDATA%\elemctl` on Windows and `$XDG_STATE_HOME/elemctl` (`~/.local/state/elemctl`) elsewhere |
186
+
187
+ ### The local registry of uploads
188
+
189
+ The platform keeps the commit of a build uploaded into an existing project and nothing else
190
+ of where the build came from. So every upload elemctl makes – `deploy`, `builds upload`,
191
+ `probe` – also appends a line to `uploads.jsonl` in the data directory above: the build id,
192
+ the project, the version, the branch, the commit, whether the tree had uncommitted changes,
193
+ the directory of the sources, the stand, the command and the time. `builds list --brief`
194
+ and `apps get` fill the branch and the commit the card left empty from it and name the
195
+ source of each value.
196
+
197
+ The registry is local. A build uploaded from another machine, from CI or by an elemctl that
198
+ had no registry yet is not in it, and there the listings show what the platform knows. A
199
+ registry that cannot be written is a warning and never a failed upload; the file can be
200
+ deleted at any time, and only the history of this machine goes with it.
185
201
 
186
202
  ### The CI environment
187
203
 
@@ -276,7 +292,7 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
276
292
  |---|---|
277
293
  | `list_apps` | list of applications; the deleted ones are hidden unless `include_deleted` asks for them, `name` filters by a substring of the name on the client and `status` by the status word; the answer carries the counters and a `summary` line next to `applications`, `brief` (the default) keeps id, name, status, uri and the applied version |
278
294
  | `find_app` | find an application by its exact name: the id and a `found` flag; deleted ones are skipped unless `include_deleted` is set |
279
- | `get_app` | application card: status, uri, the actual project version |
295
+ | `get_app` | application card: status, uri, the actual project version; `applied-build` carries the branch and the commit of the build it runs, from the build card or from the local registry of uploads |
280
296
  | `create_app` | create an application; with only a `project_id` the source is the project's latest build. The answer carries `sign-in` – the way in; `verify` waits for the application and checks the build it really runs |
281
297
  | `ensure_app` | create an application by name only if it does not exist yet; an existing one is not recreated (`created: false`); `verify` checks the build the application really runs |
282
298
  | `start_app` | start the application |
@@ -286,16 +302,18 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
286
302
  | `debug_info` | debug-session data: `debug-token` and `debug-address` (debugging must be enabled on the server) |
287
303
  | `list_spaces` | list of spaces |
288
304
  | `list_projects` | list of projects; `name` filters by a substring of the name on the client, the deleted ones are hidden unless `include_deleted` is set; `brief` (the default) – id, name, project kind, space, application count, deletion flag |
289
- | `list_builds` | a project's builds, newest first; the answer is an object `{total, shown, summary, builds}`; `limit` (default 10, 0 – all), `brief` (the default) keeps id, versions, date, branch and commit |
305
+ | `list_builds` | a project's builds, newest first; the answer is an object `{total, shown, summary, builds}`; `limit` (default 10, 0 – all), `brief` (the default) keeps id, versions, date, branch and commit, and names where the branch and the commit came from: the card or the local registry of uploads |
290
306
  | `get_build` | the whole card of one build; `version` is the build's version (`1.0-42`), an id is accepted too and resolved through the listing |
291
307
  | `build_assembly` | build a `.xasm`/`.xlib` archive from the sources locally (does not talk to the platform) |
292
308
  | `inspect_assembly` | parse a built archive: manifest, project properties, subsystems and global types with qualified names (local) |
293
- | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log` |
294
- | `probe` | check the compilation with the server compiler without touching the working application; errors with file, line and column, cleans up after itself |
309
+ | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log`; a server that is still starting is waited out for up to `server_start_timeout` seconds (900 by default) |
310
+ | `probe` | check the compilation with the server compiler without touching the working application; errors with file, line and column, cleans up after itself; with `keep` the report names the command that removes what was left |
311
+ | `probe_cleanup` | remove a probe left on the stand, by `keep` or by a cleanup that broke off, starting from its application: the application, the probe build in the probe's own project and the project when nothing is left in it; an application that is not a probe's is refused |
295
312
  | `apply_build` | apply an uploaded build to the application by its id |
296
313
  | `verify_deploy` | verify the apply actually took effect: failed tasks, the applied build, the availability of the uri |
297
314
  | `list_user_lists` | user lists; `name` filters by a substring of the presentation |
298
315
  | `configure_user_list` | self-registration and password sign-in; without the flags it only reports the current state |
316
+ | `token_access` | a user's access to the HTTP services of an application by a token, the flag behind a 500 "Token access is denied"; shows it, and with `enabled` switches it and reads it back; an empty `user` means the account elemctl signs in with |
299
317
  | `list_branches` | list of development-environment branches; the `project_id` and `name` filters are optional |
300
318
  | `merge_branch` | accept the changes of a development-environment branch |
301
319
  | `debug_adapter` | the path to the platform debug adapter from a plugin; a missing plugin is an answer (`found: false`), not an error (local) |
@@ -71,6 +71,9 @@ Common prefix: `{base}/console/api/v2`. Request and response bodies are JSON, ap
71
71
  - `POST /applications/{id}/project/update` – apply a build to the application. Body: `{"source": {"type": "repository", "image-id": "<build id>"}}` or `{"source": {"type": "repository", "project-id": "<id>", "assembly-version": "<version>"}}` (assembly-version is optional).
72
72
  - `POST /applications/{id}/dumps` – create a dump. Body: `include-users`, `include-binary-data` (booleans), `description` (string).
73
73
  - `GET /applications/{id}/dumps/{dumpId}` – dump status.
74
+ - `GET /applications/{id}/users` – the users connected to the application, each `{user-list-id, user-id, presentation, is-admin, token-access-enabled}`. The users of the control panel are among them: the platform connects them itself, and it names such a user by the login. `token-access-enabled` is the access of the user to the HTTP services of the application by a token. Without it a call of a service with the user's token is refused with a 500 "Token access is denied", whatever the rights of the user.
75
+ - `PUT /applications/{id}/users/change-token-access` – switch that access. Body: `{"user-list-id", "user-id", "enable-access"}`, all three required; the answer is the connection as it became. A user who is not connected to the application is refused with a 500 "Can't change user token access" and no word about the cause, so the client finds the connection first and names the user when there is none. The reference documents the method under v2 and v2.1 with the same body, and a live check got the same answer from both; the client takes the v2 prefix, like every other request.
76
+ - `GET /me` – the user the credentials belong to: `id`, `login`, `presentation`, `user-list-id`.
74
77
 
75
78
  Application statuses: stable `Running`, `Stopped`, `Error`; transitional `Starting`, `Stopping`, `Initializing`, `Updating`, `Frozen`, `Creating`. During transitions the `status` field may also be empty.
76
79
 
@@ -89,7 +92,7 @@ Application statuses: stable `Running`, `Stopped`, `Error`; transitional `Starti
89
92
  - Uploading a build file – a binary POST (Content-Type `application/octet-stream`, body – the file bytes):
90
93
  - `POST /projects/{id}/assemblies` – add a build to an existing project;
91
94
  - `POST /projects` – create a new project from a build.
92
- The only query parameter, and an optional one at that, is `SpaceId`; note that its name is in PascalCase. The method has no `BranchName`, `CommitId` or `CommitMessage` parameters: the Console API reference does not list them, and the server ignores them when sent. A direct POST with a real hash answers `commit-id: null`. The commit on a build card only comes from the project's link to its repository, and the client does not send those parameters. The response carries the id of the created build in one of the fields `image-id`, `assembly-id` or `id`, checked in that order. Next to it sits an `artifact` object describing the project the build landed in: `artifact-id` is the project id and opens as a project card, `configuration-id` is the `Ид` of `Проект.yaml`, and `name` is the project presentation. The console shows a project under the name of the last uploaded build, meaning the manifest `Name`. So a build uploaded into a project under a different name renames that project and its group, and deleting the build does not undo it. The client refuses such an upload and names the price; uploading a foreign build on purpose takes `--force-rename`. The check is best effort: when the names cannot be compared, because the manifest is unreadable or the project card is unreachable, the upload proceeds as before. Not being able to compare is no proof of danger.
95
+ The space goes as the optional `SpaceId` query parameter; note that its name is in PascalCase. The commit the build was made from goes as `commit-id`, a query parameter the reference documents for `POST /projects/{id}/assemblies`, and the server puts it on the build card: that is the commit the schema guard of the next deploy compares against (section 7). The reference lists `branch-name`, `commit-message` and `modified` for the same method too, and the client sends none of them. A live check found the server taking them and showing none on the card: its `branch-name` names a branch of group development, not of git, and `modified=1` is refused with a 500. The PascalCase `CommitId`, `BranchName` and `CommitMessage` are not parameters of the method at all, and the server ignores them. `POST /projects` documents no commit parameter, so a build that creates its project carries no commit. What the platform does not keep – the branch, whether the tree had uncommitted changes, the directory of the sources – the client keeps in a local registry of uploads (section 7). The response carries the id of the created build in one of the fields `image-id`, `assembly-id` or `id`, checked in that order. Next to it sits an `artifact` object describing the project the build landed in: `artifact-id` is the project id and opens as a project card, `configuration-id` is the `Ид` of `Проект.yaml`, and `name` is the project presentation. The console shows a project under the name of the last uploaded build, meaning the manifest `Name`. So a build uploaded into a project under a different name renames that project and its group, and deleting the build does not undo it. The client refuses such an upload and names the price; uploading a foreign build on purpose takes `--force-rename`. The check is best effort: when the names cannot be compared, because the manifest is unreadable or the project card is unreachable, the upload proceeds as before. Not being able to compare is no proof of danger.
93
96
  - **A project is identified by the pair `Vendor` + `Name` of the manifest** (section 6.8). `POST /projects` therefore does not always create a project: when a project with that pair already exists, the build is added to it and its `artifact-id` comes back in the response. There are two ways to hit a 409 `ALREADY_EXISTS`. The first is uploading a version that is already there, answered with "Версия сборки ... уже присутствует в группе проекта". The second is registering the same vendor and name under another project, answered with "Сборка с именем поставщика ... уже зарегистрирована в другом проекте"; that one happens even with a freshly generated `Ид` in `Проект.yaml`.
94
97
  - `GET /projects/{id}/assemblies` – list of builds. Each element contains `assembly-version`, a string like `1.0-42`, and an id in `id` or `image-id`. The response is either an array or an object with the list in the `items` or `assemblies` field. **The method has no pages and reports no total.** `limit`, `size`, `pageSize`, `count`, `top`, `maxResults`, `page`, `pageNumber`, `offset`, `skip`, `from` and `start` are all ignored: the answers to every one of them match byte for byte, and neither the headers nor the body carry a counter or a cursor. Verified by live calls on two installations. **The platform deletes builds nobody uses,** and age has nothing to do with it: the vendor's help calls this automatic deletion of unused builds. A build an application runs is kept, and so are a library build another project uses, a release build, the project's default build and the build the project's repository was created from. Everything else goes when the collector gets to it. Seen live: seventeen builds of one day's series were made and one survived, the one the application runs, while a build from two months earlier is still listed because it is the project's first. So a listing is not the project's history and not a page of it. It is what survived, and the client must say so.
95
98
  - `GET /projects/{id}/assemblies/{version}` – build card, `DELETE .../{version}` – delete. The last segment is what the method calls it: the version, which is `assembly-version` or `project-version`, a string like `1.0-42`. It is not the id of the card: a UUID there is answered with a 404 "Assembly with version <uuid> not found". Checked live on two installations of different ages, both behave this way. The pages used to claim the opposite, that only a UUID works and a version gets a 400 "Version is not a valid UUID"; anyone following that claim was left with an unreachable card whichever form they gave. An id is still an address a caller holds: the build list prints it, and an upload answers with one. So the client accepts both forms and looks the value up in the build list to get the version the method takes. A value in no card is named as missing instead of becoming a 404 out of the depths of the platform. When the address is refused with a 400 or a 404, the client tries the id as the segment too: no reachable installation wants it, but the 400 the pages described had to come from somewhere, and the second spelling costs one request. Note that the platform renumbers the manifest version on upload. Deleting a build is rejected with a 500 while an application created from it still exists (section 6.9); once that application is really gone, the same request succeeds. A 500 is an answer, not a misunderstood address: it is raised as it is and never retried with another spelling.
@@ -120,6 +123,7 @@ A user list holds either the users of an application, which has a list of its ow
120
123
  - `GET|PUT /user-lists/{id}/settings/self-registration` – `{enabled, phone-required, email-required}`. This is the panel's "allow users to register themselves". The PUT wants the whole object.
121
124
  - `GET|POST /user-lists/{id}/settings/account-services-settings`, `PUT|DELETE .../{account-service-id}` – the account services of the list. An entry is `{account-service-id, account-service-type, local-id, enabled, create-user-on-auth, additional-settings}`. The type `Local` authenticates by a password, so the panel's "allow signing in with a login and a password" is that entry being `enabled`. The other types are external services: `OIDC`, `Cas`, `ActiveDirectory`, `Esia`. The PUT wants the whole entry back.
122
125
  - `GET /applications/{id}/userlists` – the ids of the lists connected to the application; `POST` connects, `DELETE` disconnects. Note the spelling: no dash here. There are no per-connection settings: the link is a set of ids and nothing more.
126
+ - `GET /user-lists/{id}/users` – the users of the list, `id` and `login` among their fields. An entry carries the access tokens of the user as well, secrets included, so the client takes nothing but the ids out of it.
123
127
  - The application card names the application's own list in `default-user-list`. That is the list of its users, and the panel list connected to it is a separate one.
124
128
 
125
129
  Two things the panel can do and the API cannot, so both stay manual:
@@ -196,6 +200,8 @@ Compatibility is checked against the `РежимСовместимости` prop
196
200
  9. **Deletion runs in the background and in order.** `DELETE /applications/{id}` returns immediately, and the application lives on for a while with a `DeleteApplication` task. While it exists, deleting the build it was created from is rejected with a 500. The order for cleanup is: delete the application, wait until its card answers 404 or its status becomes `Deleted`, and only then delete the build. A read of the card that breaks off during this wait is a missed poll as well, as in section 6.4.
197
201
  10. **Compilation is the server's, and it happens on apply.** A local build only packs an archive. The syntax, the types and the visibility of the sources are checked by the server compiler when a build is applied or an application is created out of it. There is no separate "compile" endpoint, so the only way to check the sources without risking the working application is a throwaway application created from the same build (section 7, `probe`).
198
202
  11. **Signing in to a freshly created application.** A new application gets its own empty user list (`default-user-list`, section 4.7), password sign-in in it is off, and it has no account service. The accounts used to sign in to other applications therefore do not work here, and connecting another application's user list (`POST /applications/{id}/userlists`) together with enabling the local sign-in does not change that; this was verified. What works is a control-panel account: the platform connects its users to the application itself, and the sign-in works right away. The tool has to say so out loud when it creates an application (section 7, `apps create` and `apps ensure`): the way in does not follow from the card, and it cannot be found by trying, because a user has a failed-attempt counter.
203
+ 12. **A server that is still starting.** After a start or an update the server takes minutes to bring its console up; thirteen of them were seen after one update. All that time every console request, the token request included, is answered with a 404 whose text names the console application: `Application "console" not found`. That is the status a missing application or build gets, so only the text tells them apart. The client recognizes the answer in one place, for every request it makes, and raises an error that says what it means: the server is starting, repeat once `/console` answers 302. `deploy` waits it out by itself at any step of its cycle, for up to `--server-start-timeout` seconds (900 by default, 0 turns the wait off), and announces the start and the end of the wait. A request the console refused was never processed, so asking again is safe whatever its method. The other commands do not wait: they name the cause and stop.
204
+ 13. **A removal is applied without a question.** A build whose sources no longer have a tabular part is applied as it is: the part goes, and its rows go with it. There is no refusal and no warning, the task ends well and the application keeps running; that was seen on a catalog with a row in the part. An attribute of a tabular part and an attribute of the object go the same way, with their values. A narrowed length or a changed type recreates the data of the object instead. What the deploy does about either is in section 7.
199
205
 
200
206
  ## 7. CLI requirements
201
207
 
@@ -218,9 +224,11 @@ Commands, with the significant flags in parentheses:
218
224
  `apps ensure NAME [--project-id --version-id --latest-build --space-id
219
225
  --tech-version --no-dev-mode --wait --verify --no-verify --apply]`,
220
226
  `apps apply [APP_ID] VERSION_ID`,
221
- `apps delete APP_ID`, `apps start [APP_ID]`, `apps stop [APP_ID]`.
227
+ `apps delete APP_ID`, `apps start [APP_ID]`, `apps stop [APP_ID]`,
228
+ `apps token-access APP_ID [--user --enable --disable]`.
222
229
  - `apps list --name` filters by a case-insensitive name substring, and it does so on the client because the platform ignores the query parameter (section 4.1). `--status` selects by the whole status word, several of them separated by commas. `--brief` prints brief cards instead of full ones: id, name, status, uri, applied version.
223
230
  - `apps list` hides the deleted applications. They stay in the platform list under the `Deleted` status, and a stand a few months old answers with hundreds of cards of which a handful are alive. `--include-deleted` brings them back, and so does `--status deleted`: a filter that would answer with nothing is worse than no filter. A cut nobody is told about is a trap of its own, so the command ends with a count line on stderr, "7 live of 324", plus the number shown when a filter narrowed the answer further. Whatever is cut, stdout stays the same JSON array.
231
+ - `apps get` adds `applied-build` to the card: the brief card of the build the application runs, with its branch and commit from the build card or from the local registry of uploads, in the shape `builds list --brief` prints. It is null when the card names no applied build.
224
232
  - `APP_ID` of `apps get`, `delete`, `start`, `stop` and `debug` is the application id (UUID) or its exact name. A value that is not a UUID is resolved through the list by an exact case-insensitive match, and deleted applications do not count. No match is an error, and several matches are an error listing the ids: destructive commands must not guess.
225
233
  - `apps find` searches for an exact, case-insensitive name match among the fields `name`, `display-name` and `publication-context`. Output is `{"id": ..., "found": true|false}` with return code 0 in both cases: the absence of an application is an answer, not an error. A non-zero return code means the request failed and comes with JSON carrying an `error` field on stderr. In scripts, check the `found` field, not the return code.
226
234
  - Deleted applications remain in the platform list with the `Deleted` status and their former `id`. `apps find` skips them: the found id must be usable, otherwise the caller gets an id on which `apps get` and `deploy` return 404. The `--include-deleted` flag restores the former behaviour, searching among all applications including deleted ones.
@@ -231,6 +239,7 @@ Commands, with the significant flags in parentheses:
231
239
  - A source given by `--version-id` is looked up in the build list of the project before anything is created. The project is `--project-id`, or `ELEMENT_PROJECT_ID` when the flag is absent. The platform deletes the builds nobody uses and cannot create an application from a deleted one: it answers with a bare 400 "Can't create application", which reads like a limit on the number of applications. So the command refuses by itself. The refusal names the cause and offers the build that a running application of the project runs, or `--latest-build` when no application runs one. A project taken from `ELEMENT_PROJECT_ID` is named in the refusal, because the build may belong to another project. Without a project there is no list to look in, and the create goes as before.
232
240
  - Waiting means verifying. A failed apply is rolled back by the platform to the previous build, and the application comes up `Running` all the same, so a card handed back after a wait is not evidence that the build asked for is the one running. `--wait` therefore ends with the same check `apps apply` and `verify-deploy` do: the applied build id against the requested one, the application tasks that failed since the creation started, the uri. It puts the report into the `verify` field of the output and answers with exit code 1 when the check does not pass. `--verify` asks for the check on its own, and waits too, because there is nothing to check on an application still being created. `--no-verify` brings back the plain wait. Without either flag nothing is waited for and nothing is checked, as before.
233
241
  - The application exists once the create has answered, so a wait or a check that breaks off does not lose it. The output still carries the id: the card of `apps create`, the `id` of `apps ensure` with `applied: null`, since nothing was checked. The `wait-error` field holds the error that ended the wait, stderr names the `verify-deploy` call that checks the build later, and the exit code is 1. The answer used to be a bare network error without the id, and the id of an application that came up minutes later had to be looked up by name.
242
+ - `apps token-access APP_ID` shows or switches the access of a user to the HTTP services of the application by a token (section 4.1). The application is named explicitly, by the argument or by `--app-id`: `ELEMENT_APP_ID` names the working application, and a switch that opens its services must not land there by default. `--user` is a login, a presentation or a user id, and without it the command speaks about the account elemctl itself signs in with (`GET /me`). Without `--enable` or `--disable` it only reads; both at once is an error. A switch reads the connection back, so `token-access-enabled` in the output is what the platform keeps after the change, and a flag that did not move is an error with exit code 1. The output is `{"app-id", "user", "user-id", "user-list-id", "token-access-enabled", "changed"}`, where `changed` says whether this very call altered anything: the state that is already there sends no request. A user who is not connected to the application is named as such, with the users that are, before anything is sent.
234
243
  - `spaces list`.
235
244
  - `user-lists list [--name]`, `user-lists get [LIST] [--app]`,
236
245
  `user-lists self-registration [LIST] [--app --enable --disable]`,
@@ -248,9 +257,10 @@ Commands, with the significant flags in parentheses:
248
257
  - `projects list [--name --include-deleted]`, `projects get [PROJECT_ID]`, `projects delete PROJECT_ID`.
249
258
  - `projects list --name` filters by a case-insensitive name substring, and it does so on the client because the platform answers the full list (section 4.3). Projects marked deleted are hidden unless `--include-deleted` is given: a stand a few months old keeps hundreds of them in the list against a handful of live ones, and a check for a project name must not cost the full listing.
250
259
  - `builds list [--project-id --limit --brief]`, `builds get VERSION [--project-id]`,
251
- `builds upload FILE [--project-id --new-project --force-rename --space-id
252
- --branch --commit --commit-message]`, `builds delete VERSION [--project-id]`.
253
- `builds upload` reports the chosen target in the output through `project-id` and
260
+ `builds upload FILE [--project-id --new-project --force-rename --space-id]`,
261
+ `builds delete VERSION [--project-id]`.
262
+ `builds upload` sends the commit the manifest of the archive names as `commit-id`
263
+ (section 4.4) and reports the chosen target in the output through `project-id` and
254
264
  `project-id-source` (`flag`, `env` or none) and notes on stderr when the target comes
255
265
  from `ELEMENT_PROJECT_ID`. `--new-project` ignores the environment binding and always
256
266
  creates a new project; it is mutually exclusive with `--project-id`. `--force-rename`
@@ -263,6 +273,24 @@ Commands, with the significant flags in parentheses:
263
273
  listing: the platform hands out the numbers of a base version one after another, so a
264
274
  number the listing has not got is a build already taken away, and the line says how many
265
275
  are missing.
276
+ `--brief` prints the id, the versions, the date, the branch and the commit of a build.
277
+ The branch and the commit come from the card when the platform filled them, otherwise
278
+ from the local registry of uploads, and `branch-name-source` and `commit-id-source`
279
+ say which answered: `platform`, `registry`, or null when neither knows. The registry
280
+ alone knows `dirty`, whether the tree had uncommitted changes, and `project-dir`, the
281
+ directory the build was made from.
282
+ - The local registry of uploads. Every upload elemctl makes – `deploy`, `builds upload`,
283
+ `probe` – appends a JSON line to `uploads.jsonl` in the data directory of the user:
284
+ `ELEMCTL_DATA_DIR` when it is set, otherwise `%LOCALAPPDATA%\elemctl` on Windows and
285
+ `$XDG_STATE_HOME/elemctl` (`~/.local/state/elemctl`) elsewhere. A line holds the build
286
+ id, the project id, the version, the branch, the commit, the `dirty` flag, the directory
287
+ of the sources, the archive, the stand, the command and the time. The platform keeps the
288
+ commit alone, and with several sessions deploying from one machine a build on an
289
+ application could not be traced to the working tree it came from. The registry is
290
+ local: a build uploaded from another machine, from CI or by an elemctl that had no
291
+ registry yet is not in it. A registry that cannot be written is a warning on stderr,
292
+ never a failure – the build is on the server by then – and one that cannot be read
293
+ reads as empty.
266
294
  - `build [--project-dir --output --build-version --last-build --commit
267
295
  --branch --kind {application,library} --require-clean]` – build the archive locally.
268
296
  Output: `file`, `name`, `vendor`, `version`, `version-source`
@@ -277,9 +305,11 @@ Commands, with the significant flags in parentheses:
277
305
  - `inspect FILE` – parse a prebuilt archive (section 5.1). Local as well: the platform is
278
306
  not called, and the connection flags are refused the same way.
279
307
  - `deploy [--app-id --project-id --project-dir --output --build-version
280
- --branch --commit --commit-message --dry-run --require-clean]` –
308
+ --branch --commit --dry-run --require-clean --allow-data-loss
309
+ --server-start-timeout]` –
281
310
  the full cycle: build -> upload -> apply -> restart -> verification of the actual apply (section 6.1). Output – a JSON report with fields: `app-id`, `uri`, `status`, `version`, `assembly-id`, `applied-version`, `applied` (true, false or null, where null means the actual version could not be determined), `uri-status`, `problems` (list of strings, the platform's texts as they came), `problems-lines` (the same broken into plain lines: JSON escapes a multi-line refusal into `
282
- ` and ` ` exactly where it has to be read), `ok` (boolean), `dirty` and `dirty-files` (uncommitted changes of the project directory at build time). The build captures the current disk state, so the divergence from HEAD must be visible; a warning also goes to stderr, and null means git was unavailable. `hint` points at the log of the server when a task was refused without a compilation error in its text. The platform may answer with "Contact administrator for details" alone, and the cause then sits in the server log: the last `Caused by` line, with `SrcPath:` beside it naming the file the apply stopped at. An apply that leaves the application in `Error` ends the deploy with an error, and that error carries the same hint. Return code 0 only when `ok`. `--dry-run` builds and stops there, and `--require-clean` aborts before building on a dirty tree.
311
+ ` and ` ` exactly where it has to be read), `ok` (boolean), `dirty` and `dirty-files` (uncommitted changes of the project directory at build time). The build captures the current disk state, so the divergence from HEAD must be visible; a warning also goes to stderr, and null means git was unavailable. `hint` points at the log of the server when a task was refused without a compilation error in its text. The platform may answer with "Contact administrator for details" alone, and the cause then sits in the server log: the last `Caused by` line, with `SrcPath:` beside it naming the file the apply stopped at. An apply that leaves the application in `Error` ends the deploy with an error, and that error carries the same hint. Return code 0 only when `ok`. `--dry-run` builds and stops there, and `--require-clean` aborts before building on a dirty tree. `--server-start-timeout` is how many seconds a server that is still starting is waited out (section 6.12).
312
+ Before anything is built, the schema guard reads the sources against the commit the applied build was made from, the `commit-id` of its card (section 4.4). The project directory is found the way the build finds it. A narrowed length or a changed type of an attribute, a dimension or a resource, the attributes of a tabular part included, and a removed dimension recreate or break the data, so the deploy refuses them unless `--allow-data-loss` is given. A removed attribute, resource, tabular part or attribute of a tabular part is a deliberate edit the server applies without asking (section 6.13): the deploy names each one on stderr and in the `schema-warnings` field and goes on. Fields are matched by `Ид`, so a rename keeps its data, and across a translation of the description only an `Ид` can tell that an element is gone. `schema-check` says what the guard did: `clean`, `warned` (removals only), `allowed`, or `skipped:<reason>` when there was nothing to compare against: `no-project-dir`, `read-failed`, `no-applied-build`, `applied-build-not-listed`, `no-commit-id` or `commit-unavailable`, each explained in words of its own. A skipped check is said once more after the verdict: a passed verification alone read as if the schema had been checked too.
283
313
  - `verify-deploy [APP_ID] [--app-id --version-id --expected-version --since-minutes]` –
284
314
  the verification of section 6.1 on its own, deploying nothing. It looks at the
285
315
  application tasks in an error status raised over the last `--since-minutes` minutes,
@@ -291,9 +321,17 @@ Commands, with the significant flags in parentheses:
291
321
  after `apps create`: a build that failed to apply is rolled back silently, and a status
292
322
  of `Running` proves nothing.
293
323
  - `probe [--project-dir --output --build-version --name --space-id --keep
294
- --require-clean]` – an isolated compilation check of the sources: build ->
324
+ --require-clean]`, `probe --cleanup APP_ID` – an isolated compilation check of the sources: build ->
295
325
  upload -> a throwaway application (that is the compilation, section 6.10) ->
296
- errors with file and position -> cleanup. `ELEMENT_APP_ID` and
326
+ errors with file and position -> cleanup. Before the build the manifest is
327
+ checked for what the server needs to take a probe: `Представление`
328
+ (`Presentation`), without which the console refuses the upload with a bare 500;
329
+ `ЯзыкРазработки` (`DevelopmentLanguage`), a required property without which no
330
+ application is created; and `ЯзыкиЛокализации` (`LocalizationLanguages`)
331
+ whenever `ЯзыкПоУмолчанию` (`DefaultLanguage`) is set, since the server refuses
332
+ that pair without naming the cause. A missing key stops the probe before
333
+ anything is built or uploaded, and the error names every such key with the
334
+ line to add, in the spelling the manifest uses. `ELEMENT_APP_ID` and
297
335
  `ELEMENT_PROJECT_ID` are deliberately left unused: the probe must not be able to
298
336
  reach the working application, and the target project is chosen by the platform
299
337
  out of the vendor and the name of the manifest (section 6.8). The default build
@@ -303,12 +341,14 @@ Commands, with the significant flags in parentheses:
303
341
  comparison. Cleanup runs whether the compilation passed or failed, in the order
304
342
  of section 6.9: the application, then the build, then the project, and the
305
343
  project only if the probe itself created it. Output: `ok`, `project-dir`,
306
- `vendor`, `name`, `file`, `version`, `project-id`, `assembly-id`, `app-id`,
344
+ `vendor`, `name`, `file`, `version`, `project-id`, `project-created`,
345
+ `assembly-id`, `app-id`,
307
346
  `app-name`, `status`, `errors` (a list of `{file, entry, line, column,
308
347
  environment, message}`, where `file` is the path relative to the project
309
348
  directory), `messages` (the platform texts verbatim, so nothing is lost when the
310
349
  failure is not a compilation one), `cleanup` (`kept`, `app-deleted`,
311
- `assembly-deleted`, `project-deleted`, `problems`) and `hint`, the pointer to the
350
+ `assembly-deleted`, `project-deleted`, `problems`, `command`, `steps`) and
351
+ `hint`, the pointer to the
312
352
  server log that the `deploy` report carries too. `hint` is filled when the server
313
353
  refused and named no file; a wait that ran out of time leaves it empty. A stand that does not know
314
354
  the compatibility mode of the project refuses the whole project and then
@@ -322,6 +362,34 @@ Commands, with the significant flags in parentheses:
322
362
  does leave behind is a tombstone: the platform keeps deleted applications in
323
363
  the list with the `Deleted` status and their former id, and there is no API to
324
364
  remove them.
365
+ Whatever a probe leaves, on purpose with `--keep` or through a cleanup step that
366
+ failed, comes with the commands that remove it, in `cleanup` and on stderr:
367
+ `command` is the one command, `probe --cleanup APP_ID`, and `steps` are the same
368
+ by hand in the order of section 6.9, with the build addressed in the probe's own
369
+ project. A bare `builds delete` looks in the project of `ELEMENT_PROJECT_ID`, where
370
+ the probe build is not, and a build deleted right after its application is
371
+ refused with a 500 until the application is gone. Both lines name the `--env-file`
372
+ the probe was run with.
373
+ `probe --cleanup APP_ID` removes a probe left on the stand, starting from its
374
+ application, an id or a name. The application card names the project and the build
375
+ it was created from, so nothing has to be remembered between the runs. Only a
376
+ probe's application is touched: its name starts with `elemctl-probe-`, or the build
377
+ it runs carries `-probe-` in its version, which covers a probe named with `--name`.
378
+ Any other application is refused with the reason, and so is the one
379
+ `ELEMENT_APP_ID` names. The order is that of section 6.9: the application, a wait
380
+ until it is gone, the build of this very probe (its token in the version), and the
381
+ project last. The project goes only when no build is left in it and no live
382
+ application runs it, and never when it is the project of `ELEMENT_PROJECT_ID`: a
383
+ probe usually lands in the project that owns its sources, the working one, while a
384
+ project the probe created ends up empty. The builds other runs uploaded into the
385
+ probe's application are left to the platform, which deletes the builds nobody
386
+ uses. A second run finishes what the first one left: an application that is
387
+ already a tombstone is not deleted twice, since the list keeps its card, and a
388
+ project deleted already is not deleted again. The run builds nothing, so the flags
389
+ of a probe run are refused beside `--cleanup`. Output: `ok`, `app-id`, `app-name`,
390
+ `project-id`, `app-deleted`, `builds` (`{id, version, deleted}` each),
391
+ `project-deleted`, `project-kept` (why the project stayed) and `problems`; return
392
+ code 0 only when `ok`.
325
393
  - `branches list [--project-id --name]`, `branches get ID`,
326
394
  `branches create NAME [--project-id --app-id]`,
327
395
  `branches update ID [--app-id]`, `branches delete ID`,
@@ -332,7 +400,7 @@ Commands, with the significant flags in parentheses:
332
400
  - `debug-adapter` – the path to the platform debug adapter directory supplied by a plugin (the `elemctl.debug_adapter` entry-point group, section 10). Output `{"path": ..., "found": true, "adapter-class": ...}` when present or `{"path": null, "found": false}`; exit code 0 in both cases. The `path` is a ready value for the VS Code extension's `xbsl.debug.adapterPath` (a directory with a `repo/` subdirectory).
333
401
  - `plugins` – diagnostics: what the plugins bring. `debug-adapter` holds the declared adapter directories and whether each of them holds jars. `commands` holds the commands of the plugins with the entry point they arrived through and the name of their MCP tool, which is `null` when the command stays out of MCP. `failures` holds what was left out: a plugin that did not load, or a command that would have taken over a name of the core, each with the entry point and the reason. The answer looks like `{"debug-adapter": [{"path": ..., "has-jars": true|false}], "commands": [{"name": ..., "source": ..., "mcp": ...}], "failures": [{"source": ..., "error": ...}]}`.
334
402
  - The subcommands the plugins bring (section 10, the `elemctl.commands` group) stand alongside the commands of the core and are listed by `--help`. They may not take over a name of the core; the command reference describes the core alone. A plugin that fails to load is left out and does not take the CLI down (section 10): every command names it on stderr, and a call to a command that is missing while plugins failed is refused with JSON on stderr, the failures in its `plugin-failures` field.
335
- - `self-update [--version X]` – update the installed elemctl by unpacking the wheel from PyPI into site-packages, without touching busy exe files. Plain pipx or pip breaks the install when `elemctl.exe` is held by a running MCP server. Here only the package files are updated, and the exe stub calls the new code. The command also fixes `pipx_metadata.json`. Output is `{updated, from, to}`.
403
+ - `self-update [--version X]` – update the installed elemctl by unpacking the wheel from PyPI into site-packages, without touching busy exe files. Plain pipx or pip breaks the install when `elemctl.exe` is held by a running MCP server. Here only the package files are updated, and the exe stub calls the new code. The command also fixes `pipx_metadata.json`. Output is `{updated, from, to}`. Without `--version` the latest release is asked of every source PyPI has. Both listings of releases, the simple index and the JSON summary, are cached node by node and may name the previous release for minutes after a new one is out, so the command reads both, takes the newer answer and then asks for the pages of the three next numbers (`0.44.1`, `0.45.0` and `1.0.0` after `0.44.0`): the page of a new release is there as soon as it is published. When the sources disagree, a line on stderr says what each of them named. An installation newer than every source is left as it is rather than replaced with the release before. A version given with `--version` that the index does not list yet is looked up on its own page, and only a 404 there means the version does not exist.
336
404
  - `mcp` – start the MCP server; without the extra installed – a clear error with the hint `pip install "elemctl[mcp]"`.
337
405
 
338
406
  Positional APP_ID and PROJECT_ID marked as optional above are taken from the configuration when absent, from `ELEMENT_APP_ID` and `ELEMENT_PROJECT_ID`. If those are empty too, the command errors out.
@@ -345,7 +413,8 @@ Server name `elemctl`, stdio transport, credentials from the same environment va
345
413
  (section 7): `name` by a case-insensitive substring on the client (section 4.1), `status`
346
414
  by the whole status word, and the deleted applications hidden unless asked for. The answer
347
415
  is an object with `total`, `live`, `shown`, a `summary` line and `applications`, so that
348
- what was hidden is stated rather than guessed at; `get_app(app_id)`, `find_app(name)`,
416
+ what was hidden is stated rather than guessed at; `get_app(app_id)` – the card with
417
+ `applied-build`, as `apps get` prints it (section 7), `find_app(name)`,
349
418
  `create_app(name, project_id="", version_id="", space_id="",
350
419
  development_mode=True, verify=False)` – when only project_id is given, the project's latest
351
420
  build is automatically used as the source (section 6.2); `verify=True` waits for the
@@ -368,16 +437,18 @@ id (UUID) or the exact application name (resolved like the CLI does),
368
437
  `list_projects(name="", include_deleted=False)` – the filters of `projects list` (section 7),
369
438
  `list_builds(project_id, limit=10, brief=True)` – an object `{total, shown, summary, builds}`:
370
439
  the listing has to say whether it is the whole store, judged by the gaps in the build
371
- numbering (section 4.4),
440
+ numbering (section 4.4), and a brief card names the source of its branch and commit, the
441
+ card or the local registry of uploads, the way `builds list --brief` does (section 7),
372
442
  `get_build(project_id, version)` – the whole card of one build, addressed by the build
373
443
  version (section 4.4; an id is accepted and resolved through the listing),
374
444
  `build_assembly(project_dir="", output_dir="", version="")`,
375
445
  `inspect_assembly(file)` – parsing of a built archive (section 5.1; a local operation),
376
446
  `deploy(app_id, project_id, project_dir="", version="", branch="",
377
- commit_message="")` – returns the deploy report plus a `log` field with progress
378
- lines; `probe(project_dir="", space_id="", keep=False)` – an isolated
447
+ server_start_timeout=900)` – returns the deploy report plus a `log` field with progress
448
+ lines, and waits out a server that is still starting (section 6.12); `probe(project_dir="", space_id="", keep=False)` – an isolated
379
449
  compilation check that does not touch the working application (section 7),
380
- the report plus a `log` field; `apply_build(app_id, version_id)`, `verify_deploy(app_id,
450
+ the report plus a `log` field; `probe_cleanup(app_id)` – `probe --cleanup` (section 7),
451
+ the removal of a probe left on the stand, the report plus a `log` field; `apply_build(app_id, version_id)`, `verify_deploy(app_id,
381
452
  expected_version="", since_minutes=30)` – verification of the apply per section 6.1;
382
453
  `list_app_tasks(app_id="")`, `list_branches(project_id="", name="")`,
383
454
  `merge_branch(branch_id)`, `list_user_lists(name="")` and
@@ -385,7 +456,10 @@ expected_version="", since_minutes=30)` – verification of the apply per sectio
385
456
  the sign-in settings of a user list (section 4.7) in one call: the list is given by id, by
386
457
  presentation or by the application whose own list it is; both flags are optional, and
387
458
  without them the tool only reports the state (`self-registration-enabled`,
388
- `password-login-enabled`, `changed`).
459
+ `password-login-enabled`, `changed`); `token_access(app_id, user="", enabled=None)` – the
460
+ access of a user to the HTTP services of the application by a token, as `apps token-access`
461
+ shows and switches it (section 7): `app_id` is required, an empty `user` means the account
462
+ elemctl signs in with, and without `enabled` the tool only reads.
389
463
 
390
464
  The tools the plugins bring (section 10, the `elemctl.commands` group) are registered
391
465
  alongside these: the schema is built out of the declared arguments, the description is the