@revoengine/cli 1.0.10 → 1.0.11

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 (79) hide show
  1. package/README.md +312 -33
  2. package/dist/src/cli.js +58 -7
  3. package/dist/src/client.d.ts +356 -5
  4. package/dist/src/client.js +803 -19
  5. package/dist/src/commands/auth.js +4 -2
  6. package/dist/src/commands/component.js +260 -141
  7. package/dist/src/commands/database-schemas.d.ts +2 -0
  8. package/dist/src/commands/database-schemas.js +188 -0
  9. package/dist/src/commands/database-views.d.ts +2 -0
  10. package/dist/src/commands/database-views.js +123 -0
  11. package/dist/src/commands/endpoints.js +114 -0
  12. package/dist/src/commands/env.js +44 -24
  13. package/dist/src/commands/events.d.ts +2 -0
  14. package/dist/src/commands/events.js +146 -0
  15. package/dist/src/commands/groups.d.ts +2 -0
  16. package/dist/src/commands/groups.js +169 -0
  17. package/dist/src/commands/index.d.ts +8 -0
  18. package/dist/src/commands/index.js +8 -0
  19. package/dist/src/commands/job-templates.d.ts +2 -0
  20. package/dist/src/commands/job-templates.js +101 -0
  21. package/dist/src/commands/metadata.js +29 -7
  22. package/dist/src/commands/project.js +10 -3
  23. package/dist/src/commands/role-groups.d.ts +2 -0
  24. package/dist/src/commands/role-groups.js +152 -0
  25. package/dist/src/commands/schedules.d.ts +2 -0
  26. package/dist/src/commands/schedules.js +141 -0
  27. package/dist/src/commands/terminal-service.d.ts +38 -0
  28. package/dist/src/commands/terminal-service.js +210 -0
  29. package/dist/src/commands/terminal.d.ts +22 -0
  30. package/dist/src/commands/terminal.js +511 -0
  31. package/dist/src/component-lock.d.ts +100 -2
  32. package/dist/src/component-lock.js +304 -15
  33. package/dist/src/config.d.ts +10 -2
  34. package/dist/src/config.js +49 -14
  35. package/dist/src/database-schema-artifacts.d.ts +7 -0
  36. package/dist/src/database-schema-artifacts.js +8 -0
  37. package/dist/src/env-sync.d.ts +0 -3
  38. package/dist/src/env-sync.js +3 -19
  39. package/dist/src/metadata-backfill.d.ts +16 -6
  40. package/dist/src/metadata-backfill.js +1069 -18
  41. package/dist/src/project.d.ts +2 -0
  42. package/dist/src/project.js +4 -17
  43. package/dist/src/prompt.js +10 -18
  44. package/dist/src/resource-metadata.d.ts +1 -0
  45. package/dist/src/resource-metadata.js +3 -0
  46. package/dist/src/resource-syncs/database-schema-sync.d.ts +117 -0
  47. package/dist/src/resource-syncs/database-schema-sync.js +2289 -0
  48. package/dist/src/resource-syncs/database-view-sync.d.ts +124 -0
  49. package/dist/src/resource-syncs/database-view-sync.js +1317 -0
  50. package/dist/src/resource-syncs/endpoint-sync.d.ts +96 -0
  51. package/dist/src/resource-syncs/endpoint-sync.js +1283 -0
  52. package/dist/src/resource-syncs/event-sync.d.ts +99 -0
  53. package/dist/src/resource-syncs/event-sync.js +949 -0
  54. package/dist/src/resource-syncs/group-sync.d.ts +86 -0
  55. package/dist/src/resource-syncs/group-sync.js +882 -0
  56. package/dist/src/resource-syncs/job-template-sync.d.ts +85 -0
  57. package/dist/src/resource-syncs/job-template-sync.js +782 -0
  58. package/dist/src/resource-syncs/role-group-sync.d.ts +83 -0
  59. package/dist/src/resource-syncs/role-group-sync.js +597 -0
  60. package/dist/src/resource-syncs/schedule-sync.d.ts +111 -0
  61. package/dist/src/resource-syncs/schedule-sync.js +1302 -0
  62. package/dist/src/resource-syncs/util.d.ts +19 -0
  63. package/dist/src/resource-syncs/util.js +116 -0
  64. package/dist/src/runtime-view.d.ts +1 -0
  65. package/dist/src/runtime-view.js +6 -1
  66. package/dist/src/sync-output.d.ts +38 -0
  67. package/dist/src/sync-output.js +131 -0
  68. package/dist/src/tracked-resources.d.ts +1 -1
  69. package/dist/src/tracked-resources.js +26 -2
  70. package/dist/src/types.d.ts +224 -0
  71. package/dist/src/ui.d.ts +3 -0
  72. package/dist/src/ui.js +67 -18
  73. package/dist/src/utils.d.ts +2 -0
  74. package/dist/src/utils.js +64 -0
  75. package/dist/src/workspace-component.d.ts +2 -0
  76. package/dist/src/workspace-component.js +34 -0
  77. package/dist/src/workspace-resource.d.ts +2 -0
  78. package/dist/src/workspace-resource.js +52 -0
  79. package/package.json +8 -3
package/README.md CHANGED
@@ -21,13 +21,21 @@ Inspect the local runtime and config path:
21
21
  revo -i
22
22
  ```
23
23
 
24
- Log in and save your default credentials:
24
+ Add a project connection. The new project becomes active immediately:
25
+
26
+ ```bash
27
+ revo projects add local --url http://localhost:3000
28
+ revo projects list
29
+ revo auth status
30
+ ```
31
+
32
+ To use the original `default` connection instead, save its credentials:
25
33
 
26
34
  ```bash
27
35
  revo auth login
28
36
  ```
29
37
 
30
- `revo auth login` opens an interactive terminal prompt for your API key. If you are already logged in, the CLI warns and asks you to `revo auth logout` first.
38
+ `revo auth login` opens a masked interactive terminal prompt for your API key and saves the `default` login. If you are already logged in, the CLI warns and asks you to `revo auth logout` first. For named connections, use `revo projects add <name>`.
31
39
 
32
40
  The CLI validates the API key against `/api/v1/me` and infers the RevoEngine instance from the authenticated profile for tenant-scoped operations such as component push.
33
41
 
@@ -37,6 +45,25 @@ Check the active session:
37
45
  revo auth status
38
46
  ```
39
47
 
