elemctl 0.44.0__tar.gz → 0.46.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 (83) hide show
  1. {elemctl-0.44.0 → elemctl-0.46.0}/PKG-INFO +35 -9
  2. {elemctl-0.44.0 → elemctl-0.46.0}/README.md +34 -8
  3. {elemctl-0.44.0 → elemctl-0.46.0}/docs/SPEC.md +122 -26
  4. {elemctl-0.44.0 → elemctl-0.46.0}/docs/SPEC.ru.md +280 -35
  5. {elemctl-0.44.0 → elemctl-0.46.0}/docs/changelog.md +97 -0
  6. {elemctl-0.44.0 → elemctl-0.46.0}/docs/changelog.ru.md +94 -0
  7. {elemctl-0.44.0 → elemctl-0.46.0}/docs/cli.md +54 -7
  8. {elemctl-0.44.0 → elemctl-0.46.0}/docs/cli.ru.md +54 -7
  9. {elemctl-0.44.0 → elemctl-0.46.0}/docs/config.md +26 -3
  10. {elemctl-0.44.0 → elemctl-0.46.0}/docs/config.ru.md +24 -3
  11. {elemctl-0.44.0 → elemctl-0.46.0}/docs/mcp.md +8 -5
  12. {elemctl-0.44.0 → elemctl-0.46.0}/docs/mcp.ru.md +11 -5
  13. {elemctl-0.44.0 → elemctl-0.46.0}/docs/platform.md +11 -4
  14. {elemctl-0.44.0 → elemctl-0.46.0}/docs/platform.ru.md +93 -10
  15. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/__init__.py +1 -1
  16. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/build.py +4 -0
  17. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/cli.py +168 -27
  18. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/client.py +478 -37
  19. elemctl-0.46.0/src/elemctl/deploy.py +758 -0
  20. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/errors.py +10 -0
  21. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/i18n.py +459 -30
  22. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/mcp_server.py +131 -14
  23. elemctl-0.46.0/src/elemctl/probe.py +888 -0
  24. elemctl-0.46.0/src/elemctl/registry.py +269 -0
  25. elemctl-0.46.0/src/elemctl/schema.py +596 -0
  26. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/selfupdate.py +181 -35
  27. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/versions.py +62 -2
  28. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/PKG-INFO +35 -9
  29. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/SOURCES.txt +8 -0
  30. elemctl-0.46.0/tests/test_app_users.py +104 -0
  31. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_cli.py +24 -0
  32. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_client.py +99 -11
  33. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_deploy.py +488 -7
  34. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_i18n.py +4 -1
  35. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_mcp.py +53 -1
  36. elemctl-0.46.0/tests/test_numbering_jumps.py +184 -0
  37. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_probe.py +68 -0
  38. elemctl-0.46.0/tests/test_probe_cleanup.py +388 -0
  39. elemctl-0.46.0/tests/test_registry.py +499 -0
  40. elemctl-0.46.0/tests/test_schema.py +723 -0
  41. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_selfupdate.py +24 -11
  42. elemctl-0.46.0/tests/test_selfupdate_latest.py +270 -0
  43. elemctl-0.46.0/tests/test_server_starting.py +266 -0
  44. elemctl-0.46.0/tests/test_token_access.py +248 -0
  45. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_versions.py +11 -0
  46. elemctl-0.44.0/src/elemctl/deploy.py +0 -493
  47. elemctl-0.44.0/src/elemctl/probe.py +0 -457
  48. elemctl-0.44.0/src/elemctl/schema.py +0 -221
  49. elemctl-0.44.0/tests/test_schema.py +0 -247
  50. {elemctl-0.44.0 → elemctl-0.46.0}/.env.example +0 -0
  51. {elemctl-0.44.0 → elemctl-0.46.0}/LICENSE +0 -0
  52. {elemctl-0.44.0 → elemctl-0.46.0}/MANIFEST.in +0 -0
  53. {elemctl-0.44.0 → elemctl-0.46.0}/NOTICE +0 -0
  54. {elemctl-0.44.0 → elemctl-0.46.0}/ORIGIN.md +0 -0
  55. {elemctl-0.44.0 → elemctl-0.46.0}/docs/index.md +0 -0
  56. {elemctl-0.44.0 → elemctl-0.46.0}/docs/index.ru.md +0 -0
  57. {elemctl-0.44.0 → elemctl-0.46.0}/docs/library.md +0 -0
  58. {elemctl-0.44.0 → elemctl-0.46.0}/docs/library.ru.md +0 -0
  59. {elemctl-0.44.0 → elemctl-0.46.0}/pyproject.toml +0 -0
  60. {elemctl-0.44.0 → elemctl-0.46.0}/setup.cfg +0 -0
  61. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/__main__.py +0 -0
  62. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/auth.py +0 -0
  63. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/config.py +0 -0
  64. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/plugins.py +0 -0
  65. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl/transport.py +0 -0
  66. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/dependency_links.txt +0 -0
  67. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/entry_points.txt +0 -0
  68. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/requires.txt +0 -0
  69. {elemctl-0.44.0 → elemctl-0.46.0}/src/elemctl.egg-info/top_level.txt +0 -0
  70. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_build.py +0 -0
  71. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_changelog_link.py +0 -0
  72. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_cli_docs.py +0 -0
  73. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_config.py +0 -0
  74. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_conventions.py +0 -0
  75. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_docs_coverage.py +0 -0
  76. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_extract_adapter.py +0 -0
  77. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_plugins.py +0 -0
  78. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_rebuild_docs.py +0 -0
  79. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_release_notes.py +0 -0
  80. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_transport.py +0 -0
  81. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_user_lists.py +0 -0
  82. {elemctl-0.44.0 → elemctl-0.46.0}/tests/test_workflows.py +0 -0
  83. {elemctl-0.44.0 → elemctl-0.46.0}/tools/extract_adapter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elemctl
