vortex-cli 6.4.1__tar.gz → 8.0.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. vortex_cli-8.0.0/PKG-INFO +629 -0
  2. vortex_cli-8.0.0/README.md +585 -0
  3. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/pyproject.toml +1 -1
  4. vortex_cli-8.0.0/vortex/cli.py +751 -0
  5. vortex_cli-8.0.0/vortex/commands/app.py +746 -0
  6. vortex_cli-8.0.0/vortex/commands/clean.py +122 -0
  7. vortex_cli-8.0.0/vortex/commands/clone.py +470 -0
  8. vortex_cli-8.0.0/vortex/commands/compile.py +485 -0
  9. vortex_cli-8.0.0/vortex/commands/config.py +67 -0
  10. vortex_cli-8.0.0/vortex/commands/db.py +1340 -0
  11. vortex_cli-8.0.0/vortex/commands/execute.py +103 -0
  12. vortex_cli-8.0.0/vortex/commands/keyword.py +686 -0
  13. vortex_cli-8.0.0/vortex/commands/log.py +203 -0
  14. vortex_cli-8.0.0/vortex/commands/object_.py +1089 -0
  15. vortex_cli-8.0.0/vortex/commands/status.py +214 -0
  16. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/watch.py +42 -104
  17. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/libs.py +38 -67
  18. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/logging.py +5 -3
  19. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/main.py +195 -299
  20. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/models.py +104 -405
  21. vortex_cli-8.0.0/vortex/output.py +171 -0
  22. vortex_cli-8.0.0/vortex/registry.py +307 -0
  23. vortex_cli-8.0.0/vortex/schedule.py +226 -0
  24. vortex_cli-8.0.0/vortex/soap.py +138 -0
  25. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/spinner.py +5 -5
  26. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/util.py +7 -31
  27. vortex_cli-8.0.0/vortex/webdesign.py +1122 -0
  28. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/workspace.py +62 -41
  29. vortex_cli-8.0.0/vortex_cli.egg-info/PKG-INFO +629 -0
  30. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex_cli.egg-info/SOURCES.txt +5 -13
  31. vortex_cli-6.4.1/PKG-INFO +0 -535
  32. vortex_cli-6.4.1/README.md +0 -491
  33. vortex_cli-6.4.1/vortex/cli.py +0 -1385
  34. vortex_cli-6.4.1/vortex/commands/agenda.py +0 -163
  35. vortex_cli-6.4.1/vortex/commands/clean.py +0 -214
  36. vortex_cli-6.4.1/vortex/commands/clone.py +0 -630
  37. vortex_cli-6.4.1/vortex/commands/compile.py +0 -288
  38. vortex_cli-6.4.1/vortex/commands/config.py +0 -126
  39. vortex_cli-6.4.1/vortex/commands/copy.py +0 -214
  40. vortex_cli-6.4.1/vortex/commands/db.py +0 -375
  41. vortex_cli-6.4.1/vortex/commands/delete.py +0 -141
  42. vortex_cli-6.4.1/vortex/commands/execute.py +0 -88
  43. vortex_cli-6.4.1/vortex/commands/export.py +0 -120
  44. vortex_cli-6.4.1/vortex/commands/import_.py +0 -29
  45. vortex_cli-6.4.1/vortex/commands/keyword.py +0 -309
  46. vortex_cli-6.4.1/vortex/commands/list.py +0 -186
  47. vortex_cli-6.4.1/vortex/commands/log.py +0 -107
  48. vortex_cli-6.4.1/vortex/commands/new.py +0 -660
  49. vortex_cli-6.4.1/vortex/commands/pull.py +0 -398
  50. vortex_cli-6.4.1/vortex/commands/push.py +0 -303
  51. vortex_cli-6.4.1/vortex/commands/render.py +0 -77
  52. vortex_cli-6.4.1/vortex/commands/schema.py +0 -669
  53. vortex_cli-6.4.1/vortex/commands/status.py +0 -86
  54. vortex_cli-6.4.1/vortex/commands/undo.py +0 -144
  55. vortex_cli-6.4.1/vortex/gateway.py +0 -894
  56. vortex_cli-6.4.1/vortex/soap.py +0 -641
  57. vortex_cli-6.4.1/vortex/webdesign.py +0 -653
  58. vortex_cli-6.4.1/vortex_cli.egg-info/PKG-INFO +0 -535
  59. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/LICENSE +0 -0
  60. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/setup.cfg +0 -0
  61. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/__init__.py +0 -0
  62. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/__main__.py +0 -0
  63. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/colour.py +0 -0
  64. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/__init__.py +0 -0
  65. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/code.py +0 -0
  66. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/docs.py +0 -0
  67. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/find.py +0 -0
  68. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/grep.py +0 -0
  69. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/libs.py +0 -0
  70. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/commands/use.py +0 -0
  71. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/constants.py +0 -0
  72. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/docs/Blackbook v2.md +0 -0
  73. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/docs/Blackbook.pdf +0 -0
  74. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/docs/index.html +0 -0
  75. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/docs/marked.min.js +0 -0
  76. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex/lib/puakma-6.0.40.jar +0 -0
  77. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex_cli.egg-info/dependency_links.txt +0 -0
  78. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex_cli.egg-info/entry_points.txt +0 -0
  79. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex_cli.egg-info/requires.txt +0 -0
  80. {vortex_cli-6.4.1 → vortex_cli-8.0.0}/vortex_cli.egg-info/top_level.txt +0 -0