48
+ Connect this computer as an Agent Gateway terminal with the same CLI installation and login:
49
+
50
+ ```bash
51
+ revo terminal connect --workspace "$HOME/projects/my-project" --name "Work Mac"
52
+ revo terminal status
53
+ revo --version
54
+ ```
55
+
56
+ Pairing appears in AI Agents → Terminals for approval and access configuration; personal Vault settings also shows the grant. `revo terminal connect` runs in the foreground; stop it with Ctrl+C after approval if you want to move it into the background. Install a per-user background service for the approved terminal: LaunchAgent on macOS or `systemd --user` on Linux.
57
+
58
+ Each registration has a stable `agentTerminalId` and a model reference token `[AGENT_TERMINAL/<agentTerminalId>](Name)`. Existing local `runner.json` entries with `deviceId` are read with the same ID, so they do not need to be paired again. Access defaults to `restricted: true`; the owner can explicitly grant access to users, groups, or the entire instance.
59
+
60
+ ```bash
61
+ revo terminal service install --workspace "$HOME/projects/my-project"
62
+ revo terminal service uninstall --workspace "$HOME/projects/my-project"
63
+ ```
64
+
65
+ The service starts at login, reconnects automatically, and pins the environment active at installation (or an explicit `--project <name>`). Install one service per workspace/profile; pass the same `--project` to uninstall after switching environments. Uninstall stops the service but keeps the terminal grant and local registration. `revo terminal disconnect --workspace <path>` revokes the grant and removes its local credential; uninstall the service first. On macOS, service logs are in `~/Library/Logs/RevoEngine/`. On Linux, inspect them with `journalctl --user -u <unit-name>`; `install` prints the unit name. Linux user services normally stop after logout unless an administrator enables user lingering. The runner uses your OS permissions; the workspace controls the starting directory, not OS sandbox access. A personal API key is required.
66
+
40
67
  Remove stored credentials:
41
68
 
42
69
  ```bash
@@ -52,7 +79,7 @@ revo --help
52
79
  Initialize a project for ambient low-code editor globals:
53
80
 
54
81
  ```bash
55
- revo project
82
+ revo project init
56
83
  revo project init ./app
57
84
  revo project init ./app --identity-mode stableKey --stable-key-name resourceKey --resources component
58
85
  revo project init ./app --identity-mode componentId
@@ -76,22 +103,245 @@ When compiler options are missing, project initialization sets `target: ES2022`,
76
103
 
77
104
  Stable-key mode manages only components that contain the configured metadata property. Component UUIDs remain in API requests and lock diagnostics, but they are not used as durable identity. Duplicate stable-key values block plan, pull, and push. Use `--identity-mode componentId` only for a workspace that intentionally remains bound to one RevoEngine instance.
78
105
 
79
- During interactive init, the CLI asks for the stable key metadata name and which resource families it should track. Press Enter to use `stableKey` and track `all` resources. For non-interactive runs, `--resources <list>` accepts `all` or comma-separated resource names such as `component`; when omitted it defaults to `all`. Project initialization also backfills missing stable-key metadata for every tracked component while preserving existing keys. Pass `--no-metadata-backfill` only when initialization must not write remote component metadata.
106
+ During interactive init, the CLI asks for the stable key metadata name and which resource families it should track. Press Enter to use `stableKey` and track `all` resources. For non-interactive runs, `--resources <list>` accepts `all` or comma-separated resource names such as `component`, `endpoint`, `group`, `role-group`, `job-template`, `schedule`, `event`, `database-schema`, or `database-view`; when omitted it defaults to `all`. Project initialization backfills missing stable-key metadata for the established resource families while preserving existing keys. Database Schema and Database View backfill are deliberately excluded from automatic initialization because large catalogs and metadata-only database updates require an explicit operator review. Init prints the exact follow-up plan command. Pass `--no-metadata-backfill` when initialization must not write any remote metadata.
80
107
 
81
108
  Backfill stable-key metadata for tracked resources with an explicit plan/apply flow:
82
109
 
