@beryl-so/cli 0.63.2 → 0.67.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/README.md +4 -3
- package/dist/beryl-test-skill.js +6 -4
- package/dist/commands/accounts.js +36 -12
- package/dist/commands/environments.js +5 -0
- package/dist/commands/health.js +3 -1
- package/dist/commands/projects.js +19 -15
- package/dist/commands/tests.js +24 -8
- package/dist/commands/tracker.js +4 -1
- package/dist/context.js +1 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# beryl CLI
|
|
4
4
|
|
|
5
|
-
Beryl on the command line: create projects,
|
|
5
|
+
Beryl on the command line: create projects, author tests,
|
|
6
6
|
trigger runs in CI, manage everything the web app can, plus an MCP server (`beryl mcp`)
|
|
7
7
|
that exposes every command to coding agents.
|
|
8
8
|
|
|
@@ -166,7 +166,7 @@ Send, list, and revoke workspace invitations, and accept ones sent to you.
|
|
|
166
166
|
|
|
167
167
|
### projects
|
|
168
168
|
|
|
169
|
-
Create and manage projects: a site
|
|
169
|
+
Create and manage projects: a site you author tests for and run.
|
|
170
170
|
|
|
171
171
|
`beryl projects` with no subcommand runs `projects list`.
|
|
172
172
|
|
|
@@ -174,7 +174,7 @@ Create and manage projects: a site Beryl explores, authors tests for, and runs.
|
|
|
174
174
|
| --- | --- | --- |
|
|
175
175
|
| `beryl projects list` | List projects in the workspace | `projects_list` |
|
|
176
176
|
| `beryl projects get` | Show one project, including its current exploration state | `projects_get` |
|
|
177
|
-
| `beryl projects create [url]` | Create a project
|
|
177
|
+
| `beryl projects create [url]` | Create a project for a URL, or an empty one with just --name | `projects_create` |
|
|
178
178
|
| `beryl projects rename <name>` | Rename a project | `projects_rename` |
|
|
179
179
|
| `beryl projects quarantine [state]` | Turn auto quarantine on or off and tune when it mutes and releases a test | `projects_quarantine` |
|
|
180
180
|
| `beryl projects delete` | Delete a project and all its tests and runs | `projects_delete` |
|
|
@@ -354,6 +354,7 @@ Durable identities on the site under test: what an authenticated test signs in a
|
|
|
354
354
|
| Command | Summary | MCP tool |
|
|
355
355
|
| --- | --- | --- |
|
|
356
356
|
| `beryl accounts list` | List the test accounts an environment's tests sign in as | `accounts_list` |
|
|
357
|
+
| `beryl accounts get <account-id>` | Show one test account: origin, lifetime, sign-in state | `accounts_get` |
|
|
357
358
|
| `beryl accounts create` | Add a test account: the customer's own, or one Beryl signs up | `accounts_create` |
|
|
358
359
|
| `beryl accounts signup <account-id>` | Store a test account's signup plan and sign it up on its environment | `accounts_signup` |
|
|
359
360
|
| `beryl accounts set-login <account-id>` | Store the sign-in plan a run replays once, plus the probe that proves it | `accounts_set_login` |
|
package/dist/beryl-test-skill.js
CHANGED
|
@@ -115,7 +115,9 @@ Set up (once): if you cannot call the Beryl tools yet, run \`beryl init\` in a t
|
|
|
115
115
|
install the browser and wire the tools. Then, before the first plan:
|
|
116
116
|
|
|
117
117
|
- \`envs_list\`: the root URL gotos resolve against (§2). If it is empty, set it with
|
|
118
|
-
\`envs_update
|
|
118
|
+
\`envs_update\` to a URL Beryl's cloud can reach, never \`localhost\`, \`127.0.0.1\`
|
|
119
|
+
or a private IP (refused). For a local dev server, pass \`url-override\` to
|
|
120
|
+
\`tests_create\` and \`runs_local\` instead.
|
|
119
121
|
- \`accounts_list\`: who do authenticated tests sign in as (§1)? Store its sign-in with
|
|
120
122
|
\`accounts_set_login\`, prove it with \`accounts_check\`.
|
|
121
123
|
- \`mailbox_get\`: the address the account receives mail at (§5).
|
|
@@ -143,9 +145,9 @@ An authenticated test **signs in as an account that already exists** — it does
|
|
|
143
145
|
one up. Start every authoring session with \`accounts_list\`:
|
|
144
146
|
|
|
145
147
|
\`\`\`
|
|
146
|
-
label email type
|
|
147
|
-
default * qa@acme.test
|
|
148
|
-
admin qa+admin@x7k2p9.email.beryl.so
|
|
148
|
+
label email type login status
|
|
149
|
+
default * qa@acme.test provided password ready
|
|
150
|
+
admin qa+admin@x7k2p9.email.beryl.so provisioned (permanent) otp ready
|
|
149
151
|
\`\`\`
|
|
150
152
|
|
|
151
153
|
Author the sign-in as ordinary opening steps citing the reserved handles — fill
|
|
@@ -26,7 +26,7 @@ function accountTable(rows) {
|
|
|
26
26
|
return table(rows.map((a) => ({
|
|
27
27
|
label: a.identity_label + (a.is_default ? " *" : ""),
|
|
28
28
|
email: a.email,
|
|
29
|
-
type: a.type,
|
|
29
|
+
type: a.type + (a.lifetime ? ` (${a.lifetime})` : ""),
|
|
30
30
|
login: a.login_method,
|
|
31
31
|
status: a.status,
|
|
32
32
|
id: a.id,
|
|
@@ -58,14 +58,31 @@ export const testAccountCommands = [
|
|
|
58
58
|
return { data: rows, human: accountTable(rows) };
|
|
59
59
|
},
|
|
60
60
|
},
|
|
61
|
+
{
|
|
62
|
+
name: "accounts get",
|
|
63
|
+
summary: "Show one test account: origin, lifetime, sign-in state",
|
|
64
|
+
description: "One test account by id. `type` is its origin: captured (a session from the Chrome " +
|
|
65
|
+
"plugin), provisioned (Beryl signed it up; `lifetime` permanent or throwaway), or " +
|
|
66
|
+
"provided (your own account).",
|
|
67
|
+
scope: "project",
|
|
68
|
+
args: [{ name: "account-id", description: "Account id from `beryl accounts list`", required: true }],
|
|
69
|
+
examples: ["beryl accounts get acc_123"],
|
|
70
|
+
async run(ctx, input) {
|
|
71
|
+
const { workspaceId, projectId } = await ctx.requireProject(input);
|
|
72
|
+
const account = (await ctx.client.get(`${accountsPath(workspaceId, projectId)}/${arg(input, "account-id")}`));
|
|
73
|
+
return { data: account, human: accountTable([account]) };
|
|
74
|
+
},
|
|
75
|
+
},
|
|
61
76
|
{
|
|
62
77
|
name: "accounts create",
|
|
63
78
|
summary: "Add a test account: the customer's own, or one Beryl signs up",
|
|
64
|
-
description: "Two kinds. `--type
|
|
65
|
-
"the site: pass --email and --password, and it is usable immediately.
|
|
66
|
-
"reserves one Beryl will sign up itself, addressed at the project
|
|
67
|
-
"`
|
|
68
|
-
"
|
|
79
|
+
description: "Two kinds. `--type provided` records a dedicated account you already have on " +
|
|
80
|
+
"the site: pass --email and --password, and it is usable immediately. " +
|
|
81
|
+
"`--type provisioned` reserves one Beryl will sign up itself, addressed at the project " +
|
|
82
|
+
"mailbox; `--lifetime` says whether it is kept (permanent, the default) or a " +
|
|
83
|
+
"throwaway. It starts `pending` and becomes usable after `beryl accounts signup`. " +
|
|
84
|
+
"A captured account (a signed-in session from the Chrome plugin) is not created here. " +
|
|
85
|
+
"Works for Google-only apps too: bank a dedicated Google test account as provided " +
|
|
69
86
|
"and author its sign-in plan through Google's form. " +
|
|
70
87
|
"The first account an environment gets is its default whatever you pass.",
|
|
71
88
|
scope: "project",
|
|
@@ -73,19 +90,25 @@ export const testAccountCommands = [
|
|
|
73
90
|
{
|
|
74
91
|
name: "type",
|
|
75
92
|
type: "string",
|
|
76
|
-
enum: ["
|
|
77
|
-
description: "Whose account this is (default:
|
|
93
|
+
enum: ["provided", "provisioned"],
|
|
94
|
+
description: "Whose account this is (default: provided when --password is given)",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "lifetime",
|
|
98
|
+
type: "string",
|
|
99
|
+
enum: ["permanent", "throwaway"],
|
|
100
|
+
description: "provisioned only: keep it, or a throwaway (default permanent)",
|
|
78
101
|
},
|
|
79
102
|
{
|
|
80
103
|
name: "label",
|
|
81
104
|
type: "string",
|
|
82
105
|
description: "Identity label a plan's auth_label names (default 'default')",
|
|
83
106
|
},
|
|
84
|
-
{ name: "email", type: "string", description: "
|
|
107
|
+
{ name: "email", type: "string", description: "provided only: the account's email" },
|
|
85
108
|
{
|
|
86
109
|
name: "password",
|
|
87
110
|
type: "string",
|
|
88
|
-
description: "
|
|
111
|
+
description: "provided only: stored encrypted as a project secret, never returned",
|
|
89
112
|
},
|
|
90
113
|
{
|
|
91
114
|
name: "login-method",
|
|
@@ -98,7 +121,7 @@ export const testAccountCommands = [
|
|
|
98
121
|
],
|
|
99
122
|
examples: [
|
|
100
123
|
"beryl accounts create --email qa@acme.test --password 'hunter2'",
|
|
101
|
-
"beryl accounts create --type
|
|
124
|
+
"beryl accounts create --type provisioned --login-method otp",
|
|
102
125
|
"beryl accounts create --email admin@acme.test --password 'hunter2' --label admin",
|
|
103
126
|
"beryl accounts create --email qa@gmail.com --password 'hunter2' # Google-only app",
|
|
104
127
|
],
|
|
@@ -106,7 +129,8 @@ export const testAccountCommands = [
|
|
|
106
129
|
const { workspaceId, projectId } = await ctx.requireProject(input);
|
|
107
130
|
const password = flagStr(input, "password");
|
|
108
131
|
const account = (await ctx.client.post(accountsPath(workspaceId, projectId), {
|
|
109
|
-
type: flagStr(input, "type") ?? (password ? "
|
|
132
|
+
type: flagStr(input, "type") ?? (password ? "provided" : "provisioned"),
|
|
133
|
+
lifetime: flagStr(input, "lifetime") ?? null,
|
|
110
134
|
identity_label: flagStr(input, "label") ?? "default",
|
|
111
135
|
email: flagStr(input, "email") ?? null,
|
|
112
136
|
password: password ?? null,
|
|
@@ -29,6 +29,11 @@ export const environmentCommands = [
|
|
|
29
29
|
{
|
|
30
30
|
name: "envs get",
|
|
31
31
|
summary: "Show one environment",
|
|
32
|
+
description: "`site_health_runs_reset_fields` and `site_health_tracker_reset_fields` name stored Site " +
|
|
33
|
+
"Health settings that were invalid and fell back to defaults (`*` = all of them). " +
|
|
34
|
+
"Scheduled and CI runs, or ticket filing, auto-close and the digest, stop until they are " +
|
|
35
|
+
"saved again: `envs update` with any `--health-*` flag rewrites the run settings, any " +
|
|
36
|
+
"`--tracker-*` flag the tracker settings.",
|
|
32
37
|
scope: "project",
|
|
33
38
|
args: [{ name: "env-id", description: "Environment id", required: true }],
|
|
34
39
|
async run(ctx, input) {
|
package/dist/commands/health.js
CHANGED
|
@@ -277,7 +277,9 @@ export const healthCommands = [
|
|
|
277
277
|
"and on desktop separately (`speeds`, each with its own Core Web Vitals) and takes " +
|
|
278
278
|
"the worse of the two; one that couldn't be measured is left out. A category's `unchecked` lists checks this run " +
|
|
279
279
|
"couldn't determine (e.g. robots.txt timed out): they neither pass nor fail. Pass --report for a single-page check started with " +
|
|
280
|
-
"`health run --path`."
|
|
280
|
+
"`health run --path`. `site_health_runs_reset_fields` and `site_health_tracker_reset_fields` " +
|
|
281
|
+
"name stored settings that were invalid and fell back to defaults (`*` = all of them): " +
|
|
282
|
+
"scheduled and CI runs, or ticket filing, stop until they are saved again with `envs update`.",
|
|
281
283
|
scope: "project",
|
|
282
284
|
flags: [
|
|
283
285
|
ENV_FLAG,
|
|
@@ -37,7 +37,7 @@ export const projectCommands = [
|
|
|
37
37
|
summary: "List projects in the workspace",
|
|
38
38
|
scope: "workspace",
|
|
39
39
|
groupDefault: true,
|
|
40
|
-
groupSummary: "Create and manage projects: a site
|
|
40
|
+
groupSummary: "Create and manage projects: a site you author tests for and run.",
|
|
41
41
|
async run(ctx, input) {
|
|
42
42
|
const ws = await ctx.requireWorkspace(input);
|
|
43
43
|
const rows = (await ctx.client.get(`/workspaces/${ws}/projects`));
|
|
@@ -70,7 +70,7 @@ export const projectCommands = [
|
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
name: "projects create",
|
|
73
|
-
summary: "Create a project
|
|
73
|
+
summary: "Create a project for a URL, or an empty one with just --name",
|
|
74
74
|
scope: "workspace",
|
|
75
75
|
args: [
|
|
76
76
|
{
|
|
@@ -95,24 +95,26 @@ export const projectCommands = [
|
|
|
95
95
|
},
|
|
96
96
|
{ name: "force-new-login", type: "boolean", description: "Ignore any reusable saved login" },
|
|
97
97
|
{
|
|
98
|
-
name: "
|
|
98
|
+
name: "explore",
|
|
99
99
|
type: "boolean",
|
|
100
|
-
description: "
|
|
101
|
-
"
|
|
100
|
+
description: "Also start a cloud exploration that authors tests for you. Off by default: author " +
|
|
101
|
+
"tests with `beryl tests create` or your coding agent over MCP",
|
|
102
|
+
mcpDescription: "Leave unset: you author the tests yourself with `tests create`. Set only when the " +
|
|
103
|
+
"user explicitly asks for a cloud exploration",
|
|
102
104
|
},
|
|
103
|
-
{ name: "watch", type: "boolean", description: "
|
|
105
|
+
{ name: "watch", type: "boolean", description: "Start the exploration (implies --explore) and stream it live" },
|
|
104
106
|
{ name: "timeout", type: "number", description: "With --watch: max minutes to wait" },
|
|
105
107
|
],
|
|
106
108
|
examples: [
|
|
107
|
-
"beryl projects create https://app.example.com
|
|
109
|
+
"beryl projects create https://app.example.com",
|
|
108
110
|
"beryl projects create https://app.example.com --auth gated",
|
|
109
|
-
"beryl projects create https://app.example.com --auth public --no-explore",
|
|
110
111
|
'beryl projects create --name "Acme production"',
|
|
111
112
|
],
|
|
112
113
|
async run(ctx, input) {
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
114
|
+
const watch = flagBool(input, "watch");
|
|
115
|
+
if (input.flags.explore === false && watch)
|
|
115
116
|
throw new UsageError("--no-explore cannot be combined with --watch");
|
|
117
|
+
const explore = flagBool(input, "explore") || watch;
|
|
116
118
|
const ws = await ctx.requireWorkspace(input);
|
|
117
119
|
const rawUrl = input.args.url;
|
|
118
120
|
const url = typeof rawUrl === "string" ? rawUrl : "";
|
|
@@ -121,7 +123,9 @@ export const projectCommands = [
|
|
|
121
123
|
// later with `beryl envs update <env-id>` or author over the CLI/MCP.
|
|
122
124
|
if (!url) {
|
|
123
125
|
if (!name)
|
|
124
|
-
throw new UsageError("Provide a URL
|
|
126
|
+
throw new UsageError("Provide a URL, or --name to create an empty project");
|
|
127
|
+
if (explore)
|
|
128
|
+
throw new UsageError("--explore and --watch need a URL to explore");
|
|
125
129
|
const created = (await ctx.client.post(`/workspaces/${ws}/projects`, {
|
|
126
130
|
name,
|
|
127
131
|
}));
|
|
@@ -137,13 +141,13 @@ export const projectCommands = [
|
|
|
137
141
|
root_url: url,
|
|
138
142
|
requires_auth_choice: auth,
|
|
139
143
|
force_new_login: flagBool(input, "force-new-login"),
|
|
140
|
-
skip_exploration:
|
|
144
|
+
skip_exploration: !explore,
|
|
141
145
|
}));
|
|
142
|
-
if (
|
|
146
|
+
if (!explore)
|
|
143
147
|
return {
|
|
144
148
|
data: created,
|
|
145
|
-
human: `${green("Project created")}: ${created.project_id}
|
|
146
|
-
`Ready for your own tests
|
|
149
|
+
human: `${green("Project created")}: ${created.project_id}\n` +
|
|
150
|
+
`Ready for your own tests: author a plan and push it with \`beryl tests create\`.`,
|
|
147
151
|
};
|
|
148
152
|
// The agent cannot start until a login is captured, so there is nothing to watch.
|
|
149
153
|
if (created.auth_status === "needs_capture")
|
package/dist/commands/tests.js
CHANGED
|
@@ -89,7 +89,7 @@ function verifyFailureResult(err) {
|
|
|
89
89
|
// The concise human table for `tests list` — the full TestResponse is a 24-column
|
|
90
90
|
// firehose of internal ids that wraps unreadably in a normal terminal. `--wide`
|
|
91
91
|
// (and `--json`) still expose every field.
|
|
92
|
-
const LIST_COLUMNS = ["title", "status", "access", "id", "last_result_status", "last_run_at"];
|
|
92
|
+
const LIST_COLUMNS = ["title", "surface", "status", "access", "id", "last_result_status", "last_run_at"];
|
|
93
93
|
const ACCESS_VALUES = ["read", "write"];
|
|
94
94
|
function accessFlag(input, fallback) {
|
|
95
95
|
const raw = flagStr(input, "access") ?? fallback;
|
|
@@ -101,6 +101,7 @@ function accessFlag(input, fallback) {
|
|
|
101
101
|
function conciseTestRow(row) {
|
|
102
102
|
return {
|
|
103
103
|
title: row.nl_title,
|
|
104
|
+
surface: row.surface,
|
|
104
105
|
status: row.quarantined ? "quarantined" : row.is_active ? "active" : "inactive",
|
|
105
106
|
access: row.access,
|
|
106
107
|
id: row.id,
|
|
@@ -188,8 +189,8 @@ export const testCommands = [
|
|
|
188
189
|
{
|
|
189
190
|
name: "status",
|
|
190
191
|
type: "string",
|
|
191
|
-
description: "With --page, show only this bucket: passed, failed
|
|
192
|
-
"quarantined, or unstable
|
|
192
|
+
description: "With --page, show only this bucket: passed, failing (failed or errored), " +
|
|
193
|
+
"failed, errored, cancelled, quarantined, or unstable",
|
|
193
194
|
},
|
|
194
195
|
{
|
|
195
196
|
name: "ungrouped",
|
|
@@ -291,7 +292,8 @@ export const testCommands = [
|
|
|
291
292
|
"reconcile with that test (`tests get` / `tests set-plan`), don't rename-and-retry; a " +
|
|
292
293
|
"409 `plan_hash_mismatch` means the submitted plan is not the bytes that were replayed " +
|
|
293
294
|
"(re-run `tests create`); a 429 with Retry-After 30 means the verify slots are " +
|
|
294
|
-
"saturated (wait and retry)."
|
|
295
|
+
"saturated (wait and retry). A server-side verify that could not run (verdict `flag`) " +
|
|
296
|
+
"still banks the test but returns verified:false and exits 1; prove it with `tests recompile`.",
|
|
295
297
|
scope: "project",
|
|
296
298
|
flags: [
|
|
297
299
|
{ name: "title", type: "string", required: true, description: "Title for the new test" },
|
|
@@ -374,7 +376,18 @@ export const testCommands = [
|
|
|
374
376
|
const verifyInCloud = async (reason) => {
|
|
375
377
|
ctx.err(yellow(`! ${reason}, so this plan is verified server-side instead.`));
|
|
376
378
|
try {
|
|
377
|
-
|
|
379
|
+
const created = await bank({ verify: true, plan_hash: compiled.plan_hash });
|
|
380
|
+
if (created.verified === false) {
|
|
381
|
+
// The replay could not run (verdict "flag"): saved, but nothing was proven.
|
|
382
|
+
return {
|
|
383
|
+
data: created,
|
|
384
|
+
human: yellow(`Banked UNVERIFIED: ${created.id}. The server-side replay could not run` +
|
|
385
|
+
(created.verify_message ? ` (${String(created.verify_message)})` : "") +
|
|
386
|
+
"; the test is saved but unproven. Prove it with `tests recompile`."),
|
|
387
|
+
exitCode: 1,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return { data: created };
|
|
378
391
|
}
|
|
379
392
|
catch (err) {
|
|
380
393
|
const failure = verifyFailureResult(err);
|
|
@@ -524,8 +537,9 @@ export const testCommands = [
|
|
|
524
537
|
ctx.err(yellow(`! The proof ran against ${urlOverride}, not the environment's root URL — ` +
|
|
525
538
|
"the banked test is unproven against its real target until a run there passes."));
|
|
526
539
|
}
|
|
540
|
+
// The server saw verify:false; the proof is the local replay, unless it ran off-target.
|
|
527
541
|
return {
|
|
528
|
-
data: created,
|
|
542
|
+
data: { ...created, verified: !urlOverride, verdict: "keep", verified_by: "local" },
|
|
529
543
|
human: green(`✓ Replay passed locally — banked as ${created.id}`),
|
|
530
544
|
};
|
|
531
545
|
},
|
|
@@ -583,7 +597,8 @@ export const testCommands = [
|
|
|
583
597
|
description: "Groups are project-defined labels used to filter, run, or schedule a slice of the " +
|
|
584
598
|
"suite (`beryl runs trigger --group <name>`). This REPLACES the whole set: pass every " +
|
|
585
599
|
"group you want, or none to clear it. Names must already exist in the project " +
|
|
586
|
-
"(`beryl groups list`); an unknown name is an error, never a new group."
|
|
600
|
+
"(`beryl groups list`); an unknown name is an error, never a new group. Every " +
|
|
601
|
+
"surface of the test carries the same set.",
|
|
587
602
|
scope: "project",
|
|
588
603
|
args: [{ name: "test-id", description: "Test id", required: true }],
|
|
589
604
|
flags: [
|
|
@@ -611,7 +626,8 @@ export const testCommands = [
|
|
|
611
626
|
summary: "Mark a test read or write",
|
|
612
627
|
description: "read: the test only reads the app. write: it creates, edits, renames, deletes or " +
|
|
613
628
|
"toggles something that persists. The label is yours to set; Beryl does not infer it " +
|
|
614
|
-
"from the plan. A write test must clean up in `after`, ending with a proof expect."
|
|
629
|
+
"from the plan. A write test must clean up in `after`, ending with a proof expect. " +
|
|
630
|
+
"The label covers every surface of the test, so each surface's plan must clean up.",
|
|
615
631
|
scope: "project",
|
|
616
632
|
args: [
|
|
617
633
|
{ name: "test-id", description: "Test id", required: true },
|
package/dist/commands/tracker.js
CHANGED
|
@@ -195,7 +195,10 @@ export const trackerCommands = [
|
|
|
195
195
|
"revoked; ticket changes queue until you reconnect), the number of queued changes, " +
|
|
196
196
|
"open tickets (filed in the tracker), `unfiled_tickets` the tracker hasn't accepted " +
|
|
197
197
|
"yet with its `last_sync_error`, digest findings, and `last_sync`: what the latest run filed, " +
|
|
198
|
-
"updated, closed or skipped.
|
|
198
|
+
"updated, closed or skipped. `reset_fields` names stored settings that were invalid and " +
|
|
199
|
+
"fell back to defaults (`*` = all of them); filing, auto-close and the digest stop " +
|
|
200
|
+
"(`last_sync.skipped: settings_invalid`) until they are saved again. Change settings " +
|
|
201
|
+
"with `envs update --tracker-*`.",
|
|
199
202
|
scope: "project",
|
|
200
203
|
flags: [ENV_FLAG],
|
|
201
204
|
async run(ctx, input) {
|
package/dist/context.js
CHANGED
|
@@ -133,8 +133,7 @@ export function createContext(options) {
|
|
|
133
133
|
projectId = projects[0].id;
|
|
134
134
|
}
|
|
135
135
|
else if (projects.length === 0) {
|
|
136
|
-
throw new CliError("This workspace has no project yet
|
|
137
|
-
"`beryl projects create <url>` (add --no-explore to author tests yourself).");
|
|
136
|
+
throw new CliError("This workspace has no project yet. Create one with `beryl projects create <url>`.");
|
|
138
137
|
}
|
|
139
138
|
else {
|
|
140
139
|
projectId = await pickOne(ctx, projects, "project", ambiguousMessage(ctx, "project", projects));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beryl-so/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Beryl on the command line: projects,
|
|
3
|
+
"version": "0.67.0",
|
|
4
|
+
"description": "Beryl on the command line: projects, tests, runs, and an MCP server over the same commands.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://beryl.so/docs/cli",
|