3
- Version: 0.44.0
3
+ Version: 0.46.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,38 @@ 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`, `ELEMCTL_DATA_DIR` and `ELEMCTL_REGISTRY_LIMIT` are
209
+ set through the 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
+ | `ELEMCTL_REGISTRY_LIMIT` | how many uploads the local registry of uploads keeps; 1000 by default, `0` keeps every one |
219
+
220
+ ### The local registry of uploads
221
+
222
+ The platform keeps the commit of a build uploaded into an existing project and nothing else
223
+ of where the build came from. So every upload elemctl makes – `deploy`, `builds upload`,
224
+ `probe` – also appends a line to `uploads.jsonl` in the data directory above: the build id,
225
+ the project, the version, the branch, the commit, whether the tree had uncommitted changes,
226
+ the directory of the sources, the stand, the command and the time. `builds list --brief`
227
+ and `apps get` fill the branch and the commit the card left empty from it and name the
228
+ source of each value.
229
+
230
+ The registry is local. A build uploaded from another machine, from CI or by an elemctl that
231
+ had no registry yet is not in it, and there the listings show what the platform knows. A
232
+ registry that cannot be written is a warning and never a failed upload; the file can be
233
+ deleted at any time, and only the history of this machine goes with it.
234
+
235
+ The registry keeps the newest thousand uploads, `ELEMCTL_REGISTRY_LIMIT` sets another
236
+ number, and `0` keeps every one. Once the file has grown past the limit by a tenth, the next
237
+ upload cuts it back to the newest lines: the builds a project still lists and an application
238
+ still runs are the recent ones, and a file nobody trimmed grew for as long as the machine
239
+ deployed.
217
240
 
218
241
  ### The CI environment
219
242
 
@@ -308,7 +331,7 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
308
331
  |---|---|
309
332
  | `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
333
  | `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 |
334
+ | `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
335
  | `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
336
  | `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
337
  | `start_app` | start the application |
@@ -318,16 +341,19 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
318
341
  | `debug_info` | debug-session data: `debug-token` and `debug-address` (debugging must be enabled on the server) |
319
342
  | `list_spaces` | list of spaces |
320
343
  | `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 |
344
+ | `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
345
  | `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
346
  | `build_assembly` | build a `.xasm`/`.xlib` archive from the sources locally (does not talk to the platform) |
324
347
  | `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 |
348
+ | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log`; `allow_data_loss` lets through what the schema guard refuses (a narrowing, a type change, a catalog removed whole), like `--allow-data-loss`; a server that is still starting is waited out for up to `server_start_timeout` seconds (900 by default) |
349
+ | `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 |
350
+ | `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; a probe given its own name and version is known by the local registry of uploads, which also names the builds deployed into it; an application that is not a probe's is refused |
327
351
  | `apply_build` | apply an uploaded build to the application by its id |
328
352
  | `verify_deploy` | verify the apply actually took effect: failed tasks, the applied build, the availability of the uri |
329
353
  | `list_user_lists` | user lists; `name` filters by a substring of the presentation |
330
354
  | `configure_user_list` | self-registration and password sign-in; without the flags it only reports the current state |
355
+ | `list_app_users` | who is connected to an application: the user list, the id, the presentation, whether an administrator and whether token access is on, with a count line; the platform gives no login here |
356
+ | `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
357
  | `list_branches` | list of development-environment branches; the `project_id` and `name` filters are optional |
332
358
  | `merge_branch` | accept the changes of a development-environment branch |
333
359
  | `debug_adapter` | the path to the platform debug adapter from a plugin; a missing plugin is an answer (`found: false`), not an error (local) |
@@ -340,7 +366,7 @@ A single environment is not a limit. Every tool that talks to the platform takes
340
366
 
341
367
  `list_projects` behaves the same way and returns id, name, project kind, space, application count and the deletion flag. Its `name` filters by a substring too, and projects marked deleted stay hidden until `include_deleted` is set: a stand a few months old keeps hundreds of them against a handful of live ones.
342
368
 