83
110
  ```bash
84
- revo metadata plan --env test
85
- revo metadata apply --env test --yes
111
+ revo metadata plan --project test
112
+ revo metadata apply --project test --yes
113
+ ```
114
+
115
+ Backfill only writes resources missing the configured stable-key metadata unless `--force` is passed. Generated resource keys use `category/name#<random-hex>`. Database Schema and Database View keys are immutable once present, even with `--force`. Database View backfill reads the current view and uses the deployed full `PUT` API with the same definition, type, version, and ACL, changing only user metadata to add the Stable Key. Because this is a full view update, run it in a reviewed maintenance window. Database Schema backfill also plans column keys in `definition[].metadata.<stable-key-name>` for root tables only, using `category/table/column#<random-hex>`; existing, malformed, or duplicate column keys are never overwritten, including with `--force`. Partition definitions inherit their root table's columns and never receive independent column keys.
116
+
117
+ ### Database Schemas
118
+
119
+ Database Schemas use an explicit SOURCE bootstrap followed by a portable pull:
120
+
121
+ ```bash
122
+ revo metadata plan --project test --resources database-schema
123
+ revo metadata apply --project test --resources database-schema --yes
124
+ # Generate Stable Keys only for root schemas and leave partitions unmanaged:
125
+ revo metadata plan --project test --resources database-schema --skip-partitions
126
+ revo metadata apply --project test --resources database-schema --skip-partitions --yes
127
+ revo database-schemas pull --all --project test
128
+ # Fail when any active schema or partition remains unmanaged:
129
+ revo database-schemas pull --all --project test --strict
130
+ # Compare desired manifests, the selected lock baseline, and live E2E without writes:
131
+ revo database-schemas plan --all --project e2e
132
+ revo database-schemas plan --all --project e2e --json
133
+ # Review only root schemas; partitions are excluded from the API catalog, workspace comparison, and strict coverage:
134
+ revo database-schemas plan --all --project e2e --skip-partitions
135
+ # Add one cached bulk size request for table/index/audit risk context:
136
+ revo database-schemas plan --all --project e2e --with-stats
137
+ # CI convergence and Stable Key coverage gate:
138
+ revo database-schemas plan --all --project e2e --strict
139
+ # Create, safely update, and verify managed root schemas and their partitions:
140
+ revo database-schemas push --all --project e2e --yes
141
+ # Or create one reviewed graph node by Stable Key:
142
+ revo database-schemas push 'Sales/Orders#1234abcd' --project e2e --yes
143
+ # Only after reviewing safe remote content drift; --force never bypasses manual DDL migration:
144
+ revo database-schemas push --all --project e2e --yes --force
145
+ # Destructive prune of previously managed partitions only:
146
+ revo database-schemas push --all --project e2e --yes --force --prune-partitions
147
+ # Destructive removal of reviewed target-only root schemas (no active partitions or Database View dependencies):
148
+ revo database-schemas push --all --project e2e --yes --force --prune-orphans
149
+ # After a reviewed deletion on the source, remove stale local desired manifests and locks only:
150
+ revo database-schemas pull --all --project test --yes --force --prune-orphans
151
+ ```
152
+
153
+ The catalog is read in deterministic pages of 200 records. Pass `--skip-partitions` to `metadata plan` and `metadata apply` when only root Database Schemas should receive generated table Stable Keys; the CLI adds a server-side `parent isNull` filter and defensively excludes any partition returned by the API. Without this flag, root schemas and partitions remain in scope for table keys, while column-key backfill always remains root-only. Root manifests are written below `<workspace>/DatabaseSchemas/<category>/`; every managed partition has its own nested manifest under its parent and carries its own Stable Key plus `parentStableKey`. Partition manifests do not duplicate the inherited column definition.
154
+
155
+ Manifests retain the complete non-reserved user metadata and portable column/partition configuration. Instance UUIDs, column definition IDs, versions, timestamps, records, details, users, ACL, audit settings, and tags are excluded. ACL, audit, and tags are returned only as pull diagnostics and are outside the portable hash; the lock retains only a root's source `restricted` boolean so first creation can safely reject a restricted source without storing target principals. Foreign references remain visible in the column definition with `migration.foreignReferences: "manual"` because they require operator migration. Missing Stable Keys are reported as unmanaged and skipped; duplicates, invalid keys, parent cycles, missing parents, and path collisions stop the pull before files change. A locally edited manifest is preserved unless `--force` is supplied. A normal pull never deletes local manifests. After reviewing source deletions, `pull --prune-orphans --yes --force` removes only local manifests and lock entries that no longer exist on the selected source; it never deletes any target table.
156
+
157
+ `database-schemas plan` is fileless and read-only. It reports three-way states plus root/partition orphans, previously managed partition removals, unmanaged WIP resources, collisions, reconciled manual work, and `manual-schema-migration-required`. Pass `--skip-partitions` for a root-schema-only view: partitions are excluded server-side with `parent isNull`, local partition manifests are excluded too, and they do not contribute to `--strict` coverage. This view intentionally cannot report partition drift, lifecycle work, or unmanaged partitions. Table names, parent relationships, partition bounds, column removals, unsafe keyless column additions, and structural changes without exact column identity remain manual. Changes to an existing column are operational when desired and target definitions share one unique column Stable Key; this includes rename, type, default, nullability, array, primary-key, unique, and index fields. A required, defaulted, indexed, unique, or primary-key new column is also operational when its desired definition carries one unique Stable Key that is absent from the target. A rename is still blocked as manual when the table has an active Database View or foreign-reference declaration. Column presentation order, column metadata, and adding an explicitly nullable column without a default, primary key, unique constraint, index, or foreign reference remain safe definition changes. Every reported change includes an operational hint covering the relevant lock, scan, rewrite, index, validation, conversion, or data-loss risk. `--with-stats` performs exactly one cached bulk `/api/v1/databases/stats` request; the default plan avoids that database-size query. `--strict` accepts only converged resources and informational target-only orphans, and fails for drift, collisions, manual migrations, deletions, missing baselines, or incomplete Stable Key coverage.
158
+
159
+ `database-schemas push` creates missing schemas and applies reviewed safe or controlled operational updates. It re-plans live state, then resolves an exact Stable Key match and fetches its current version immediately before every write; it never sends source UUIDs, rows, ACLs, audit or tags. Existing target column IDs are reattached first by a unique shared column Stable Key and otherwise by exact column name. With a unique shared key, the CLI imports changes to type, default, nullability, array, primary-key, unique, index, name, description, and metadata while preserving the target column identity. It also creates a required, defaulted, indexed, unique, or primary-key column when the new desired definition has one unique Stable Key absent from the target; no instance-local definition ID is sent for that new column. These structural writes can still fail when live data is incompatible and should be run in a reviewed maintenance window; every write is followed by an exact GET and portable-hash verification before the selected environment baseline is recorded. The write is still refused if an active Database View appears after planning a rename. Column drops, unsafe additions without a unique key, structural changes without a unique shared key, malformed or duplicate column keys, and foreign-reference deployment remain manual; `--force` can overwrite reviewed portable content drift but never bypasses those blockers. If an environment lock baseline was lost, `--force` first adopts an exactly matching target through GET-and-hash verification only; it sends no PUT. A reviewed safe difference without that baseline can also be aligned with `--force`. When a manually aligned target already matches the manifest, push verifies the live hash and advances only the selected lock baseline. Audited targets show an audit-trigger-rebuild warning, serialize writes, and retry one audit-lock conflict only after fresh validation. Root tables are created `restricted=false` and `audit=false`; a root pulled as restricted is reported as `access-policy-required` and skipped. Partitions follow root → child → nested-child order, reference the resolved target parent by name, and inherit definition, audit and ACL from that target parent. A failed or unavailable parent skips only its dependent branch, while unrelated creates continue. Removing a previously managed partition manifest produces `delete-partition`; deletion requires all of `--prune-partitions --yes --force`, is processed leaf-to-root, rechecks the live parent and active Database View dependencies, then records an environment tombstone after readback. A target-only root marked `orphan-root` can be deleted only with `--prune-orphans --yes --force`; it is revalidated by Stable Key and hash, and deletion is blocked when it has an active partition or Database View dependency. Unmanaged target-only partitions are never deleted. A tombstoned Stable Key is never recreated automatically, and overlapping replacement bounds require two separate pushes: prune the old partition first, then create the new partition with a new Stable Key.
160
+
161
+ ### Database Views
162
+
163
+ Database Views are migrated only after their Database Schemas and column Stable Keys converge on the target:
164
+
165
+ ```bash
166
+ revo metadata plan --project test --resources database-view
167
+ revo metadata apply --project test --resources database-view --yes
168
+ revo database-views pull --all --project test
169
+ revo database-views plan --all --project e2e --strict
170
+ revo database-views push --all --project e2e --yes
171
+ # Or deploy one reviewed ordinary view by Stable Key:
172
+ revo database-views push 'Reporting/high_value_customers#f00dbabe' --project e2e --yes
173
+ # Materialized writes need their own explicit operational gate:
174
+ revo database-views push --all --project e2e --yes --allow-materialized
175
+ ```
176
+
177
+ The workspace contains `STRUCTURED` and `RAW_SQL` `VIEW` and `MATERIALIZED_VIEW` manifests below `<workspace>/DatabaseViews/`. A `RAW_SQL` manifest retains the SQL text and source schema Stable Keys, while a `STRUCTURED` manifest additionally retains referenced-column Stable Keys; neither retains instance IDs, generated lineage, versions, or source ACL principals. RAW_SQL preview and writes require the target's `databaseViewsRawSql` feature flag and `RESOURCE_ADMIN` permission. A materialized manifest retains the ordered `uniqueKey` and index columns but drops server-generated index names; independent index definitions are normalized deterministically. A plan is fileless: it resolves every source on the target, runs a bounded `take: 0` preview, reports materialization/quota risk and active refresh schedules, and blocks collisions, missing baselines, incompatible output, and any rename or type/mode transition. Materialized creates and updates require `--allow-materialized`; an active refresh schedule blocks an update and must be coordinated manually. Create re-plans live, previews again immediately before POST, and creates a private target view with empty users and groups. Updates fetch the exact live record, then send the full desired definition in a PUT with the current optimistic version while preserving its target-local ACL; preview and post-write hash verification are repeated before advancing the baseline. `--force` may overwrite reviewed portable content drift, but never identity, source-readiness, preview, ACL, rename, type, mode, schedule, or materialized-write-gate blockers. An identical target with a missing baseline is adopted by GET-and-hash verification without a PUT. A matching private view with an empty target-local ACL is `clean`; source ACLs are never copied, and access can be configured independently on the target. For the TEST → E2E operating procedure, including stable-key bootstrap, plan artifacts, target-local ACL work, materialized-view maintenance windows, and strict verification, see [the Database Views runbook](docs/runbooks/database-views-test-to-e2e.md).
178
+
179
+ Job templates use the same metadata bootstrap and workspace boundary. Generate keys on the source environment, then pull portable manifests into `<workspace>/JobTemplates`:
180
+
181
+ ```bash
182
+ revo metadata plan --project test --resources job-template
183
+ revo metadata apply --project test --resources job-template --yes
184
+ revo job-templates pull --all --project test
185
+ revo job-templates plan --all --project e2e
186
+ revo job-templates plan --all --project e2e --json
187
+ revo job-templates push --all --project e2e --yes
188
+ # Only after reviewing remote-changed, conflict, or missing-lock:
189
+ revo job-templates push --all --project e2e --yes --force
190
+ ```
191
+
192
+ ### Endpoints
193
+
194
+ ```bash
195
+ # Establish Stable Key identity on SOURCE, then pull portable endpoint configuration to
196
+ # <workspace>/Endpoints and extend .revoengine/revo.lock.json.
197
+ revo metadata plan --project test --resources endpoint
198
+ revo metadata apply --project test --resources endpoint --yes
199
+ revo endpoints pull --all --project test
200
+ revo endpoints plan --all --project e2e
201
+ revo endpoints plan --all --project e2e --json
202
+ revo endpoints push --all --project e2e --yes
203
+ revo endpoints plan --all --project e2e --strict
204
+ ```
205
+
206
+ Endpoint plan is fileless and read-only. It compares portable workspace manifests, the selected target-environment baseline in `.revoengine/revo.lock.json`, and the live target. Component dependencies are resolved only by exact stable key. Latest bindings require identical portable Component content in the workspace and target; pinned bindings require the pulled digest, workspace digest, and target digest to all match. Dependency mismatches block every Endpoint write and instruct the operator to align Components before Endpoints.
207
+
208
+ Push recomputes the live plan, resolves target Component UUIDs and versions only in memory, and rejects all hard blockers before the first write. Creates, updates, and exact Stable Key restores converge configuration first and then the desired active state. Every write is fetched again and compared by the full portable hash before the target lock baseline is updated. `--force` can accept reviewed three-way content drift, but cannot bypass identity, route, dependency, restore-safety, or concurrency checks. Target-only and unmanaged Endpoints remain untouched, and `--prune` is rejected.
209
+
210
+ For the complete **SOURCE** → **TARGET** operator flow, Component dependency gate,
211
+ GitLab CI plan artifact, manual PROD approval, strict verification, and rollback,
212
+ see [the Endpoint runbook](https://gitlab.com/revoengine/cli/-/blob/master/docs/runbooks/endpoint-source-to-target.md).
213
+
214
+ Job-template manifests keep portable `options` and legacy `inputs`, reference their component by component stable key, and exclude UUIDs, versions, audit data, pinned component versions, and `triggerUser`. When `triggerUser` is present, pull prints a warning because the execution principal must be configured independently per environment.
215
+
216
+ Schedules support source bootstrap, portable pull, planning, and deployment for user-managed `JOB_TEMPLATE` targets and Materialized View refresh targets:
217
+
218
+ ```bash
219
+ # Establish stable-key identity for the source schedules.
220
+ revo metadata plan --project test --resources schedule
221
+ revo metadata apply --project test --resources schedule --yes
222
+
223
+ # Event bootstrap currently covers only JOB_TEMPLATE targets.
224
+ revo metadata plan --project test --resources event
225
+ revo metadata apply --project test --resources event --yes
226
+
227
+ # Pull source Schedule definitions and their lock baselines.
228
+ revo schedules pull --all --project test
229
+
230
+ # Compare the local definitions, the E2E lock baseline, and live E2E schedules.
231
+ revo schedules plan --all --project e2e
232
+ revo schedules plan --all --project e2e --json
233
+ revo schedules plan --all --project e2e --strict
234
+
235
+ # Create disabled Schedules and safely update existing definitions.
236
+ revo schedules push --all --project e2e --yes
237
+ # Materialized View refresh definitions require an additional operational gate.
238
+ revo schedules push --all --project e2e --yes --allow-materialized
239
+ # Only after reviewing remote-changed, conflict, or missing-lock:
240
+ revo schedules push --all --project e2e --yes --force --allow-materialized
241
+
242
+ # Deliberately activate only candidates created or updated by this push.
243
+ revo schedules push --all --project e2e --yes --allow-materialized --activate
244
+ ```
245
+
246
+ Each manifest references either a Job Template by Stable Key or a Materialized View by Database View Stable Key plus `CONCURRENT` or `BLOCKING` refresh mode. It excludes Schedule UUIDs, dependency UUIDs, versions, source `active`, and `targetVersion`. Source `active` becomes an editable `activationCandidate`; Job Template `sourceTargetConfig` is retained for operator context only. Before a Schedule can be created or updated, its dependency must resolve to exactly one compatible live target by exact Stable Key. A target-kind transition is reported as a warning and conflict, and can be applied only after review with `--force`. Missing or ambiguous dependencies, ordinary Views, `AGENT`, unrelated `PLATFORM_OPERATION`, system-managed, deleted, and unmanaged Schedules remain blocking or explicit exclusions. `--strict` fails for drift, blockers, or exclusions; target-only orphans remain informational.
247
+
248
+ Schedule push repeats its live preflight immediately before each write. Creates always send `active: false`; ordinary updates do not change the target activation state. Every create or update re-resolves the target Schedule and dependency, uses the live Schedule version for updates, re-fetches the result, verifies its portable hash, and then advances the selected environment baseline. Materialized View writes require `--allow-materialized`; that gate cannot be bypassed with `--force`. Deploy Database Views before their refresh Schedules. `remote-changed`, `conflict` (including target-kind transitions), and `missing-lock` require explicit `--force`. An exactly matching `missing-lock` target is re-read and adopted into the selected environment baseline without a PUT. There is no Schedule prune: target-only orphans remain untouched.
249
+
250
+ `schedules push --activate` is the optional final activation phase. It activates only candidates created or updated and verified in that same push, and never disables an already active target. Interactive use asks for a second confirmation; non-interactive use requires both `--yes` and `--activate`. Activation failures are isolated per Schedule.
251
+
252
+ Events currently support the source pull step for `JOB_TEMPLATE` targets. After assigning Stable Keys to Events and their Job Templates, pull the portable source manifests and lock baselines:
253
+
254
+ ```bash
255
+ revo metadata plan --project test --resources event
256
+ revo metadata apply --project test --resources event --yes
257
+ revo events pull --all --project test
258
+ revo events plan --all --project e2e
259
+ revo events plan --all --project e2e --json
260
+ revo events plan --all --project e2e --strict
261
+
262
+ # Create disabled Events and safely update their configuration.
263
+ revo events push --all --project e2e --yes
264
+ # Only after reviewing remote-changed, conflict, or missing-lock states:
265
+ revo events push --all --project e2e --yes --force
266
+
267
+ # After the configuration phase completes, align active state with source.
268
+ revo events push --all --project e2e --yes --activate
269
+ ```
270
+
271
+ The resulting `<workspace>/Events/**/event.json` manifests retain the Event name, category, description, type, filter, metadata, activation declaration, and API configuration fields that are portable. They replace `targetId` with the Job Template Stable Key and exclude instance UUIDs, target version/configuration, Event version, audits, execution history, and deletion fields. Events targeting `AGENT`, deleted Events, and Events whose target Job Template has no Stable Key are reported as exclusions and are not written. Pull preserves a locally changed Event manifest unless it is repeated with `--force`.
272
+
273
+ `events plan` is read-only. It compares each local Event with the selected environment's lock baseline and live target, then reports `clean`, `create`, `safe-update`, `remote-changed`, `conflict`, `missing-lock`, `activation-drift`, `orphan`, `collision`, and `skipped`. A difference only in `active` is always `activation-drift`, never a skip. Each Job Template Stable Key must resolve exactly once on the target; missing or ambiguous dependencies block the plan. Orphans and exclusions are reported but are not changed. `--strict` accepts only `clean`, informational `orphan`, and `skipped` states.
274
+
275
+ `events push` repeats the live preflight for every write and resolves `target.jobTemplateStableKey` to one exact target UUID and fresh version. Creates run before updates in Stable Key order and always send `active: false`; ordinary updates never change target activation. Each write is read back and verified against the full portable Event configuration before its environment baseline advances. The current Event API has no write contract for unknown `extensions`; they are retained by pull for visibility but block plan/push rather than risking a partial migration. `remote-changed`, `conflict`, and `missing-lock` require `--force`; invalid identity, unresolved dependencies, unmanaged targets, and API errors never become forceable. Orphans and skipped Events remain untouched.
276
+
277
+ `events push --activate` is the optional second phase. It starts only after all configuration writes have verified successfully, then activates or disables verified Events to match source `active`. Interactive use asks for a second confirmation; non-interactive use requires `--yes --activate`. Activation results, including partial failures, are present in both terminal and JSON output.
278
+
279
+ For the complete **SOURCE** → **TARGET** operator and CI sequence, including the required Component gate, plan artifact, and rollback procedure, see [the Job Template runbook](https://gitlab.com/revoengine/cli/-/blob/master/docs/runbooks/job-template-test-to-e2e.md). The commands in that runbook use TEST → E2E as a concrete example.
280
+
281
+ ### Group migration
282
+
283
+ Groups use the same configured workspace and shared `.revoengine/revo.lock.json` as the other resource families. A Group manifest is stored below `<workspace>/Groups/` and contains only the portable name, category, description, user-owned metadata, and Stable Key. UUIDs, versions, members, user identifiers, member counts, leader, avatar, and access type are not persisted. The shared lock stores a `GROUP` owner only as another Group Stable Key. A source `USER` owner is recorded only as a manual-owner policy, never as a user UUID.
284
+
285
+ ```bash
286
+ # Establish Stable Keys on the source environment. Existing keys are preserved.
287
+ revo metadata plan --project test --resources group
288
+ revo metadata apply --project test --resources group --yes
289
+
290
+ # Pull portable source configuration and the TEST baseline.
291
+ revo groups pull --all --project test
292
+
293
+ # Compare the local desired state, E2E baseline, and live E2E Groups.
294
+ revo groups plan --all --project e2e
295
+ revo groups plan --all --project e2e --json
296
+ revo groups plan --all --project e2e --strict
297
+
298
+ # Apply after review. Push recomputes the live plan and never consumes plan JSON.
299
+ revo groups push --all --project e2e --yes
300
+ ```
301
+
302
+ `plan` reports missing `GROUP`-owned structures as `create` when the owner can be resolved on the target or created earlier in the same acyclic dependency graph. Missing source `USER`-owned structures are `manual-owner`: create them in the target UI with a target-local user owner and the exact source Stable Key, then run plan again. A same category/name target Group with a missing or different Stable Key is a blocking `collision`; the CLI never infers identity from its name.
303
+
304
+ `push` resolves every source `GROUP` owner by Stable Key to its target UUID immediately before POST or PUT. Create sends `members: []`. Updates synchronize a source `GROUP` owner relationship, but preserve a target-local owner when the source policy is `USER`. Member data is never hashed, compared, or sent. Target-only Groups remain `orphan` and are never deleted. Cyclic owner graphs cannot be created through the current single-Group API when the target has no bootstrap Group, so plan blocks them before any write. After an explicitly reviewed manual bootstrap creates both cycle members with temporary target-local owners and exact Stable Keys, plan reports owner drift and push safely closes the cycle with target Group UUIDs. An atomic/deferred-owner backend contract remains the preferred fully automatic solution.
305
+
306
+ For the complete **SOURCE** → **TARGET** operator flow, GitLab CI artifact
307
+ template, bootstrap procedure, and rollback, see [the Group runbook](https://gitlab.com/revoengine/cli/-/blob/master/docs/runbooks/group-source-to-target.md).
308
+
309
+ ### Role-group migration
310
+
311
+ Role groups use the same lock-based `pull -> plan -> push` workflow as components. Generate stable keys on TEST first. Before deploying to another environment, copy the exact TEST `metadata.stableKey` to any matching role group that already exists there. Members and user UUIDs are always excluded.
312
+
313
+ Role-group manifests are committed below `RoleGroups/` in the workspace configured by `revo project init`. For a project configured with `workspace: "backend"`, the files live below `backend/RoleGroups/`. Sync baselines live in the shared `.revoengine/revo.lock.json`; TEST, E2E and PROD hashes are isolated by environment name. Role-group lock entries contain no UUID or version.
314
+
315
+ ```bash
316
+ # Bootstrap missing role-group stable keys on the source environment.
317
+ revo metadata plan --project test --resources role-group
318
+ revo metadata apply --project test --resources role-group --yes
319
+
320
+ # Pull the portable desired state into the configured workspace.
321
+ revo role-groups pull --all --project test
322
+
323
+ # Preview E2E without changing files, lock, or the environment.
324
+ revo role-groups plan --all --project e2e
325
+ revo role-groups plan --all --project e2e --json
326
+
327
+ # Apply after review. Push recomputes the live plan and resolves target UUID/version.
328
+ revo role-groups push --all --project e2e --yes
329
+
330
+ # Verify convergence. Orphans and unrelated unmanaged groups remain untouched.
331
+ revo role-groups plan --all --project e2e --strict
86
332
  ```
87
333
 
88
- Backfill only writes resources missing the configured stable-key metadata unless `--force` is passed. Generated component keys use `category/name#<random-hex>`.
334
+ `plan` performs a three-way comparison between the local manifest, the selected environment baseline in `revo.lock.json`, and the live target. It reports `clean`, `create`, `safe-update`, `remote-changed`, `conflict`, `missing-lock`, `orphan`, `collision`, and `skipped`. JSON output may be retained as a CI review artifact, but it is never accepted as push input.
335
+
336
+ `push` resolves the current target UUID by stableKey and reads the current target version immediately before mutation. A matching resource is updated in place even when its UUID differs from TEST. Base fields use the optimistic-version `PUT`; role relationships are synchronized separately through the backend `roleAdd` and `roleDelete` operations. `--force` may adopt or overwrite reviewed content drift, but never bypasses missing/duplicate stable keys, unknown system roles, or ambiguous identity. Prune is disabled until the backend soft-delete contract is confirmed. To roll back an update, restore the previous manifest commit, run plan again, and push that desired state.
337
+
338
+ Artifacts from the earlier experimental `resource` workflow under `.revoengine/resources`, `.revoengine/plans`, and `.revoengine/resources.lock.json` are ignored with a warning and are not removed automatically. The old `revo resource ...` command is no longer part of the CLI surface.
89
339
 
90
340
  ## Common commands
91
341
 
92
342
  ```bash
93
343
  revo endpoints
94
- revo project ./app
344
+ revo project init ./app
95
345
  revo search CODE button
96
346
  revo search SIMPLE customer
97
347
  revo request GET /api/component/list
@@ -139,6 +389,22 @@ revo component push --all --yes
139
389
  revo component push --all --force
140
390
  ```
141
391
 
392
+ For a migration from a saved source profile to another instance, use the same workspace workflow as Job Templates and Role Groups. Without `--project`, component commands use the active project. With `--project <name>`, they use that saved profile for one invocation and record a separate baseline under `components.<stableKey>.environments.<name>` in `.revoengine/revo.lock.json`. This profile-based workflow requires `componentIdentity.mode: "stableKey"` in `.revoengine/revo.json`; it refuses UUID-only identity so different instance UUIDs cannot be mistaken for missing components.
393
+
394
+ ```bash
395
+ # Pull TEST into the workspace and record the TEST baseline.
396
+ revo component pull --all --yes --project test
397
+
398
+ # Compare local source with live E2E and the E2E baseline.
399
+ revo component plan --all --project e2e
400
+ revo component plan --all --project e2e --json
401
+
402
+ # Create missing target components or safely update managed target components.
403
+ revo component push --all --yes --project e2e
404
+ ```
405
+
406
+ The profile mode matches components by the configured stable key. It adopts an already identical target as the E2E baseline, creates a component missing from E2E, and blocks target drift without an E2E baseline. Commands targeting `default` retain their legacy lock behavior.
407
+
142
408
  Debug one local component in sandbox:
143
409
 
144
410
  ```bash
@@ -148,6 +414,8 @@ revo component debug 6dfb536a-1111-4222-8333-123456789abc --timeout 30 --memory
148
414
  revo component debug 6dfb536a-1111-4222-8333-123456789abc --stream
149
415
  ```
150
416
 
417
+ `--raw-debug` saves the full request and source map as a private file under the CLI config directory and prints only its path to stderr. Delete that file when the investigation is finished.
418
+
151
419
  Pulled components are stored as a tree:
152
420
 
153
421
  ```text
@@ -187,20 +455,27 @@ Bulk sync behavior:
187
455
  - Sync logs show direction explicitly: `RevoEngine -> path` for pull and `RevoEngine <- path` for push.
188
456
  - Bulk runs print a summary such as `Deployed 54/67, Skipped 13/67 in 13s`.
189
457
 
190
- ## Environments
458
+ ## Projects
191
459
 
192
- Save named environment profiles once, then compare and mirror components between environments terraform-style:
460
+ Save named project connections and switch the active one for ordinary CLI commands. `revo project init` configures the local workspace:
193
461
 
194
462
  ```bash
195
- revo env add develop --url https://api.dev.revong.com
196
- revo env add e2e --url https://api.e2e.revong.com
197
- revo env list
198
- revo env remove e2e
463
+ revo projects add develop --url https://api.dev.revong.com
464
+ revo projects add e2e --url https://api.e2e.revong.com
465
+ revo projects add prod --url https://app.revo.com
466
+ revo projects list
467
+ revo projects set develop
468
+ revo auth status
469
+ revo endpoints
470
+ revo projects set default
471
+ revo projects remove e2e
199
472
  ```
200
473
 
201
- `revo env add` prompts for the API key, validates it against `/api/v1/me`, and stores the profile (with the inferred instance) next to your default login in the OS config directory. Use `--offline` to skip validation. `revo auth logout` clears only the default login and keeps named environment profiles.
474
+ `revo projects add` prompts for the API key, validates it against `/api/v1/me`, asks whether it is production, saves it, and makes it active. Use `--offline` to skip validation. `revo projects list` marks the active connection with `*`; `revo -i` and `revo auth status` show its name and API URL. `revo projects set <name>` switches the persistent default for subsequent commands. `revo projects set default` selects the original `revo auth login` credentials. An explicit `--project <name>` selects one profile for a single invocation without changing the active project. `--env` and `revo env` remain supported as compatibility aliases. Named profiles keep their own URL, key, and instance even when `REVO_URL`, `REVO_TOKEN`, or `REVO_INSTANCE` is set. Removing the active profile returns to `default`.
202
475
 
203
- Compare two environments:
476
+ `revo auth logout` clears only the original default login and keeps named project profiles and the active selection. Resource sync commands use the active named profile when `--project` is omitted; their existing requirement for a named profile remains. A production profile (stored as `"production": true` in `config.json`) requires an interactive confirmation before the first POST, PUT, PATCH, or DELETE in every CLI invocation. This protection cannot be bypassed with `--yes`, `--force`, or non-interactive CI.
477
+
478
+ Cross-environment component operations remain available as advanced commands:
204
479
 
205
480
  ```bash
206
481
  revo env diff --from develop --to e2e
@@ -256,35 +531,35 @@ This writes `.revoengine/revo.json` with:
256
531
  2. Save environment profiles:
257
532
 
258
533
  ```bash
259
- revo env add test --url https://api.test.revong.com
260
- revo env add dev --url https://api.dev.revong.com
261
- revo env list
534
+ revo projects add test --url https://api.test.revong.com
535
+ revo projects add dev --url https://api.dev.revong.com
536
+ revo projects list
262
537
  ```
263
538
 
264
539
  For one-off commands without a saved profile, use `default` plus environment variables:
265
540
 
266
541
  ```bash
267
- REVO_URL="https://api.dev.revong.com" REVO_TOKEN="$REVO_DEV_TOKEN" revo metadata plan --env default
542
+ REVO_URL="https://api.dev.revong.com" REVO_TOKEN="$REVO_DEV_TOKEN" revo metadata plan --project default
268
543
  ```
269
544
 
270
545
  3. Plan metadata backfill before writing anything:
271
546
 
272
547
  ```bash
273
- revo metadata plan --env test
274
- revo metadata plan --env dev
548
+ revo metadata plan --project test
549
+ revo metadata plan --project dev
275
550
  ```
276
551
 
277
552
  Use JSON when reviewing exact resources:
278
553
 
279
554
  ```bash
280
- revo metadata plan --env test --json
555
+ revo metadata plan --project test --json
281
556
  ```
282
557
 
283
558
  4. Apply metadata backfill:
284
559
 
285
560
  ```bash
286
- revo metadata apply --env test --yes
287
- revo metadata apply --env dev --yes
561
+ revo metadata apply --project test --yes
562
+ revo metadata apply --project dev --yes
288
563
  ```
289
564
 
290
565
  Important: if the same resources already exist in multiple environments, do not treat independently generated random suffixes as interchangeable. `category/name#aaaa1111` and `category/name#bbbb2222` are different stable keys, even when the readable prefix matches. Pick a source of truth and make the target environment use the exact same metadata value, including casing, before running destructive sync.
@@ -292,14 +567,14 @@ Important: if the same resources already exist in multiple environments, do not
292
567
  5. Verify metadata backfill:
293
568
 
294
569
  ```bash
295
- revo metadata plan --env test
296
- revo metadata plan --env dev
570
+ revo metadata plan --project test
571
+ revo metadata plan --project dev
297
572
  ```
298
573
 
299
574
  Expected after a successful backfill:
300
575
 
301
576
  ```text
302
- Plan: 0 to update, N already populated.
577
+ Plan: 0 to update, N already populated, 0 blocked.
303
578
  ```
304
579
 
305
580
  6. Preview environment drift:
@@ -336,14 +611,15 @@ Only use `--prune --force` after reviewing the plan. It deletes target resources
336
611
 
337
612
  ## Configuration
338
613
 
339
- The CLI reads configuration in this order:
614
+ The CLI selects a project from `--project <name>` or the active project. For a named project, it uses that project's URL, key, and instance; explicit `--url`, `--token`, and `--instance` flags can override individual values. Named projects do not inherit values from environment variables or the `default` login.
615
+
616
+ For `default`, the CLI reads configuration in this order:
340
617
 
341
618
  1. CLI flags such as `--url` and `--token`
342
- 2. A named environment profile when a command is invoked with `--from`/`--to` (profiles resolve exclusively and are not mixed with environment variables or the stored default login)
343
- 3. Environment variables such as `REVO_URL` and `REVO_TOKEN`
344
- 4. Stored config in the OS config directory
619
+ 2. Environment variables such as `REVO_URL` and `REVO_TOKEN`
620
+ 3. Stored config in the OS config directory
345
621
 
346
- This means environment variables override the locally stored config, which is the intended setup for CI and non-interactive automation.
622
+ This means environment variables override the locally stored `default` config, which supports CI and non-interactive automation.
347
623
 
348
624
  Use `--url` for one-off local or dedicated API targets:
349
625
 
@@ -372,9 +648,12 @@ Supported environment variables:
372
648
  - `REVO_URL` or `REVO_BASE_URL`
373
649
  - `REVO_TOKEN` or `REVO_API_KEY`
374
650
  - `REVO_NO_UPDATE_NOTIFIER`
651
+ - `REVO_TRUSTED_SERVICE_ORIGINS` (comma-separated exact HTTPS origins for custom sandbox services)
375
652
  - `REVOENGINE_URL` or `REVOENGINE_BASE_URL`
376
653
  - `REVOENGINE_TOKEN` or `REVOENGINE_API_KEY`
377
654
 
655
+ Authenticated API requests reject cross-origin pagination links and redirects. The sandbox service advertised by the authenticated profile may use a different origin: matching first-party API/sandbox hosts and `localhost` services are trusted automatically. For a custom sandbox, set `REVO_TRUSTED_SERVICE_ORIGINS` to its exact origin before running editor-type update or component debug. Do not include a path or credentials in this setting.
656
+
378
657
  Example for CI:
379
658
 
380
659
  ```bash
package/dist/src/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { realpathSync } from 'node:fs';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import { RevoClient } from "./client.js";
4
- import { resolveRuntimeConfig } from "./config.js";
5
- import { handleAuthCommand, handleComponentCommand, handleEndpointsCommand, handleEnvCommand, handleInfoCommand, handleMetadataCommand, handleProjectCommand, handleRequestCommand, handleSearchCommand, } from "./commands/index.js";
4
+ import { getActiveEnvironmentName } from "./config.js";
5
+ import { handleAuthCommand, handleComponentCommand, handleDatabaseSchemasCommand, handleDatabaseViewsCommand, handleEndpointsCommand, handleEnvCommand, handleEventsCommand, handleGroupsCommand, handleInfoCommand, handleJobTemplatesCommand, handleMetadataCommand, handleProjectCommand, handleRequestCommand, handleRoleGroupsCommand, handleSearchCommand, handleSchedulesCommand, handleTerminalCommand, } from "./commands/index.js";
6
6
  import { buildRuntimeViewModel } from "./runtime-view.js";
7
7
  import { renderHelp, renderOverview } from "./ui.js";
8
8
  import { maybeNotifyUpdateAvailable } from "./update-notifier.js";
@@ -136,23 +136,36 @@ function printError(error) {
136
136
  process.stderr.write(`${danger('Error:')} ${message}\n`);
137
137
  }
138
138
  function resolveClient(args) {
139
- const runtime = resolveRuntimeConfig({
139
+ return new RevoClient({
140
140
  baseUrl: typeof args.url === 'string' ? args.url : typeof args.baseUrl === 'string' ? args.baseUrl : undefined,
141
141
  instance: typeof args.instance === 'string' ? args.instance : typeof args.i === 'string' ? args.i : undefined,
142
142
  token: typeof args.token === 'string' ? args.token : typeof args.t === 'string' ? args.t : undefined,
143
+ envName: typeof args.env === 'string' ? args.env : undefined,
143
144
  });
144
- return new RevoClient(runtime);
145
145
  }
146
146
  function createContext(args) {
147
- const client = resolveClient(args);
147
+ if (args.project !== undefined && args.env !== undefined) {
148
+ throw new Error('Use either --project or --env, not both.');
149
+ }
150
+ if (args.project !== undefined && (typeof args.project !== 'string' || !args.project.trim())) {
151
+ throw new Error('--project requires a saved project name.');
152
+ }
153
+ const active = getActiveEnvironmentName();
154
+ const selectedProject = args.project === undefined ? args.env : args.project;
155
+ const effectiveArgs = selectedProject === undefined && active !== 'default'
156
+ ? { ...args, env: active }
157
+ : args.project !== undefined ? { ...args, env: selectedProject } : args;
158
+ const client = resolveClient(effectiveArgs);
148
159
  return {
149
- args,
160
+ args: effectiveArgs,
150
161
  client,
162
+ componentEnvironment: typeof effectiveArgs.env === 'string' ? effectiveArgs.env : undefined,
151
163
  cwd: process.cwd(),
152
164
  packageVersion,
153
165
  print,
154
166
  println,
155
167
  error: (message) => printError(new Error(message)),
168
+ warn: (message) => process.stderr.write(`Warning: ${message}\n`),
156
169
  };
157
170
  }
158
171
  function printHelp() {
@@ -188,22 +201,48 @@ export async function main(argv = process.argv.slice(2)) {
188
201
  await handleAuthCommand(context);
189
202
  return;
190
203
  }
204
+ if (command === 'terminal') {
205
+ const terminalIndex = argv.indexOf('terminal');
206
+ const terminalArgs = argv.slice(terminalIndex + 1);
207
+ const action = args._[1] || 'help';
208
+ const actionIndex = terminalArgs.indexOf(action);
209
+ if (actionIndex >= 0)
210
+ terminalArgs.splice(actionIndex, 1);
211
+ await handleTerminalCommand([action, ...argv.slice(0, terminalIndex), ...terminalArgs]);
212
+ return;
213
+ }
191
214
  if (command === 'component') {
192
215
  await handleComponentCommand(context);
193
216
  return;
194
217
  }
218
+ if (command === 'database-schemas') {
219
+ await handleDatabaseSchemasCommand(context);
220
+ return;
221
+ }
222
+ if (command === 'database-views') {
223
+ await handleDatabaseViewsCommand(context);
224
+ return;
225
+ }
195
226
  if (command === 'endpoints') {
196
227
  await handleEndpointsCommand(context);
197
228
  return;
198
229
  }
199
- if (command === 'env') {
230
+ if (command === 'projects' || command === 'env') {
200
231
  await handleEnvCommand(context);
201
232
  return;
202
233
  }
234
+ if (command === 'events') {
235
+ await handleEventsCommand(context);
236
+ return;
237
+ }
203
238
  if (command === 'metadata') {
204
239
  await handleMetadataCommand(context);
205
240
  return;
206
241
  }
242
+ if (command === 'job-templates') {
243
+ await handleJobTemplatesCommand(context);
244
+ return;
245
+ }
207
246
  if (command === 'project') {
208
247
  await handleProjectCommand(context);
209
248
  return;
@@ -216,6 +255,18 @@ export async function main(argv = process.argv.slice(2)) {
216
255
  await handleRequestCommand(context);
217
256
  return;
218
257
  }
258
+ if (command === 'role-groups') {
259
+ await handleRoleGroupsCommand(context);
260
+ return;
261
+ }
262
+ if (command === 'groups') {
263
+ await handleGroupsCommand(context);
264
+ return;
265
+ }
266
+ if (command === 'schedules') {
267
+ await handleSchedulesCommand(context);
268
+ return;
269
+ }
219
270
  throw new Error(`Unknown command: ${command}`);
220
271
  }
221
272
  if (isDirectExecution()) {