@@ -0,0 +1,629 @@
1
+ Metadata-Version: 2.4
2
+ Name: vortex_cli
3
+ Version: 8.0.0
4
+ Summary: Vortex CLI
5
+ Author-email: Jordan Amos <jordan.amos@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2023 jordanamos
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Keywords: vortex,cli,puakma,tornado
29
+ Classifier: Intended Audience :: Developers
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Natural Language :: English
32
+ Classifier: Programming Language :: Python
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Programming Language :: Python :: 3 :: Only
35
+ Requires-Python: >=3.10
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE
38
+ Requires-Dist: httpx>=0.27
39
+ Requires-Dist: tabulate>=0.9
40
+ Requires-Dist: watchfiles>=0.19
41
+ Provides-Extra: keyring
42
+ Requires-Dist: keyring; extra == "keyring"
43
+ Dynamic: license-file
44
+
45
+ # Vortex CLI
46
+
47
+ [![Build Status](https://dev.azure.com/amostj/vortex-cli/_apis/build/status%2Fjordanamos.vortex-cli?branchName=main)](https://dev.azure.com/amostj/vortex-cli/_build/latest?definitionId=11&branchName=main) [![PyPI version](https://badge.fury.io/py/vortex-cli.svg)](https://badge.fury.io/py/vortex-cli)
48
+
49
+ Vortex CLI is a command line alternative to the [Puakma Vortex IDE](https://github.com/brendonupson/PuakmaVortex) that simplifies the process of developing Puakma Applications on a [Puakma Tornado Server](https://github.com/brendonupson/Puakma) using Visual Studio Code. It allows you to clone applications from the server to a local workspace, edit the files using Visual Studio Code, and automatically upload changes to the server as you work.
50
+
51
+ Vortex CLI also comes pre-packaged with the necessary Puakma .jar files for development.
52
+
53
+ #### Visual Studio Code and Extensions
54
+
55
+ While it is possible to use without it, this software has been purposefully designed for use with [Visual Studio Code](https://github.com/microsoft/vscode) and the [Project Manager For Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-dependency) or the [Extension Pack For Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack) extension. This software leverages [Workspaces](https://code.visualstudio.com/docs/editor/workspaces) in Visual Studio Code and manages a `vortex.code-workspace` file within the workspace.
56
+
57
+ ## Installation
58
+
59
+ 1. Install the tool using pip.
60
+
61
+ ```
62
+ pip install vortex-cli
63
+ ```
64
+
65
+ 2. It is recommended to set the workspace you would like to work out of via the `VORTEX_HOME` environment variable.
66
+
67
+ On Unix:
68
+
69
+ ```
70
+ export VORTEX_HOME=/path/to/workspace
71
+ ```
72
+
73
+ Otherwise, Vortex CLI will use a default **'vortex-cli-workspace'** directory inside your home directory.
74
+
75
+ 3. Run vortex with the `--init` flag to create your workspace (If it doesn't already exist) and the necessary config files:
76
+ ```
77
+ vortex --init
78
+ ```
79
+
80
+ 4. Define the servers you will be working with in the `servers.ini` file inside the `.config` directory within your workspace. You can quickly access this using the `code` command to view your workspace in VSCode.
81
+
82
+ ```
83
+ vortex code
84
+ ```
85
+
86
+ In the `servers.ini` file, you can define as many servers as you need, each with their own unique name. For example:
87
+
88
+ ```
89
+ [DEFAULT] ; This section is optional and only useful if you have multiple definitions
90
+ port = 80 ; Options provided under DEFAULT will be applied to all definitions if not provided
91
+ soap_path = system/SOAPDesigner.pma
92
+ default = server1 ; Useful when you have multiple definitions
93
+
94
+
95
+ [server1] ; This can be called whatever you want and can be referenced using the '--server' flag
96
+ host = example.com
97
+ port = 8080 ; we can overwrite the DEFAULT value
98
+ username = myuser ; Optional - Prompted at runtime if not provided
99
+ password = mypassword ; Optional - Prompted at runtime if not provided
100
+ ; Optional
101
+ gateway_path = vortex/gateway.pma ; the default: through the vortex gateway. Blank = webdesign's vortex API directly - see Backend: gateway or webdesign
102
+ clone_with_resources = html,css,js ; resources with these extensions are always cloned - 'clone --get-resources' still clones ALL resources
103
+ lib_path = ; optional extra jars to add to the classpath (the server's own jars are downloaded automatically - see 'vortex libs')
104
+ workspace_folders = ~/dev/shared,notes ; extra folders to mount in the generated .code-workspace files. Relative paths resolve against the workspace root. Under [DEFAULT] they are added to every workspace; here they apply to this server's workspace (and the global one)
105
+ java_home = /usr/lib/jvm/java-17-openjdk-amd64/ ; The local path to the JRE to use. Should be the same version running on your server
106
+ java_environment_name = JavaSE-17 ; Java Execution Environment name https://docs.osgi.org/reference/eenames.html
107
+ ```
108
+
109
+ ## Upgrading to 8.0
110
+
111
+ 8.0 reorganises the server commands into `vortex <noun> <verb>` over four entities - `app`,
112
+ `object`, `keyword` and `db` - so people and AI agents can drive a server predictably.
113
+ Everything else keeps its 7.x shape. It is a breaking release: each removed 7.x command still
114
+ exists for one release as a stub that **runs nothing**, prints its 8.0 replacement and exits 1.
115
+
116
+ | 7.x | 8.0 |
117
+ |---|---|
118
+ | `list` | `app list` (`ls` stays, = `app list --local`) |
119
+ | `new app` | `app create` |
120
+ | `new object` / `new object --update` | `object create` / `object update` |
121
+ | `new keyword`, `keyword APP --name --values` | `keyword set NAME VALUE... --app-id APP` |
122
+ | `keyword APP` | `keyword list --app-id APP` |
123
+ | `copy IDS --app-id DEST` | `object copy IDS --app-id SRC --to-app-id DEST` (`--app-id` now means the SOURCE) |
124
+ | `delete` | `object delete IDS --app-id APP` |
125
+ | `import` / `export` | `app import` (`--group` now required) / `app export` |
126
+ | `db ID --sql` | `db query DB --app-id APP` (no `--update` flag) |
127
+ | `db NAME --list` / `--schema T` | `db list-tables` / `db get-table` |
128
+ | `schema --add-table` ... `--delete-column` | `db create-table` ... `db delete-column` |
129
+ | `schema --ddl` | removed |
130
+ | `config --check-gateway` | `status` |
131
+
132
+ - **Numeric IDs, no guessing.** `--app-id` and `APP_ID` are numeric everywhere (only
133
+ `clone APP...` still takes a TemplateName, group or `group/name`), and `--app-id` is
134
+ required on every `object`, `keyword` and `db` command - it is never inferred from a clone.
135
+ The server is `-s/--server`, else the `vortex use` default; `SERVER:ID` qualifiers and
136
+ inferring the server from local clones are gone.
137
+ - **No clone needed for server work.** When the app *is* cloned, every change is written
138
+ into the clone too (see [Local clones stay in sync](#local-clones-stay-in-sync)).
139
+ - **Output for scripts and agents.** Readable by default; `--json` on every entity command
140
+ and `status` prints one envelope with a machine-readable error code. Exit codes are 0/1
141
+ (2 for bad arguments). See [Output, errors and exit codes](#output-errors-and-exit-codes).
142
+ - **`gateway_path` alone picks the route.** Set (the default `vortex/gateway.pma`) means the
143
+ gateway, required - no probe, no fallback; blank means webdesign's `vortex` API directly.
144
+ The 7.x server options for choosing SOAP and for pinning the log's database connection
145
+ are gone and silently ignored if still present. **Blank `gateway_path` on any server that
146
+ has no gateway** (the old SOAP servers, and any server still running the old gateway) or
147
+ 8.0 cannot reach it. SOAP is used only for console commands (`status`, `execute`) on
148
+ servers without the gateway.
149
+ - **`protected = true` only means `watch` skips the server** unless `--include-protected`.
150
+ The typed server-name confirmation is gone from every command; the gateway's roles are the
151
+ protection.
152
+ - **`clone` no longer downloads the server libraries.** It prints a one-line
153
+ `vortex libs --refresh` hint when they are not cached; `compile` fetches them on first use.
154
+ - **`watch` is no longer the only deploy path:** `object create`/`update --source/--data`
155
+ and `compile --upload` upload content too. A running watch blocks them (and any compile).
156
+ - **`clean`, `grep`, `find`** take one `--app-id`. `list --show-inactive` and
157
+ `list --connections` are gone (the inventory has no `DisableApp` flag; use
158
+ `db list --local`).
159
+
160
+ ## Upgrading from 6.x or 7.x
161
+
162
+ 6.0 added the gateway as an opt-in alternative to the SOAP designer, and 7.0 replaced the old
163
+ gateway application with today's pass-through to webdesign's `vortex` API (removing `push`,
164
+ `pull`, `undo`, `render`, `agenda`, `compile` and the undo journal). 8.0 supersedes both:
165
+ follow [Upgrading to 8.0](#upgrading-to-80) - in particular, set `gateway_path` per server.
166
+
167
+ ## Upgrading to 5.0
168
+
169
+ 5.0 changes some defaults you may rely on:
170
+
171
+ - **`resource_ext_only` is replaced by `clone_with_resources` - and the meaning flipped.**
172
+ Previously the extensions *restricted* what `--get-resources` cloned. Now resources with the
173
+ listed extensions are **always** cloned, and `--get-resources` clones every resource
174
+ unfiltered. Rename the key in `servers.ini` (vortex warns while the old key is present).
175
+ - **`vortex watch` now watches every cloned app across all servers** and uploads each change to
176
+ the server it was cloned from. Use `--server` for the old single-server behaviour, and mark
177
+ production definitions `protected = true` so they are never watched by accident.
178
+ - `find`, `grep` and `vortex list --local` now search all cloned apps unless `--server` is
179
+ given, and ID-taking commands infer their server from local clones (see below).
180
+
181
+ ## Usage
182
+
183
+ For a full list of commands see `--help` (every command and verb has its own:
184
+ `vortex db update-column --help`).
185
+
186
+ ### Command Overview
187
+
188
+ ```
189
+ ── app ──────────────────────────────────────────────────────────────────────
190
+ vortex app list [--group --name --template --strict --local --show-inherited
191
+ --all --ids-only --open-urls --open-dev-urls] [--json]
192
+ vortex app get APP_ID [--show-params] [--json]
193
+ vortex app create --name N --group G [--template --inherit-from --description]
194
+ vortex app update APP_ID [--name --group --description --inherit-from --template]
195
+ [--param NAME=VALUE ...] [--remove-param NAME ...]
196
+ vortex app export APP_ID... [--out-dir --exclude-source --timeout]
197
+ vortex app import FILE.pmx --name N --group G
198
+
199
+ ── object ───────────────────────────────────────────────────────────────────
200
+ vortex object get ID --app-id ID [--show-source --show-data] [--json]
201
+ vortex object create --app-id ID --type T --name N [--source FILE --data FILE
202
+ --content-type --comment --inherit-from --open-action
203
+ --save-action --parent-page] [schedule options]
204
+ vortex object update ID... --app-id ID [--source FILE --data FILE] [metadata options]
205
+ [schedule options]
206
+ schedule options (SCHEDULED_ACTION only): --schedule N|S|I|H|D|W|M|Y --interval N
207
+ --days SMTWHFA --start-time HH:mm --finish-time HH:mm --date N --month N
208
+ vortex object copy ID... --app-id SRC --to-app-id TGT [--copy-params]
209
+ vortex object delete ID... --app-id ID [--yes]
210
+
211
+ ── keyword ──────────────────────────────────────────────────────────────────
212
+ vortex keyword list --app-id ID [--local] [--reveal] [--json]
213
+ vortex keyword get NAME --app-id ID [--local] [--reveal] [--json]
214
+ vortex keyword set NAME [VALUE...] --app-id ID
215
+ vortex keyword delete NAME --app-id ID [--yes]
216
+
217
+ ── db ───────────────────────────────────────────────────────────────────────
218
+ vortex db list --app-id ID [--local] [--json]
219
+ vortex db get DB --app-id ID [--json]
220
+ vortex db query DB --app-id ID [SQL | --file F | -] [--limit N] [--all-cols] [--json]
221
+ vortex db list-tables DB --app-id ID [--json]
222
+ vortex db get-table DB TABLE --app-id ID [--json]
223
+ vortex db create-table DB TABLE --app-id ID [--description]
224
+ vortex db update-table DB TABLE --app-id ID [--name --description]
225
+ vortex db delete-table DB TABLE --app-id ID [--yes]
226
+ vortex db create-column DB TABLE COLUMN --app-id ID --type T [--size N --pk --not-null
227
+ --unique --auto-increment --ref TABLE --cascade-delete --description]
228
+ vortex db update-column DB TABLE COLUMN --app-id ID [--name --type --size --description
229
+ --pk|--no-pk --null|--not-null --unique|--no-unique
230
+ --auto-increment|--no-auto-increment --ref TABLE|--no-ref
231
+ --cascade-delete|--no-cascade-delete]
232
+ vortex db delete-column DB TABLE COLUMN --app-id ID [--yes]
233
+
234
+ ── Workspace ────────────────────────────────────────────────────────────────
235
+ vortex ls [app list filters] = app list --local
236
+ vortex clone APP... [--group --reclone --all --get-resources --open-urls --timeout]
237
+ vortex compile --app-id ID [--object ID...] [--upload [--include-source]] [--show-warnings]
238
+ vortex watch [--include-protected]
239
+ vortex clean [--app-id ID] [--all --include-libs]
240
+ vortex grep PATTERN [--app-id ID] [--output-paths|--output-apps]
241
+ [--include-resources|--type]
242
+ vortex find QUERY [--app-id ID] [--strict --inherits-from|--parent-page --ids-only
243
+ --show-params --type]
244
+ vortex code
245
+ vortex libs [--refresh]
246
+
247
+ ── Server and setup ─────────────────────────────────────────────────────────
248
+ vortex status [--show-permissions] [--json]
249
+ vortex log [-n --source -m --errors-only|--debug-only|--info-only -k -d]
250
+ vortex execute CMD | --refresh-design APP_ID | --run PATH | --show-schedule
251
+ | --refresh-agenda | --flush-cache
252
+ vortex config --sample | --list-servers | --set S O V | --set-password
253
+ | --output-config-path | --output-workspace-path | --output-server-config
254
+ | --update-vscode-settings | --reset-vscode-settings
255
+ vortex use SERVER_NAME
256
+ vortex docs [--serve --port]
257
+ ```
258
+
259
+ Every server command takes `-s/--server NAME` (default: the server set with `vortex use`).
260
+ `--show-X` adds X to what is **printed**; `--include-X` adds X to what is **sent**.
261
+
262
+ Each entity command makes at most three small requests (three per ID for multi-ID
263
+ commands); only `clone` downloads a whole application.
264
+
265
+ ### Output, errors and exit codes
266
+
267
+ Output is readable by default - tables for `list`, key/value for `get`. `--json` (every
268
+ `app`, `object`, `keyword` and `db` command, and `status`) prints exactly one JSON envelope
269
+ on stdout; logs, progress and prompts always go to stderr:
270
+
271
+ ```json
272
+ {"ok": true, "server": "dev", "data": {"appid": 9, "appname": "app", "appgroup": "bettrackr"}}
273
+ {"ok": false, "server": "dev", "error": {"code": "FORBIDDEN", "role": "GatewayDBWrite", "message": "..."}}
274
+ ```
275
+
276
+ `data` keeps the server's own lowercase keys (`designbucketid`, `appname`). `error.code` is
277
+ the gateway's refusal code as sent (`FORBIDDEN` with the missing `role`, `NOT_FOUND`,
278
+ `SYSTEM_DB`, `SQL_NOT_ALLOWED`, `WEBDESIGN_UNAVAILABLE`, ...), or one the CLI sets:
279
+ `NOT_FOUND` (404), `FORBIDDEN` (a login page, 401/403), `UNAVAILABLE` (network, timeout, a
280
+ missing route), `CONFIRMATION_REQUIRED` and `ERROR`. A `hint` says what to do next when
281
+ there is something to do.
282
+
283
+ Exit codes: `0` success, `1` failure (including a partly failed multi-ID command, whose
284
+ `data` then lists each ID's result), `2` bad arguments.
285
+
286
+ Nothing ever prompts without a terminal. The only wizards are `app create` and
287
+ `object create` run with no arguments in a terminal. Deletes look the item up, show it and
288
+ ask; `--yes` confirms, and without a terminal and without `--yes` they fail with
289
+ `CONFIRMATION_REQUIRED` and send nothing.
290
+
291
+ `vortex status --show-permissions` lists every server command, whether this identity may run
292
+ it and the gateway role it is missing - read from the gateway's own route table (`whoami`),
293
+ so it is always the server's current rules.
294
+
295
+ ### Updates are partial
296
+
297
+ Pass only what changes. The CLI starts from the server's current values, because
298
+ webdesign's writes replace whole rows (an omitted field is written blank):
299
+
300
+ - `app update` always reads the application row first (`GET ""`), overlays the passed
301
+ fields and writes it back. `--param NAME=VALUE` replaces every param of that name,
302
+ `--remove-param NAME` removes them; the whole param list is read, merged and written back.
303
+ - `object update` always reads the object from the **server** - never the clone, which lacks
304
+ `Options` and unfetched resources and may hold undeployed edits - and writes it back with
305
+ only the passed fields changed. `--source FILE` / `--data FILE` upload content (one ID).
306
+ - `keyword set` replaces a keyword's **whole** value list - there is no per-value edit - and
307
+ folds duplicate KEYWORD rows of the same name into the oldest.
308
+ - `db update-table` / `update-column` start from the current dictionary row; the `--no-*`
309
+ forms and `--null` turn things off.
310
+
311
+ Keyword and param writes are read-then-write: a concurrent edit between the two is lost.
312
+
313
+ No cache flush is needed after a write: webdesign's `vortex` API flushes the application's
314
+ cache itself (`flushHttpServerCache`) after every design, design-param, keyword, app-param
315
+ and application write, so a manual cache flush is never required after one.
316
+
317
+ ### Console shortcuts
318
+
319
+ `vortex execute CMD` sends any console command (the gateway's `POST console`, which needs
320
+ `GatewaySystem`, or the SOAP console without the gateway). The shortcuts send the exact
321
+ strings the server's addins match:
322
+
323
+ | Shortcut | Sends | Effect |
324
+ |---|---|---|
325
+ | `--show-schedule` | `tell agenda schedule` | lists every scheduled action and its next run (was `--schedule`) |
326
+ | `--refresh-agenda` | `tell agenda refresh` | AGENDA rereads every schedule now |
327
+ | `--flush-cache` | `tell http cache flush` | clears the design cache and all action class loaders |
328
+ | `--refresh-design APP_ID` | `tell agenda run .../RefreshDesign?&AppID=N` | rebuilds the application's design from its template |
329
+ | `--run PATH` | `tell agenda run /group/app.pma/action` | runs the action at that local path now |
330
+
331
+ `tell http flush cache` is **not** a valid command: the HTTP addin only matches
332
+ `cache flush`, and anything else does nothing, silently. Use `--flush-cache`.
333
+ `execute --schedule` was renamed to `--show-schedule` (`object update --schedule` now sets
334
+ a schedule); the old flag runs nothing and prints the new one.
335
+
336
+ ### Local clones stay in sync
337
+
338
+ Server commands never need a clone. When the application **is** cloned, every write runs in
339
+ this order:
340
+
341
+ 1. Take the application's workspace lock. A running `vortex watch` holds it, so the command
342
+ stops here - before any request - with a hint to stop the watch.
343
+ 2. Make the change on the server.
344
+ 3. Write the server's reply into the clone.
345
+
346
+ If step 3 fails after the server change succeeded, the command exits 1, says what differs and
347
+ prints the command to re-sync (`vortex clone APP_ID -s SERVER`).
348
+
349
+ | Command | Local effect |
350
+ |---|---|
351
+ | `app update` | details and params; a name or group change moves the folder |
352
+ | `object create` / `update` / `delete` | the object's file and manifest entry (a metadata-only change moves the file but never overwrites its content; an uploaded class also lands in `zbin/`) |
353
+ | `object copy` | the target application's clone |
354
+ | `keyword set` / `delete` | the clone's stored keywords |
355
+ | `compile` | writes `zbin/`; `--upload` stores the uploaded blobs |
356
+ | `execute --refresh-design` | none - prints that the clone is out of date |
357
+ | `app create` / `import` / `export`, all `db` commands | none |
358
+
359
+ A clone stores the design objects, the application's details (with its description), its
360
+ params, its keywords and its DB connections (id, name, database). `keyword list --local` and
361
+ `db list --local` read them with no request. Dictionary tables and columns are not stored.
362
+
363
+ ### Scheduled actions
364
+
365
+ A scheduled action's schedule lives in its `Options` (a comma-separated `name=value` string
366
+ that the AGENDA addin reads - it is not a design param). `object create` and `object update`
367
+ set it with flags, for SCHEDULED_ACTION objects only:
368
+
369
+ ```
370
+ vortex object create --app-id 62 --type scheduled_action --name Nightly --schedule N
371
+ vortex object update 7901 --app-id 62 --schedule D --start-time 02:30 --days MTWHF
372
+ vortex object update 7901 --app-id 62 --schedule N # stop it running
373
+ vortex object get 7901 --app-id 62 # the parsed schedule
374
+ ```
375
+
376
+ | Flag | Option | Values |
377
+ |---|---|---|
378
+ | `--schedule` | `Schedule=` | `N` never, `S` second, `I` minute, `H` hour, `D` day, `W` week, `M` month, `Y` year |
379
+ | `--interval` | `Interval=` | units between runs, >= 1 |
380
+ | `--days` | `Days=` | letters from `SMTWHFA` (S=Sun M=Mon T=Tue W=Wed H=Thu F=Fri A=Sat) |
381
+ | `--start-time` | `StartTime=` | `HH:mm`, 24-hour; minute `*` = a random minute |
382
+ | `--finish-time` | `FinishTime=` | `HH:mm` (up to `24:00`); only used by S/I/H schedules |
383
+ | `--date` | `Date=` | 1-31 (M and Y) |
384
+ | `--month` | `Month=` | 1-12 (Y) |
385
+
386
+ - **Merged, never replaced.** Only the keys you pass change, in place and in canonical
387
+ casing; `LastRun` (AGENDA's own) and any other key stay, in order. AGENDA reads the first
388
+ case-insensitive `key=` anywhere in the string, so a change an earlier entry would hide
389
+ (`StartDate=` hides `Date=`) is refused.
390
+ - **Checked first.** Values are validated before anything is sent (exit 2). A schedule flag
391
+ on any other `--type` is a usage error; on `object update`, every ID is read first and if
392
+ any is not a scheduled action the whole command fails with `WRONG_TYPE` and nothing is
393
+ written.
394
+ - **Applied at once.** After a successful schedule change the CLI sends one
395
+ `tell agenda refresh` for the whole command (the console route `vortex execute` uses:
396
+ the gateway's `POST console`, `GatewaySystem`, or the SOAP console without the gateway).
397
+ It has to: when an action starts, AGENDA writes back the `Options` it cached at its last
398
+ refresh (AGENDA `updateDesignBucket` / `AgendaItem.getOptionString`), so without a
399
+ refresh a run within the next 15 minutes would undo the change. Only the moment between
400
+ the write and the refresh remains. If the refresh fails or is refused, the change is
401
+ still written and the command exits 0 with a loud warning to run
402
+ `vortex execute "tell agenda refresh" -s SERVER` (naming the missing role for
403
+ `FORBIDDEN`); `--json` reports `"agendaRefreshed": true|false` (plus
404
+ `agendaRefreshError` when false).
405
+ - **LastRun race.** AGENDA also writes `LastRun` into `Options` whenever the action
406
+ starts; if that lands between the command's read and write, the old `LastRun` is written
407
+ back and the action may run one interval early.
408
+
409
+ ### Keyword values and secrets
410
+
411
+ Keywords are an application's live configuration, and in practice they hold credentials in
412
+ cleartext - API keys, passwords, vendor secrets, signing keys. `vortex keyword` therefore
413
+ **redacts by default**, in readable and `--json` output alike:
414
+
415
+ ```
416
+ vortex keyword list --app-id 9 # every keyword (secrets redacted)
417
+ vortex keyword get AppVersion --app-id 9 # just this one
418
+ vortex keyword set AppVersion 3.7.0 --app-id 9 # replace its values
419
+ vortex keyword list --app-id 9 --reveal # print secret values in full
420
+ vortex keyword list --app-id 9 --local # the clone's copy, no request
421
+ ```
422
+
423
+ - A keyword is treated as secret when its **name** contains a marker such as `password`,
424
+ `passwd`, `passphrase`, `secret`, `credential`, `signature`, `apikey`, `privatekey`,
425
+ `keystore`, `webhook`, `connectionstring` or `mnemonic`, or when any *word* of the name
426
+ is one of `key`, `keys`, `pwd`, `token`, `salt`, `hash`, `private`, `auth`, `bearer`,
427
+ `cert`, `pem`, `jwt`, `dsn`, `otp`, `pin`, `seed` or `sig`. Names are split on
428
+ camelCase/snake_case/kebab-case, so `AccessKeyId` and `API_KEY` are redacted while
429
+ `Monkey` and `Concert` are not. The match is on the name only, and deliberately biased
430
+ towards over-redaction: a false positive costs one `--reveal`.
431
+ - Redacted values print as `<redacted>`, one per value, so the value *count* stays visible.
432
+ - `keyword set` prints the prior values beside the new ones (redacted for secret names).
433
+ Negative numbers such as `-1` work as values as they are. A value that looks like an
434
+ option (`-abc`, `--x`) needs the options first and `--` before the name:
435
+ `vortex keyword set --app-id 9 -- Flags -abc --x`.
436
+
437
+ ### Cloning a whole group
438
+
439
+ `vortex clone` is the one command that takes names as well as IDs:
440
+
441
+ ```
442
+ vortex clone 13 # by ID
443
+ vortex clone bettrackr_app # by TemplateName
444
+ vortex clone bettrackr/app # by group/name
445
+ vortex clone BetTrackr # every non-inherited application in the BetTrackr group
446
+ vortex clone -a BetTrackr # ... including the inherited ones
447
+ vortex clone --group BetTrackr # explicitly a group, never a TemplateName
448
+ ```
449
+
450
+ A group clone skips inherited applications unless `--all`/`-a` is given (the inventory has no
451
+ `DisableApp` flag, so disabled applications are not skipped). An application you name
452
+ outright is always cloned. Groups are matched the way `app list --group` matches them - a
453
+ case-insensitive substring - except that an exact group name always wins, so cloning
454
+ `BetTrackr` never drags in `BetTrackrLegacy`. If a partial name still spans several groups,
455
+ vortex stops and lists them. A bare word that is genuinely both a TemplateName and a group
456
+ is refused: use `--group NAME` or the ID. References may be qualified as `SERVER:REF`
457
+ (`dev:BetTrackr`).
458
+
459
+ ### Working with Multiple Servers
460
+
461
+ Each section in `servers.ini` defines a server (hosts must be unique across
462
+ sections). Cloned apps remember which server they came from:
463
+
464
+ - `vortex watch` watches **every** cloned app and uploads each change to the
465
+ server it was cloned from. Use `--server` to watch a single server only.
466
+ - `find`, `grep` and `ls` search across all cloned apps unless `--server` is given.
467
+ - `watch`, `clone` and `clean` take a workspace-wide lock: only one watch at a
468
+ time, and cloning or cleaning is refused while a watch is running. Commands
469
+ that write into one cloned application (every mirrored server write,
470
+ `compile`) take that application's lock, so they are refused for apps a
471
+ watch is watching and run concurrently otherwise.
472
+ - In VS Code, app folders are listed in per-server blocks with the server's jars
473
+ on the Java classpath. For a guaranteed-correct classpath, open a single
474
+ server's own workspace with `vortex code -s <server>`.
475
+
476
+ Every server command targets `-s <server>`, else the `vortex use` default:
477
+
478
+ ```
479
+ vortex use dev
480
+ vortex app list
481
+ ```
482
+
483
+ #### Credentials
484
+
485
+ `username`/`password` can be left out of `servers.ini`. Each server's
486
+ credentials resolve in this order and are only requested when a command
487
+ actually connects to that server:
488
+
489
+ 1. The system keyring - store with `vortex config --set-password -s <server>`
490
+ (requires `pip install keyring`)
491
+ 2. Per-server environment variables `VORTEX_USERNAME_<SERVER>` /
492
+ `VORTEX_PASSWORD_<SERVER>` (e.g. `VORTEX_PASSWORD_DEV`)
493
+ 3. `VORTEX_USERNAME` / `VORTEX_PASSWORD`
494
+ 4. An interactive prompt naming the server
495
+
496
+ #### Protected Servers
497
+
498
+ `protected = true` means one thing: `vortex watch` skips the server unless
499
+ `--include-protected` is given, so saving a file can never hot-deploy to it by
500
+ accident. There are no write confirmations - the gateway's roles are the protection, so run
501
+ agents against production with an identity whose roles fit the job.
502
+
503
+ ### Backend: gateway or webdesign
504
+
505
+ Each server picks where requests go, explicitly - nothing is probed and nothing falls back:
506
+
507
+ | `gateway_path` | Behaviour |
508
+ |---|---|
509
+ | set (the default `vortex/gateway.pma`) | through the vortex gateway: required and presumed installed; any failure is an error |
510
+ | blank | webdesign's `vortex` action directly (`webdesign_path` + `/vortex`): the same routes and bodies, with **no** role checks |
511
+
512
+ The gateway (`vortex/gateway`, a Puakma application you deploy) is `system/webdesign`'s
513
+ `vortex` JSON API at a different address - `https://<host>/vortex/gateway.pma/api/<path>` is
514
+ webdesign's `/system/webdesign.pma/vortex/<path>` - with three things in front of it:
515
+
516
+ - **Role checks.** Every route needs a role, checked on the server: `GatewayDesignRead`,
517
+ `GatewayDesignWrite`, `GatewayDBRead`, `GatewayDBWrite`, `GatewaySystem` and `Admin`
518
+ (every route). Write implies read. A route the gateway does not map is refused.
519
+ `vortex status --show-permissions` shows which commands your identity may run.
520
+ - **Guards.** The gateway never addresses the Puakma system database (`SYSTEM_DB`), never
521
+ lets an id from one application be used under another (`NOT_FOUND`), and runs exactly one
522
+ `SELECT`/`INSERT`/`UPDATE`/`DELETE` per SQL request (`SQL_NOT_ALLOWED`: DDL, `WITH`, and
523
+ any `;`).
524
+ - **Its own routes:** `whoami` (`status`), the server log (`log`), the console (`execute`),
525
+ `.pmx` export and import.
526
+
527
+ On a server with a blank `gateway_path`:
528
+
529
+ | Command | Behaviour |
530
+ |---|---|
531
+ | `app`, `object`, `keyword`, `db`, `clone`, `compile`, `watch`, `libs` | the same routes, sent to webdesign's `/vortex` |
532
+ | `db query` | a CLI-side guard replaces the gateway's: one `SELECT`/`INSERT`/`UPDATE`/`DELETE` statement, refused otherwise with `SQL_NOT_ALLOWED` before anything is sent |
533
+ | `app export` | webdesign's `ExportPMX` |
534
+ | `status` | the console `status` command over SOAP (`soap_path`); `--show-permissions` says "no gateway: webdesign direct, no role checks" |
535
+ | `log` | a `PMALOG` query through webdesign's SQL route, on the system-database connection owned by the ungrouped `puakma` application (found once per run) |
536
+ | `execute` | the console command over SOAP |
537
+ | `app import` | unavailable (`UNAVAILABLE`) |
538
+
539
+ Without the gateway there are no role checks, no system-database block and no cross-app
540
+ ownership checks: use the gateway on any server an agent works against. If a gateway deploy
541
+ ever breaks the gateway, blanking `gateway_path` reaches the server through webdesign to fix
542
+ it.
543
+
544
+ There is **no undo**: nothing keeps a journal of what a write replaced. Deletes and uploads
545
+ are final.
546
+
547
+ > **Note:** the gateway's roles are only a real boundary for an identity whose *sole* route to
548
+ > the server is the gateway. Any identity that can reach `system/webdesign` or deploy code can
549
+ > grant itself any role.
550
+
551
+ ### Java Design Objects, `zbin/` and `vortex compile`
552
+
553
+ The server runs compiled classes, not source. There are three ways to get a class there:
554
+
555
+ - **`vortex compile --app-id ID [--object ID...] --upload`** builds the cloned application's
556
+ Java into `zbin/` with ecj 3.46.0 (the compiler PuakmaVortexVSCode uses), run by the
557
+ server's `java_home` against the server's own jars, for the server's
558
+ `java_environment_name` (`JavaSE-17` -> `--release 17`; unset is an error naming the
559
+ setting). `--upload` sends each compiled class to its existing design element, one at a
560
+ time (`--include-source` adds the `.java`); it refuses when anything failed to compile and
561
+ never creates elements (`object create` does). ecj is downloaded once from Maven Central;
562
+ the server's libraries are fetched on first use.
563
+ - **`vortex object update ID --app-id APP --data Foo.class [--source Foo.java]`** uploads a
564
+ class you built yourself.
565
+ - **`vortex watch`** uploads what the IDE's Java build writes into `zbin/`.
566
+
567
+ Tornado loads one class per design element, so nested classes never ship. `compile` treats
568
+ a source as a **compile error** - exit 1, its classes named, nothing written to `zbin/` for
569
+ it, never uploaded - when it produces `Outer$*.class` files (inner, anonymous or local
570
+ classes) or uses lambdas or method references (its bytes reference
571
+ `java/lang/invoke/LambdaMetafactory`). Use top-level SHARED_CODE classes instead. A `switch`
572
+ over an enum is fine: ecj keeps it inside the class (javac would add a synthetic `Outer$1`).
573
+ `watch` likewise refuses to upload a class compiled alongside `$` siblings.
574
+
575
+ `compile` always writes into the clone, so it takes the application's lock and is refused
576
+ while `vortex watch` runs - with or without `--upload`.
577
+
578
+ ### Server-Provided Java Libraries
579
+
580
+ The IDE's Java build, IntelliSense and `vortex compile` need the Puakma framework jar and the
581
+ server's shared libraries on the classpath. vortex downloads them from each server's
582
+ webdesign `vortex` API (`systemjar` and `libraries`, through the gateway when
583
+ `gateway_path` is set - `GatewayDesignRead`) and caches them per server under
584
+ `<workspace>/<host>/.lib/`:
585
+
586
+ - `clone` does **not** download them; it prints a one-line `vortex libs --refresh -s SERVER`
587
+ hint when they are not cached. `compile` and `watch` fetch them on first use.
588
+ - `vortex libs` shows what's cached for each server; `vortex libs --refresh` re-downloads
589
+ (add `-s <server>` for one server), e.g. after a server upgrade.
590
+ - Each server's VS Code workspace (`vortex code -s <server>`) uses that server's own cached
591
+ jars, so identical class names on different servers/versions never cross-contaminate.
592
+ - `vortex clean` keeps each host's `.lib` cache; pass `--include-libs` to remove it as well.
593
+
594
+ ### Databases and the data dictionary
595
+
596
+ Every `db` command takes `--app-id` (every database route is app-scoped) and a `DB`: the
597
+ connection name, the database name or the connection ID, resolved within that application.
598
+
599
+ ```
600
+ vortex db list --app-id 9
601
+ vortex db query bettrackr --app-id 9 "SELECT * FROM account" --limit 5
602
+ vortex db query 3 --app-id 9 --file report.sql --json
603
+ vortex db get-table bettrackr invoice --app-id 9
604
+ ```
605
+
606
+ `db query` sends the statement as given, apart from adding `LIMIT n` (default 10) to a
607
+ `SELECT` that has none - a full page of rows is flagged as possibly truncated. There is no
608
+ `--update` flag: the gateway classifies the statement (`SELECT` needs `GatewayDBRead`,
609
+ `INSERT`/`UPDATE`/`DELETE` `GatewayDBWrite`, everything else is refused). A numeric `DB` is one
610
+ request; a name is two.
611
+
612
+ The `create-`/`update-`/`delete-` table and column commands record design-time definitions in
613
+ the Puakma data dictionary (the PMATABLE/ATTRIBUTE tables). They **never run DDL** - deletes
614
+ only remove dictionary rows, never real tables or columns - so change the real table by hand.
615
+
616
+ ```
617
+ vortex db create-table mydb invoice --app-id 9 --description "Customer invoices"
618
+ vortex db create-column mydb invoice invoice_id --app-id 9 --type INTEGER --pk --auto-increment
619
+ vortex db create-column mydb invoice total --app-id 9 --type NUMERIC --size 10,2 --not-null
620
+ vortex db create-column mydb invoice customer_id --app-id 9 --type INTEGER --ref customer
621
+ vortex db update-column mydb invoice total --app-id 9 --null
622
+ ```
623
+
624
+ - `--type`: `VARCHAR`, `CHAR`, `LONGTEXT`, `INTEGER`, `DATETIME`, `NUMERIC`, `LONGBLOB` or
625
+ `JSON`. `--size` only for `VARCHAR` (default 50), `CHAR` (default 1) and `NUMERIC`
626
+ (default `6,2`); changing the type without `--size` resets the size to the new type's
627
+ default.
628
+ - `--ref TABLE` records the referenced table only - the dictionary has no referenced-column
629
+ field. There is no `--default` or `--position` (webdesign ignores both).