343
- `list_builds` answers with brief cards as well, holding id, versions, date, branch and commit, and with the ten newest builds unless `limit` says otherwise; 0 lifts the cut. The cards sit under `builds`, next to the counters `total` (how many builds the platform returned) and `shown`, plus a `summary` line. The platform's listing is not the project's whole history: it deletes the builds nobody uses, whatever their age. The build an application runs, the project's first build and a release build stay. The listing has no pages, and `summary` says plainly that what you see is the remainder of the history. It reads that off the answer itself: the platform hands out the numbers of one base version consecutively, so a number missing from the listing is a build already taken away.
369
+ `list_builds` answers with brief cards as well, holding id, versions, date, branch and commit, and with the ten newest builds unless `limit` says otherwise; 0 lifts the cut. The cards sit under `builds`, next to the counters `total` (how many builds the platform returned) and `shown`, plus a `summary` line. The platform's listing is not the project's whole history: it deletes the builds nobody uses, whatever their age. The build an application runs, the project's first build and a release build stay. The listing has no pages, and `summary` says plainly that what you see is the remainder of the history. It reads that off the answer itself: the platform hands out the numbers of one base version consecutively, so a number missing from the listing is a build already taken away – unless it is a jump. A build uploaded by the vendor and the name keeps the number of its archive and the count goes on from it, and a hole under such a build of this machine is named in `summary` as a jump rather than a deletion.
344
370
 
345
371
  `get_build` hands back one card whole and is addressed by the build version. An id is accepted as well and looked up in the listing, because the address the method understands is the version, not the id of a card.
346
372
 
@@ -173,15 +173,38 @@ 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`, `ELEMCTL_DATA_DIR` and `ELEMCTL_REGISTRY_LIMIT` are
177
+ set through the 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
+ | `ELEMCTL_REGISTRY_LIMIT` | how many uploads the local registry of uploads keeps; 1000 by default, `0` keeps every one |
187
+
188
+ ### The local registry of uploads
189
+
190
+ The platform keeps the commit of a build uploaded into an existing project and nothing else
191
+ of where the build came from. So every upload elemctl makes – `deploy`, `builds upload`,
192
+ `probe` – also appends a line to `uploads.jsonl` in the data directory above: the build id,
193
+ the project, the version, the branch, the commit, whether the tree had uncommitted changes,
194
+ the directory of the sources, the stand, the command and the time. `builds list --brief`
195
+ and `apps get` fill the branch and the commit the card left empty from it and name the
196
+ source of each value.
197
+
198
+ The registry is local. A build uploaded from another machine, from CI or by an elemctl that
199
+ had no registry yet is not in it, and there the listings show what the platform knows. A
200
+ registry that cannot be written is a warning and never a failed upload; the file can be
201
+ deleted at any time, and only the history of this machine goes with it.
202
+
203
+ The registry keeps the newest thousand uploads, `ELEMCTL_REGISTRY_LIMIT` sets another
204
+ number, and `0` keeps every one. Once the file has grown past the limit by a tenth, the next
205
+ upload cuts it back to the newest lines: the builds a project still lists and an application
206
+ still runs are the recent ones, and a file nobody trimmed grew for as long as the machine
207
+ deployed.
185
208
 
186
209
  ### The CI environment
187
210
 
@@ -276,7 +299,7 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
276
299
  |---|---|
277
300
  | `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
301
  | `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 |
302
+ | `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
303
  | `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
304
  | `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
305
  | `start_app` | start the application |
@@ -286,16 +309,19 @@ The server reads connection credentials from the same `ELEMENT_*` variables / `.
286
309
  | `debug_info` | debug-session data: `debug-token` and `debug-address` (debugging must be enabled on the server) |
287
310
  | `list_spaces` | list of spaces |
288
311
  | `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 |
312
+ | `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
313
  | `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
314
  | `build_assembly` | build a `.xasm`/`.xlib` archive from the sources locally (does not talk to the platform) |
292
315
  | `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 |
316
+ | `deploy` | the whole cycle from sources, with a check that the build was applied; the verdict is `ok`, the details are `problems` and `log`; `allow_data_loss` lets through what the schema guard refuses (a narrowing, a type change, a catalog removed whole), like `--allow-data-loss`; a server that is still starting is waited out for up to `server_start_timeout` seconds (900 by default) |
317
+ | `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 |
318
+ | `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; a probe given its own name and version is known by the local registry of uploads, which also names the builds deployed into it; an application that is not a probe's is refused |
295
319
  | `apply_build` | apply an uploaded build to the application by its id |
296
320
  | `verify_deploy` | verify the apply actually took effect: failed tasks, the applied build, the availability of the uri |
297
321
  | `list_user_lists` | user lists; `name` filters by a substring of the presentation |
298
322
  | `configure_user_list` | self-registration and password sign-in; without the flags it only reports the current state |
323
+ | `list_app_users` | who is connected to an application: the user list, the id, the presentation, whether an administrator and whether token access is on, with a count line; the platform gives no login here |
324
+ | `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
325
  | `list_branches` | list of development-environment branches; the `project_id` and `name` filters are optional |
300
326
  | `merge_branch` | accept the changes of a development-environment branch |
301
327
  | `debug_adapter` | the path to the platform debug adapter from a plugin; a missing plugin is an answer (`found: false`), not an error (local) |
@@ -308,7 +334,7 @@ A single environment is not a limit. Every tool that talks to the platform takes
308
334
 
