@flowriki/agent 0.1.0-beta.42 → 0.1.0-beta.43
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/{chunk-FKD5OAUV.js → chunk-ZMHE47A5.js} +460 -425
- package/dist/cli.js +101 -1
- package/dist/engine.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
helperRunner,
|
|
15
15
|
mirrorCheckTargets,
|
|
16
16
|
openRunSession,
|
|
17
|
+
parseGherkin,
|
|
17
18
|
prepareBrowsers,
|
|
18
19
|
replayCase,
|
|
19
20
|
replayFlow,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
runtimeValue,
|
|
23
24
|
start,
|
|
24
25
|
status
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ZMHE47A5.js";
|
|
26
27
|
|
|
27
28
|
// src/cli.ts
|
|
28
29
|
import { parseArgs } from "util";
|
|
@@ -218,6 +219,20 @@ var ServiceClient = class {
|
|
|
218
219
|
return this.call(`/api/agent/library?${query}`);
|
|
219
220
|
}
|
|
220
221
|
/** Test cases written, edited or linked in one commit; duplicates skipped. */
|
|
222
|
+
readCases(projectId, refs) {
|
|
223
|
+
const ids = refs.filter((r) => /^tc_/.test(r.trim()));
|
|
224
|
+
const names = refs.filter((r) => !/^tc_/.test(r.trim()));
|
|
225
|
+
const q = new URLSearchParams({ projectId, ...ids.length ? { ids: ids.join(",") } : {}, ...names.length ? { names: names.join("|") } : {} });
|
|
226
|
+
return this.call(`/api/agent/cases/read?${q}`);
|
|
227
|
+
}
|
|
228
|
+
/** Test cases written down — business steps, no flows yet — on Claude's
|
|
229
|
+
* working branch. */
|
|
230
|
+
writeCases(projectId, groups, changeId) {
|
|
231
|
+
return this.call(
|
|
232
|
+
`/api/agent/cases/batch?projectId=${encodeURIComponent(projectId)}`,
|
|
233
|
+
{ method: "POST", body: JSON.stringify({ groups, ...changeId ? { changeId } : {} }) }
|
|
234
|
+
);
|
|
235
|
+
}
|
|
221
236
|
saveLibrary(projectId, input) {
|
|
222
237
|
return this.call(`/api/agent/library?projectId=${encodeURIComponent(projectId)}`, { method: "POST", body: JSON.stringify(input) });
|
|
223
238
|
}
|
|
@@ -839,6 +854,11 @@ THE MODEL \u2014 get this right before recording anything:
|
|
|
839
854
|
- A TEST CASE is the test. It strings flows together as rows (in the same
|
|
840
855
|
browser, or a new one for a second person) and switches on the checks it is
|
|
841
856
|
about. Build it with preview_case, then save_case \u2014 which runs it first.
|
|
857
|
+
- A test case can be WRITTEN BEFORE IT IS AUTOMATED: business steps (Given /
|
|
858
|
+
When / Then) and no flows \u2014 imported from a spreadsheet, or written with
|
|
859
|
+
write_test_cases. To automate one, record the flows its steps need, then
|
|
860
|
+
save_case with the SAME name in the SAME folder: that fills it, and its
|
|
861
|
+
business steps stay. Its Then lines are the checks to switch on.
|
|
842
862
|
- SIGN-IN is shared setup: a flow or case that needs somebody signed in uses a
|
|
843
863
|
sign-in profile from the catalog (start_flow's signIn), never typed login steps.
|
|
844
864
|
None yet? Make it: record the login as a flow that ends with a check proving
|
|
@@ -1293,6 +1313,86 @@ ${page}`);
|
|
|
1293
1313
|
return text(out);
|
|
1294
1314
|
}
|
|
1295
1315
|
},
|
|
1316
|
+
{
|
|
1317
|
+
name: "read_test_cases",
|
|
1318
|
+
title: "Read test cases",
|
|
1319
|
+
description: "Read test cases by id (tc_\u2026) or exact name: their feature, business steps (Given / When / Then), whether they are automated, and the flows they run. Read a case's steps before automating it.",
|
|
1320
|
+
inputSchema: {
|
|
1321
|
+
type: "object",
|
|
1322
|
+
properties: { projectId: { type: "string" }, cases: { type: "array", items: { type: "string" }, description: "Ids or names." } },
|
|
1323
|
+
required: ["cases"],
|
|
1324
|
+
additionalProperties: false
|
|
1325
|
+
},
|
|
1326
|
+
annotations: { readOnlyHint: true },
|
|
1327
|
+
run: async (args) => {
|
|
1328
|
+
const projectId = await projectFor(args["projectId"]);
|
|
1329
|
+
const refs = Array.isArray(args["cases"]) ? args["cases"].map(String) : [];
|
|
1330
|
+
const { cases, missing } = await service.readCases(projectId, refs);
|
|
1331
|
+
const parts = cases.map((c) => [
|
|
1332
|
+
`${c.folder} \u203A ${c.name} (${c.id}) \u2014 ${c.automated ? `automated, rows: ${c.rows.join(" \u2192 ")}` : "not automated yet"}`,
|
|
1333
|
+
...c.description ? [` ${c.description}`] : [],
|
|
1334
|
+
...c.businessSteps.length ? c.businessSteps.map((s) => ` ${s.keyword} ${s.text}`) : [" (no business steps written)"]
|
|
1335
|
+
].join("\n"));
|
|
1336
|
+
if (missing.length) parts.push(`Not found: ${missing.join(", ")} \u2014 project_catalog lists the test cases.`);
|
|
1337
|
+
return text(parts.join("\n\n") || "No test cases found.");
|
|
1338
|
+
}
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
name: "write_test_cases",
|
|
1342
|
+
title: "Write test cases down, before automating them",
|
|
1343
|
+
description: "Write test cases as business steps \u2014 Given / When / Then \u2014 with no flows yet, grouped by feature (the case folder), on Claude's working branch for review. They show as not automated until a test case with the same name is saved into the same folder with save_case, which keeps these steps. A case its folder already has is skipped. Use it when asked to write, plan or list test cases; record and save_case only when asked to automate.",
|
|
1344
|
+
inputSchema: {
|
|
1345
|
+
type: "object",
|
|
1346
|
+
properties: {
|
|
1347
|
+
projectId: { type: "string" },
|
|
1348
|
+
features: {
|
|
1349
|
+
type: "array",
|
|
1350
|
+
description: 'One entry per feature (case folder), e.g. "Account \u2013 Sign up".',
|
|
1351
|
+
items: {
|
|
1352
|
+
type: "object",
|
|
1353
|
+
properties: {
|
|
1354
|
+
feature: { type: "string" },
|
|
1355
|
+
cases: {
|
|
1356
|
+
type: "array",
|
|
1357
|
+
items: {
|
|
1358
|
+
type: "object",
|
|
1359
|
+
properties: {
|
|
1360
|
+
name: { type: "string", description: 'The scenario it proves, e.g. "A taken email is refused".' },
|
|
1361
|
+
description: { type: "string" },
|
|
1362
|
+
steps: { type: "array", description: `Given / When / Then lines, e.g. "Given the sign-up form is open", "When I sign up with a taken email", "Then I see 'That email is taken'". And / But continue the line above.`, items: { type: "string" } }
|
|
1363
|
+
},
|
|
1364
|
+
required: ["name", "steps"],
|
|
1365
|
+
additionalProperties: false
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
},
|
|
1369
|
+
required: ["feature", "cases"],
|
|
1370
|
+
additionalProperties: false
|
|
1371
|
+
}
|
|
1372
|
+
},
|
|
1373
|
+
branch: { type: "string", description: "Optional: the id of one of Claude's open branches to write to (list_my_branches). Default: the working branch." }
|
|
1374
|
+
},
|
|
1375
|
+
required: ["features"],
|
|
1376
|
+
additionalProperties: false
|
|
1377
|
+
},
|
|
1378
|
+
run: async (args) => {
|
|
1379
|
+
const projectId = await projectFor(args["projectId"]);
|
|
1380
|
+
const features = Array.isArray(args["features"]) ? args["features"] : [];
|
|
1381
|
+
const groups = features.map((f) => ({
|
|
1382
|
+
folder: String(f.feature ?? "").trim(),
|
|
1383
|
+
cases: (Array.isArray(f.cases) ? f.cases : []).map((c) => {
|
|
1384
|
+
const lines = Array.isArray(c.steps) ? c.steps.map(String) : [];
|
|
1385
|
+
const steps = parseGherkin(lines.join("\n"));
|
|
1386
|
+
if (!steps) throw new Error(`the steps of "${String(c.name ?? "")}" must each start with Given, When, Then, And or But`);
|
|
1387
|
+
return { name: String(c.name ?? "").trim(), ...typeof c.description === "string" ? { description: c.description } : {}, businessSteps: steps };
|
|
1388
|
+
})
|
|
1389
|
+
}));
|
|
1390
|
+
const done = await service.writeCases(projectId, groups, str(args["branch"]));
|
|
1391
|
+
catalogs.delete(projectId);
|
|
1392
|
+
const skipped = done.skipped.length ? ` Skipped ${done.skipped.length} the folder already had: ${done.skipped.map((s) => `"${s.name}"`).join(", ")}.` : "";
|
|
1393
|
+
return text(`Wrote ${done.created.length} test case${done.created.length === 1 ? "" : "s"}, not automated yet, on Claude's working branch ${done.branch}.${skipped}`);
|
|
1394
|
+
}
|
|
1395
|
+
},
|
|
1296
1396
|
{
|
|
1297
1397
|
name: "create_sign_in",
|
|
1298
1398
|
title: "Make a sign-in profile",
|
package/dist/engine.js
CHANGED
package/package.json
CHANGED