@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 +21 -0
- package/README.md +25 -24
- package/dist/cli.js +78 -50
- package/package.json +29 -21
- package/dist/cli.js.map +0 -1
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
|
|
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": "..." } }`
|
|
42
|
-
| `~/.cervio/state.json` | `{ "lastHost": "<host>" }`
|
|
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`
|
|
48
|
-
- `CERVIO_TOKEN`
|
|
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
|
|
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
|
-
|
|
67
|
-
|
|
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>`, `--
|
|
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`
|
|
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`
|
|
146
|
-
to already exist on the host** (i.e. at least one prior non-dev push)
|
|
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`
|
|
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
|
|
182
|
-
|
|
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
|
|
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 --
|
|
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`
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
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
|
|
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` (
|
|
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
|
-
*
|
|
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
|
|
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)
|
|
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
|
|
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(
|
|
161
|
-
warn: (msg) => console.warn(
|
|
162
|
-
error: (msg) => console.error(
|
|
163
|
-
step: (msg) => console.log(
|
|
164
|
-
dim: (msg) => console.log(
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
271
|
+
await writeJsonFile(credentialsPath(), creds);
|
|
252
272
|
}
|
|
253
273
|
async function readState() {
|
|
254
|
-
return readJsonFile(
|
|
274
|
+
return readJsonFile(statePath(), {});
|
|
255
275
|
}
|
|
256
276
|
async function writeState(state) {
|
|
257
|
-
await writeJsonFile(
|
|
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
|
|
415
|
-
let artifactSha256
|
|
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
|
-
|
|
488
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
693
|
+
zipPath = packed.outputPath;
|
|
664
694
|
zipFileName = `${packed.pluginKey}.zip`;
|
|
665
695
|
}
|
|
666
696
|
const form = new FormData();
|
|
667
|
-
form.set("file",
|
|
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
|
|
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 ? ` (
|
|
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
|
|
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
|
-
|
|
957
|
-
watcher
|
|
958
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
4
|
-
"description": "Developer CLI for Cervio
|
|
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
|
-
"
|
|
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
|
|
33
|
+
"@cervio/create-plugin": "^1.0.0",
|
|
34
|
+
"@cervio/plugin-core": "^1.0.0"
|
|
20
35
|
},
|
|
21
36
|
"devDependencies": {
|
|
22
|
-
"@types/node": "^
|
|
37
|
+
"@types/node": "^26.0.0",
|
|
23
38
|
"@types/prompts": "^2.4.9",
|
|
24
|
-
"tsup": "^
|
|
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":"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","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"]}
|