309
335
  `list_projects` behaves the same way and returns id, name, project kind, space, application count and the deletion flag. Its `name` filters by a substring too, and projects marked deleted stay hidden until `include_deleted` is set: a stand a few months old keeps hundreds of them against a handful of live ones.
310
336
 
311
- `list_builds` answers with brief cards as well, holding id, versions, date, branch and commit, and with the ten newest builds unless `limit` says otherwise; 0 lifts the cut. The cards sit under `builds`, next to the counters `total` (how many builds the platform returned) and `shown`, plus a `summary` line. The platform's listing is not the project's whole history: it deletes the builds nobody uses, whatever their age. The build an application runs, the project's first build and a release build stay. The listing has no pages, and `summary` says plainly that what you see is the remainder of the history. It reads that off the answer itself: the platform hands out the numbers of one base version consecutively, so a number missing from the listing is a build already taken away.
337
+ `list_builds` answers with brief cards as well, holding id, versions, date, branch and commit, and with the ten newest builds unless `limit` says otherwise; 0 lifts the cut. The cards sit under `builds`, next to the counters `total` (how many builds the platform returned) and `shown`, plus a `summary` line. The platform's listing is not the project's whole history: it deletes the builds nobody uses, whatever their age. The build an application runs, the project's first build and a release build stay. The listing has no pages, and `summary` says plainly that what you see is the remainder of the history. It reads that off the answer itself: the platform hands out the numbers of one base version consecutively, so a number missing from the listing is a build already taken away – unless it is a jump. A build uploaded by the vendor and the name keeps the number of its archive and the count goes on from it, and a hole under such a build of this machine is named in `summary` as a jump rather than a deletion.
312
338
 
313
339
  `get_build` hands back one card whole and is addressed by the build version. An id is accepted as well and looked up in the listing, because the address the method understands is the version, not the id of a card.
314
340
 
@@ -71,8 +71,11 @@ 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
- Application statuses: stable `Running`, `Stopped`, `Error`; transitional `Starting`, `Stopping`, `Initializing`, `Updating`, `Frozen`, `Creating`. During transitions the `status` field may also be empty.
78
+ Application statuses: stable `Running`, `Stopped`, `Error`; transitional `Starting`, `Stopping`, `Initializing`, `Updating`, `Frozen`, `Creating`, `Deleting`. During transitions the `status` field may also be empty. The reference describes `status` as a plain string and lists no values, so this list is what live checks have met. `Deleting` lasts while the `DeleteApplication` task runs, and then the application stays in the list under `Deleted` (section 6.9). `UNKNOWN`, in capitals, was met on an application whose database files were gone: it could be neither started nor deleted, because a deletion begins with an export of the data. The client does not count it as a stable status, so a wait for one runs out its timeout on such an application and names the status.
76
79
 
77
80
  ### 4.2. Technology version
78
81
 
@@ -82,17 +85,18 @@ Application statuses: stable `Running`, `Stopped`, `Error`; transitional `Starti
82
85
  ### 4.3. Spaces and projects
83
86
 
84
87
  - `GET /spaces` – list of spaces.
85
- - `GET /projects` – list of projects; `GET /projects/{id}` – card; `DELETE /projects/{id}` – delete. The list is answered in full whatever the query, and deleted projects stay in it under the `deleted` flag with their former id. Filtering by name and hiding the deleted ones is the client's work, as with applications (section 4.1).
88
+ - `GET /projects` – list of projects; `GET /projects/{id}` – card; `DELETE /projects/{id}` – delete. The list is answered in full whatever the query, and deleted projects stay in it under the `deleted` flag with their former id. Filtering by name and hiding the deleted ones is the client's work, as with applications (section 4.1). A project card carries no status at all: the `deleted` flag is the only mark of its state.
86
89
 
87
90
  ### 4.4. Project builds (assemblies)
88
91
 
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
- - `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.
94
+ - `POST /projects` – create a new project from a build, or add the build to the project the vendor and the name of the manifest already belong to;
95
+ - `POST /spaces/{space-id}/projects` – the same, with a new project created in that space.
96
+ The space of an upload into a project goes as the optional `space-id` query parameter, spelled the way the reference spells it. A live check found the server reading it: an id that is not a UUID is refused with a 400 and an unknown space with a 404, while the PascalCase `SpaceId` the client used to send went through unread. `POST /projects` documents no space parameter, and the server reads neither spelling there: a new project uploaded with `space-id=not-a-uuid` was created all the same. So the space of a new project goes into the path of `POST /spaces/{space-id}/projects`, which answers an unknown space with a 404 and adds a build whose vendor and name already have a project to that project, the way `POST /projects` does. 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 two uploads treat the version of the archive differently. An upload into a project, `POST /projects/{id}/assemblies`, does not read it at all: the server takes the base from the `Версия` of the project descriptor and gives the build the highest number of that base plus one. Checked live: an archive of `1.0.0-i1` became `1.0.0-1`, the next one, `1.0.0-10001`, became `1.0.0-2`, a `1.0.0-2` already in the project became `1.0.0-3`, and `1.0.1-7` became `1.0.0-502` in a project whose descriptor says `1.0.0`. That upload answers with the card of the build, and its `assembly-version` is the number the server handed out. An upload by the vendor and the name, `POST /projects`, keeps the version of the archive as it is, a suffix that is not a number included, and answers a version the project already has with a 409 (below). So the suffix of a version, the number of a CI run for instance, survives the second way and never the first: what ties a build uploaded into a project to its run is the name of the archive and the commit on the card. 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
97
  - **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
