@beryl-so/cli 0.77.1 → 0.78.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/dist/beryl-test-skill.js +7 -0
- package/dist/commands/runs.js +4 -3
- package/dist/commands/watch.js +21 -10
- package/dist/schema.generated.js +31 -1
- package/dist/skill-tables.js +1 -0
- package/package.json +1 -1
package/dist/beryl-test-skill.js
CHANGED
|
@@ -425,6 +425,13 @@ observable proof the flow worked.
|
|
|
425
425
|
chrome. Target the element that carries the text (the \`h1\`, the toast), assert the
|
|
426
426
|
page with \`have_title\` (substring), or check "this string is visible somewhere"
|
|
427
427
|
with \`expect_kind: "visible"\` + a \`text=…\` selector.
|
|
428
|
+
- **For output that varies run to run** (a chatbot or AI assistant reply), assert its
|
|
429
|
+
meaning with \`expect_kind: "judged"\`: \`selector\` locates the reply (the LAST match
|
|
430
|
+
is judged, so a selector matching every assistant message reads the newest one) and
|
|
431
|
+
\`expect_text\` states the criteria in plain words ("Lists at least two decisions and
|
|
432
|
+
names the people involved; no error or refusal"). Beryl waits up to 120s for the text
|
|
433
|
+
to appear and stop changing, then a model passes or fails it and the failure carries
|
|
434
|
+
the model's reason. Write criteria a correct answer always meets, never exact wording.
|
|
428
435
|
- **If you can't name a success signal, the flow is not test-worthy.** Don't bank a
|
|
429
436
|
test that verifies nothing; explore a different flow.
|
|
430
437
|
- **Don't work around a real app failure to make a test go green.** A genuinely broken
|
package/dist/commands/runs.js
CHANGED
|
@@ -152,9 +152,10 @@ export const runCommands = [
|
|
|
152
152
|
"settled tests only: anything still running, healing or queued is left out. A result " +
|
|
153
153
|
"carries `heal` when Beryl healed it: its steps were rewritten with the intent " +
|
|
154
154
|
"unchanged, proved in a browser and it re-ran green; `version_no` is the revision it " +
|
|
155
|
-
"wrote (see `tests diff`) and `rationale` the agent's reason. A
|
|
156
|
-
"
|
|
157
|
-
"
|
|
155
|
+
"wrote (see `tests diff`) and `rationale` the agent's reason. A red that Beryl tried and " +
|
|
156
|
+
"failed to heal carries `heal_attempt`: `status` is how the heal ended, `reason` why, " +
|
|
157
|
+
"and `heal_job_id` the job. A red that Beryl did not try to heal carries " +
|
|
158
|
+
"`heal_skip_reason` saying why. " +
|
|
158
159
|
"`runs report` returns the generated report document, `runs explain` an AI explanation " +
|
|
159
160
|
"of one failed result.",
|
|
160
161
|
scope: "project",
|
package/dist/commands/watch.js
CHANGED
|
@@ -46,6 +46,13 @@ export function findingsGateLine(gate) {
|
|
|
46
46
|
}
|
|
47
47
|
return `findings gate unknown: ${gate.reason ?? "not evaluated"}`;
|
|
48
48
|
}
|
|
49
|
+
export function healNote(r) {
|
|
50
|
+
if (r.heal_attempt) {
|
|
51
|
+
const why = r.heal_attempt.reason ? `: ${r.heal_attempt.reason.slice(0, 300)}` : "";
|
|
52
|
+
return `Auto-heal did not fix it (${r.heal_attempt.status})${why}`;
|
|
53
|
+
}
|
|
54
|
+
return r.heal_skip_reason ?? null;
|
|
55
|
+
}
|
|
49
56
|
// Auth, client and wrong-host errors fail identically on every retry; only a network
|
|
50
57
|
// blip, a timeout, throttling or a 5xx is worth waiting out.
|
|
51
58
|
function isRetryable(e) {
|
|
@@ -102,8 +109,9 @@ export async function watchRun(ctx, ws, project, runId, timeoutMinutes, opts = {
|
|
|
102
109
|
ctx.err(red(detail.replace(/^/gm, " ")));
|
|
103
110
|
process.stdout.write(`::error title=${escapeAnnotationProp(r.title || r.id)}::${escapeAnnotationData(detail)}\n`);
|
|
104
111
|
}
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
const note = ok ? null : healNote(r);
|
|
113
|
+
if (note)
|
|
114
|
+
ctx.err(dim(` ${note}`));
|
|
107
115
|
};
|
|
108
116
|
if (!ctx.json)
|
|
109
117
|
ctx.err(dim(`watching run ${runId}`));
|
|
@@ -260,14 +268,17 @@ export async function watchRun(ctx, ws, project, runId, timeoutMinutes, opts = {
|
|
|
260
268
|
`| ${counters.passed} | ${counters.failed} | ${counters.errored} | ${counters.cancelled} | ${counters.quarantined} | ${counters.total} |`,
|
|
261
269
|
...(gate ? ["", findingsGateLine(gate)] : []),
|
|
262
270
|
...(link ? ["", `[Open the run in Beryl](${link})`] : []),
|
|
263
|
-
...failures.flatMap((r) =>
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
+
...failures.flatMap((r) => {
|
|
272
|
+
const note = healNote(r);
|
|
273
|
+
return [
|
|
274
|
+
"",
|
|
275
|
+
`**✗ ${r.title || r.id}**`,
|
|
276
|
+
"```",
|
|
277
|
+
String(r.error_message ?? "").slice(0, CI_ERROR_MAX_LEN),
|
|
278
|
+
"```",
|
|
279
|
+
...(note ? ["", note] : []),
|
|
280
|
+
];
|
|
281
|
+
}),
|
|
271
282
|
"",
|
|
272
283
|
];
|
|
273
284
|
try {
|
package/dist/schema.generated.js
CHANGED
|
@@ -85,7 +85,8 @@ export const ACTION_PLAN_SCHEMA = {
|
|
|
85
85
|
"have_count",
|
|
86
86
|
"persisted",
|
|
87
87
|
"gone",
|
|
88
|
-
"count_delta"
|
|
88
|
+
"count_delta",
|
|
89
|
+
"judged"
|
|
89
90
|
],
|
|
90
91
|
"title": "ExpectKind",
|
|
91
92
|
"type": "string"
|
|
@@ -835,6 +836,35 @@ export const ACTION_PLAN_SCHEMA = {
|
|
|
835
836
|
]
|
|
836
837
|
}
|
|
837
838
|
},
|
|
839
|
+
{
|
|
840
|
+
"if": {
|
|
841
|
+
"properties": {
|
|
842
|
+
"expect_kind": {
|
|
843
|
+
"const": "judged"
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
"required": [
|
|
847
|
+
"expect_kind"
|
|
848
|
+
]
|
|
849
|
+
},
|
|
850
|
+
"then": {
|
|
851
|
+
"properties": {
|
|
852
|
+
"expect_text": {
|
|
853
|
+
"not": {
|
|
854
|
+
"type": "null"
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
"selector": {
|
|
858
|
+
"minLength": 1,
|
|
859
|
+
"type": "string"
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
"required": [
|
|
863
|
+
"expect_text",
|
|
864
|
+
"selector"
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
},
|
|
838
868
|
{
|
|
839
869
|
"if": {
|
|
840
870
|
"properties": {
|
package/dist/skill-tables.js
CHANGED
|
@@ -57,6 +57,7 @@ export const EXPECT_DOCS = {
|
|
|
57
57
|
persisted: "The record just created is present — a visible match for the `{{unique}}`-named row",
|
|
58
58
|
gone: "Zero matches — absent from the DOM, stronger than `hidden`",
|
|
59
59
|
count_delta: "The match count moved by signed `expect_delta` vs the `capture_ref` baseline",
|
|
60
|
+
judged: "A model judges the LAST match's text, once it stops changing, against the plain-language criteria in `expect_text`: for answers that vary in wording (a chatbot reply)",
|
|
60
61
|
};
|
|
61
62
|
export const EXTRACT_DOCS = {
|
|
62
63
|
code: "the one-time code",
|