@cervio/cli 0.1.3 → 1.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Cervio S.r.l.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @cervio/cli
2
2
 
3
- Developer CLI for Cervio route plugins — login, validate, pack, push, and manage releases,
3
+ Developer CLI for Cervio route plugins - login, validate, pack, push, and manage releases,
4
4
  built on top of `@cervio/plugin-core`.
5
5
 
6
6
  The binary is `cervio`. This document is the **command reference** (source of truth for flags
@@ -38,19 +38,20 @@ can `cervio push --dev` upsert a scratch artifact on that plugin.
38
38
 
39
39
  | File | Purpose |
40
40
  |---|---|
41
- | `~/.cervio/credentials.json` | `{ "<host>": { "token": "..." } }` — saved by `cervio login`, one token per host. |
42
- | `~/.cervio/state.json` | `{ "lastHost": "<host>" }` — last host successfully pushed to, used for the multi-instance guard. |
41
+ | `~/.cervio/credentials.json` | `{ "<host>": { "token": "..." } }` - saved by `cervio login`, one token per host. |
42
+ | `~/.cervio/state.json` | `{ "lastHost": "<host>" }` - last host successfully pushed to, used for the multi-instance guard. |
43
43
  | `./cervio.json` | Per-project config: `{ "host": "...", "plugin_key": "...", "route_slug": "...", "dev_conflict_minutes": 30 }`. |
44
44
 
45
45
  Env overrides:
46
46
 
47
- - `CERVIO_URL` — host URL (wins over `cervio.json`, loses to an explicit `--host` flag)
48
- - `CERVIO_TOKEN` — bearer token (wins over `~/.cervio/credentials.json` entirely)
47
+ - `CERVIO_URL` - host URL (wins over `cervio.json`, loses to an explicit `--host` flag)
48
+ - `CERVIO_TOKEN` - bearer token (wins over `~/.cervio/credentials.json` entirely)
49
+ - `CERVIO_CONFIG_DIR` - folder for `credentials.json` and `state.json` instead of `~/.cervio` (useful on CI runners)
49
50
 
50
51
  Host resolution order for most commands: `--host` flag → `CERVIO_URL` → `cervio.json` `"host"`.
51
52
  Token resolution order: `CERVIO_TOKEN` → `~/.cervio/credentials.json` entry for the resolved host.
52
53
 
53
- Do not duplicate multi-instance guidance here — use the auth-instances docs (or `cervio whoami` /
54
+ Do not duplicate multi-instance guidance here - use the auth-instances docs (or `cervio whoami` /
54
55
  `--expect-host` / `--yes` as documented below).
55
56
 
56
57
  ## PAT scopes
@@ -62,9 +63,12 @@ used with this CLI needs:
62
63
  |---|---|
63
64
  | **`plugin:push`** | `push`, `rollback`, `route set` (implies `plugin:read`) |
64
65
  | **`plugin:read`** | `status`, `versions`, `download`, `doctor` entity check (`GET /api/v1/entities`), `route set` slug lookup |
66
+ | **`admin:read` / `admin:write`** | Admin REST (`/api/v1/admin/**`) - not needed for CLI plugin commands |
67
+ | **`records:read` / `records:write`** | Entity records/documents API - not needed for CLI plugin commands |
68
+ | **`me:read` / `me:write`** | Personal `/api/v1/me/**` endpoints - not needed for CLI (`GET /me` also accepts `plugin:read`) |
65
69
 
66
- A legacy/unscoped token (created before scopes existed) has full access to everything.
67
- `GET /api/v1/me` itself has no scope requirement.
70
+ New PATs require at least one scope. Legacy unscoped tokens are rejected on any route that
71
+ declares scopes. Use **`plugin:read` + `plugin:push`** for this CLI.
68
72
 
69
73
  ## Flag matrix
70
74
 
@@ -83,7 +87,7 @@ A legacy/unscoped token (created before scopes existed) has full access to every
83
87
  | `versions` | `--host <url>`, `--json` |
84
88
  | `download` | `--host <url>`, `--release <semver>`, `--dev`, `-o/--output <path>`, `--json` |
85
89
  | `rollback <version>` | `--host <url>`, `--json` |
86
- | `route set` | `--host <url>`, `--slug <slug>`, `--cache on\|off`, `--dev-channel on\|off`, `--json` |
90
+ | `route set` | `--host <url>`, `--slug <slug>`, `--dev-channel on\|off`, `--json` |
87
91
  | `open` | `--host <url>` |
88
92
 
89
93
  `--json` is for agents/CI: machine-readable stdout, no interactive prompts (failures become
@@ -130,7 +134,7 @@ Packs the plugin (via `packPlugin`) and writes `./.cervio/out/<plugin_key>.zip`.
130
134
  Flow:
131
135
 
132
136
  1. Resolves the host (`cervio.json` / `CERVIO_URL` / `--host`) and **always prints**
133
- `Publishing to <host> (org: <name>)` (org name falls back to `organization_id` — see
137
+ `Publishing to <host> (org: <name>)` (org name falls back to `organization_id` - see
134
138
  "Known gaps" below).
135
139
  2. If `--expect-host` is set and doesn't match the resolved host (after trailing-slash
136
140
  normalization), fails without pushing.
@@ -142,8 +146,8 @@ Flow:
142
146
  `cervio.json`), prompts to continue; `--force` skips the prompt; `--json` returns
143
147
  `{ "error": "dev_channel_conflict", ... }` and **does not push**.
144
148
  5. Packs the plugin (or validates `--file`) and `POST`s it to `/api/v1/admin/plugins/upload` as
145
- `multipart/form-data` — see "Upload request format" below. **`--dev` requires the plugin
146
- to already exist on the host** (i.e. at least one prior non-dev push) — the dev channel
149
+ `multipart/form-data` - see "Upload request format" below. **`--dev` requires the plugin
150
+ to already exist on the host** (i.e. at least one prior non-dev push) - the dev channel
147
151
  upserts a scratch artifact for an existing `installed_plugins` row and cannot create one.
148
152
  6. On success, updates `lastHost` in `~/.cervio/state.json`.
149
153
 
@@ -164,7 +168,7 @@ Fetches the ZIP through the admin API (so the PAT never talks to Storage directl
164
168
  - release: `GET /api/v1/admin/plugins/{id}/versions/{versionId}/artifact`
165
169
  - dev: `GET /api/v1/admin/plugins/{id}/dev-channel/artifact`
166
170
 
167
- `--release` and `--dev` are mutually exclusive (not `--version` — that flag is reserved for the CLI itself). Use this to pull a known-good host
171
+ `--release` and `--dev` are mutually exclusive (not `--version` - that flag is reserved for the CLI itself). Use this to pull a known-good host
168
172
  artifact for local inspection, dogfood restore, or re-push to `--dev`.
169
173
 
170
174
  ### `cervio status [--host <url>] [--dev] [--json]`
@@ -178,10 +182,8 @@ With `--dev`, also prints `updated_by_email` and `updated_at` from the remote de
178
182
 
179
183
  ### `cervio init [name]`
180
184
 
181
- Scaffolds a new plugin project via `npx create-cervio-plugin` (see
182
- [`packages/create-cervio-plugin`](../create-cervio-plugin)). Inside this monorepo, npx
183
- resolves the local workspace bin automatically. Optional positional `name` is passed through
184
- to the scaffolder.
185
+ Scaffolds a new plugin project with [`@cervio/create-plugin`](../create-plugin), the same
186
+ scaffolder as `npm create @cervio/plugin`. The optional positional `name` is passed through.
185
187
 
186
188
  ### `cervio watch [--push] [--dev] [--host <url>]`
187
189
 
@@ -208,7 +210,7 @@ Lists released versions (`GET /api/v1/admin/plugins/{id}/versions`), newest firs
208
210
 
209
211
  Looks up the version row matching the given semver label, then activates it via
210
212
  `POST /api/v1/admin/plugins/{id}/versions/{versionId}/activate` (the route takes the version
211
- row's UUID, not the semver string — the CLI resolves this for you).
213
+ row's UUID, not the semver string - the CLI resolves this for you).
212
214
 
213
215
  ### `cervio route set [options]`
214
216
 
@@ -216,7 +218,6 @@ row's UUID, not the semver string — the CLI resolves this for you).
216
218
  |---|---|
217
219
  | `--host <url>` | Override resolved host |
218
220
  | `--slug <slug>` | New route slug |
219
- | `--cache on\|off` | Enable/disable route artifact caching |
220
221
  | `--dev-channel on\|off` | Enable/disable the plugin **dev channel** (required before `push --dev` is useful in the UI) |
221
222
  | `--json` | Machine-readable output |
222
223
 
@@ -228,13 +229,13 @@ Example:
228
229
 
229
230
  ```bash
230
231
  cervio route set --dev-channel on
231
- cervio route set --slug timesheets --cache off --dev-channel on
232
+ cervio route set --slug timesheets --dev-channel on
232
233
  ```
233
234
 
234
235
  ### `cervio open [--host <url>]`
235
236
 
236
237
  Opens `<host>/r/<route_slug>` (from `cervio.json`) in the default browser. Does not append
237
- `?channel=dev` — open that URL manually when inspecting the dev channel.
238
+ `?channel=dev` - open that URL manually when inspecting the dev channel.
238
239
 
239
240
  ## CI / automation tips
240
241
 
@@ -251,16 +252,16 @@ cervio status --dev --json
251
252
 
252
253
  ## Upload request format
253
254
 
254
- Matches `app/api/v1/admin/plugins/upload/route.ts` exactly: `multipart/form-data` with:
255
+ `POST /api/v1/admin/plugins/upload` takes `multipart/form-data` with:
255
256
 
256
257
  | Field | Type | Notes |
257
258
  |---|---|---|
258
259
  | `file` | Blob (required) | The packed `.zip`, content-type `application/zip`. |
259
- | `plugin_id` | string (UUID) | Optional; omitted by this CLI — the backend resolves/creates the plugin by the `plugin_key` embedded in the manifest. |
260
+ | `plugin_id` | string (UUID) | Optional; omitted by this CLI - the backend resolves/creates the plugin by the `plugin_key` embedded in the manifest. |
260
261
  | `changelog` | string | Optional, from `--changelog`. Ignored for `channel=dev`. |
261
262
  | `plugin_name` / `plugin_description` / `plugin_type` | string | Optional metadata overrides; not currently set by this CLI. |
262
263
  | `set_current` | `"true"` \| `"false"` | Whether to activate the uploaded release version; driven by `--no-activate`. Ignored for `channel=dev`. |
263
- | `channel` | `"release"` (default) \| `"dev"` | Set to `"dev"` by `push --dev`. The route also accepts `?channel=dev` as a query param — the CLI uses the form field. |
264
+ | `channel` | `"release"` (default) \| `"dev"` | Set to `"dev"` by `push --dev`. The route also accepts `?channel=dev` as a query param - the CLI uses the form field. |
264
265
 
265
266
  Response shape depends on `channel`:
266
267
 
package/dist/cli.js CHANGED
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from 'module';
3
2
  import { Command } from 'commander';
3
+ import { createRequire } from 'module';
4
4
  import { spawn } from 'child_process';
5
- import chalk from 'chalk';
6
- import { promises } from 'fs';
5
+ import { styleText } from 'util';
6
+ import { promises, openAsBlob, watch } from 'fs';
7
7
  import path from 'path';
8
- import { validatePluginDir, validatePluginZipBuffer, parseManifestObject, packPlugin } from '@cervio/plugin-core';
8
+ import { validatePluginDir, validatePluginZipBuffer, parseManifestObject, packPlugin, PLUGIN_ARTIFACT_SOFT_STRONG_WARN_BYTES, PLUGIN_ARTIFACT_SOFT_WARN_BYTES } from '@cervio/plugin-core';
9
9
  import os from 'os';
10
+ import { createPlugin } from '@cervio/create-plugin';
10
11
  import prompts2 from 'prompts';
11
- import open from 'open';
12
- import chokidar from 'chokidar';
12
+
13
+ var CLI_VERSION = createRequire(import.meta.url)("../package.json").version;
14
+ var USER_AGENT = `cervio-cli/${CLI_VERSION} node/${process.versions.node}`;
13
15
 
14
16
  // src/api.ts
15
17
  var ApiError = class extends Error {
@@ -31,6 +33,7 @@ function createApiClient(opts) {
31
33
  const url = pathname.startsWith("http") ? pathname : `${baseUrl}${pathname}`;
32
34
  const headers = new Headers(init.headers);
33
35
  if (token) headers.set("Authorization", `Bearer ${token}`);
36
+ headers.set("User-Agent", USER_AGENT);
34
37
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
35
38
  let res;
36
39
  try {
@@ -39,7 +42,7 @@ function createApiClient(opts) {
39
42
  throw new ApiError(0, `Could not reach ${url}: ${err.message}`);
40
43
  }
41
44
  const contentType = res.headers.get("content-type") ?? "";
42
- let body = null;
45
+ let body;
43
46
  if (contentType.includes("application/json")) {
44
47
  body = await res.json().catch(() => null);
45
48
  } else {
@@ -59,7 +62,7 @@ function createApiClient(opts) {
59
62
  request,
60
63
  /** No scope requirement. */
61
64
  getMe: () => request("/api/v1/me"),
62
- /** Requires PAT scope `plugin:read` (or an unscoped/legacy token). */
65
+ /** Requires PAT scope `plugin:read` (legacy unscoped PATs are rejected). */
63
66
  listEntities: (search) => request(
64
67
  `/api/v1/entities${search ? `?search=${encodeURIComponent(search)}` : ""}`
65
68
  ),
@@ -87,16 +90,16 @@ function createApiClient(opts) {
87
90
  body: JSON.stringify(data)
88
91
  }),
89
92
  /**
90
- * Matches app/api/v1/admin/plugins/upload/route.ts exactly. Requires PAT
93
+ * `POST /api/v1/admin/plugins/upload`. Requires PAT
91
94
  * scope `plugin:push`. multipart/form-data fields:
92
95
  * - `file` (required): the packed .zip, content-type application/zip.
93
- * - `plugin_id` (optional UUID): omitted by this CLI — the backend
96
+ * - `plugin_id` (optional UUID): omitted by this CLI - the backend
94
97
  * resolves/creates the plugin by the `plugin_key` embedded in the manifest.
95
98
  * - `changelog`, `plugin_name`, `plugin_description`, `plugin_type` (optional).
96
99
  * - `set_current` ("true"/"false"): whether to activate the uploaded
97
100
  * release version. Ignored for `channel=dev`.
98
101
  * - `channel` ("release" default, or "dev"): dev-channel pushes require
99
- * the plugin to already exist (a prior release push) — the route
102
+ * the plugin to already exist (a prior release push) - the route
100
103
  * returns `plugin_not_found` otherwise. Response shape depends on
101
104
  * the channel (see `UploadReleaseResult` / `UploadDevResult`).
102
105
  */
@@ -117,6 +120,7 @@ async function downloadBinary(pathname, opts) {
117
120
  const url = pathname.startsWith("http") ? pathname : `${opts.host}${pathname}`;
118
121
  const headers = new Headers({ Accept: "application/zip, application/octet-stream, */*" });
119
122
  if (opts.token) headers.set("Authorization", `Bearer ${opts.token}`);
123
+ headers.set("User-Agent", USER_AGENT);
120
124
  let res;
121
125
  try {
122
126
  res = await fetch(url, { headers });
@@ -125,7 +129,7 @@ async function downloadBinary(pathname, opts) {
125
129
  }
126
130
  if (!res.ok) {
127
131
  const contentType = res.headers.get("content-type") ?? "";
128
- let body = null;
132
+ let body;
129
133
  if (contentType.includes("application/json")) {
130
134
  body = await res.json().catch(() => null);
131
135
  } else {
@@ -157,11 +161,11 @@ var CliError = class extends Error {
157
161
  };
158
162
  var log = {
159
163
  info: (msg) => console.log(msg),
160
- success: (msg) => console.log(chalk.green("\u2714"), msg),
161
- warn: (msg) => console.warn(chalk.yellow("\u26A0"), msg),
162
- error: (msg) => console.error(chalk.red("\u2716"), msg),
163
- step: (msg) => console.log(chalk.cyan("\u2192"), msg),
164
- dim: (msg) => console.log(chalk.dim(msg))
164
+ success: (msg) => console.log(styleText("green", "\u2714"), msg),
165
+ warn: (msg) => console.warn(styleText("yellow", "\u26A0"), msg),
166
+ error: (msg) => console.error(styleText("red", "\u2716"), msg),
167
+ step: (msg) => console.log(styleText("cyan", "\u2192"), msg),
168
+ dim: (msg) => console.log(styleText("dim", msg))
165
169
  };
166
170
  function printResult(json, data, human) {
167
171
  if (json) {
@@ -205,6 +209,20 @@ function minutesSince(isoDate) {
205
209
  const ms = Date.now() - new Date(isoDate).getTime();
206
210
  return ms / 6e4;
207
211
  }
212
+ async function openUrl(url) {
213
+ const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", '""', url.replace(/&/g, "^&")]] : ["xdg-open", [url]];
214
+ await new Promise((resolve) => {
215
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
216
+ child.once("error", () => {
217
+ log.info(`Open this URL in your browser: ${url}`);
218
+ resolve();
219
+ });
220
+ child.once("spawn", () => {
221
+ child.unref();
222
+ resolve();
223
+ });
224
+ });
225
+ }
208
226
 
209
227
  // src/commands/build.ts
210
228
  async function buildCommand() {
@@ -214,12 +232,14 @@ async function buildCommand() {
214
232
  await runCommand(pm, ["run", "build"], { cwd });
215
233
  log.success("Build complete.");
216
234
  }
217
- var CERVIO_DIR = path.join(os.homedir(), ".cervio");
218
- var CREDENTIALS_PATH = path.join(CERVIO_DIR, "credentials.json");
219
- var STATE_PATH = path.join(CERVIO_DIR, "state.json");
235
+ function cervioConfigDir() {
236
+ return process.env.CERVIO_CONFIG_DIR || path.join(os.homedir(), ".cervio");
237
+ }
238
+ var credentialsPath = () => path.join(cervioConfigDir(), "credentials.json");
239
+ var statePath = () => path.join(cervioConfigDir(), "state.json");
220
240
  var PROJECT_CONFIG_FILENAME = "cervio.json";
221
241
  async function ensureCervioDir() {
222
- await promises.mkdir(CERVIO_DIR, { recursive: true });
242
+ await promises.mkdir(cervioConfigDir(), { recursive: true, mode: 448 });
223
243
  }
224
244
  async function readJsonFile(filePath, fallback) {
225
245
  try {
@@ -239,7 +259,7 @@ function normalizeHost(host) {
239
259
  return host.trim().replace(/\/+$/, "");
240
260
  }
241
261
  async function readCredentials() {
242
- return readJsonFile(CREDENTIALS_PATH, {});
262
+ return readJsonFile(credentialsPath(), {});
243
263
  }
244
264
  async function getToken(host) {
245
265
  const creds = await readCredentials();
@@ -248,13 +268,13 @@ async function getToken(host) {
248
268
  async function saveToken(host, token) {
249
269
  const creds = await readCredentials();
250
270
  creds[normalizeHost(host)] = { token };
251
- await writeJsonFile(CREDENTIALS_PATH, creds);
271
+ await writeJsonFile(credentialsPath(), creds);
252
272
  }
253
273
  async function readState() {
254
- return readJsonFile(STATE_PATH, {});
274
+ return readJsonFile(statePath(), {});
255
275
  }
256
276
  async function writeState(state) {
257
- await writeJsonFile(STATE_PATH, state);
277
+ await writeJsonFile(statePath(), state);
258
278
  }
259
279
  async function getLastHost() {
260
280
  const state = await readState();
@@ -411,8 +431,8 @@ async function downloadCommand(opts) {
411
431
  const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key);
412
432
  let channel = "release";
413
433
  let versionLabel = null;
414
- let contentSha256 = null;
415
- let artifactSha256 = null;
434
+ let contentSha256;
435
+ let artifactSha256;
416
436
  let bytes;
417
437
  let defaultFileName;
418
438
  try {
@@ -481,12 +501,9 @@ async function downloadCommand(opts) {
481
501
  if (data.artifact_sha256) log.info(` artifact_sha256: ${data.artifact_sha256}`);
482
502
  });
483
503
  }
484
-
485
- // src/commands/init.ts
486
504
  async function initCommand(name) {
487
- const args = name ? [name] : [];
488
- log.step('Scaffolding via "npx create-cervio-plugin"...');
489
- await runCommand("npx", ["create-cervio-plugin", ...args]);
505
+ log.step("Scaffolding a new Cervio plugin...");
506
+ await createPlugin(name ? [name] : []);
490
507
  }
491
508
  async function loginCommand(opts) {
492
509
  if (!opts.host) {
@@ -513,6 +530,8 @@ async function loginCommand(opts) {
513
530
  log.info(` org: ${me.organization_name ?? me.organization_id}`);
514
531
  log.info(` auth: ${me.auth_method}`);
515
532
  }
533
+
534
+ // src/commands/open.ts
516
535
  async function openCommand(opts) {
517
536
  const ctx = await resolveContext({ host: opts.host });
518
537
  const projectConfig = requireProjectConfig(ctx);
@@ -521,7 +540,7 @@ async function openCommand(opts) {
521
540
  }
522
541
  const url = `${ctx.host}/r/${projectConfig.route_slug}`;
523
542
  log.step(`Opening ${url}`);
524
- await open(url);
543
+ await openUrl(url);
525
544
  }
526
545
  async function packForPublish(dir = process.cwd()) {
527
546
  const result = await packPlugin({ dir });
@@ -545,6 +564,15 @@ async function packCommand(opts) {
545
564
  log.success(`Packed ${data.pluginKey} (${formatBytes(data.sizeBytes)})`);
546
565
  log.info(` content_sha256: ${data.contentSha256}`);
547
566
  log.info(` output: ${data.outputPath}`);
567
+ if (data.sizeBytes >= PLUGIN_ARTIFACT_SOFT_STRONG_WARN_BYTES) {
568
+ log.warn(
569
+ `Artifact is large (${formatBytes(data.sizeBytes)} \u2265 3 MB). Cold open will be slow; trim the ZIP (target < 1 MB).`
570
+ );
571
+ } else if (data.sizeBytes >= PLUGIN_ARTIFACT_SOFT_WARN_BYTES) {
572
+ log.warn(
573
+ `Artifact is above the soft budget (${formatBytes(data.sizeBytes)} \u2265 1 MB). Prefer a smaller bundle for faster opens.`
574
+ );
575
+ }
548
576
  });
549
577
  }
550
578
  var DEFAULT_DEV_CONFLICT_MINUTES = 30;
@@ -636,10 +664,12 @@ async function pushCommand(opts) {
636
664
  }
637
665
  }
638
666
  }
639
- let zipBuffer;
667
+ let zipPath;
640
668
  let zipFileName;
641
669
  if (opts.file) {
642
670
  const filePath = path.resolve(process.cwd(), opts.file);
671
+ zipPath = filePath;
672
+ let zipBuffer;
643
673
  try {
644
674
  zipBuffer = await promises.readFile(filePath);
645
675
  } catch (err) {
@@ -660,11 +690,11 @@ async function pushCommand(opts) {
660
690
  log.info(`Using existing ZIP ${filePath} (content_sha256=${validated.value.contentSha256})`);
661
691
  } else {
662
692
  const packed = await packForPublish(process.cwd());
663
- zipBuffer = await promises.readFile(packed.outputPath);
693
+ zipPath = packed.outputPath;
664
694
  zipFileName = `${packed.pluginKey}.zip`;
665
695
  }
666
696
  const form = new FormData();
667
- form.set("file", new Blob([zipBuffer], { type: "application/zip" }), zipFileName);
697
+ form.set("file", await openAsBlob(zipPath, { type: "application/zip" }), zipFileName);
668
698
  if (opts.changelog) form.set("changelog", opts.changelog);
669
699
  form.set("set_current", String(opts.activate !== false));
670
700
  if (opts.dev) form.set("channel", "dev");
@@ -680,7 +710,7 @@ async function pushCommand(opts) {
680
710
  }
681
711
  if (err.code === "plugin_not_found" && opts.dev) {
682
712
  throw new CliError(
683
- `Plugin "${projectConfig.plugin_key}" does not exist on ${host} yet. Dev-channel pushes require a prior release push \u2014 run "cervio push" (without --dev) once first.`
713
+ `Plugin "${projectConfig.plugin_key}" does not exist on ${host} yet. Dev-channel pushes require a prior release push - run "cervio push" (without --dev) once first.`
684
714
  );
685
715
  }
686
716
  throw new CliError(`Upload failed: ${err.message}`);
@@ -773,7 +803,6 @@ async function routeSetCommand(opts) {
773
803
  requireToken(ctx);
774
804
  const projectConfig = requireProjectConfig(ctx);
775
805
  const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key);
776
- const cache = parseOnOff(opts.cache, "--cache");
777
806
  const devChannel = parseOnOff(opts.devChannel, "--dev-channel");
778
807
  let slug = opts.slug;
779
808
  if (!slug) {
@@ -785,12 +814,11 @@ async function routeSetCommand(opts) {
785
814
  }
786
815
  const { route_config } = await ctx.client.setRouteConfig(pluginId, {
787
816
  route_slug: slug,
788
- artifact_cache_enabled: cache,
789
817
  dev_channel_enabled: devChannel
790
818
  });
791
819
  printResult(!!opts.json, { host: ctx.host, plugin_key: projectConfig.plugin_key, route_config }, (data) => {
792
820
  const rc = data.route_config;
793
- const extras = rc ? ` (cache=${rc.artifact_cache_enabled ? "on" : "off"}, dev_channel=${rc.dev_channel_enabled ? "on" : "off"})` : "";
821
+ const extras = rc ? ` (dev_channel=${rc.dev_channel_enabled ? "on" : "off"})` : "";
794
822
  log.success(
795
823
  `Updated route config for ${data.plugin_key} on ${data.host}: /r/${rc?.route_slug}` + extras
796
824
  );
@@ -863,7 +891,7 @@ async function statusCommand(opts) {
863
891
  log.info(`local: ${data.local_content_sha256}`);
864
892
  if (data.remote_check_unavailable) {
865
893
  log.warn(
866
- `remote: unavailable \u2014 the ${opts.dev ? "dev-channel" : "plugin detail"} endpoint is not implemented on this host yet.`
894
+ `remote: unavailable - the ${opts.dev ? "dev-channel" : "plugin detail"} endpoint is not implemented on this host yet.`
867
895
  );
868
896
  return;
869
897
  }
@@ -953,14 +981,17 @@ async function watchCommand(opts) {
953
981
  }
954
982
  };
955
983
  log.info(`Watching ${srcDir} for changes (Ctrl+C to stop)...`);
956
- const watcher = chokidar.watch(srcDir, { ignoreInitial: true });
957
- watcher.on("all", () => {
958
- void runCycle();
984
+ let debounce;
985
+ const watcher = watch(srcDir, { recursive: true }, () => {
986
+ clearTimeout(debounce);
987
+ debounce = setTimeout(() => void runCycle(), 100);
959
988
  });
960
989
  await runCycle();
961
990
  await new Promise((resolve) => {
962
991
  process.on("SIGINT", () => {
963
- void watcher.close().then(() => resolve());
992
+ clearTimeout(debounce);
993
+ watcher.close();
994
+ resolve();
964
995
  });
965
996
  });
966
997
  }
@@ -979,7 +1010,6 @@ async function whoamiCommand(opts) {
979
1010
  }
980
1011
 
981
1012
  // src/index.ts
982
- var CLI_VERSION = createRequire(import.meta.url)("../package.json").version;
983
1013
  function action(fn) {
984
1014
  return async (...args) => {
985
1015
  try {
@@ -999,7 +1029,7 @@ function action(fn) {
999
1029
  };
1000
1030
  }
1001
1031
  var program = new Command();
1002
- program.name("cervio").description("Cervio route plugin developer CLI").version(CLI_VERSION);
1032
+ program.name("cervio").description("Cervio plugin developer CLI").version(CLI_VERSION);
1003
1033
  program.command("login").description("Authenticate with a Cervio host and save the token").option("--host <url>", "Cervio host, e.g. https://app.example.com").option("--token <token>", "Personal access token (prompted if omitted)").action(action(loginCommand));
1004
1034
  program.command("whoami").description("Print the current host and identity").option("--host <url>", "Override the resolved host").option("--json", "Output JSON").action(action(whoamiCommand));
1005
1035
  program.command("build").description("Run the project build script (pnpm/npm run build)").action(action(buildCommand));
@@ -1014,11 +1044,9 @@ program.command("versions").description("List released versions for the current
1014
1044
  program.command("download").description("Download a release or dev-channel ZIP from the host").option("--host <url>", "Override the resolved host").option("--release <semver>", "Download a specific release version (default: current)").option("--dev", "Download the dev-channel artifact instead of a release").option("-o, --output <path>", "Output path (default: .cervio/out/<plugin_key>-\u2026.zip)").option("--json", "Output JSON").action(action(downloadCommand));
1015
1045
  program.command("rollback <version>").description("Activate a previously released version").option("--host <url>", "Override the resolved host").option("--json", "Output JSON").action(action(rollbackCommand));
1016
1046
  var route = program.command("route").description("Manage the plugin route configuration");
1017
- route.command("set").description("Update the route slug, cache, and/or dev-channel setting").option("--host <url>", "Override the resolved host").option("--slug <slug>", "New route slug").option("--cache <onoff>", 'Enable/disable route caching ("on" or "off")').option("--dev-channel <onoff>", 'Enable/disable the plugin dev channel ("on" or "off")').option("--json", "Output JSON").action(action(routeSetCommand));
1047
+ route.command("set").description("Update the route slug and/or the dev-channel setting").option("--host <url>", "Override the resolved host").option("--slug <slug>", "New route slug").option("--dev-channel <onoff>", 'Enable/disable the plugin dev channel ("on" or "off")').option("--json", "Output JSON").action(action(routeSetCommand));
1018
1048
  program.command("open").description("Open the plugin route in a browser").option("--host <url>", "Override the resolved host").action(action(openCommand));
1019
1049
  program.parseAsync(process.argv).catch((err) => {
1020
1050
  log.error(err instanceof Error ? err.message : String(err));
1021
1051
  process.exitCode = 1;
1022
1052
  });
1023
- //# sourceMappingURL=cli.js.map
1024
- //# sourceMappingURL=cli.js.map
package/package.json CHANGED
@@ -1,44 +1,52 @@
1
1
  {
2
2
  "name": "@cervio/cli",
3
- "version": "0.1.3",
4
- "description": "Developer CLI for Cervio route plugins: login, validate, pack, push, and manage releases.",
3
+ "version": "1.0.0",
4
+ "description": "Developer CLI for Cervio plugins: login, validate, pack, push and manage releases.",
5
+ "keywords": [
6
+ "cervio",
7
+ "cli",
8
+ "plugin"
9
+ ],
10
+ "license": "MIT",
11
+ "homepage": "https://github.com/cervio-app/cervio-devkit/tree/main/packages/cli#readme",
12
+ "bugs": "https://github.com/cervio-app/cervio-devkit/issues",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/cervio-app/cervio-devkit.git",
16
+ "directory": "packages/cli"
17
+ },
5
18
  "type": "module",
6
19
  "bin": {
7
20
  "cervio": "./dist/cli.js"
8
21
  },
9
22
  "files": [
10
23
  "dist",
11
- "README.md"
24
+ "README.md",
25
+ "LICENSE"
12
26
  ],
27
+ "engines": {
28
+ "node": ">=26"
29
+ },
13
30
  "dependencies": {
14
- "chalk": "^5.6.2",
15
- "chokidar": "^4.0.3",
16
- "commander": "^14.0.3",
17
- "open": "^10.2.0",
31
+ "commander": "^15.0.0",
18
32
  "prompts": "^2.4.2",
19
- "@cervio/plugin-core": "^0.1.1"
33
+ "@cervio/create-plugin": "^1.0.0",
34
+ "@cervio/plugin-core": "^1.0.0"
20
35
  },
21
36
  "devDependencies": {
22
- "@types/node": "^22.15.0",
37
+ "@types/node": "^26.0.0",
23
38
  "@types/prompts": "^2.4.9",
24
- "tsup": "^8.5.0",
25
- "typescript": "^5.8.3"
39
+ "tsup": "^9.0.0",
40
+ "typescript": "^5.8.3",
41
+ "vitest": "^5.0.5"
26
42
  },
27
43
  "publishConfig": {
28
44
  "access": "public"
29
45
  },
30
- "engines": {
31
- "node": ">=18.17"
32
- },
33
- "license": "UNLICENSED",
34
- "keywords": [
35
- "cervio",
36
- "cli",
37
- "plugin"
38
- ],
39
46
  "scripts": {
40
47
  "build": "tsup --config tsup.config.ts",
41
48
  "dev": "tsup --config tsup.config.ts --watch",
42
- "typecheck": "tsc -p tsconfig.json --noEmit"
49
+ "typecheck": "tsc -p tsconfig.json --noEmit",
50
+ "test": "vitest run"
43
51
  }
44
52
  }
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api.ts","../src/util.ts","../src/commands/build.ts","../src/config.ts","../src/context.ts","../src/commands/doctor.ts","../src/commands/download.ts","../src/commands/init.ts","../src/commands/login.ts","../src/commands/open.ts","../src/commands/pack.ts","../src/commands/push.ts","../src/commands/rollback.ts","../src/commands/route.ts","../src/commands/status.ts","../src/commands/validate.ts","../src/commands/versions.ts","../src/commands/watch.ts","../src/commands/whoami.ts","../src/index.ts"],"names":["path","fs","prompts","route_config","validatePluginDir"],"mappings":";;;;;;;;;;;;;;AAQO,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EAClC,MAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EAEA,WAAA,CAAY,MAAA,EAAgB,OAAA,EAAiB,IAAA,EAAe,IAAA,EAAgB;AAC1E,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF,CAAA;AAqGO,SAAS,gBAAgB,IAAA,EAAwC;AACtE,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAC5C,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AAEnB,EAAA,eAAe,OAAA,CAAqB,QAAA,EAAkB,IAAA,GAAoB,EAAC,EAAe;AACxF,IAAA,MAAM,GAAA,GAAM,SAAS,UAAA,CAAW,MAAM,IAAI,QAAA,GAAW,CAAA,EAAG,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA;AAC1E,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA;AACxC,IAAA,IAAI,OAAO,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA;AACzD,IAAA,IAAI,CAAC,QAAQ,GAAA,CAAI,QAAQ,GAAG,OAAA,CAAQ,GAAA,CAAI,UAAU,kBAAkB,CAAA;AAEpE,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,GAAG,IAAA,EAAM,SAAS,CAAA;AAAA,IAC7C,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,SAAS,CAAA,EAAG,CAAA,gBAAA,EAAmB,GAAG,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,IAC3E;AAEA,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AACvD,IAAA,IAAI,IAAA,GAAgB,IAAA;AACpB,IAAA,IAAI,WAAA,CAAY,QAAA,CAAS,kBAAkB,CAAA,EAAG;AAC5C,MAAA,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAAA,IAC1C,CAAA,MAAO;AACL,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,IAAA,GAAO,IAAA,IAAQ,IAAA;AAAA,IACjB;AAEA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAA,GACJ,IAAA,IAAQ,OAAO,IAAA,KAAS,YAAY,OAAQ,IAAA,CAAiC,OAAA,KAAY,QAAA,GACpF,KAAgC,OAAA,GACjC,CAAA,2BAAA,EAA8B,GAAA,CAAI,MAAM,KAAK,QAAQ,CAAA,CAAA,CAAA;AAC3D,MAAA,MAAM,IAAA,GACJ,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,OAAQ,IAAA,CAAiC,KAAA,KAAU,QAAA,GAClF,IAAA,CAAgC,KAAA,GACjC,MAAA;AACN,MAAA,MAAM,IAAI,QAAA,CAAS,GAAA,CAAI,MAAA,EAAQ,OAAA,EAAS,MAAM,IAAI,CAAA;AAAA,IACpD;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA;AAAA,IAGA,KAAA,EAAO,MAAM,OAAA,CAAoB,YAAY,CAAA;AAAA;AAAA,IAG7C,YAAA,EAAc,CAAC,MAAA,KACb,OAAA;AAAA,MACE,mBAAmB,MAAA,GAAS,CAAA,QAAA,EAAW,mBAAmB,MAAM,CAAC,KAAK,EAAE,CAAA;AAAA,KAC1E;AAAA;AAAA,IAGF,WAAA,EAAa,MAAM,OAAA,CAAsC,uBAAuB,CAAA;AAAA;AAAA,IAGhF,SAAA,EAAW,CAAC,QAAA,KACV,OAAA;AAAA,MACE,yBAAyB,QAAQ,CAAA;AAAA,KACnC;AAAA;AAAA,IAGF,eAAe,CAAC,QAAA,KACd,OAAA,CAAgD,CAAA,sBAAA,EAAyB,QAAQ,CAAA,YAAA,CAAc,CAAA;AAAA;AAAA,IAGjG,cAAc,CAAC,QAAA,KACb,OAAA,CAA8C,CAAA,sBAAA,EAAyB,QAAQ,CAAA,SAAA,CAAW,CAAA;AAAA;AAAA,IAG5F,eAAA,EAAiB,CAAC,QAAA,EAAkB,SAAA,KAClC,OAAA;AAAA,MACE,CAAA,sBAAA,EAAyB,QAAQ,CAAA,UAAA,EAAa,SAAS,CAAA,SAAA,CAAA;AAAA,MACvD,EAAE,QAAQ,MAAA;AAAO,KACnB;AAAA;AAAA,IAGF,gBAAgB,CAAC,QAAA,KACf,OAAA,CAA8C,CAAA,sBAAA,EAAyB,QAAQ,CAAA,aAAA,CAAe,CAAA;AAAA;AAAA,IAGhG,gBAAgB,CACd,QAAA,EACA,SAEA,OAAA,CAA8C,CAAA,sBAAA,EAAyB,QAAQ,CAAA,aAAA,CAAA,EAAiB;AAAA,MAC9F,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC1B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBH,YAAA,EAAc,CAAC,IAAA,KACb,OAAA,CAAsB,8BAAA,EAAgC,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMtF,uBAAA,EAAyB,CAAC,QAAA,EAAkB,SAAA,KAC1C,cAAA;AAAA,MACE,CAAA,sBAAA,EAAyB,QAAQ,CAAA,UAAA,EAAa,SAAS,CAAA,SAAA,CAAA;AAAA,MACvD,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA;AAAM,KACzB;AAAA;AAAA,IAGF,mBAAA,EAAqB,CAAC,QAAA,KACpB,cAAA,CAAe,CAAA,sBAAA,EAAyB,QAAQ,CAAA,qBAAA,CAAA,EAAyB,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO;AAAA,GACrG;AACF;AAUA,eAAe,cAAA,CACb,UACA,IAAA,EACiC;AACjC,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,UAAA,CAAW,MAAM,CAAA,GAAI,WAAW,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG,QAAQ,CAAA,CAAA;AAC5E,EAAA,MAAM,UAAU,IAAI,OAAA,CAAQ,EAAE,MAAA,EAAQ,kDAAkD,CAAA;AACxF,EAAA,IAAI,IAAA,CAAK,OAAO,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAEnE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,SAAS,CAAA;AAAA,EACpC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,SAAS,CAAA,EAAG,CAAA,gBAAA,EAAmB,GAAG,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EAC3E;AAEA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AACvD,IAAA,IAAI,IAAA,GAAgB,IAAA;AACpB,IAAA,IAAI,WAAA,CAAY,QAAA,CAAS,kBAAkB,CAAA,EAAG;AAC5C,MAAA,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAAA,IAC1C,CAAA,MAAO;AACL,MAAA,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAAA,IACxC;AACA,IAAA,MAAM,OAAA,GACJ,IAAA,IAAQ,OAAO,IAAA,KAAS,YAAY,OAAQ,IAAA,CAAiC,OAAA,KAAY,QAAA,GACpF,KAAgC,OAAA,GACjC,CAAA,2BAAA,EAA8B,GAAA,CAAI,MAAM,KAAK,QAAQ,CAAA,CAAA,CAAA;AAC3D,IAAA,MAAM,IAAA,GACJ,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,OAAQ,IAAA,CAAiC,KAAA,KAAU,QAAA,GAClF,IAAA,CAAgC,KAAA,GACjC,MAAA;AACN,IAAA,MAAM,IAAI,QAAA,CAAS,GAAA,CAAI,MAAA,EAAQ,OAAA,EAAS,MAAM,IAAI,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,WAAA,GAAc,MAAM,GAAA,CAAI,WAAA,EAAY;AAC1C,EAAA,MAAM,WAAA,GAAc,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,qBAAqB,CAAA,IAAK,EAAA;AAC9D,EAAA,MAAM,aAAA,GAAgB,qBAAA,CAAsB,IAAA,CAAK,WAAW,CAAA;AAC5D,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA;AAAA,IAC9B,QAAA,EAAU,aAAA,GAAgB,CAAC,CAAA,IAAK,IAAA;AAAA,IAChC,YAAA,EAAc,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AAAA,IAChD,aAAA,EAAe,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AAAA,IACjD,cAAA,EAAgB,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,mBAAmB;AAAA,GACrD;AACF;ACzSO,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA;AAAA,EAElC,QAAA;AAAA,EACA,WAAA,CAAY,OAAA,EAAiB,QAAA,GAAW,CAAA,EAAG;AACzC,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AACF,CAAA;AAEO,IAAM,GAAA,GAAM;AAAA,EACjB,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,GAAG,CAAA;AAAA,EACtC,OAAA,EAAS,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,KAAA,CAAM,KAAA,CAAM,QAAG,CAAA,EAAG,GAAG,CAAA;AAAA,EAC3D,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,KAAK,KAAA,CAAM,MAAA,CAAO,QAAG,CAAA,EAAG,GAAG,CAAA;AAAA,EAC1D,KAAA,EAAO,CAAC,GAAA,KAAgB,OAAA,CAAQ,MAAM,KAAA,CAAM,GAAA,CAAI,QAAG,CAAA,EAAG,GAAG,CAAA;AAAA,EACzD,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,QAAG,CAAA,EAAG,GAAG,CAAA;AAAA,EACvD,GAAA,EAAK,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,KAAA,CAAM,GAAA,CAAI,GAAG,CAAC;AAClD,CAAA;AAGO,SAAS,WAAA,CAAe,IAAA,EAAe,IAAA,EAAS,KAAA,EAAgC;AACrF,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,OAAA,CAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,IAAA,EAAM,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,EAC3C,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,IAAI,CAAA;AAAA,EACZ;AACF;AAEO,SAAS,UAAA,CACd,OAAA,EACA,IAAA,EACA,IAAA,GAAyB,EAAC,EACX;AACf,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM;AAAA,MACjC,GAAA,EAAK,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAAA,MAC7B,KAAA,EAAO,SAAA;AAAA,MACP,KAAA,EAAO,QAAQ,QAAA,KAAa;AAAA,KAC7B,CAAA;AACD,IAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ,OAAO,IAAI,QAAA,CAAS,CAAA,eAAA,EAAkB,OAAO,CAAA,GAAA,EAAM,GAAA,CAAI,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAC7F,IAAA,KAAA,CAAM,EAAA,CAAG,MAAA,EAAQ,CAAC,IAAA,KAAS;AACzB,MAAA,IAAI,IAAA,KAAS,GAAG,OAAA,EAAQ;AAAA,WACnB,MAAA,CAAO,IAAI,QAAA,CAAS,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,mBAAA,EAAsB,IAAI,CAAA,CAAA,EAAI,IAAA,IAAQ,CAAC,CAAC,CAAA;AAAA,IAChG,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAGA,eAAsB,qBAAqB,GAAA,EAAsC;AAC/E,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,MAAM,OAAO,IAAS,CAAA;AAC7C,EAAA,MAAMA,KAAAA,GAAO,MAAM,OAAO,MAAW,CAAA;AACrC,EAAA,IAAI,WAAWA,KAAAA,CAAK,IAAA,CAAK,KAAK,gBAAgB,CAAC,GAAG,OAAO,MAAA;AACzD,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,IAAI,KAAA,GAAQ,IAAA,EAAM,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAC/B,EAAA,IAAI,QAAQ,KAAA,GAAQ,IAAA;AACpB,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,OAAO,KAAA,IAAS,IAAA,IAAQ,SAAA,GAAY,KAAA,CAAM,SAAS,CAAA,EAAG;AACpD,IAAA,KAAA,IAAS,IAAA;AACT,IAAA,SAAA,IAAa,CAAA;AAAA,EACf;AACA,EAAA,OAAO,CAAA,EAAG,MAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,SAAS,CAAC,CAAA,CAAA;AAChD;AAEO,SAAS,aAAa,OAAA,EAAyB;AACpD,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,EAAI,GAAI,IAAI,IAAA,CAAK,OAAO,EAAE,OAAA,EAAQ;AAClD,EAAA,OAAO,EAAA,GAAK,GAAA;AACd;;;ACvEA,eAAsB,YAAA,GAA8B;AAClD,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,EAAA,MAAM,EAAA,GAAK,MAAM,oBAAA,CAAqB,GAAG,CAAA;AACzC,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,SAAA,EAAY,EAAE,CAAA,eAAA,EAAkB,GAAG,CAAA,CAAE,CAAA;AAC9C,EAAA,MAAM,UAAA,CAAW,IAAI,CAAC,KAAA,EAAO,OAAO,CAAA,EAAG,EAAE,KAAK,CAAA;AAC9C,EAAA,GAAA,CAAI,QAAQ,iBAAiB,CAAA;AAC/B;ACSA,IAAM,aAAa,IAAA,CAAK,IAAA,CAAK,EAAA,CAAG,OAAA,IAAW,SAAS,CAAA;AACpD,IAAM,gBAAA,GAAmB,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,kBAAkB,CAAA;AACjE,IAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,YAAY,CAAA;AAC9C,IAAM,uBAAA,GAA0B,aAAA;AAEvC,eAAe,eAAA,GAAiC;AAC9C,EAAA,MAAMC,SAAG,KAAA,CAAM,UAAA,EAAY,EAAE,SAAA,EAAW,MAAM,CAAA;AAChD;AAEA,eAAe,YAAA,CAAgB,UAAkB,QAAA,EAAyB;AACxE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAMA,QAAA,CAAG,QAAA,CAAS,UAAU,MAAM,CAAA;AAC9C,IAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,EAA+B,IAAA,KAAS,QAAA,EAAU,OAAO,QAAA;AAC9D,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAEA,eAAe,aAAA,CAAc,UAAkB,IAAA,EAA8B;AAC3E,EAAA,MAAM,eAAA,EAAgB;AACtB,EAAA,MAAMA,QAAA,CAAG,UAAU,QAAA,EAAU,CAAA,EAAG,KAAK,SAAA,CAAU,IAAA,EAAM,IAAA,EAAM,CAAC,CAAC;AAAA,CAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAO,CAAA;AACpF;AAGO,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,OAAO,IAAA,CAAK,IAAA,EAAK,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACvC;AAEA,eAAsB,eAAA,GAAwC;AAC5D,EAAA,OAAO,YAAA,CAA0B,gBAAA,EAAkB,EAAE,CAAA;AACvD;AAEA,eAAsB,SAAS,IAAA,EAA2C;AACxE,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,EAAgB;AACpC,EAAA,OAAO,KAAA,CAAM,aAAA,CAAc,IAAI,CAAC,CAAA,EAAG,KAAA;AACrC;AAEA,eAAsB,SAAA,CAAU,MAAc,KAAA,EAA8B;AAC1E,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,EAAgB;AACpC,EAAA,KAAA,CAAM,aAAA,CAAc,IAAI,CAAC,CAAA,GAAI,EAAE,KAAA,EAAM;AACrC,EAAA,MAAM,aAAA,CAAc,kBAAkB,KAAK,CAAA;AAC7C;AAQA,eAAsB,SAAA,GAA+B;AACnD,EAAA,OAAO,YAAA,CAAuB,UAAA,EAAY,EAAE,CAAA;AAC9C;AAEA,eAAsB,WAAW,KAAA,EAAgC;AAC/D,EAAA,MAAM,aAAA,CAAc,YAAY,KAAK,CAAA;AACvC;AAEA,eAAsB,WAAA,GAA2C;AAC/D,EAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,EAAU;AAC9B,EAAA,OAAO,KAAA,CAAM,QAAA;AACf;AAEA,eAAsB,YAAY,IAAA,EAA6B;AAC7D,EAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,EAAU;AAC9B,EAAA,KAAA,CAAM,QAAA,GAAW,cAAc,IAAI,CAAA;AACnC,EAAA,MAAM,WAAW,KAAK,CAAA;AACxB;AAEO,SAAS,iBAAA,CAAkB,GAAA,GAAM,OAAA,CAAQ,GAAA,EAAI,EAAW;AAC7D,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,uBAAuB,CAAA;AAC/C;AAEA,eAAsB,iBAAA,CAAkB,GAAA,GAAM,OAAA,CAAQ,GAAA,EAAI,EAAkC;AAC1F,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,MAAMA,QAAA,CAAG,SAAS,iBAAA,CAAkB,GAAG,GAAG,MAAM,CAAA;AAC5D,IAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,EAA+B,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AAC9D,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAaO,SAAS,YAAY,IAAA,EAGL;AACrB,EAAA,MAAM,OAAO,IAAA,CAAK,OAAA,IAAW,QAAQ,GAAA,CAAI,UAAA,IAAc,KAAK,aAAA,EAAe,IAAA;AAC3E,EAAA,OAAO,IAAA,GAAO,aAAA,CAAc,IAAI,CAAA,GAAI,MAAA;AACtC;AAMA,eAAsB,aAAa,IAAA,EAA2C;AAC5E,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,OAAO,QAAQ,GAAA,CAAI,YAAA;AACjD,EAAA,OAAO,SAAS,IAAI,CAAA;AACtB;;;AClHA,eAAsB,cAAA,CAAe,IAAA,GAA0B,EAAC,EAA6B;AAC3F,EAAA,MAAM,aAAA,GAAgB,MAAM,iBAAA,EAAkB;AAC9C,EAAA,MAAM,OAAO,WAAA,CAAY,EAAE,SAAS,IAAA,CAAK,IAAA,EAAM,eAAe,CAAA;AAC9D,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,QAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,YAAA,CAAa,IAAI,CAAA;AACrC,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,EAAE,IAAA,EAAM,OAAO,CAAA;AAC9C,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAQ,aAAA,EAAc;AAC9C;AAEO,SAAS,aAAa,GAAA,EAA8B;AACzD,EAAA,IAAI,CAAC,IAAI,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,QAAA;AAAA,MACR,CAAA,iBAAA,EAAoB,GAAA,CAAI,IAAI,CAAA,2BAAA,EAA8B,IAAI,IAAI,CAAA,sBAAA;AAAA,KACpE;AAAA,EACF;AACA,EAAA,OAAO,GAAA,CAAI,KAAA;AACb;AAEO,SAAS,qBAAqB,GAAA,EAAqC;AACxE,EAAA,IAAI,CAAC,IAAI,aAAA,EAAe;AACtB,IAAA,MAAM,IAAI,SAAS,yEAAyE,CAAA;AAAA,EAC9F;AACA,EAAA,OAAO,GAAA,CAAI,aAAA;AACb;AAGA,eAAsB,eAAA,CAAgB,KAAsB,SAAA,EAAoC;AAC9F,EAAA,MAAM,EAAA,GAAK,MAAM,kBAAA,CAAmB,GAAA,EAAK,SAAS,CAAA;AAClD,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,MAAM,IAAI,QAAA;AAAA,MACR,CAAA,2BAAA,EAA8B,SAAS,CAAA,WAAA,EAAc,GAAA,CAAI,IAAI,CAAA,wCAAA;AAAA,KAC/D;AAAA,EACF;AACA,EAAA,OAAO,EAAA;AACT;AAGA,eAAsB,kBAAA,CACpB,KACA,SAAA,EACwB;AACxB,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,GAAA,CAAI,OAAO,WAAA,EAAY;AACjD,EAAA,OAAO,OAAA,CAAQ,KAAK,CAAC,CAAA,KAAM,EAAE,UAAA,KAAe,SAAS,GAAG,EAAA,IAAM,IAAA;AAChE;;;AClDA,eAAsB,cAAc,IAAA,EAAwD;AAC1F,EAAA,MAAM,SAAwB,EAAC;AAC/B,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AAExB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAC9C,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,iBAAA,EAAmB,IAAI,IAAA,EAAM,MAAA,EAAQ,GAAA,CAAI,IAAA,EAAM,CAAA;AAAA,EACrE,SAAS,GAAA,EAAK;AACZ,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,iBAAA,EAAmB,IAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,GAAG,CAAA;AAC5G,IAAA,OAAO,MAAA,CAAO,MAAA,EAAQ,IAAA,CAAK,IAAI,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,CAAC,IAAI,KAAA,EAAO;AACd,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,eAAA,EAAiB,IAAI,KAAA,EAAO,MAAA,EAAQ,oEAAoE,CAAA;AAAA,EAC9H,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,eAAA,EAAiB,IAAI,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,WAAmD,EAAC;AACxD,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,GAAK,MAAM,GAAA,CAAI,MAAA,CAAO,KAAA,EAAM;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,CAAA,oBAAA,EAAuB,EAAA,CAAG,WAAW,CAAA,CAAA,EAAI,CAAA;AACjG,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,aAAA,EAAe,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,EAAA,CAAG,KAAA,IAAS,EAAA,CAAG,OAAA,EAAS,CAAA;AAE7E,IAAA,MAAM,WAAA,GAAc,MAAM,GAAA,CAAI,MAAA,CAAO,YAAA,EAAa;AAClD,IAAA,QAAA,GAAW,WAAA,CAAY,QAAA;AACvB,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,mBAAA,EAAqB,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,QAAA,CAAS,MAAM,CAAA,iBAAA,CAAA,EAAqB,CAAA;AAAA,EACpG,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,KAAa,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,CAAA,EAAM;AACzE,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,aAAA,EAAe,IAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,CAAI,OAAA,EAAS,CAAA;AAAA,IACrE,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,IAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,GAAG,CAAA;AAAA,IAC7G;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAeD,IAAAA,CAAK,IAAA,CAAK,GAAA,EAAK,eAAe,CAAA;AACnD,EAAA,IAAI,mBAA6B,EAAC;AAClC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,KAAK,KAAA,CAAM,MAAMC,SAAG,QAAA,CAAS,YAAA,EAAc,MAAM,CAAC,CAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,oBAAoB,GAAG,CAAA;AACtC,IAAA,IAAI,OAAO,EAAA,EAAI;AACb,MAAA,gBAAA,GAAmB,OAAO,KAAA,CAAM,QAAA,CAAS,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AAC1D,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,CAAA,WAAA,EAAc,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,CAAA;AAAA,IAClG,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,IAAI,KAAA,EAAO,MAAA,EAAQ,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,IACzE;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,EAAA,EAAI,OAAO,MAAA,EAAQ,CAAA,4BAAA,EAA+B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,IAAI,CAAA;AAAA,EAC9I;AAEA,EAAA,MAAM,UAAA,GAAa,MAAM,iBAAA,CAAkB,GAAG,CAAA;AAC9C,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,UAAA,CAAW,KACP,EAAE,IAAA,EAAM,eAAe,EAAA,EAAI,IAAA,EAAM,QAAQ,CAAA,eAAA,EAAkB,UAAA,CAAW,MAAM,aAAa,CAAA,CAAA,KACzF,EAAE,IAAA,EAAM,eAAe,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,UAAA,CAAW,KAAA;AAAM,GACjE;AAEA,EAAA,IAAI,iBAAiB,MAAA,EAAQ;AAC3B,IAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AACjD,IAAA,MAAM,OAAA,GAAU,iBAAiB,MAAA,CAAO,CAAC,SAAS,CAAC,KAAA,CAAM,GAAA,CAAI,IAAI,CAAC,CAAA;AAClE,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,OAAA,CAAQ,MAAA,KAAW,CAAA,GACf,EAAE,IAAA,EAAM,kBAAkB,EAAA,EAAI,IAAA,EAAM,MAAA,EAAQ,gBAAA,CAAiB,IAAA,CAAK,IAAI,GAAE,GACxE,EAAE,IAAA,EAAM,gBAAA,EAAkB,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,CAAA,SAAA,EAAY,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAG,KACpF;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,MAAA,EAAQ,KAAK,IAAI,CAAA;AAC1B;AAEA,SAAS,MAAA,CAAO,QAAuB,IAAA,EAAsB;AAC3D,EAAA,MAAM,KAAK,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,EAAE,EAAE,CAAA;AACnC,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,EAAM,EAAE,EAAA,EAAI,MAAA,IAAU,MAAM;AACxC,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,EAAA,GAAK,QAAA,GAAM,QAAA;AAChC,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,EAAA,EAAK,KAAA,CAAM,MAAM,CAAA,CAAE,CAAA;AAAA,IACrD;AACA,IAAA,IAAI,EAAA,EAAI,GAAA,CAAI,OAAA,CAAQ,oBAAoB,CAAA;AAAA,SACnC,GAAA,CAAI,MAAM,qBAAqB,CAAA;AAAA,EACtC,CAAC,CAAA;AACD,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,EACrB;AACF;ACrEA,eAAsB,gBAAgB,IAAA,EAAsC;AAC1E,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,OAAA;AACrC,EAAA,IAAI,IAAA,CAAK,OAAO,OAAA,EAAS;AACvB,IAAA,MAAM,IAAI,SAAS,0CAA0C,CAAA;AAAA,EAC/D;AAEA,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,GAAA,EAAK,cAAc,UAAU,CAAA;AAEpE,EAAA,IAAI,OAAA,GAA6B,SAAA;AACjC,EAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,EAAA,IAAI,aAAA,GAA+B,IAAA;AACnC,EAAA,IAAI,cAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,eAAA;AAEJ,EAAA,IAAI;AACF,IAAA,IAAI,KAAK,GAAA,EAAK;AACZ,MAAA,OAAA,GAAU,KAAA;AACV,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,MAAA,CAAO,oBAAoB,QAAQ,CAAA;AAC5D,MAAA,KAAA,GAAQ,MAAA,CAAO,KAAA;AACf,MAAA,aAAA,GAAgB,MAAA,CAAO,aAAA;AACvB,MAAA,cAAA,GAAiB,MAAA,CAAO,cAAA;AACxB,MAAA,eAAA,GAAkB,CAAA,EAAG,cAAc,UAAU,CAAA,QAAA,CAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,MAAM,EAAE,QAAQ,eAAA,EAAgB,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,UAAU,QAAQ,CAAA;AACvE,MAAA,IAAI,SAAA,GAAY,eAAA,EAAiB,EAAA,IAAM,MAAA,CAAO,kBAAA;AAC9C,MAAA,YAAA,GAAe,iBAAiB,OAAA,IAAW,IAAA;AAC3C,MAAA,aAAA,GAAgB,iBAAiB,cAAA,IAAkB,IAAA;AACnD,MAAA,cAAA,GAAiB,iBAAiB,eAAA,IAAmB,IAAA;AAErD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,aAAa,QAAQ,CAAA;AAC3D,QAAA,MAAM,MAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,OAAO,CAAA;AACtD,QAAA,IAAI,CAAC,GAAA,EAAK;AACR,UAAA,MAAM,IAAI,QAAA;AAAA,YACR,YAAY,OAAO,CAAA,gBAAA,EAAmB,cAAc,UAAU,CAAA,IAAA,EAAO,IAAI,IAAI,CAAA,wBAAA;AAAA,WAC/E;AAAA,QACF;AACA,QAAA,SAAA,GAAY,GAAA,CAAI,EAAA;AAChB,QAAA,YAAA,GAAe,GAAA,CAAI,OAAA;AACnB,QAAA,aAAA,GAAgB,IAAI,cAAA,IAAkB,IAAA;AACtC,QAAA,cAAA,GAAiB,GAAA,CAAI,eAAA;AAAA,MACvB;AAEA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,MAAM,IAAI,SAAS,CAAA,QAAA,EAAW,aAAA,CAAc,UAAU,CAAA,4BAAA,EAA+B,GAAA,CAAI,IAAI,CAAA,KAAA,CAAO,CAAA;AAAA,MACtG;AAEA,MAAA,MAAM,SAAS,MAAM,GAAA,CAAI,MAAA,CAAO,uBAAA,CAAwB,UAAU,SAAS,CAAA;AAC3E,MAAA,KAAA,GAAQ,MAAA,CAAO,KAAA;AACf,MAAA,IAAI,MAAA,CAAO,YAAA,EAAc,YAAA,GAAe,MAAA,CAAO,YAAA;AAC/C,MAAA,IAAI,MAAA,CAAO,aAAA,EAAe,aAAA,GAAgB,MAAA,CAAO,aAAA;AACjD,MAAA,IAAI,MAAA,CAAO,cAAA,EAAgB,cAAA,GAAiB,MAAA,CAAO,cAAA;AACnD,MAAA,eAAA,GAAkB,CAAA,EAAG,aAAA,CAAc,UAAU,CAAA,EAAA,EAAK,gBAAgB,SAAS,CAAA,IAAA,CAAA;AAAA,IAC7E;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,KAAa,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,CAAA,EAAM;AACzE,MAAA,MAAM,IAAI,QAAA;AAAA,QACR,CAAA,sCAAA,EAAyC,IAAI,IAAI,CAAA,wCAAA;AAAA,OACnD;AAAA,IACF;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,MAAM,UAAA,GAAaD,IAAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,EAAI,EAAG,IAAA,CAAK,MAAA,IAAUA,IAAAA,CAAK,IAAA,CAAK,SAAA,EAAW,KAAA,EAAO,eAAe,CAAC,CAAA;AAC1G,EAAA,MAAMC,QAAAA,CAAG,MAAMD,IAAAA,CAAK,OAAA,CAAQ,UAAU,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AAC5D,EAAA,MAAMC,QAAAA,CAAG,SAAA,CAAU,UAAA,EAAY,KAAK,CAAA;AAEpC,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,EAAA,EAAI,IAAA;AAAA,IACJ,MAAM,GAAA,CAAI,IAAA;AAAA,IACV,YAAY,aAAA,CAAc,UAAA;AAAA,IAC1B,OAAA;AAAA,IACA,OAAA,EAAS,YAAA;AAAA,IACT,cAAA,EAAgB,aAAA;AAAA,IAChB,eAAA,EAAiB,cAAA;AAAA,IACjB,OAAO,KAAA,CAAM,UAAA;AAAA,IACb,IAAA,EAAM;AAAA,GACR;AAEA,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,OAAA,EAAS,CAAC,IAAA,KAAS;AAC1C,IAAA,GAAA,CAAI,OAAA,CAAQ,CAAA,WAAA,EAAc,IAAA,CAAK,UAAU,GAAG,IAAA,CAAK,OAAA,GAAU,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,CAAA,CAAA,GAAK,QAAQ,CAAA,QAAA,EAAM,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AACzG,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC3C,IAAA,IAAI,KAAK,cAAA,EAAgB,GAAA,CAAI,KAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,cAAc,CAAA,CAAE,CAAA;AAC7E,IAAA,IAAI,KAAK,eAAA,EAAiB,GAAA,CAAI,KAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,eAAe,CAAA,CAAE,CAAA;AAAA,EACjF,CAAC,CAAA;AACH;;;ACzGA,eAAsB,YAAY,IAAA,EAAyC;AACzE,EAAA,MAAM,IAAA,GAAO,IAAA,GAAO,CAAC,IAAI,IAAI,EAAC;AAC9B,EAAA,GAAA,CAAI,KAAK,+CAA+C,CAAA;AACxD,EAAA,MAAM,WAAW,KAAA,EAAO,CAAC,sBAAA,EAAwB,GAAG,IAAI,CAAC,CAAA;AAC3D;ACPA,eAAsB,aAAa,IAAA,EAAwD;AACzF,EAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,IAAA,MAAM,IAAI,SAAS,4EAA4E,CAAA;AAAA,EACjG;AACA,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AAEpC,EAAA,IAAI,QAAQ,IAAA,CAAK,KAAA;AACjB,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,QAAA,GAAW,MAAMC,QAAA,CAAQ;AAAA,MAC7B,IAAA,EAAM,UAAA;AAAA,MACN,IAAA,EAAM,OAAA;AAAA,MACN,OAAA,EAAS,6BAA6B,IAAI,CAAA;AAAA,KAC3C,CAAA;AACD,IAAA,KAAA,GAAQ,OAAO,QAAA,CAAS,KAAA,KAAU,WAAW,QAAA,CAAS,KAAA,CAAM,MAAK,GAAI,EAAA;AAAA,EACvE;AACA,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,SAAS,oBAAoB,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,EAAE,IAAA,EAAM,OAAO,CAAA;AAC9C,EAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,KAAA,EAAM;AAE9B,EAAA,MAAM,SAAA,CAAU,MAAM,KAAK,CAAA;AAE3B,EAAA,GAAA,CAAI,OAAA,CAAQ,CAAA,aAAA,EAAgB,IAAI,CAAA,CAAE,CAAA;AAClC,EAAA,GAAA,CAAI,KAAK,CAAA,SAAA,EAAY,EAAA,CAAG,KAAA,IAAS,EAAA,CAAG,OAAO,CAAA,CAAE,CAAA;AAC7C,EAAA,GAAA,CAAI,KAAK,CAAA,SAAA,EAAY,EAAA,CAAG,iBAAA,IAAqB,EAAA,CAAG,eAAe,CAAA,CAAE,CAAA;AACjE,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,SAAA,EAAY,EAAA,CAAG,WAAW,CAAA,CAAE,CAAA;AACvC;AC7BA,eAAsB,YAAY,IAAA,EAAwC;AACxE,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAC9C,EAAA,IAAI,CAAC,cAAc,UAAA,EAAY;AAC7B,IAAA,MAAM,IAAI,SAAS,6CAA6C,CAAA;AAAA,EAClE;AAEA,EAAA,MAAM,MAAM,CAAA,EAAG,GAAA,CAAI,IAAI,CAAA,GAAA,EAAM,cAAc,UAAU,CAAA,CAAA;AACrD,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAW,GAAG,CAAA,CAAE,CAAA;AACzB,EAAA,MAAM,KAAK,GAAG,CAAA;AAChB;ACFA,eAAsB,cAAA,CAAe,GAAA,GAAM,OAAA,CAAQ,GAAA,EAAI,EAA0B;AAC/E,EAAA,MAAM,MAAA,GAAS,MAAM,UAAA,CAAW,EAAE,KAAK,CAAA;AACvC,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,IAAA,MAAM,IAAI,QAAA,CAAS,CAAA,aAAA,EAAgB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EACnD;AAEA,EAAA,MAAM,MAAA,GAASF,IAAAA,CAAK,IAAA,CAAK,GAAA,EAAK,WAAW,KAAK,CAAA;AAC9C,EAAA,MAAMC,SAAG,KAAA,CAAM,MAAA,EAAQ,EAAE,SAAA,EAAW,MAAM,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAaD,KAAK,IAAA,CAAK,MAAA,EAAQ,GAAG,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,IAAA,CAAM,CAAA;AACpE,EAAA,MAAMC,QAAAA,CAAG,SAAA,CAAU,UAAA,EAAY,MAAA,CAAO,MAAM,MAAM,CAAA;AAElD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA;AAAA,IACxB,aAAA,EAAe,OAAO,KAAA,CAAM,aAAA;AAAA,IAC5B,SAAA,EAAW,OAAO,KAAA,CAAM,SAAA;AAAA,IACxB;AAAA,GACF;AACF;AAEA,eAAsB,YAAY,IAAA,EAAuD;AACvF,EAAA,MAAM,SAAS,MAAM,cAAA,CAAe,KAAK,GAAA,IAAO,OAAA,CAAQ,KAAK,CAAA;AAC7D,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,CAAC,IAAA,KAAS;AACzC,IAAA,GAAA,CAAI,OAAA,CAAQ,UAAU,IAAA,CAAK,SAAS,KAAK,WAAA,CAAY,IAAA,CAAK,SAAS,CAAC,CAAA,CAAA,CAAG,CAAA;AACvE,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,kBAAA,EAAqB,IAAA,CAAK,aAAa,CAAA,CAAE,CAAA;AAClD,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,kBAAA,EAAqB,IAAA,CAAK,UAAU,CAAA,CAAE,CAAA;AAAA,EACjD,CAAC,CAAA;AACH;ACTA,IAAM,4BAAA,GAA+B,EAAA;AAErC,eAAsB,YAAY,IAAA,EAAkC;AAClE,EAAA,MAAM,aAAA,GAAgB,MAAM,iBAAA,EAAkB;AAC9C,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,MAAM,IAAI,SAAS,yEAAyE,CAAA;AAAA,EAC9F;AAEA,EAAA,MAAM,OAAO,WAAA,CAAY,EAAE,SAAS,IAAA,CAAK,IAAA,EAAM,eAAe,CAAA;AAC9D,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,SAAS,gFAAgF,CAAA;AAAA,EACrG;AAEA,EAAA,IAAI,KAAK,UAAA,IAAc,aAAA,CAAc,IAAA,CAAK,UAAU,MAAM,IAAA,EAAM;AAC9D,IAAA,MAAM,UAAU,CAAA,cAAA,EAAiB,IAAI,iCAAiC,aAAA,CAAc,IAAA,CAAK,UAAU,CAAC,CAAA,CAAA,CAAA;AACpG,IAAA,IAAI,KAAK,IAAA,EAAM;AACb,MAAA,OAAA,CAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,OAAO,KAAA,EAAO,eAAA,EAAiB,IAAA,EAAM,QAAA,EAAU,cAAc,IAAA,CAAK,UAAU,GAAE,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAC1H,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACnB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAI,SAAS,OAAO,CAAA;AAAA,EAC5B;AAEA,EAAA,MAAM,KAAA,GAAQ,MAAM,YAAA,CAAa,IAAI,CAAA;AACrC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,QAAA,CAAS,CAAA,iBAAA,EAAoB,IAAI,CAAA,2BAAA,EAA8B,IAAI,CAAA,QAAA,CAAU,CAAA;AAAA,EACzF;AACA,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,EAAE,IAAA,EAAM,OAAO,CAAA;AAE9C,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,KAAA,EAAM;AAC9B,IAAA,OAAA,GAAU,EAAA,CAAG,qBAAqB,EAAA,CAAG,eAAA;AAAA,EACvC,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,GAAA,CAAI,IAAA,CAAK,iBAAiB,IAAI,CAAA,EAAG,UAAU,CAAA,OAAA,EAAU,OAAO,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,CAAE,CAAA;AAEtE,EAAA,MAAM,QAAA,GAAW,MAAM,WAAA,EAAY;AACnC,EAAA,IAAI,QAAA,IAAY,aAAa,IAAA,EAAM;AACjC,IAAA,IAAI,KAAK,IAAA,EAAM;AAGb,MAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACb,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,IAAA,CAAK,SAAA;AAAA,YACH,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,cAAA,EAAgB,IAAA,EAAM,WAAW,QAAA,EAAS;AAAA,YAC9D,IAAA;AAAA,YACA;AAAA;AACF,SACF;AACA,QAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACnB,QAAA;AAAA,MACF;AAAA,IACF,CAAA,MAAA,IAAW,CAAC,IAAA,CAAK,GAAA,EAAK;AACpB,MAAA,MAAM,QAAA,GAAW,MAAMC,QAAAA,CAAQ;AAAA,QAC7B,IAAA,EAAM,SAAA;AAAA,QACN,IAAA,EAAM,SAAA;AAAA,QACN,OAAA,EAAS,CAAA,iBAAA,EAAoB,QAAQ,CAAA,yBAAA,EAA4B,IAAI,CAAA,CAAA,CAAA;AAAA,QACrE,OAAA,EAAS;AAAA,OACV,CAAA;AACD,MAAA,IAAI,CAAC,SAAS,OAAA,EAAS;AACrB,QAAA,GAAA,CAAI,KAAK,iBAAiB,CAAA;AAC1B,QAAA;AAAA,MACF;AAAA,IACF,CAAA,MAAO;AACL,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,kBAAA,EAAqB,QAAQ,CAAA,IAAA,EAAO,IAAI,CAAA,8BAAA,CAAgC,CAAA;AAAA,IACnF;AAAA,EACF;AAEA,EAAA,IAAI,KAAK,GAAA,EAAK;AACZ,IAAA,MAAM,QAAA,GAAW,MAAM,uBAAA,CAAwB;AAAA,MAC7C,MAAA;AAAA,MACA,aAAA;AAAA,MACA,gBAAA,EAAA,CAAmB,MAAM,MAAA,CAAO,MAAM,IAAI,KAAA,IAAS,IAAA;AAAA,MACnD,KAAA,EAAO,CAAC,CAAC,IAAA,CAAK;AAAA,KACf,CAAA;AACD,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAI,KAAK,IAAA,EAAM;AACb,QAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,sBAAA,EAAwB,IAAA,EAAM,QAAA,EAAS,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AACjG,QAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACnB,QAAA;AAAA,MACF;AACA,MAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACf,QAAA,MAAM,QAAA,GAAW,MAAMA,QAAAA,CAAQ;AAAA,UAC7B,IAAA,EAAM,SAAA;AAAA,UACN,IAAA,EAAM,SAAA;AAAA,UACN,OAAA,EAAS,CAAA,gCAAA,EAAmC,QAAA,CAAS,gBAAA,IAAoB,cAAc,IAAI,QAAA,CAAS,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAC,CAAA,wBAAA,CAAA;AAAA,UAC1H,OAAA,EAAS;AAAA,SACV,CAAA;AACD,QAAA,IAAI,CAAC,SAAS,OAAA,EAAS;AACrB,UAAA,GAAA,CAAI,KAAK,wCAAwC,CAAA;AACjD,UAAA;AAAA,QACF;AAAA,MACF,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,KAAK,2DAA2D,CAAA;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,MAAM,WAAWF,IAAAA,CAAK,OAAA,CAAQ,QAAQ,GAAA,EAAI,EAAG,KAAK,IAAI,CAAA;AACtD,IAAA,IAAI;AACF,MAAA,SAAA,GAAY,MAAMC,QAAAA,CAAG,QAAA,CAAS,QAAQ,CAAA;AAAA,IACxC,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,QAAA;AAAA,QACR,CAAA,sBAAA,EAAyB,QAAQ,CAAA,EAAA,EAAK,GAAA,YAAe,QAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,OACxF;AAAA,IACF;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,uBAAA,CAAwB,SAAS,CAAA;AACzD,IAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACjB,MAAA,MAAM,IAAI,SAAS,CAAA,oBAAA,EAAuB,IAAA,CAAK,IAAI,CAAA,GAAA,EAAM,SAAA,CAAU,KAAK,CAAA,CAAE,CAAA;AAAA,IAC5E;AACA,IAAA,IAAI,SAAA,CAAU,KAAA,CAAM,SAAA,KAAc,aAAA,CAAc,UAAA,EAAY;AAC1D,MAAA,MAAM,IAAI,QAAA;AAAA,QACR,mBAAmB,SAAA,CAAU,KAAA,CAAM,SAAS,CAAA,8BAAA,EAAiC,cAAc,UAAU,CAAA,EAAA;AAAA,OACvG;AAAA,IACF;AACA,IAAA,WAAA,GAAcD,IAAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,CAAE,SAAS,MAAM,CAAA,GACjDA,IAAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,GACtB,CAAA,EAAG,SAAA,CAAU,MAAM,SAAS,CAAA,IAAA,CAAA;AAChC,IAAA,GAAA,CAAI,KAAK,CAAA,mBAAA,EAAsB,QAAQ,oBAAoB,SAAA,CAAU,KAAA,CAAM,aAAa,CAAA,CAAA,CAAG,CAAA;AAAA,EAC7F,CAAA,MAAO;AACL,IAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,OAAA,CAAQ,KAAK,CAAA;AACjD,IAAA,SAAA,GAAY,MAAMC,QAAAA,CAAG,QAAA,CAAS,MAAA,CAAO,UAAU,CAAA;AAC/C,IAAA,WAAA,GAAc,CAAA,EAAG,OAAO,SAAS,CAAA,IAAA,CAAA;AAAA,EACnC;AAEA,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,EAAA,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,IAAI,IAAA,CAAK,CAAC,SAAS,CAAA,EAAG,EAAE,IAAA,EAAM,iBAAA,EAAmB,CAAA,EAAG,WAAW,CAAA;AAChF,EAAA,IAAI,KAAK,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,KAAK,SAAS,CAAA;AACxD,EAAA,IAAA,CAAK,IAAI,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,QAAA,KAAa,KAAK,CAAC,CAAA;AACvD,EAAA,IAAI,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,WAAW,KAAK,CAAA;AAEvC,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAM,MAAA,CAAO,YAAA,CAAa,IAAI,CAAA;AAAA,EACzC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,MAAA,IAAI,KAAK,IAAA,EAAM;AACb,QAAA,OAAA,CAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,OAAO,KAAA,EAAO,GAAA,CAAI,IAAA,IAAQ,eAAA,EAAiB,SAAS,GAAA,CAAI,OAAA,EAAS,MAAK,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAClH,QAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACnB,QAAA;AAAA,MACF;AACA,MAAA,IAAI,GAAA,CAAI,IAAA,KAAS,kBAAA,IAAsB,IAAA,CAAK,GAAA,EAAK;AAC/C,QAAA,MAAM,IAAI,QAAA;AAAA,UACR,CAAA,QAAA,EAAW,aAAA,CAAc,UAAU,CAAA,oBAAA,EAAuB,IAAI,CAAA,0GAAA;AAAA,SAChE;AAAA,MACF;AACA,MAAA,MAAM,IAAI,QAAA,CAAS,CAAA,eAAA,EAAkB,GAAA,CAAI,OAAO,CAAA,CAAE,CAAA;AAAA,IACpD;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,MAAM,YAAY,IAAI,CAAA;AAEtB,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAM,GAAG,MAAA,EAAO,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAClE,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,YAAY,KAAA,EAAO;AAC5B,IAAA,GAAA,CAAI,QAAQ,CAAA,OAAA,EAAU,MAAA,CAAO,OAAO,UAAU,CAAA,uBAAA,EAA0B,IAAI,CAAA,CAAE,CAAA;AAC9E,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,kBAAA,EAAqB,MAAA,CAAO,WAAA,CAAY,cAAc,CAAA,CAAE,CAAA;AACjE,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,kBAAA,EAAqB,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA,CAAE,CAAA;AAAA,EAC/D,CAAA,MAAO;AACL,IAAA,GAAA,CAAI,OAAA,CAAQ,CAAA,OAAA,EAAU,MAAA,CAAO,MAAA,CAAO,UAAU,CAAA,CAAA,EAAI,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,IAAA,EAAO,IAAI,CAAA,CAAE,CAAA;AACrF,IAAA,GAAA,CAAI,KAAK,CAAA,kBAAA,EAAqB,MAAA,CAAO,OAAA,CAAQ,cAAA,IAAkB,OAAO,CAAA,CAAE,CAAA;AACxE,IAAA,IAAI,OAAO,MAAA,EAAQ,GAAA,CAAI,IAAI,CAAA,EAAA,EAAK,MAAA,CAAO,MAAM,CAAA,CAAE,CAAA;AAAA,EACjD;AACF;AAEA,eAAe,OAAO,MAAA,EAA4C;AAChE,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,OAAO,KAAA,EAAM;AAAA,EAC5B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,eAAe,wBAAwB,IAAA,EAK0D;AAC/F,EAAA,IAAI,IAAA,CAAK,OAAO,OAAO,IAAA;AACvB,EAAA,MAAM,WAAW,MAAM,qBAAA,CAAsB,KAAK,MAAA,EAAQ,IAAA,CAAK,cAAc,UAAU,CAAA;AACvF,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAEtB,EAAA,IAAI,UAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,cAAc,QAAQ,CAAA;AACpD,IAAA,UAAA,GAAa,GAAA,CAAI,WAAA;AAAA,EACnB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,KAAa,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,CAAA,EAAM;AAGzE,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACA,EAAA,IAAI,CAAC,UAAA,EAAY,UAAA,EAAY,OAAO,IAAA;AAEpC,EAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,aAAA,CAAc,oBAAA,IAAwB,4BAAA;AAClE,EAAA,MAAM,UAAA,GAAa,YAAA,CAAa,UAAA,CAAW,UAAU,CAAA;AACrD,EAAA,MAAM,QAAA,GACJ,CAAC,CAAC,IAAA,CAAK,oBACP,CAAC,CAAC,UAAA,CAAW,gBAAA,IACb,WAAW,gBAAA,CAAiB,WAAA,EAAY,KAAM,IAAA,CAAK,iBAAiB,WAAA,EAAY;AAElF,EAAA,IAAI,CAAC,QAAA,IAAY,UAAA,IAAc,cAAA,EAAgB;AAC7C,IAAA,OAAO,EAAE,kBAAkB,UAAA,CAAW,gBAAA,IAAoB,MAAM,UAAA,EAAY,UAAA,CAAW,UAAA,EAAY,WAAA,EAAa,UAAA,EAAW;AAAA,EAC7H;AACA,EAAA,OAAO,IAAA;AACT;AAEA,eAAe,qBAAA,CACb,QACA,SAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,OAAO,WAAA,EAAY;AAC7C,IAAA,OAAO,OAAA,CAAQ,KAAK,CAAC,CAAA,KAAM,EAAE,UAAA,KAAe,SAAS,GAAG,EAAA,IAAM,IAAA;AAAA,EAChE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;AChQA,eAAsB,eAAA,CACpB,SACA,IAAA,EACe;AACf,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,GAAA,EAAK,cAAc,UAAU,CAAA;AAEpE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,aAAa,QAAQ,CAAA;AAC3D,EAAA,MAAM,QAAQ,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,OAAO,CAAA;AACxD,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,QAAA;AAAA,MACR,eAAe,OAAO,CAAA,YAAA,EAAe,cAAc,UAAU,CAAA,IAAA,EAAO,IAAI,IAAI,CAAA,mDAAA;AAAA,KAC9E;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,MAAM,GAAA,CAAI,OAAO,eAAA,CAAgB,QAAA,EAAU,MAAM,EAAE,CAAA;AAElE,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,EAAE,MAAM,GAAA,CAAI,IAAA,EAAM,UAAA,EAAY,aAAA,CAAc,YAAY,OAAA,EAAS,GAAG,MAAA,EAAO,EAAG,CAAC,IAAA,KAAS;AAC/G,IAAA,GAAA,CAAI,OAAA,CAAQ,aAAa,IAAA,CAAK,UAAU,IAAI,OAAO,CAAA,IAAA,EAAO,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AAAA,EACvE,CAAC,CAAA;AACH;;;ACtBA,SAAS,UAAA,CAAW,OAA2B,IAAA,EAAmC;AAChF,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAChC,EAAA,MAAM,UAAA,GAAa,MAAM,WAAA,EAAY;AACrC,EAAA,IAAI,UAAA,KAAe,MAAM,OAAO,IAAA;AAChC,EAAA,IAAI,UAAA,KAAe,OAAO,OAAO,KAAA;AACjC,EAAA,MAAM,IAAI,QAAA,CAAS,CAAA,EAAG,IAAI,CAAA,uBAAA,CAAyB,CAAA;AACrD;AAEA,eAAsB,gBAAgB,IAAA,EAMpB;AAChB,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,GAAA,EAAK,cAAc,UAAU,CAAA;AAEpE,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,CAAK,KAAA,EAAO,SAAS,CAAA;AAC9C,EAAA,MAAM,UAAA,GAAa,UAAA,CAAW,IAAA,CAAK,UAAA,EAAY,eAAe,CAAA;AAI9D,EAAA,IAAI,OAAO,IAAA,CAAK,IAAA;AAChB,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,EAAE,cAAAE,aAAAA,EAAa,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,eAAe,QAAQ,CAAA;AACjE,IAAA,IAAA,GAAOA,aAAAA,EAAc,cAAc,aAAA,CAAc,UAAA;AAAA,EACnD;AACA,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,SAAS,+EAA+E,CAAA;AAAA,EACpG;AAEA,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,eAAe,QAAA,EAAU;AAAA,IACjE,UAAA,EAAY,IAAA;AAAA,IACZ,sBAAA,EAAwB,KAAA;AAAA,IACxB,mBAAA,EAAqB;AAAA,GACtB,CAAA;AAED,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,UAAA,EAAY,aAAA,CAAc,UAAA,EAAY,YAAA,EAAa,EAAG,CAAC,IAAA,KAAS;AACzG,IAAA,MAAM,KAAK,IAAA,CAAK,YAAA;AAChB,IAAA,MAAM,MAAA,GAAS,EAAA,GACX,CAAA,QAAA,EAAW,EAAA,CAAG,sBAAA,GAAyB,IAAA,GAAO,KAAK,CAAA,cAAA,EAAiB,EAAA,CAAG,mBAAA,GAAsB,IAAA,GAAO,KAAK,CAAA,CAAA,CAAA,GACzG,EAAA;AACJ,IAAA,GAAA,CAAI,OAAA;AAAA,MACF,CAAA,yBAAA,EAA4B,KAAK,UAAU,CAAA,IAAA,EAAO,KAAK,IAAI,CAAA,KAAA,EAAQ,EAAA,EAAI,UAAU,CAAA,CAAA,GAAK;AAAA,KACxF;AAAA,EACF,CAAC,CAAA;AACH;AC/CA,eAAsB,cAAc,IAAA,EAAuE;AACzG,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAE9C,EAAA,MAAM,KAAA,GAAQ,MAAMC,iBAAAA,CAAkB,OAAA,CAAQ,KAAK,CAAA;AACnD,EAAA,IAAI,CAAC,MAAM,EAAA,EAAI;AACb,IAAA,MAAM,IAAI,QAAA,CAAS,CAAA,gCAAA,EAAmC,KAAA,CAAM,KAAK,CAAA,CAAE,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,kBAAA,CAAmB,GAAA,EAAK,cAAc,UAAU,CAAA;AACvE,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM;AAAA,MAC9B,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,YAAY,aAAA,CAAc,UAAA;AAAA,MAC1B,oBAAA,EAAsB,MAAM,KAAA,CAAM,aAAA;AAAA,MAClC,KAAA,EAAO;AAAA,KACT,EAAG,CAAC,IAAA,KAAS;AACX,MAAA,GAAA,CAAI,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,UAAU,CAAA,yBAAA,EAA4B,IAAA,CAAK,IAAI,CAAA,KAAA,CAAO,CAAA;AACxE,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,wBAAA,EAA2B,IAAA,CAAK,oBAAoB,CAAA,CAAE,CAAA;AAAA,IACjE,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,EAAA,IAAI,aAAA,GAA+B,IAAA;AACnC,EAAA,IAAI,cAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,SAAA,GAA2B,IAAA;AAC/B,EAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,EAAA,IAAI;AACF,IAAA,IAAI,KAAK,GAAA,EAAK;AACZ,MAAA,MAAM,EAAE,WAAA,EAAY,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,cAAc,QAAQ,CAAA;AAC/D,MAAA,YAAA,GAAe,aAAa,cAAA,IAAkB,IAAA;AAC9C,MAAA,aAAA,GAAgB,IAAA;AAChB,MAAA,cAAA,GAAiB,aAAa,gBAAA,IAAoB,IAAA;AAClD,MAAA,SAAA,GAAY,aAAa,UAAA,IAAc,IAAA;AAAA,IACzC,CAAA,MAAO;AACL,MAAA,MAAM,EAAE,eAAA,EAAgB,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,UAAU,QAAQ,CAAA;AAC/D,MAAA,YAAA,GAAe,iBAAiB,cAAA,IAAkB,IAAA;AAClD,MAAA,aAAA,GAAgB,iBAAiB,OAAA,IAAW,IAAA;AAAA,IAC9C;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,KAAa,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,CAAA,EAAM;AACzE,MAAA,aAAA,GAAgB,IAAA;AAAA,IAClB,CAAA,MAAO;AACL,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,CAAC,aAAA,IAAiB,iBAAiB,IAAA,IAAQ,YAAA,KAAiB,MAAM,KAAA,CAAM,aAAA;AAEvF,EAAA,WAAA;AAAA,IACE,CAAC,CAAC,IAAA,CAAK,IAAA;AAAA,IACP;AAAA,MACE,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,OAAA,EAAS,IAAA,CAAK,GAAA,GAAM,KAAA,GAAQ,SAAA;AAAA,MAC5B,YAAY,aAAA,CAAc,UAAA;AAAA,MAC1B,oBAAA,EAAsB,MAAM,KAAA,CAAM,aAAA;AAAA,MAClC,qBAAA,EAAuB,YAAA;AAAA,MACvB,cAAA,EAAgB,aAAA;AAAA,MAChB,OAAA,EAAS,MAAA;AAAA,MACT,wBAAA,EAA0B,aAAA;AAAA,MAC1B,GAAI,KAAK,GAAA,GACL;AAAA,QACE,gBAAA,EAAkB,cAAA;AAAA,QAClB,UAAA,EAAY;AAAA,UAEd;AAAC,KACP;AAAA,IACA,CAAC,IAAA,KAAS;AACR,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAW,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AAC/B,MAAA,GAAA,CAAI,KAAK,CAAA,QAAA,EAAW,IAAA,CAAK,UAAU,CAAA,EAAA,EAAK,IAAA,CAAK,OAAO,CAAA,SAAA,CAAW,CAAA;AAC/D,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAW,IAAA,CAAK,oBAAoB,CAAA,CAAE,CAAA;AAC/C,MAAA,IAAI,KAAK,wBAAA,EAA0B;AACjC,QAAA,GAAA,CAAI,IAAA;AAAA,UACF,CAAA,+BAAA,EACE,IAAA,CAAK,GAAA,GAAM,aAAA,GAAgB,eAC7B,CAAA,8CAAA;AAAA,SACF;AACA,QAAA;AAAA,MACF;AACA,MAAA,GAAA,CAAI,IAAA,CAAK,CAAA,QAAA,EAAW,IAAA,CAAK,qBAAA,IAAyB,QAAQ,CAAA,EAAG,IAAA,CAAK,cAAA,GAAiB,CAAA,GAAA,EAAM,IAAA,CAAK,cAAc,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,CAAE,CAAA;AACtH,MAAA,IAAI,KAAK,GAAA,EAAK;AACZ,QAAA,GAAA,CAAI,IAAA,CAAK,CAAA,YAAA,EAAe,IAAA,CAAK,gBAAA,IAAoB,WAAW,CAAA,CAAE,CAAA;AAC9D,QAAA,GAAA,CAAI,IAAA,CAAK,CAAA,YAAA,EAAe,IAAA,CAAK,UAAA,IAAc,QAAQ,CAAA,CAAE,CAAA;AAAA,MACvD;AACA,MAAA,IAAI,IAAA,CAAK,OAAA,EAAS,GAAA,CAAI,OAAA,CAAQ,aAAa,CAAA;AAAA,WACtC,GAAA,CAAI,KAAK,8EAA8E,CAAA;AAAA,IAC9F;AAAA,GACF;AACF;AC3FA,eAAsB,gBAAgB,IAAA,EAAuD;AAC3F,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACpC,EAAA,MAAM,MAAA,GAAS,MAAMA,iBAAAA,CAAkB,GAAG,CAAA;AAE1C,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,IAAA,IAAI,KAAK,IAAA,EAAM;AACb,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,MAAA,CAAO,KAAA,EAAM,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AACvE,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACnB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAI,QAAA,CAAS,CAAA,mBAAA,EAAsB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EACzD;AAEA,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,EAAE,EAAA,EAAI,IAAA,EAAM,GAAG,MAAA,CAAO,KAAA,EAAM,EAAG,CAAC,IAAA,KAAS;AAChE,IAAA,GAAA,CAAI,QAAQ,kBAAkB,CAAA;AAC9B,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,SAAS,CAAA,CAAE,CAAA;AAC/C,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,aAAa,CAAA,CAAE,CAAA;AAAA,EACrD,CAAC,CAAA;AACH;;;ACjBA,eAAsB,gBAAgB,IAAA,EAAwD;AAC5F,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,aAAA,GAAgB,qBAAqB,GAAG,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,GAAA,EAAK,cAAc,UAAU,CAAA;AAEpE,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,GAAA,CAAI,MAAA,CAAO,aAAa,QAAQ,CAAA;AAC3D,IAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,UAAA,EAAY,aAAA,CAAc,UAAA,EAAY,QAAA,EAAS,EAAG,CAAC,IAAA,KAAS;AACrG,MAAA,KAAA,MAAW,CAAA,IAAK,KAAK,QAAA,EAAU;AAC7B,QAAA,GAAA,CAAI,KAAK,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,EAAA,EAAK,CAAA,CAAE,kBAAkB,EAAE,CAAA,EAAA,EAAK,EAAE,UAAU,CAAA,EAAG,EAAE,SAAA,GAAY,CAAA,EAAA,EAAK,EAAE,SAAS,CAAA,CAAA,GAAK,EAAE,CAAA,CAAE,CAAA;AAAA,MAC7G;AAAA,IACF,CAAC,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,eAAe,QAAA,KAAa,GAAA,CAAI,WAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,CAAA,EAAM;AACzE,MAAA,MAAM,IAAI,QAAA;AAAA,QACR,CAAA,0BAAA,EAA6B,QAAQ,CAAA,gCAAA,EAAmC,GAAA,CAAI,IAAI,CAAA,KAAA;AAAA,OAClF;AAAA,IACF;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;ACZA,eAAsB,aAAa,IAAA,EAAmC;AACpE,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,EAAA,MAAM,MAAA,GAASJ,IAAAA,CAAK,IAAA,CAAK,GAAA,EAAK,KAAK,CAAA;AAEnC,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,MAAM,WAAW,YAAY;AAC3B,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,OAAA,GAAU,IAAA;AACV,MAAA;AAAA,IACF;AACA,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,KAAK,eAAe,CAAA;AACxB,MAAA,MAAM,YAAA,EAAa;AAEnB,MAAA,GAAA,CAAI,KAAK,eAAe,CAAA;AACxB,MAAA,MAAM,MAAA,GAAS,MAAMI,iBAAAA,CAAkB,GAAG,CAAA;AAC1C,MAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,QAAA,GAAA,CAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAC9C,QAAA;AAAA,MACF;AACA,MAAA,GAAA,CAAI,OAAA,CAAQ,CAAA,uBAAA,EAA0B,MAAA,CAAO,KAAA,CAAM,aAAa,CAAA,CAAA,CAAG,CAAA;AAEnE,MAAA,IAAI,KAAK,IAAA,EAAM;AACb,QAAA,GAAA,CAAI,KAAK,CAAA,OAAA,EAAU,IAAA,CAAK,GAAA,GAAM,iBAAA,GAAoB,EAAE,CAAA,GAAA,CAAK,CAAA;AACzD,QAAA,MAAM,WAAA,CAAY,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,KAAK,IAAA,CAAK,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,CAAA;AAAA,MACtE;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,GAAA,CAAI,MAAM,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IAC5D,CAAA,SAAE;AACA,MAAA,OAAA,GAAU,KAAA;AACV,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,OAAA,GAAU,KAAA;AACV,QAAA,KAAK,QAAA,EAAS;AAAA,MAChB;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,SAAA,EAAY,MAAM,CAAA,gCAAA,CAAkC,CAAA;AAC7D,EAAA,MAAM,UAAU,QAAA,CAAS,KAAA,CAAM,QAAQ,EAAE,aAAA,EAAe,MAAM,CAAA;AAC9D,EAAA,OAAA,CAAQ,EAAA,CAAG,OAAO,MAAM;AACtB,IAAA,KAAK,QAAA,EAAS;AAAA,EAChB,CAAC,CAAA;AAED,EAAA,MAAM,QAAA,EAAS;AAEf,EAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACnC,IAAA,OAAA,CAAQ,EAAA,CAAG,UAAU,MAAM;AACzB,MAAA,KAAK,QAAQ,KAAA,EAAM,CAAE,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,IAC3C,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;;;AC/DA,eAAsB,cAAc,IAAA,EAAwD;AAC1F,EAAA,MAAM,MAAM,MAAM,cAAA,CAAe,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AACpD,EAAA,YAAA,CAAa,GAAG,CAAA;AAChB,EAAA,MAAM,EAAA,GAAK,MAAM,GAAA,CAAI,MAAA,CAAO,KAAA,EAAM;AAElC,EAAA,WAAA,CAAY,CAAC,CAAC,IAAA,CAAK,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,GAAG,EAAA,EAAG,EAAG,CAAC,IAAA,KAAS;AAC5D,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,OAAA,EAAU,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AACjC,IAAA,OAAA,CAAQ,IAAI,CAAA,OAAA,EAAU,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,OAAO,CAAA,CAAE,CAAA;AAClD,IAAA,OAAA,CAAQ,IAAI,CAAA,OAAA,EAAU,IAAA,CAAK,iBAAA,IAAqB,IAAA,CAAK,eAAe,CAAA,CAAE,CAAA;AACtE,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,OAAA,EAAU,IAAA,CAAK,WAAW,CAAA,CAAE,CAAA;AAAA,EAC1C,CAAC,CAAA;AACH;;;ACMA,IAAM,cAAc,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA,CAAE,iBAAiB,CAAA,CAAE,OAAA;AAEtE,SAAS,OAA+B,EAAA,EAAsC;AAC5E,EAAA,OAAO,UAAU,IAAA,KAAe;AAC9B,IAAA,IAAI;AACF,MAAA,MAAM,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,IAClB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,QAAA,GAAA,CAAI,KAAA,CAAM,IAAI,OAAO,CAAA;AACrB,QAAA,OAAA,CAAQ,WAAW,GAAA,CAAI,QAAA;AAAA,MACzB,CAAA,MAAA,IAAW,eAAe,QAAA,EAAU;AAClC,QAAA,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,GAAA,CAAI,OAAO,CAAA,EAAG,GAAA,CAAI,IAAA,GAAO,CAAA,EAAA,EAAK,GAAA,CAAI,IAAI,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,CAAE,CAAA;AAC7D,QAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,MAAM,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAC1D,QAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAA;AACF;AAEA,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,OAAA,CACG,KAAK,QAAQ,CAAA,CACb,YAAY,mCAAmC,CAAA,CAC/C,QAAQ,WAAW,CAAA;AAEtB,OAAA,CACG,QAAQ,OAAO,CAAA,CACf,WAAA,CAAY,oDAAoD,EAChE,MAAA,CAAO,cAAA,EAAgB,2CAA2C,CAAA,CAClE,OAAO,iBAAA,EAAmB,6CAA6C,EACvE,MAAA,CAAO,MAAA,CAAO,YAAY,CAAC,CAAA;AAE9B,OAAA,CACG,QAAQ,QAAQ,CAAA,CAChB,WAAA,CAAY,qCAAqC,EACjD,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,OAAO,QAAA,EAAU,aAAa,EAC9B,MAAA,CAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AAE/B,OAAA,CACG,OAAA,CAAQ,OAAO,CAAA,CACf,WAAA,CAAY,mDAAmD,CAAA,CAC/D,MAAA,CAAO,MAAA,CAAO,YAAY,CAAC,CAAA;AAE9B,OAAA,CACG,OAAA,CAAQ,UAAU,CAAA,CAClB,WAAA,CAAY,8CAA8C,CAAA,CAC1D,MAAA,CAAO,QAAA,EAAU,aAAa,CAAA,CAC9B,MAAA,CAAO,MAAA,CAAO,eAAe,CAAC,CAAA;AAEjC,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,yDAAyD,CAAA,CACrE,MAAA,CAAO,QAAA,EAAU,aAAa,CAAA,CAC9B,MAAA,CAAO,MAAA,CAAO,WAAW,CAAC,CAAA;AAE7B,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,wDAAwD,CAAA,CACpE,MAAA,CAAO,gBAAgB,4BAA4B,CAAA,CACnD,OAAO,oBAAA,EAAsB,iCAAiC,EAC9D,MAAA,CAAO,eAAA,EAAiB,+CAA+C,CAAA,CACvE,MAAA,CAAO,UAAU,sCAAsC,CAAA,CACvD,OAAO,OAAA,EAAS,0CAA0C,EAC1D,MAAA,CAAO,qBAAA,EAAuB,0CAA0C,CAAA,CACxE,MAAA,CAAO,SAAS,wDAAwD,CAAA,CACxE,OAAO,SAAA,EAAW,uCAAuC,EACzD,MAAA,CAAO,eAAA,EAAiB,iEAAiE,CAAA,CACzF,MAAA,CAAO,MAAA,CAAO,WAAW,CAAC,CAAA;AAE7B,OAAA,CACG,OAAA,CAAQ,QAAQ,CAAA,CAChB,WAAA,CAAY,sDAAsD,CAAA,CAClE,MAAA,CAAO,gBAAgB,4BAA4B,CAAA,CACnD,OAAO,OAAA,EAAS,yCAAyC,EACzD,MAAA,CAAO,QAAA,EAAU,aAAa,CAAA,CAC9B,MAAA,CAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AAE/B,OAAA,CACG,OAAA,CAAQ,aAAa,CAAA,CACrB,WAAA,CAAY,+BAA+B,CAAA,CAC3C,MAAA,CAAO,MAAA,CAAO,WAAW,CAAC,CAAA;AAE7B,OAAA,CACG,OAAA,CAAQ,OAAO,CAAA,CACf,WAAA,CAAY,sCAAsC,CAAA,CAClD,MAAA,CAAO,UAAU,uCAAuC,CAAA,CACxD,OAAO,OAAA,EAAS,uCAAuC,EACvD,MAAA,CAAO,cAAA,EAAgB,0CAA0C,CAAA,CACjE,MAAA,CAAO,MAAA,CAAO,YAAY,CAAC,CAAA;AAE9B,OAAA,CACG,QAAQ,QAAQ,CAAA,CAChB,WAAA,CAAY,6DAA6D,EACzE,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,OAAO,QAAA,EAAU,aAAa,EAC9B,MAAA,CAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AAE/B,OAAA,CACG,QAAQ,UAAU,CAAA,CAClB,WAAA,CAAY,+CAA+C,EAC3D,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,OAAO,QAAA,EAAU,aAAa,EAC9B,MAAA,CAAO,MAAA,CAAO,eAAe,CAAC,CAAA;AAEjC,OAAA,CACG,OAAA,CAAQ,UAAU,CAAA,CAClB,WAAA,CAAY,qDAAqD,CAAA,CACjE,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,MAAA,CAAO,oBAAA,EAAsB,wDAAwD,CAAA,CACrF,MAAA,CAAO,OAAA,EAAS,wDAAwD,CAAA,CACxE,MAAA,CAAO,qBAAA,EAAuB,4DAAuD,CAAA,CACrF,MAAA,CAAO,QAAA,EAAU,aAAa,CAAA,CAC9B,MAAA,CAAO,MAAA,CAAO,eAAe,CAAC,CAAA;AAEjC,OAAA,CACG,QAAQ,oBAAoB,CAAA,CAC5B,WAAA,CAAY,wCAAwC,EACpD,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,OAAO,QAAA,EAAU,aAAa,EAC9B,MAAA,CAAO,MAAA,CAAO,eAAe,CAAC,CAAA;AAEjC,IAAM,QAAQ,OAAA,CAAQ,OAAA,CAAQ,OAAO,CAAA,CAAE,YAAY,uCAAuC,CAAA;AAC1F,KAAA,CACG,OAAA,CAAQ,KAAK,CAAA,CACb,WAAA,CAAY,0DAA0D,CAAA,CACtE,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,MAAA,CAAO,eAAA,EAAiB,gBAAgB,CAAA,CACxC,MAAA,CAAO,iBAAA,EAAmB,8CAA8C,CAAA,CACxE,MAAA,CAAO,uBAAA,EAAyB,uDAAuD,CAAA,CACvF,MAAA,CAAO,QAAA,EAAU,aAAa,CAAA,CAC9B,MAAA,CAAO,MAAA,CAAO,eAAe,CAAC,CAAA;AAEjC,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,oCAAoC,CAAA,CAChD,MAAA,CAAO,cAAA,EAAgB,4BAA4B,CAAA,CACnD,MAAA,CAAO,MAAA,CAAO,WAAW,CAAC,CAAA;AAE7B,OAAA,CAAQ,WAAW,OAAA,CAAQ,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9C,EAAA,GAAA,CAAI,MAAM,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAC1D,EAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACrB,CAAC,CAAA","file":"cli.js","sourcesContent":["/**\n * Thin fetch-based client for the Cervio REST API (`/api/v1/**`).\n *\n * Shapes here are matched against the actual `app/api/v1/**` route handlers\n * (not guessed) as of this writing. See packages/cli/README.md \"PAT scopes\"\n * for the token scopes each call needs.\n */\n\nexport class ApiError extends Error {\n status: number\n code?: string\n body?: unknown\n\n constructor(status: number, message: string, code?: string, body?: unknown) {\n super(message)\n this.name = 'ApiError'\n this.status = status\n this.code = code\n this.body = body\n }\n}\n\nexport type MeResponse = {\n user_id: string\n organization_id: string\n email: string | null\n auth_method: string\n /** Not currently returned by GET /api/v1/me; kept optional for forward-compat. */\n organization_name?: string\n}\n\nexport type PluginType = 'task' | 'form' | 'task_form' | 'route'\n\nexport type PluginSummary = {\n id: string\n plugin_key: string\n plugin_name: string | null\n plugin_description: string | null\n plugin_type: PluginType\n is_active: boolean\n is_builtin: boolean\n admin_path: string | null\n}\n\n/** installed_plugins row as returned by GET /api/v1/admin/plugins/{pluginId}. */\nexport type PluginDetail = {\n id: string\n plugin_key: string\n plugin_name: string | null\n plugin_description: string | null\n plugin_type: PluginType\n is_active: boolean\n is_builtin: boolean\n admin_path: string | null\n source_type: string | null\n current_version_id: string | null\n last_uploaded_at: string | null\n required_connection_capabilities: string[]\n declared_entities: unknown[]\n declared_cervio_apis: unknown[]\n}\n\nexport type PluginVersionSummary = {\n id: string\n plugin_id: string\n version: string\n changelog: string | null\n artifact_path: string\n artifact_entry_path?: string | null\n artifact_sha256: string\n content_sha256?: string | null\n artifact_size_bytes: number\n created_at: string\n}\n\nexport type DevChannelInfo = {\n content_sha256: string\n artifact_sha256: string\n artifact_size_bytes: number\n updated_at: string\n /** User id; only present from GET .../dev-channel (not from the upload response). */\n updated_by?: string | null\n updated_by_email?: string | null\n}\n\nexport type RouteConfig = {\n id: string\n plugin_id: string\n route_slug: string\n menu_section_id: string | null\n menu_item_id: string | null\n menu_label: string | null\n menu_icon: string | null\n artifact_cache_enabled: boolean\n runtime_settings: Record<string, unknown>\n dev_channel_enabled: boolean\n}\n\nexport type UploadReleaseResult = {\n channel: 'release'\n created: boolean\n reason: string | null\n plugin: { id: string; plugin_key: string; plugin_name: string; plugin_type: PluginType }\n version: PluginVersionSummary\n}\n\nexport type UploadDevResult = {\n channel: 'dev'\n plugin: { id: string; plugin_key: string; plugin_name: string; plugin_type: PluginType }\n dev_channel: {\n content_sha256: string\n artifact_sha256: string\n artifact_size_bytes: number\n updated_at: string\n }\n}\n\nexport type UploadResult = UploadReleaseResult | UploadDevResult\n\nexport type ApiClient = ReturnType<typeof createApiClient>\n\nexport function createApiClient(opts: { host: string; token?: string }) {\n const baseUrl = opts.host.replace(/\\/+$/, '')\n const token = opts.token\n\n async function request<T = unknown>(pathname: string, init: RequestInit = {}): Promise<T> {\n const url = pathname.startsWith('http') ? pathname : `${baseUrl}${pathname}`\n const headers = new Headers(init.headers)\n if (token) headers.set('Authorization', `Bearer ${token}`)\n if (!headers.has('Accept')) headers.set('Accept', 'application/json')\n\n let res: Response\n try {\n res = await fetch(url, { ...init, headers })\n } catch (err) {\n throw new ApiError(0, `Could not reach ${url}: ${(err as Error).message}`)\n }\n\n const contentType = res.headers.get('content-type') ?? ''\n let body: unknown = null\n if (contentType.includes('application/json')) {\n body = await res.json().catch(() => null)\n } else {\n const text = await res.text().catch(() => '')\n body = text || null\n }\n\n if (!res.ok) {\n const message =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).message === 'string'\n ? (body as Record<string, string>).message\n : `Request failed with status ${res.status} (${pathname})`\n const code =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).error === 'string'\n ? (body as Record<string, string>).error\n : undefined\n throw new ApiError(res.status, message, code, body)\n }\n\n return body as T\n }\n\n return {\n baseUrl,\n token,\n request,\n\n /** No scope requirement. */\n getMe: () => request<MeResponse>('/api/v1/me'),\n\n /** Requires PAT scope `plugin:read` (or an unscoped/legacy token). */\n listEntities: (search?: string) =>\n request<{ entities: Array<{ id: string; name: string; label: string }> }>(\n `/api/v1/entities${search ? `?search=${encodeURIComponent(search)}` : ''}`,\n ),\n\n /** Requires PAT scope `plugin:read`. */\n listPlugins: () => request<{ plugins: PluginSummary[] }>('/api/v1/admin/plugins'),\n\n /** Requires PAT scope `plugin:read`. */\n getPlugin: (pluginId: string) =>\n request<{ plugin: PluginDetail; current_version: PluginVersionSummary | null }>(\n `/api/v1/admin/plugins/${pluginId}`,\n ),\n\n /** Requires PAT scope `plugin:read`. */\n getDevChannel: (pluginId: string) =>\n request<{ dev_channel: DevChannelInfo | null }>(`/api/v1/admin/plugins/${pluginId}/dev-channel`),\n\n /** Requires PAT scope `plugin:read`. */\n listVersions: (pluginId: string) =>\n request<{ versions: PluginVersionSummary[] }>(`/api/v1/admin/plugins/${pluginId}/versions`),\n\n /** Requires PAT scope `plugin:push`. `versionId` is the version row's UUID (`id`), not the semver label. */\n activateVersion: (pluginId: string, versionId: string) =>\n request<{ ok: true; plugin_id: string; current_version_id: string }>(\n `/api/v1/admin/plugins/${pluginId}/versions/${versionId}/activate`,\n { method: 'POST' },\n ),\n\n /** Requires PAT scope `plugin:read`. */\n getRouteConfig: (pluginId: string) =>\n request<{ route_config: RouteConfig | null }>(`/api/v1/admin/plugins/${pluginId}/route-config`),\n\n /** Requires PAT scope `plugin:push`. `route_slug` is required by the route on every PUT (full upsert, not a patch). */\n setRouteConfig: (\n pluginId: string,\n data: { route_slug: string; artifact_cache_enabled?: boolean; dev_channel_enabled?: boolean },\n ) =>\n request<{ route_config: RouteConfig | null }>(`/api/v1/admin/plugins/${pluginId}/route-config`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n }),\n\n /**\n * Matches app/api/v1/admin/plugins/upload/route.ts exactly. Requires PAT\n * scope `plugin:push`. multipart/form-data fields:\n * - `file` (required): the packed .zip, content-type application/zip.\n * - `plugin_id` (optional UUID): omitted by this CLI — the backend\n * resolves/creates the plugin by the `plugin_key` embedded in the manifest.\n * - `changelog`, `plugin_name`, `plugin_description`, `plugin_type` (optional).\n * - `set_current` (\"true\"/\"false\"): whether to activate the uploaded\n * release version. Ignored for `channel=dev`.\n * - `channel` (\"release\" default, or \"dev\"): dev-channel pushes require\n * the plugin to already exist (a prior release push) — the route\n * returns `plugin_not_found` otherwise. Response shape depends on\n * the channel (see `UploadReleaseResult` / `UploadDevResult`).\n */\n uploadPlugin: (form: FormData) =>\n request<UploadResult>('/api/v1/admin/plugins/upload', { method: 'POST', body: form }),\n\n /**\n * Streams a release ZIP. Requires PAT scope `plugin:read`.\n * `versionId` is the version row UUID (`id`), not the semver label.\n */\n downloadVersionArtifact: (pluginId: string, versionId: string) =>\n downloadBinary(\n `/api/v1/admin/plugins/${pluginId}/versions/${versionId}/artifact`,\n { host: baseUrl, token },\n ),\n\n /** Streams the current dev-channel ZIP. Requires PAT scope `plugin:read`. */\n downloadDevArtifact: (pluginId: string) =>\n downloadBinary(`/api/v1/admin/plugins/${pluginId}/dev-channel/artifact`, { host: baseUrl, token }),\n }\n}\n\nexport type ArtifactDownloadResult = {\n bytes: Buffer\n fileName: string | null\n versionLabel: string | null\n contentSha256: string | null\n artifactSha256: string | null\n}\n\nasync function downloadBinary(\n pathname: string,\n opts: { host: string; token?: string },\n): Promise<ArtifactDownloadResult> {\n const url = pathname.startsWith('http') ? pathname : `${opts.host}${pathname}`\n const headers = new Headers({ Accept: 'application/zip, application/octet-stream, */*' })\n if (opts.token) headers.set('Authorization', `Bearer ${opts.token}`)\n\n let res: Response\n try {\n res = await fetch(url, { headers })\n } catch (err) {\n throw new ApiError(0, `Could not reach ${url}: ${(err as Error).message}`)\n }\n\n if (!res.ok) {\n const contentType = res.headers.get('content-type') ?? ''\n let body: unknown = null\n if (contentType.includes('application/json')) {\n body = await res.json().catch(() => null)\n } else {\n body = await res.text().catch(() => '')\n }\n const message =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).message === 'string'\n ? (body as Record<string, string>).message\n : `Request failed with status ${res.status} (${pathname})`\n const code =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).error === 'string'\n ? (body as Record<string, string>).error\n : undefined\n throw new ApiError(res.status, message, code, body)\n }\n\n const arrayBuffer = await res.arrayBuffer()\n const disposition = res.headers.get('content-disposition') ?? ''\n const fileNameMatch = /filename=\"([^\"]+)\"/i.exec(disposition)\n return {\n bytes: Buffer.from(arrayBuffer),\n fileName: fileNameMatch?.[1] ?? null,\n versionLabel: res.headers.get('x-plugin-version'),\n contentSha256: res.headers.get('x-content-sha256'),\n artifactSha256: res.headers.get('x-artifact-sha256'),\n }\n}\n","import { spawn } from 'node:child_process'\nimport chalk from 'chalk'\n\nexport class CliError extends Error {\n /** Process exit code to use when this error escapes to the top-level handler. */\n exitCode: number\n constructor(message: string, exitCode = 1) {\n super(message)\n this.name = 'CliError'\n this.exitCode = exitCode\n }\n}\n\nexport const log = {\n info: (msg: string) => console.log(msg),\n success: (msg: string) => console.log(chalk.green('✔'), msg),\n warn: (msg: string) => console.warn(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✖'), msg),\n step: (msg: string) => console.log(chalk.cyan('→'), msg),\n dim: (msg: string) => console.log(chalk.dim(msg)),\n}\n\n/** Print either a JSON payload (machine-readable, one object, stdout only) or run a human renderer. */\nexport function printResult<T>(json: boolean, data: T, human: (data: T) => void): void {\n if (json) {\n console.log(JSON.stringify(data, null, 2))\n } else {\n human(data)\n }\n}\n\nexport function runCommand(\n command: string,\n args: string[],\n opts: { cwd?: string } = {},\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: opts.cwd ?? process.cwd(),\n stdio: 'inherit',\n shell: process.platform === 'win32',\n })\n child.on('error', (err) => reject(new CliError(`Failed to run \"${command}\": ${err.message}`)))\n child.on('exit', (code) => {\n if (code === 0) resolve()\n else reject(new CliError(`\"${command} ${args.join(' ')}\" exited with code ${code}`, code ?? 1))\n })\n })\n}\n\n/** Detect whether a `pnpm-lock.yaml` is present in cwd, to prefer pnpm over npm for `build`/`init`. */\nexport async function detectPackageManager(cwd: string): Promise<'pnpm' | 'npm'> {\n const { existsSync } = await import('node:fs')\n const path = await import('node:path')\n if (existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm'\n return 'npm'\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n const units = ['KB', 'MB', 'GB']\n let value = bytes / 1024\n let unitIndex = 0\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024\n unitIndex += 1\n }\n return `${value.toFixed(1)} ${units[unitIndex]}`\n}\n\nexport function minutesSince(isoDate: string): number {\n const ms = Date.now() - new Date(isoDate).getTime()\n return ms / 60_000\n}\n","import { detectPackageManager, log, runCommand } from '../util.js'\n\nexport async function buildCommand(): Promise<void> {\n const cwd = process.cwd()\n const pm = await detectPackageManager(cwd)\n log.step(`Running \"${pm} run build\" in ${cwd}`)\n await runCommand(pm, ['run', 'build'], { cwd })\n log.success('Build complete.')\n}\n","import { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nexport type Credentials = Record<string, { token: string }>\n\nexport type CliState = {\n lastHost?: string\n}\n\nexport type ProjectConfig = {\n host?: string\n plugin_key: string\n route_slug?: string\n dev_conflict_minutes?: number\n}\n\nconst CERVIO_DIR = path.join(os.homedir(), '.cervio')\nconst CREDENTIALS_PATH = path.join(CERVIO_DIR, 'credentials.json')\nconst STATE_PATH = path.join(CERVIO_DIR, 'state.json')\nexport const PROJECT_CONFIG_FILENAME = 'cervio.json'\n\nasync function ensureCervioDir(): Promise<void> {\n await fs.mkdir(CERVIO_DIR, { recursive: true })\n}\n\nasync function readJsonFile<T>(filePath: string, fallback: T): Promise<T> {\n try {\n const raw = await fs.readFile(filePath, 'utf8')\n return JSON.parse(raw) as T\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return fallback\n throw err\n }\n}\n\nasync function writeJsonFile(filePath: string, data: unknown): Promise<void> {\n await ensureCervioDir()\n await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\\n`, { mode: 0o600 })\n}\n\n/** Normalize a host URL for use as a credentials/state key (strip trailing slashes). */\nexport function normalizeHost(host: string): string {\n return host.trim().replace(/\\/+$/, '')\n}\n\nexport async function readCredentials(): Promise<Credentials> {\n return readJsonFile<Credentials>(CREDENTIALS_PATH, {})\n}\n\nexport async function getToken(host: string): Promise<string | undefined> {\n const creds = await readCredentials()\n return creds[normalizeHost(host)]?.token\n}\n\nexport async function saveToken(host: string, token: string): Promise<void> {\n const creds = await readCredentials()\n creds[normalizeHost(host)] = { token }\n await writeJsonFile(CREDENTIALS_PATH, creds)\n}\n\nexport async function removeToken(host: string): Promise<void> {\n const creds = await readCredentials()\n delete creds[normalizeHost(host)]\n await writeJsonFile(CREDENTIALS_PATH, creds)\n}\n\nexport async function readState(): Promise<CliState> {\n return readJsonFile<CliState>(STATE_PATH, {})\n}\n\nexport async function writeState(state: CliState): Promise<void> {\n await writeJsonFile(STATE_PATH, state)\n}\n\nexport async function getLastHost(): Promise<string | undefined> {\n const state = await readState()\n return state.lastHost\n}\n\nexport async function setLastHost(host: string): Promise<void> {\n const state = await readState()\n state.lastHost = normalizeHost(host)\n await writeState(state)\n}\n\nexport function projectConfigPath(cwd = process.cwd()): string {\n return path.join(cwd, PROJECT_CONFIG_FILENAME)\n}\n\nexport async function readProjectConfig(cwd = process.cwd()): Promise<ProjectConfig | null> {\n try {\n const raw = await fs.readFile(projectConfigPath(cwd), 'utf8')\n return JSON.parse(raw) as ProjectConfig\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return null\n throw err\n }\n}\n\nexport async function writeProjectConfig(\n config: ProjectConfig,\n cwd = process.cwd(),\n): Promise<void> {\n await fs.writeFile(projectConfigPath(cwd), `${JSON.stringify(config, null, 2)}\\n`)\n}\n\n/**\n * Resolve the target host from (in priority order): explicit CLI flag,\n * `CERVIO_URL` env var, then `cervio.json` in the cwd.\n */\nexport function resolveHost(opts: {\n cliHost?: string\n projectConfig?: ProjectConfig | null\n}): string | undefined {\n const host = opts.cliHost || process.env.CERVIO_URL || opts.projectConfig?.host\n return host ? normalizeHost(host) : undefined\n}\n\n/**\n * Resolve the bearer token for a host: `CERVIO_TOKEN` env var wins, otherwise\n * fall back to the stored credential for that host.\n */\nexport async function resolveToken(host: string): Promise<string | undefined> {\n if (process.env.CERVIO_TOKEN) return process.env.CERVIO_TOKEN\n return getToken(host)\n}\n\nexport { CERVIO_DIR, CREDENTIALS_PATH, STATE_PATH }\n","import { createApiClient, type ApiClient } from './api.js'\nimport { type ProjectConfig, readProjectConfig, resolveHost, resolveToken } from './config.js'\nimport { CliError } from './util.js'\n\nexport type ResolvedContext = {\n host: string\n token?: string\n client: ApiClient\n projectConfig: ProjectConfig | null\n}\n\n/** Resolve host + token + project config, in priority order: CLI flag > CERVIO_URL/CERVIO_TOKEN > cervio.json. */\nexport async function resolveContext(opts: { host?: string } = {}): Promise<ResolvedContext> {\n const projectConfig = await readProjectConfig()\n const host = resolveHost({ cliHost: opts.host, projectConfig })\n if (!host) {\n throw new CliError(\n 'No host configured. Pass --host <url>, set CERVIO_URL, or add \"host\" to cervio.json (run \"cervio login\" first).',\n )\n }\n const token = await resolveToken(host)\n const client = createApiClient({ host, token })\n return { host, token, client, projectConfig }\n}\n\nexport function requireToken(ctx: ResolvedContext): string {\n if (!ctx.token) {\n throw new CliError(\n `Not logged in to ${ctx.host}. Run \"cervio login --host ${ctx.host}\" or set CERVIO_TOKEN.`,\n )\n }\n return ctx.token\n}\n\nexport function requireProjectConfig(ctx: ResolvedContext): ProjectConfig {\n if (!ctx.projectConfig) {\n throw new CliError('No cervio.json found in the current directory. Run \"cervio init\" first.')\n }\n return ctx.projectConfig\n}\n\n/** Resolve a plugin's UUID from its plugin_key via GET /api/v1/admin/plugins. */\nexport async function resolvePluginId(ctx: ResolvedContext, pluginKey: string): Promise<string> {\n const id = await tryResolvePluginId(ctx, pluginKey)\n if (!id) {\n throw new CliError(\n `No plugin with plugin_key \"${pluginKey}\" found on ${ctx.host}. Push it once with \"cervio push\" first.`,\n )\n }\n return id\n}\n\n/** Same as {@link resolvePluginId} but returns null instead of throwing when not found. */\nexport async function tryResolvePluginId(\n ctx: ResolvedContext,\n pluginKey: string,\n): Promise<string | null> {\n const { plugins } = await ctx.client.listPlugins()\n return plugins.find((p) => p.plugin_key === pluginKey)?.id ?? null\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseManifestObject, validatePluginDir } from '@cervio/plugin-core'\nimport { ApiError } from '../api.js'\nimport { resolveContext } from '../context.js'\nimport { log, printResult } from '../util.js'\n\ntype CheckResult = { name: string; ok: boolean; detail: string }\n\nexport async function doctorCommand(opts: { host?: string; json?: boolean }): Promise<void> {\n const checks: CheckResult[] = []\n const cwd = process.cwd()\n\n let ctx\n try {\n ctx = await resolveContext({ host: opts.host })\n checks.push({ name: 'host_configured', ok: true, detail: ctx.host })\n } catch (err) {\n checks.push({ name: 'host_configured', ok: false, detail: err instanceof Error ? err.message : String(err) })\n return report(checks, opts.json)\n }\n\n if (!ctx.token) {\n checks.push({ name: 'token_present', ok: false, detail: 'No token found (env CERVIO_TOKEN or ~/.cervio/credentials.json).' })\n } else {\n checks.push({ name: 'token_present', ok: true, detail: 'found' })\n }\n\n let entities: Array<{ name: string; label: string }> = []\n try {\n const me = await ctx.client.getMe()\n checks.push({ name: 'host_reachable', ok: true, detail: `reachable, auth via ${me.auth_method}` })\n checks.push({ name: 'token_valid', ok: true, detail: me.email ?? me.user_id })\n\n const entitiesRes = await ctx.client.listEntities()\n entities = entitiesRes.entities\n checks.push({ name: 'entities_endpoint', ok: true, detail: `${entities.length} entities visible` })\n } catch (err) {\n if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {\n checks.push({ name: 'token_valid', ok: false, detail: err.message })\n } else {\n checks.push({ name: 'host_reachable', ok: false, detail: err instanceof Error ? err.message : String(err) })\n }\n }\n\n const manifestPath = path.join(cwd, 'manifest.json')\n let declaredEntities: string[] = []\n try {\n const raw = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as Record<string, unknown>\n const parsed = parseManifestObject(raw)\n if (parsed.ok) {\n declaredEntities = parsed.value.entities.map((e) => e.name)\n checks.push({ name: 'manifest_valid', ok: true, detail: `plugin_key=${parsed.value.pluginKey}` })\n } else {\n checks.push({ name: 'manifest_valid', ok: false, detail: parsed.error })\n }\n } catch (err) {\n checks.push({ name: 'manifest_valid', ok: false, detail: `manifest.json not readable: ${err instanceof Error ? err.message : String(err)}` })\n }\n\n const packResult = await validatePluginDir(cwd)\n checks.push(\n packResult.ok\n ? { name: 'build_valid', ok: true, detail: `content_sha256=${packResult.value.contentSha256}` }\n : { name: 'build_valid', ok: false, detail: packResult.error },\n )\n\n if (declaredEntities.length) {\n const known = new Set(entities.map((e) => e.name))\n const missing = declaredEntities.filter((name) => !known.has(name))\n checks.push(\n missing.length === 0\n ? { name: 'entities_exist', ok: true, detail: declaredEntities.join(', ') }\n : { name: 'entities_exist', ok: false, detail: `missing: ${missing.join(', ')}` },\n )\n }\n\n report(checks, opts.json)\n}\n\nfunction report(checks: CheckResult[], json?: boolean): void {\n const ok = checks.every((c) => c.ok)\n printResult(!!json, { ok, checks }, () => {\n for (const check of checks) {\n const marker = check.ok ? '✔' : '✖'\n log.info(`${marker} ${check.name}: ${check.detail}`)\n }\n if (ok) log.success('All checks passed.')\n else log.error('Some checks failed.')\n })\n if (!ok) {\n process.exitCode = 1\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { ApiError } from '../api.js'\nimport { requireProjectConfig, requireToken, resolveContext, resolvePluginId } from '../context.js'\nimport { CliError, log, printResult } from '../util.js'\n\nexport type DownloadOptions = {\n host?: string\n /** Semver label of a release to download (CLI flag: `--release`). */\n release?: string\n /** @deprecated Prefer `release` — kept so older callers still work if they pass `version`. */\n version?: string\n dev?: boolean\n output?: string\n json?: boolean\n}\n\n/**\n * Download a release or dev-channel ZIP from the host into the local filesystem.\n *\n * - Default: current release version (`installed_plugins.current_version_id`)\n * - `--release <semver>`: a specific released version label\n * - `--dev`: the scratch `plugin_dev_channel` artifact (mutually exclusive with `--release`)\n */\nexport async function downloadCommand(opts: DownloadOptions): Promise<void> {\n const release = opts.release ?? opts.version\n if (opts.dev && release) {\n throw new CliError('Use either --dev or --release, not both.')\n }\n\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const projectConfig = requireProjectConfig(ctx)\n const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key)\n\n let channel: 'release' | 'dev' = 'release'\n let versionLabel: string | null = null\n let contentSha256: string | null = null\n let artifactSha256: string | null = null\n let bytes: Buffer\n let defaultFileName: string\n\n try {\n if (opts.dev) {\n channel = 'dev'\n const result = await ctx.client.downloadDevArtifact(pluginId)\n bytes = result.bytes\n contentSha256 = result.contentSha256\n artifactSha256 = result.artifactSha256\n defaultFileName = `${projectConfig.plugin_key}-dev.zip`\n } else {\n const { plugin, current_version } = await ctx.client.getPlugin(pluginId)\n let versionId = current_version?.id ?? plugin.current_version_id\n versionLabel = current_version?.version ?? null\n contentSha256 = current_version?.content_sha256 ?? null\n artifactSha256 = current_version?.artifact_sha256 ?? null\n\n if (release) {\n const { versions } = await ctx.client.listVersions(pluginId)\n const hit = versions.find((v) => v.version === release)\n if (!hit) {\n throw new CliError(\n `Version \"${release}\" not found for ${projectConfig.plugin_key} on ${ctx.host}. Run \"cervio versions\".`,\n )\n }\n versionId = hit.id\n versionLabel = hit.version\n contentSha256 = hit.content_sha256 ?? null\n artifactSha256 = hit.artifact_sha256\n }\n\n if (!versionId) {\n throw new CliError(`Plugin \"${projectConfig.plugin_key}\" has no release version on ${ctx.host} yet.`)\n }\n\n const result = await ctx.client.downloadVersionArtifact(pluginId, versionId)\n bytes = result.bytes\n if (result.versionLabel) versionLabel = result.versionLabel\n if (result.contentSha256) contentSha256 = result.contentSha256\n if (result.artifactSha256) artifactSha256 = result.artifactSha256\n defaultFileName = `${projectConfig.plugin_key}-v${versionLabel ?? 'unknown'}.zip`\n }\n } catch (err) {\n if (err instanceof ApiError && (err.status === 404 || err.status === 405)) {\n throw new CliError(\n `Artifact download is not available on ${ctx.host} yet (deploy the admin artifact routes).`,\n )\n }\n throw err\n }\n\n const outputPath = path.resolve(process.cwd(), opts.output ?? path.join('.cervio', 'out', defaultFileName))\n await fs.mkdir(path.dirname(outputPath), { recursive: true })\n await fs.writeFile(outputPath, bytes)\n\n const payload = {\n ok: true as const,\n host: ctx.host,\n plugin_key: projectConfig.plugin_key,\n channel,\n version: versionLabel,\n content_sha256: contentSha256,\n artifact_sha256: artifactSha256,\n bytes: bytes.byteLength,\n path: outputPath,\n }\n\n printResult(!!opts.json, payload, (data) => {\n log.success(`Downloaded ${data.plugin_key}${data.version ? `@${data.version}` : ' (dev)'} → ${data.path}`)\n log.info(` bytes: ${data.bytes}`)\n if (data.content_sha256) log.info(` content_sha256: ${data.content_sha256}`)\n if (data.artifact_sha256) log.info(` artifact_sha256: ${data.artifact_sha256}`)\n })\n}\n","import { log, runCommand } from '../util.js'\n\n/**\n * Scaffolds via `npx create-cervio-plugin` (see packages/create-cervio-plugin).\n * Inside this monorepo, npx resolves the local workspace bin\n * (`node_modules/.bin/create-cervio-plugin`) automatically; outside of it,\n * npx fetches the published package.\n */\nexport async function initCommand(name: string | undefined): Promise<void> {\n const args = name ? [name] : []\n log.step('Scaffolding via \"npx create-cervio-plugin\"...')\n await runCommand('npx', ['create-cervio-plugin', ...args])\n}\n","import prompts from 'prompts'\nimport { createApiClient } from '../api.js'\nimport { normalizeHost, saveToken } from '../config.js'\nimport { CliError, log } from '../util.js'\n\nexport async function loginCommand(opts: { host?: string; token?: string }): Promise<void> {\n if (!opts.host) {\n throw new CliError('--host <url> is required, e.g. cervio login --host https://app.example.com')\n }\n const host = normalizeHost(opts.host)\n\n let token = opts.token\n if (!token) {\n const response = await prompts({\n type: 'password',\n name: 'token',\n message: `Personal access token for ${host}`,\n })\n token = typeof response.token === 'string' ? response.token.trim() : ''\n }\n if (!token) {\n throw new CliError('No token provided.')\n }\n\n const client = createApiClient({ host, token })\n const me = await client.getMe()\n\n await saveToken(host, token)\n\n log.success(`Logged in to ${host}`)\n log.info(` user: ${me.email ?? me.user_id}`)\n log.info(` org: ${me.organization_name ?? me.organization_id}`)\n log.info(` auth: ${me.auth_method}`)\n}\n","import open from 'open'\nimport { requireProjectConfig, resolveContext } from '../context.js'\nimport { CliError, log } from '../util.js'\n\nexport async function openCommand(opts: { host?: string }): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n const projectConfig = requireProjectConfig(ctx)\n if (!projectConfig.route_slug) {\n throw new CliError('cervio.json has no \"route_slug\" configured.')\n }\n\n const url = `${ctx.host}/r/${projectConfig.route_slug}`\n log.step(`Opening ${url}`)\n await open(url)\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { packPlugin } from '@cervio/plugin-core'\nimport { CliError, formatBytes, log, printResult } from '../util.js'\n\nexport type PackedOutput = {\n pluginKey: string\n contentSha256: string\n sizeBytes: number\n outputPath: string\n}\n\nexport async function packForPublish(dir = process.cwd()): Promise<PackedOutput> {\n const result = await packPlugin({ dir })\n if (!result.ok) {\n throw new CliError(`Pack failed: ${result.error}`)\n }\n\n const outDir = path.join(dir, '.cervio', 'out')\n await fs.mkdir(outDir, { recursive: true })\n const outputPath = path.join(outDir, `${result.value.pluginKey}.zip`)\n await fs.writeFile(outputPath, result.value.buffer)\n\n return {\n pluginKey: result.value.pluginKey,\n contentSha256: result.value.contentSha256,\n sizeBytes: result.value.sizeBytes,\n outputPath,\n }\n}\n\nexport async function packCommand(opts: { json?: boolean; dir?: string }): Promise<void> {\n const packed = await packForPublish(opts.dir ?? process.cwd())\n printResult(!!opts.json, packed, (data) => {\n log.success(`Packed ${data.pluginKey} (${formatBytes(data.sizeBytes)})`)\n log.info(` content_sha256: ${data.contentSha256}`)\n log.info(` output: ${data.outputPath}`)\n })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport prompts from 'prompts'\nimport { validatePluginZipBuffer } from '@cervio/plugin-core'\nimport { ApiError, createApiClient } from '../api.js'\nimport {\n getLastHost,\n normalizeHost,\n readProjectConfig,\n resolveHost,\n resolveToken,\n setLastHost,\n} from '../config.js'\nimport { packForPublish } from './pack.js'\nimport { CliError, log, minutesSince } from '../util.js'\n\nexport type PushOptions = {\n host?: string\n changelog?: string\n activate?: boolean\n json?: boolean\n yes?: boolean\n expectHost?: string\n dev?: boolean\n force?: boolean\n /** Upload an existing ZIP instead of packing the current directory. */\n file?: string\n}\n\nconst DEFAULT_DEV_CONFLICT_MINUTES = 30\n\nexport async function pushCommand(opts: PushOptions): Promise<void> {\n const projectConfig = await readProjectConfig()\n if (!projectConfig) {\n throw new CliError('No cervio.json found in the current directory. Run \"cervio init\" first.')\n }\n\n const host = resolveHost({ cliHost: opts.host, projectConfig })\n if (!host) {\n throw new CliError('No host configured. Pass --host, set CERVIO_URL, or add \"host\" to cervio.json.')\n }\n\n if (opts.expectHost && normalizeHost(opts.expectHost) !== host) {\n const message = `Resolved host ${host} does not match --expect-host ${normalizeHost(opts.expectHost)}.`\n if (opts.json) {\n console.log(JSON.stringify({ ok: false, error: 'host_mismatch', host, expected: normalizeHost(opts.expectHost) }, null, 2))\n process.exitCode = 1\n return\n }\n throw new CliError(message)\n }\n\n const token = await resolveToken(host)\n if (!token) {\n throw new CliError(`Not logged in to ${host}. Run \"cervio login --host ${host}\" first.`)\n }\n const client = createApiClient({ host, token })\n\n let orgName: string | undefined\n try {\n const me = await client.getMe()\n orgName = me.organization_name ?? me.organization_id\n } catch {\n // /api/v1/me failing shouldn't block push reporting; host is still printed below.\n }\n\n log.info(`Publishing to ${host}${orgName ? ` (org: ${orgName})` : ''}`)\n\n const lastHost = await getLastHost()\n if (lastHost && lastHost !== host) {\n if (opts.json) {\n // No prompt in --json mode; the caller is expected to have already\n // confirmed via --yes or --expect-host out of band.\n if (!opts.yes) {\n console.log(\n JSON.stringify(\n { ok: false, error: 'host_changed', host, last_host: lastHost },\n null,\n 2,\n ),\n )\n process.exitCode = 1\n return\n }\n } else if (!opts.yes) {\n const response = await prompts({\n type: 'confirm',\n name: 'proceed',\n message: `Last push was to ${lastHost}. Continue publishing to ${host}?`,\n initial: false,\n })\n if (!response.proceed) {\n log.warn('Push cancelled.')\n return\n }\n } else {\n log.warn(`Host changed from ${lastHost} to ${host} (--yes supplied, continuing).`)\n }\n }\n\n if (opts.dev) {\n const conflict = await checkDevChannelConflict({\n client,\n projectConfig,\n currentUserEmail: (await safeMe(client))?.email ?? null,\n force: !!opts.force,\n })\n if (conflict) {\n if (opts.json) {\n console.log(JSON.stringify({ ok: false, error: 'dev_channel_conflict', host, conflict }, null, 2))\n process.exitCode = 1\n return\n }\n if (!opts.force) {\n const response = await prompts({\n type: 'confirm',\n name: 'proceed',\n message: `Dev channel was last updated by ${conflict.updated_by_email ?? 'someone else'} ${conflict.minutes_ago.toFixed(0)}m ago. Overwrite anyway?`,\n initial: false,\n })\n if (!response.proceed) {\n log.warn('Push cancelled (dev channel conflict).')\n return\n }\n } else {\n log.warn('Dev channel conflict detected, continuing due to --force.')\n }\n }\n }\n\n let zipBuffer: Buffer\n let zipFileName: string\n if (opts.file) {\n const filePath = path.resolve(process.cwd(), opts.file)\n try {\n zipBuffer = await fs.readFile(filePath)\n } catch (err) {\n throw new CliError(\n `Could not read --file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n const validated = await validatePluginZipBuffer(zipBuffer)\n if (!validated.ok) {\n throw new CliError(`Invalid plugin ZIP (${opts.file}): ${validated.error}`)\n }\n if (validated.value.pluginKey !== projectConfig.plugin_key) {\n throw new CliError(\n `ZIP plugin_key \"${validated.value.pluginKey}\" does not match cervio.json \"${projectConfig.plugin_key}\".`,\n )\n }\n zipFileName = path.basename(filePath).endsWith('.zip')\n ? path.basename(filePath)\n : `${validated.value.pluginKey}.zip`\n log.info(`Using existing ZIP ${filePath} (content_sha256=${validated.value.contentSha256})`)\n } else {\n const packed = await packForPublish(process.cwd())\n zipBuffer = await fs.readFile(packed.outputPath)\n zipFileName = `${packed.pluginKey}.zip`\n }\n\n const form = new FormData()\n form.set('file', new Blob([zipBuffer], { type: 'application/zip' }), zipFileName)\n if (opts.changelog) form.set('changelog', opts.changelog)\n form.set('set_current', String(opts.activate !== false))\n if (opts.dev) form.set('channel', 'dev')\n\n let upload\n try {\n upload = await client.uploadPlugin(form)\n } catch (err) {\n if (err instanceof ApiError) {\n if (opts.json) {\n console.log(JSON.stringify({ ok: false, error: err.code ?? 'upload_failed', message: err.message, host }, null, 2))\n process.exitCode = 1\n return\n }\n if (err.code === 'plugin_not_found' && opts.dev) {\n throw new CliError(\n `Plugin \"${projectConfig.plugin_key}\" does not exist on ${host} yet. Dev-channel pushes require a prior release push — run \"cervio push\" (without --dev) once first.`,\n )\n }\n throw new CliError(`Upload failed: ${err.message}`)\n }\n throw err\n }\n\n await setLastHost(host)\n\n if (opts.json) {\n console.log(JSON.stringify({ ok: true, host, ...upload }, null, 2))\n return\n }\n\n if (upload.channel === 'dev') {\n log.success(`Pushed ${upload.plugin.plugin_key} to the dev channel on ${host}`)\n log.info(` content_sha256: ${upload.dev_channel.content_sha256}`)\n log.info(` updated_at: ${upload.dev_channel.updated_at}`)\n } else {\n log.success(`Pushed ${upload.plugin.plugin_key}@${upload.version.version} to ${host}`)\n log.info(` content_sha256: ${upload.version.content_sha256 ?? '(n/a)'}`)\n if (upload.reason) log.dim(` ${upload.reason}`)\n }\n}\n\nasync function safeMe(client: ReturnType<typeof createApiClient>) {\n try {\n return await client.getMe()\n } catch {\n return null\n }\n}\n\nasync function checkDevChannelConflict(args: {\n client: ReturnType<typeof createApiClient>\n projectConfig: NonNullable<Awaited<ReturnType<typeof readProjectConfig>>>\n currentUserEmail: string | null\n force: boolean\n}): Promise<{ updated_by_email: string | null; updated_at: string; minutes_ago: number } | null> {\n if (args.force) return null\n const pluginId = await resolvePluginIdSafely(args.client, args.projectConfig.plugin_key)\n if (!pluginId) return null // plugin not created yet on host: nothing to conflict with\n\n let devChannel\n try {\n const res = await args.client.getDevChannel(pluginId)\n devChannel = res.dev_channel\n } catch (err) {\n if (err instanceof ApiError && (err.status === 404 || err.status === 405)) {\n // Older host without the dev-channel endpoint: cannot check for\n // conflicts, so proceed without blocking the push.\n return null\n }\n throw err\n }\n if (!devChannel?.updated_at) return null\n\n const conflictWindow = args.projectConfig.dev_conflict_minutes ?? DEFAULT_DEV_CONFLICT_MINUTES\n const minutesAgo = minutesSince(devChannel.updated_at)\n const sameUser =\n !!args.currentUserEmail &&\n !!devChannel.updated_by_email &&\n devChannel.updated_by_email.toLowerCase() === args.currentUserEmail.toLowerCase()\n\n if (!sameUser && minutesAgo <= conflictWindow) {\n return { updated_by_email: devChannel.updated_by_email ?? null, updated_at: devChannel.updated_at, minutes_ago: minutesAgo }\n }\n return null\n}\n\nasync function resolvePluginIdSafely(\n client: ReturnType<typeof createApiClient>,\n pluginKey: string,\n): Promise<string | null> {\n try {\n const { plugins } = await client.listPlugins()\n return plugins.find((p) => p.plugin_key === pluginKey)?.id ?? null\n } catch {\n return null\n }\n}\n","import { requireProjectConfig, requireToken, resolveContext, resolvePluginId } from '../context.js'\nimport { CliError, log, printResult } from '../util.js'\n\nexport async function rollbackCommand(\n version: string,\n opts: { host?: string; json?: boolean },\n): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const projectConfig = requireProjectConfig(ctx)\n const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key)\n\n const { versions } = await ctx.client.listVersions(pluginId)\n const match = versions.find((v) => v.version === version)\n if (!match) {\n throw new CliError(\n `No version \"${version}\" found for ${projectConfig.plugin_key} on ${ctx.host}. Run \"cervio versions\" to list available versions.`,\n )\n }\n\n const result = await ctx.client.activateVersion(pluginId, match.id)\n\n printResult(!!opts.json, { host: ctx.host, plugin_key: projectConfig.plugin_key, version, ...result }, (data) => {\n log.success(`Activated ${data.plugin_key}@${version} on ${data.host}`)\n })\n}\n","import { requireProjectConfig, requireToken, resolveContext, resolvePluginId } from '../context.js'\nimport { CliError, log, printResult } from '../util.js'\n\nfunction parseOnOff(value: string | undefined, flag: string): boolean | undefined {\n if (value === undefined) return undefined\n const normalized = value.toLowerCase()\n if (normalized === 'on') return true\n if (normalized === 'off') return false\n throw new CliError(`${flag} must be \"on\" or \"off\".`)\n}\n\nexport async function routeSetCommand(opts: {\n host?: string\n slug?: string\n cache?: string\n devChannel?: string\n json?: boolean\n}): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const projectConfig = requireProjectConfig(ctx)\n const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key)\n\n const cache = parseOnOff(opts.cache, '--cache')\n const devChannel = parseOnOff(opts.devChannel, '--dev-channel')\n\n // PUT is a full upsert: route_slug is always required. Fall back to the\n // existing config's slug (or cervio.json's route_slug) when --slug is omitted.\n let slug = opts.slug\n if (!slug) {\n const { route_config } = await ctx.client.getRouteConfig(pluginId)\n slug = route_config?.route_slug ?? projectConfig.route_slug\n }\n if (!slug) {\n throw new CliError('No route slug known. Pass --slug <slug> (or set \"route_slug\" in cervio.json).')\n }\n\n const { route_config } = await ctx.client.setRouteConfig(pluginId, {\n route_slug: slug,\n artifact_cache_enabled: cache,\n dev_channel_enabled: devChannel,\n })\n\n printResult(!!opts.json, { host: ctx.host, plugin_key: projectConfig.plugin_key, route_config }, (data) => {\n const rc = data.route_config\n const extras = rc\n ? ` (cache=${rc.artifact_cache_enabled ? 'on' : 'off'}, dev_channel=${rc.dev_channel_enabled ? 'on' : 'off'})`\n : ''\n log.success(\n `Updated route config for ${data.plugin_key} on ${data.host}: /r/${rc?.route_slug}` + extras,\n )\n })\n}\n","import { validatePluginDir } from '@cervio/plugin-core'\nimport { ApiError } from '../api.js'\nimport { requireProjectConfig, requireToken, resolveContext, tryResolvePluginId } from '../context.js'\nimport { CliError, log, printResult } from '../util.js'\n\nexport async function statusCommand(opts: { host?: string; dev?: boolean; json?: boolean }): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const projectConfig = requireProjectConfig(ctx)\n\n const local = await validatePluginDir(process.cwd())\n if (!local.ok) {\n throw new CliError(`Local plugin failed validation: ${local.error}`)\n }\n\n const pluginId = await tryResolvePluginId(ctx, projectConfig.plugin_key)\n if (!pluginId) {\n return printResult(!!opts.json, {\n host: ctx.host,\n plugin_key: projectConfig.plugin_key,\n local_content_sha256: local.value.contentSha256,\n state: 'not_pushed' as const,\n }, (data) => {\n log.warn(`\"${data.plugin_key}\" has not been pushed to ${data.host} yet.`)\n log.info(` local content_sha256: ${data.local_content_sha256}`)\n })\n }\n\n let remoteSha256: string | null = null\n let remoteVersion: string | null = null\n let updatedByEmail: string | null = null\n let updatedAt: string | null = null\n let unimplemented = false\n try {\n if (opts.dev) {\n const { dev_channel } = await ctx.client.getDevChannel(pluginId)\n remoteSha256 = dev_channel?.content_sha256 ?? null\n remoteVersion = null // dev channel has no semver label\n updatedByEmail = dev_channel?.updated_by_email ?? null\n updatedAt = dev_channel?.updated_at ?? null\n } else {\n const { current_version } = await ctx.client.getPlugin(pluginId)\n remoteSha256 = current_version?.content_sha256 ?? null\n remoteVersion = current_version?.version ?? null\n }\n } catch (err) {\n if (err instanceof ApiError && (err.status === 404 || err.status === 405)) {\n unimplemented = true\n } else {\n throw err\n }\n }\n\n const inSync = !unimplemented && remoteSha256 !== null && remoteSha256 === local.value.contentSha256\n\n printResult(\n !!opts.json,\n {\n host: ctx.host,\n channel: opts.dev ? 'dev' : 'current',\n plugin_key: projectConfig.plugin_key,\n local_content_sha256: local.value.contentSha256,\n remote_content_sha256: remoteSha256,\n remote_version: remoteVersion,\n in_sync: inSync,\n remote_check_unavailable: unimplemented,\n ...(opts.dev\n ? {\n updated_by_email: updatedByEmail,\n updated_at: updatedAt,\n }\n : {}),\n },\n (data) => {\n log.info(`host: ${data.host}`)\n log.info(`plugin: ${data.plugin_key} (${data.channel} channel)`)\n log.info(`local: ${data.local_content_sha256}`)\n if (data.remote_check_unavailable) {\n log.warn(\n `remote: unavailable — the ${\n opts.dev ? 'dev-channel' : 'plugin detail'\n } endpoint is not implemented on this host yet.`,\n )\n return\n }\n log.info(`remote: ${data.remote_content_sha256 ?? '(none)'}${data.remote_version ? ` (v${data.remote_version})` : ''}`)\n if (opts.dev) {\n log.info(`updated_by: ${data.updated_by_email ?? '(unknown)'}`)\n log.info(`updated_at: ${data.updated_at ?? '(none)'}`)\n }\n if (data.in_sync) log.success('Up to date.')\n else log.warn('Local build differs from the deployed version. Run \"cervio push\" to publish.')\n },\n )\n}\n","import { validatePluginDir } from '@cervio/plugin-core'\nimport { CliError, log, printResult } from '../util.js'\n\nexport async function validateCommand(opts: { json?: boolean; dir?: string }): Promise<void> {\n const dir = opts.dir ?? process.cwd()\n const result = await validatePluginDir(dir)\n\n if (!result.ok) {\n if (opts.json) {\n console.log(JSON.stringify({ ok: false, error: result.error }, null, 2))\n process.exitCode = 1\n return\n }\n throw new CliError(`Validation failed: ${result.error}`)\n }\n\n printResult(!!opts.json, { ok: true, ...result.value }, (data) => {\n log.success('Plugin is valid.')\n log.info(` plugin_key: ${data.pluginKey}`)\n log.info(` content_sha256: ${data.contentSha256}`)\n })\n}\n","import { ApiError } from '../api.js'\nimport { requireProjectConfig, requireToken, resolveContext, resolvePluginId } from '../context.js'\nimport { CliError, log, printResult } from '../util.js'\n\nexport async function versionsCommand(opts: { host?: string; json?: boolean }): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const projectConfig = requireProjectConfig(ctx)\n const pluginId = await resolvePluginId(ctx, projectConfig.plugin_key)\n\n try {\n const { versions } = await ctx.client.listVersions(pluginId)\n printResult(!!opts.json, { host: ctx.host, plugin_key: projectConfig.plugin_key, versions }, (data) => {\n for (const v of data.versions) {\n log.info(`${v.version} ${v.content_sha256 ?? ''} ${v.created_at}${v.changelog ? ` ${v.changelog}` : ''}`)\n }\n })\n } catch (err) {\n if (err instanceof ApiError && (err.status === 404 || err.status === 405)) {\n throw new CliError(\n `GET /api/v1/admin/plugins/${pluginId}/versions is not implemented on ${ctx.host} yet.`,\n )\n }\n throw err\n }\n}\n","import path from 'node:path'\nimport chokidar from 'chokidar'\nimport { validatePluginDir } from '@cervio/plugin-core'\nimport { buildCommand } from './build.js'\nimport { pushCommand } from './push.js'\nimport { log } from '../util.js'\n\nexport type WatchOptions = {\n push?: boolean\n dev?: boolean\n host?: string\n}\n\nexport async function watchCommand(opts: WatchOptions): Promise<void> {\n const cwd = process.cwd()\n const srcDir = path.join(cwd, 'src')\n\n let running = false\n let pending = false\n\n const runCycle = async () => {\n if (running) {\n pending = true\n return\n }\n running = true\n try {\n log.step('Rebuilding...')\n await buildCommand()\n\n log.step('Validating...')\n const result = await validatePluginDir(cwd)\n if (!result.ok) {\n log.error(`Validation failed: ${result.error}`)\n return\n }\n log.success(`Valid (content_sha256: ${result.value.contentSha256})`)\n\n if (opts.push) {\n log.step(`Pushing${opts.dev ? ' to dev channel' : ''}...`)\n await pushCommand({ host: opts.host, dev: opts.dev, activate: true })\n }\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err))\n } finally {\n running = false\n if (pending) {\n pending = false\n void runCycle()\n }\n }\n }\n\n log.info(`Watching ${srcDir} for changes (Ctrl+C to stop)...`)\n const watcher = chokidar.watch(srcDir, { ignoreInitial: true })\n watcher.on('all', () => {\n void runCycle()\n })\n\n await runCycle()\n\n await new Promise<void>((resolve) => {\n process.on('SIGINT', () => {\n void watcher.close().then(() => resolve())\n })\n })\n}\n","import { resolveContext, requireToken } from '../context.js'\nimport { printResult } from '../util.js'\n\nexport async function whoamiCommand(opts: { host?: string; json?: boolean }): Promise<void> {\n const ctx = await resolveContext({ host: opts.host })\n requireToken(ctx)\n const me = await ctx.client.getMe()\n\n printResult(!!opts.json, { host: ctx.host, ...me }, (data) => {\n console.log(`host: ${data.host}`)\n console.log(`user: ${data.email ?? data.user_id}`)\n console.log(`org: ${data.organization_name ?? data.organization_id}`)\n console.log(`auth: ${data.auth_method}`)\n })\n}\n","import { createRequire } from 'node:module'\nimport { Command } from 'commander'\nimport { ApiError } from './api.js'\nimport { buildCommand } from './commands/build.js'\nimport { doctorCommand } from './commands/doctor.js'\nimport { downloadCommand } from './commands/download.js'\nimport { initCommand } from './commands/init.js'\nimport { loginCommand } from './commands/login.js'\nimport { openCommand } from './commands/open.js'\nimport { packCommand } from './commands/pack.js'\nimport { pushCommand } from './commands/push.js'\nimport { rollbackCommand } from './commands/rollback.js'\nimport { routeSetCommand } from './commands/route.js'\nimport { statusCommand } from './commands/status.js'\nimport { validateCommand } from './commands/validate.js'\nimport { versionsCommand } from './commands/versions.js'\nimport { watchCommand } from './commands/watch.js'\nimport { whoamiCommand } from './commands/whoami.js'\nimport { CliError, log } from './util.js'\n\nconst CLI_VERSION = createRequire(import.meta.url)('../package.json').version as string\n\nfunction action<Args extends unknown[]>(fn: (...args: Args) => Promise<void>) {\n return async (...args: Args) => {\n try {\n await fn(...args)\n } catch (err) {\n if (err instanceof CliError) {\n log.error(err.message)\n process.exitCode = err.exitCode\n } else if (err instanceof ApiError) {\n log.error(`${err.message}${err.code ? ` [${err.code}]` : ''}`)\n process.exitCode = 1\n } else {\n log.error(err instanceof Error ? err.message : String(err))\n process.exitCode = 1\n }\n }\n }\n}\n\nconst program = new Command()\n\nprogram\n .name('cervio')\n .description('Cervio route plugin developer CLI')\n .version(CLI_VERSION)\n\nprogram\n .command('login')\n .description('Authenticate with a Cervio host and save the token')\n .option('--host <url>', 'Cervio host, e.g. https://app.example.com')\n .option('--token <token>', 'Personal access token (prompted if omitted)')\n .action(action(loginCommand))\n\nprogram\n .command('whoami')\n .description('Print the current host and identity')\n .option('--host <url>', 'Override the resolved host')\n .option('--json', 'Output JSON')\n .action(action(whoamiCommand))\n\nprogram\n .command('build')\n .description('Run the project build script (pnpm/npm run build)')\n .action(action(buildCommand))\n\nprogram\n .command('validate')\n .description('Validate the plugin in the current directory')\n .option('--json', 'Output JSON')\n .action(action(validateCommand))\n\nprogram\n .command('pack')\n .description('Pack the built plugin into .cervio/out/<plugin_key>.zip')\n .option('--json', 'Output JSON')\n .action(action(packCommand))\n\nprogram\n .command('push')\n .description('Validate, pack, and upload the plugin to a Cervio host')\n .option('--host <url>', 'Override the resolved host')\n .option('--changelog <text>', 'Changelog note for this version')\n .option('--no-activate', 'Upload without making this the active version')\n .option('--json', 'Output JSON (no interactive prompts)')\n .option('--yes', 'Skip the host-change confirmation prompt')\n .option('--expect-host <url>', 'Fail if the resolved host does not match')\n .option('--dev', 'Push to the dev channel instead of the release channel')\n .option('--force', 'Bypass the dev-channel conflict check')\n .option('--file <path>', 'Upload an existing ZIP instead of packing the current directory')\n .action(action(pushCommand))\n\nprogram\n .command('status')\n .description('Compare the local build against the deployed version')\n .option('--host <url>', 'Override the resolved host')\n .option('--dev', 'Compare against the dev channel instead')\n .option('--json', 'Output JSON')\n .action(action(statusCommand))\n\nprogram\n .command('init [name]')\n .description('Scaffold a new plugin project')\n .action(action(initCommand))\n\nprogram\n .command('watch')\n .description('Rebuild and validate on src/ changes')\n .option('--push', 'Push after each successful validation')\n .option('--dev', 'Push to the dev channel (with --push)')\n .option('--host <url>', 'Override the resolved host (with --push)')\n .action(action(watchCommand))\n\nprogram\n .command('doctor')\n .description('Diagnose host connectivity, auth, manifest, and entity deps')\n .option('--host <url>', 'Override the resolved host')\n .option('--json', 'Output JSON')\n .action(action(doctorCommand))\n\nprogram\n .command('versions')\n .description('List released versions for the current plugin')\n .option('--host <url>', 'Override the resolved host')\n .option('--json', 'Output JSON')\n .action(action(versionsCommand))\n\nprogram\n .command('download')\n .description('Download a release or dev-channel ZIP from the host')\n .option('--host <url>', 'Override the resolved host')\n .option('--release <semver>', 'Download a specific release version (default: current)')\n .option('--dev', 'Download the dev-channel artifact instead of a release')\n .option('-o, --output <path>', 'Output path (default: .cervio/out/<plugin_key>-….zip)')\n .option('--json', 'Output JSON')\n .action(action(downloadCommand))\n\nprogram\n .command('rollback <version>')\n .description('Activate a previously released version')\n .option('--host <url>', 'Override the resolved host')\n .option('--json', 'Output JSON')\n .action(action(rollbackCommand))\n\nconst route = program.command('route').description('Manage the plugin route configuration')\nroute\n .command('set')\n .description('Update the route slug, cache, and/or dev-channel setting')\n .option('--host <url>', 'Override the resolved host')\n .option('--slug <slug>', 'New route slug')\n .option('--cache <onoff>', 'Enable/disable route caching (\"on\" or \"off\")')\n .option('--dev-channel <onoff>', 'Enable/disable the plugin dev channel (\"on\" or \"off\")')\n .option('--json', 'Output JSON')\n .action(action(routeSetCommand))\n\nprogram\n .command('open')\n .description('Open the plugin route in a browser')\n .option('--host <url>', 'Override the resolved host')\n .action(action(openCommand))\n\nprogram.parseAsync(process.argv).catch((err) => {\n log.error(err instanceof Error ? err.message : String(err))\n process.exitCode = 1\n})\n"]}