98
  - `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
- - `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.
99
+ - `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. The version of a build uploaded into a project is the number the server gave it, not the one of its archive (the upload above). 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.
96
100
 
97
101
  Build versions are compared by the numeric suffix after the last hyphen: `1.0-10` is newer than `1.0-9`. Lexicographic comparison gives the wrong order.
98
102
 
@@ -120,6 +124,7 @@ A user list holds either the users of an application, which has a list of its ow
120
124
  - `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
125
  - `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
126
  - `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.
127
+ - `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
128
  - 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
129
 
125
130
  Two things the panel can do and the API cannot, so both stay manual:
@@ -196,6 +201,8 @@ Compatibility is checked against the `РежимСовместимости` prop
196
201
  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
202
  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
203
  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.
204
+ 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.
205
+ 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, and so does a catalog whose description is gone from the sources, with its whole table: that was seen on an empty catalog. A narrowed length or a changed type recreates the data of the object instead. What the deploy does about each is in section 7.
199
206
 
200
207
  ## 7. CLI requirements
201
208
 
@@ -218,10 +225,12 @@ Commands, with the significant flags in parentheses:
218
225
  `apps ensure NAME [--project-id --version-id --latest-build --space-id
219
226
  --tech-version --no-dev-mode --wait --verify --no-verify --apply]`,
220
227
  `apps apply [APP_ID] VERSION_ID`,
221
- `apps delete APP_ID`, `apps start [APP_ID]`, `apps stop [APP_ID]`.
228
+ `apps delete APP_ID`, `apps start [APP_ID]`, `apps stop [APP_ID]`,
229
+ `apps users [APP_ID]`, `apps token-access APP_ID [--user --enable --disable]`.
222
230
  - `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
231
  - `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.
224
- - `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.
232
+ - `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.
233
+ - `APP_ID` of `apps get`, `delete`, `start`, `stop`, `debug` and `users` 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
234
  - `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
235
  - 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.
227
236
  - `apps ensure` idempotently brings an application with the given name into existence: it searches by the `apps find` rules, where deleted ones do not count, and creates only if absent. Output is `{"id": ..., "created": true|false, "sign-in": ...}`, and `created: false` means the application already existed and was left alone. The creation flags are the same as for `apps create` and take effect only when creation happens. An existing application is never recreated: `delete` and `create` produce a new URL and break external bindings to the former one. Because the creation flags include `--version-id`, an existing application gets two more fields in the answer: `applied`, whether it runs the requested assembly, and `applied-version-id`, the one it does run. Staying silent about that cost a stand that went to work on the previous build. `--apply` brings it to the assembly in the same call, and `apps apply` does it separately. `--verify` upgrades the verdict about an application that already runs the requested assembly from the card comparison to the full check. An application `ensure` had created used to answer `applied: true` on trust, since it was created from that assembly, and now answers with the checked verdict whenever a check ran.
@@ -231,6 +240,8 @@ Commands, with the significant flags in parentheses:
231
240
  - 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
241
  - 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
242
  - 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.
243
+ - `apps users [APP_ID]` prints the users connected to the application the way `GET /applications/{id}/users` gives them (section 4.1): `user-list-id`, `user-id`, `presentation`, `is-admin`, `token-access-enabled`. There is no login among them: the platform names a user of the control panel by the login in `presentation` and any other user by its presentation. The command only reads, so the application defaults to `ELEMENT_APP_ID`, and it ends with a count line on stderr: how many users are connected, how many of them administer the application and how many reach its HTTP services by a token. Until the command the list was seen only in a refusal of `apps token-access`.
244
+ - `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
245
  - `spaces list`.
235
246
  - `user-lists list [--name]`, `user-lists get [LIST] [--app]`,
236
247
  `user-lists self-registration [LIST] [--app --enable --disable]`,
@@ -248,9 +259,11 @@ Commands, with the significant flags in parentheses:
248
259
  - `projects list [--name --include-deleted]`, `projects get [PROJECT_ID]`, `projects delete PROJECT_ID`.
249
260
  - `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
261
  - `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
262
+ `builds upload FILE [--project-id --new-project --force-rename --space-id]`,
263
+ `builds delete VERSION [--project-id]`.
264
+ `builds upload` sends the commit the manifest of the archive names as `commit-id`
265
+ (section 4.4), names on stderr a build the server numbered otherwise than its archive
266
+ (section 4.4) and reports the chosen target in the output through `project-id` and
254
267
  `project-id-source` (`flag`, `env` or none) and notes on stderr when the target comes
255
268
  from `ELEMENT_PROJECT_ID`. `--new-project` ignores the environment binding and always
256
269
  creates a new project; it is mutually exclusive with `--project-id`. `--force-rename`
@@ -261,8 +274,43 @@ Commands, with the significant flags in parentheses:
261
274
  uses, whatever their age). "30 of 30" without that line was read as the project's whole
262
275
  history. The housekeeping is judged by the facts of the answer, not by the length of the
263
276
  listing: the platform hands out the numbers of a base version one after another, so a
264
- number the listing has not got is a build already taken away, and the line says how many
265
- are missing.
277
+ hole in the numbering is a build already taken away, and the line says there are holes
278
+ without counting them. A hole can also be a jump: an upload by the vendor and the name
279
+ keeps the number of its archive, and the next upload into the project counts on from
280
+ it. Seen live, `1.0.0-3` was followed by `1.0.0-500` and `1.0.0-501`, and the numbers
281
+ between had never existed. The created stamps of the neighbours cannot tell a jump
282
+ from a loss, since the server handed out four numbers in a third of a second, so the
283
+ local registry of uploads does: a hole under a build this machine uploaded by the
284
+ vendor and the name is named as a jump and is no evidence of the housekeeping. A build
285
+ uploaded that way from elsewhere is not in the registry, and its hole still reads as a
286
+ deletion.
287
+ `--brief` prints the id, the versions, the date, the branch and the commit of a build.
288
+ The branch and the commit come from the card when the platform filled them, otherwise
289
+ from the local registry of uploads, and `branch-name-source` and `commit-id-source`
290
+ say which answered: `platform`, `registry`, or null when neither knows. The registry
291
+ alone knows `dirty`, whether the tree had uncommitted changes, and `project-dir`, the
292
+ directory the build was made from.
293
+ - The local registry of uploads. Every upload elemctl makes – `deploy`, `builds upload`,
294
+ `probe` – appends a JSON line to `uploads.jsonl` in the data directory of the user:
295
+ `ELEMCTL_DATA_DIR` when it is set, otherwise `%LOCALAPPDATA%\elemctl` on Windows and
296
+ `$XDG_STATE_HOME/elemctl` (`~/.local/state/elemctl`) elsewhere. A line holds the build
297
+ id, the project id, the version, the branch, the commit, the `dirty` flag, the directory
298
+ of the sources, the archive, the stand, the command, the application the upload was made
299
+ for (the target of a deploy, the throwaway application of a probe), the route of the
300
+ upload (`project` into a project by its id, `vendor-name` by the vendor and the name)
301
+ and the time. The platform keeps the commit alone, and with several sessions deploying
302
+ from one machine a build on an application could not be traced to the working tree it
303
+ came from. The registry is local:
304
+ a build uploaded from another machine, from CI or by an elemctl that had no registry yet
305
+ is not in it. A registry that cannot be written is a warning on stderr, never a failure
306
+ – the build is on the server by then – and one that cannot be read reads as empty. The
307
+ schema guard of `deploy` takes the commit of an applied build from here when the card of
308
+ that build carries none. The registry keeps the newest 1000 uploads,
309
+ `ELEMCTL_REGISTRY_LIMIT` sets another number and `0` keeps every one: once the file has
310
+ grown past the limit by a tenth, the next upload cuts it back to the newest lines. The
311
+ file is rewritten beside itself and swapped in by a rename, and a line another process
312
+ appended meanwhile is carried over; a swap the system refuses leaves the file as it was
313
+ until the next upload.
266
314
  - `build [--project-dir --output --build-version --last-build --commit
267
315
  --branch --kind {application,library} --require-clean]` – build the archive locally.
268
316
  Output: `file`, `name`, `vendor`, `version`, `version-source`
@@ -277,9 +325,11 @@ Commands, with the significant flags in parentheses:
277
325
  - `inspect FILE` – parse a prebuilt archive (section 5.1). Local as well: the platform is
278
326
  not called, and the connection flags are refused the same way.
279
327
  - `deploy [--app-id --project-id --project-dir --output --build-version
280
- --branch --commit --commit-message --dry-run --require-clean]` –
281
- 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.
328
+ --branch --commit --dry-run --require-clean --allow-data-loss
329
+ --server-start-timeout]` –
330
+ 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`, `assembly-version` (the version the server gave the uploaded build), `renumbered` (true when that is not the version of the archive, null when the upload did not say), `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 `
331
+ ` 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. The server numbers a build uploaded into a project itself (section 4.4), so an explicit `--build-version` it will not keep – a suffix that is not a number, no suffix at all, a base other than the `Версия` of the project – is named on stderr before the build, and a build the server numbered otherwise than its archive is named right after the upload. 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).
332
+ 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), or, when the card carries none, the commit the local registry of uploads remembers for that build. A build that created its project has no commit on its card, and the registry knows one when the build was uploaded from this machine; a line on stderr says the commit came from there, and whether that build was made from a tree with uncommitted changes, which the comparison cannot see. `schema-commit` names the commit compared against and `schema-commit-source` where it came from, `platform` or `registry`. 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. So does an element that keeps data of its own – a catalog, a document, an information or accumulation register, a constants set, an exchange plan or a settings storage – whose description is gone from the sources: its whole table goes with every row. The disk cannot tell of a file that is not there, so the guard lists the files of the applied commit with git and follows an element by its `Ид`. A description moved to another subsystem or renamed keeps its data and is compared with its old text; an element without an `Ид` cannot be told from a moved one and is left alone. A file still in its place that carries another `Ид` describes another element: the description was made anew, and the element it used to describe is followed the same way. Checked live, a catalog described anew under its old path and name was applied without a question and came out empty, so such an element is refused as a removal, and the refusal names the former `Ид` to give back when the element is meant to be the same. The fields of the two descriptions are not compared with each other: they belong to different elements. 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
333
  - `verify-deploy [APP_ID] [--app-id --version-id --expected-version --since-minutes]` –
284
334
  the verification of section 6.1 on its own, deploying nothing. It looks at the
285
335
  application tasks in an error status raised over the last `--since-minutes` minutes,
@@ -291,7 +341,7 @@ Commands, with the significant flags in parentheses:
291
341
  after `apps create`: a build that failed to apply is rolled back silently, and a status
292
342
  of `Running` proves nothing.
293
343
  - `probe [--project-dir --output --build-version --name --space-id --keep
294
- --require-clean]` – an isolated compilation check of the sources: build ->
344
+ --require-clean]`, `probe --cleanup APP_ID` – an isolated compilation check of the sources: build ->
295
345
  upload -> a throwaway application (that is the compilation, section 6.10) ->
296
346
  errors with file and position -> cleanup. Before the build the manifest is
297
347
  checked for what the server needs to take a probe: `Представление`
@@ -311,12 +361,14 @@ Commands, with the significant flags in parentheses:
311
361
  comparison. Cleanup runs whether the compilation passed or failed, in the order
312
362
  of section 6.9: the application, then the build, then the project, and the
313
363
  project only if the probe itself created it. Output: `ok`, `project-dir`,
314
- `vendor`, `name`, `file`, `version`, `project-id`, `assembly-id`, `app-id`,
364
+ `vendor`, `name`, `file`, `version`, `project-id`, `project-created`,
365
+ `assembly-id`, `app-id`,
315
366
  `app-name`, `status`, `errors` (a list of `{file, entry, line, column,
316
367
  environment, message}`, where `file` is the path relative to the project
317
368
  directory), `messages` (the platform texts verbatim, so nothing is lost when the
318
369
  failure is not a compilation one), `cleanup` (`kept`, `app-deleted`,
319
- `assembly-deleted`, `project-deleted`, `problems`) and `hint`, the pointer to the
370
+ `assembly-deleted`, `project-deleted`, `problems`, `command`, `steps`) and
371
+ `hint`, the pointer to the
320
372
  server log that the `deploy` report carries too. `hint` is filled when the server
321
373
  refused and named no file; a wait that ran out of time leaves it empty. A stand that does not know
322
374
  the compatibility mode of the project refuses the whole project and then
@@ -330,6 +382,39 @@ Commands, with the significant flags in parentheses:
330
382
  does leave behind is a tombstone: the platform keeps deleted applications in
331
383
  the list with the `Deleted` status and their former id, and there is no API to
332
384
  remove them.
385
+ Whatever a probe leaves, on purpose with `--keep` or through a cleanup step that
386
+ failed, comes with the commands that remove it, in `cleanup` and on stderr:
387
+ `command` is the one command, `probe --cleanup APP_ID`, and `steps` are the same
388
+ by hand in the order of section 6.9, with the build addressed in the probe's own
389
+ project. A bare `builds delete` looks in the project of `ELEMENT_PROJECT_ID`, where
390
+ the probe build is not, and a build deleted right after its application is
391
+ refused with a 500 until the application is gone. Both lines name the `--env-file`
392
+ the probe was run with.
393
+ `probe --cleanup APP_ID` removes a probe left on the stand, starting from its
394
+ application, an id or a name. The application card names the project and the build it
395
+ was created from, so nothing has to be remembered between the runs. Only a probe's
396
+ application is touched: its name starts with `elemctl-probe-`, or the build it runs
397
+ carries `-probe-` in its version, which covers a probe named with `--name`, or the local
398
+ registry of uploads remembers a probe of this machine creating it, which covers a probe
399
+ given both `--name` and `--build-version` and one that got deploys of its own since. Any
400
+ other application is refused with the reason, and so is the one `ELEMENT_APP_ID` names.
401
+ The order is that of section 6.9: the application, a wait until it is gone, the build of
402
+ this very probe (its token in the version, or the build the registry remembers the probe
403
+ uploading) together with every build the registry remembers uploading for this
404
+ application, and the project last. A build uploaded for the application that another
405
+ live application runs now stays, and its entry in `builds` names that application in
406
+ `kept`. The project goes only when no build is left in it and no live application runs
407
+ it, and never when it is the project of `ELEMENT_PROJECT_ID`: a probe usually lands in
408
+ the project that owns its sources, the working one, while a project the probe created
409
+ ends up empty. The builds other runs uploaded into the probe's application from another
410
+ machine, which the registry does not know, are left to the platform, which deletes the
411
+ builds nobody uses. A second run finishes what the first one left: an application that
412
+ is already a tombstone is not deleted twice, since the list keeps its card, and a
413
+ project deleted already is not deleted again. The run builds nothing, so the flags of a
414
+ probe run are refused beside `--cleanup`. Output: `ok`, `app-id`, `app-name`,
415
+ `project-id`, `app-deleted`, `builds` (`{id, version, deleted}` each),
416
+ `project-deleted`, `project-kept` (why the project stayed) and `problems`; return code 0
417
+ only when `ok`.
333
418
  - `branches list [--project-id --name]`, `branches get ID`,
334
419
  `branches create NAME [--project-id --app-id]`,
335
420
  `branches update ID [--app-id]`, `branches delete ID`,
@@ -340,7 +425,7 @@ Commands, with the significant flags in parentheses:
340
425
  - `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).
341
426
  - `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": ...}]}`.
342
427
  - 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.
343
- - `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}`.
428
+ - `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.
344
429
  - `mcp` – start the MCP server; without the extra installed – a clear error with the hint `pip install "elemctl[mcp]"`.
345
430
 
346
431
  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.
@@ -353,7 +438,8 @@ Server name `elemctl`, stdio transport, credentials from the same environment va
353
438
  (section 7): `name` by a case-insensitive substring on the client (section 4.1), `status`
354
439
  by the whole status word, and the deleted applications hidden unless asked for. The answer
355
440
  is an object with `total`, `live`, `shown`, a `summary` line and `applications`, so that
356
- what was hidden is stated rather than guessed at; `get_app(app_id)`, `find_app(name)`,
441
+ what was hidden is stated rather than guessed at; `get_app(app_id)` – the card with
442
+ `applied-build`, as `apps get` prints it (section 7), `find_app(name)`,
357
443
  `create_app(name, project_id="", version_id="", space_id="",
358
444
  development_mode=True, verify=False)` – when only project_id is given, the project's latest
359
445
  build is automatically used as the source (section 6.2); `verify=True` waits for the
@@ -376,16 +462,21 @@ id (UUID) or the exact application name (resolved like the CLI does),
376
462
  `list_projects(name="", include_deleted=False)` – the filters of `projects list` (section 7),
377
463
  `list_builds(project_id, limit=10, brief=True)` – an object `{total, shown, summary, builds}`:
378
464
  the listing has to say whether it is the whole store, judged by the gaps in the build
379
- numbering (section 4.4),
465
+ numbering (section 4.4) and naming a jump the local registry explains (section 7), and a
466
+ brief card names the source of its branch and commit, the
467
+ card or the local registry of uploads, the way `builds list --brief` does (section 7),
380
468
  `get_build(project_id, version)` – the whole card of one build, addressed by the build
381
469
  version (section 4.4; an id is accepted and resolved through the listing),
382
470
  `build_assembly(project_dir="", output_dir="", version="")`,
383
471
  `inspect_assembly(file)` – parsing of a built archive (section 5.1; a local operation),
384
- `deploy(app_id, project_id, project_dir="", version="", branch="",
385
- commit_message="")` – returns the deploy report plus a `log` field with progress
386
- lines; `probe(project_dir="", space_id="", keep=False)` – an isolated
472
+ `deploy(app_id, project_id, project_dir="", version="", branch="", allow_data_loss=False,
473
+ server_start_timeout=900)` – returns the deploy report plus a `log` field with progress
474
+ lines, and waits out a server that is still starting (section 6.12); `allow_data_loss=True`
475
+ lets through what the schema guard refuses, the way `--allow-data-loss` does in the CLI
476
+ (section 7), and without it the refusal comes back as an error before anything is built; `probe(project_dir="", space_id="", keep=False)` – an isolated
387
477
  compilation check that does not touch the working application (section 7),
388
- the report plus a `log` field; `apply_build(app_id, version_id)`, `verify_deploy(app_id,
478
+ the report plus a `log` field; `probe_cleanup(app_id)` – `probe --cleanup` (section 7),
479
+ 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,
389
480
  expected_version="", since_minutes=30)` – verification of the apply per section 6.1;
390
481
  `list_app_tasks(app_id="")`, `list_branches(project_id="", name="")`,
391
482
  `merge_branch(branch_id)`, `list_user_lists(name="")` and
@@ -393,7 +484,12 @@ expected_version="", since_minutes=30)` – verification of the apply per sectio
393
484
  the sign-in settings of a user list (section 4.7) in one call: the list is given by id, by
394
485
  presentation or by the application whose own list it is; both flags are optional, and
395
486
  without them the tool only reports the state (`self-registration-enabled`,
396
- `password-login-enabled`, `changed`).
487
+ `password-login-enabled`, `changed`); `list_app_users(app_id)` – the users connected to
488
+ the application as `apps users` shows them (section 7), in an object
489
+ `{app-id, total, summary, users}`; `token_access(app_id, user="", enabled=None)` – the
490
+ access of a user to the HTTP services of the application by a token, as `apps token-access`
491
+ shows and switches it (section 7): `app_id` is required, an empty `user` means the account
492
+ elemctl signs in with, and without `enabled` the tool only reads.
397
493
 
398
494
  The tools the plugins bring (section 10, the `elemctl.commands` group) are registered
399
495
  alongside these: the schema is built out of the declared arguments, the description is the