@flowriki/agent 0.1.0-beta.43 → 0.1.0-beta.45

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.
@@ -6,7 +6,7 @@ import os from "os";
6
6
  import path from "path";
7
7
  import { createRequire } from "module";
8
8
  import { spawnSync } from "child_process";
9
- var AGENT_VERSION = "0.1.0-beta.43";
9
+ var AGENT_VERSION = "0.1.0-beta.45";
10
10
  async function prepareBrowsers() {
11
11
  if (browsersReady()) {
12
12
  return { ok: true, already: true, message: "chromium is already installed" };
@@ -1009,6 +1009,7 @@ import { z as z5 } from "zod";
1009
1009
  import { z as z6 } from "zod";
1010
1010
  import { z as z7 } from "zod";
1011
1011
  import { z as z8 } from "zod";
1012
+ import { z as z9 } from "zod";
1012
1013
  var EngineSchema = z4.enum(["chromium", "firefox", "webkit"]);
1013
1014
  var CapabilitySchema = z4.object({
1014
1015
  id: z4.string(),
@@ -1201,6 +1202,10 @@ var TestCaseSchema = z32.object({
1201
1202
  businessSteps: z32.array(BusinessStepSchema).optional(),
1202
1203
  /** Where it came from, when not recorded here. */
1203
1204
  origin: TestCaseOriginSchema.optional(),
1205
+ /** WHEN ITS STEPS CHANGED AFTER IT WAS AUTOMATED: the automation may no
1206
+ * longer check what the words now say. Cleared when its flows are saved
1207
+ * again, or somebody confirms the automation still matches. */
1208
+ stepsChangedAt: z32.string().optional(),
1204
1209
  createdAt: z32.string(),
1205
1210
  createdBy: z32.string().default(""),
1206
1211
  updatedAt: z32.string(),
@@ -2046,6 +2051,50 @@ var ConversationSchema = z8.object({
2046
2051
  createdAt: z8.string(),
2047
2052
  updatedAt: z8.string()
2048
2053
  }).strict();
2054
+ var IMPORT_DRAFT_TTL_MS = 24 * 60 * 60 * 1e3;
2055
+ var ImportDraftCaseSchema = z9.object({
2056
+ name: z9.string().min(1).max(120),
2057
+ description: z9.string().max(4e3).default(""),
2058
+ businessSteps: z9.array(BusinessStepSchema).max(200),
2059
+ /** Its id or row in the file. */
2060
+ row: z9.string().max(200).default("")
2061
+ }).strict();
2062
+ var ImportDraftSchema = z9.object({
2063
+ id: z9.string().regex(/^imp_[A-Za-z0-9]+$/),
2064
+ projectId: z9.string().min(1),
2065
+ userId: z9.string().min(1),
2066
+ file: z9.string().max(300),
2067
+ /** Every sheet, every cell as text. */
2068
+ sheets: z9.array(z9.object({ name: z9.string().max(200), rows: z9.array(z9.array(z9.string())) }).strict()).max(200),
2069
+ status: z9.enum(["waiting", "converting", "done", "failed"]).default("waiting"),
2070
+ /** What the assistant made of it: features, each with its cases. */
2071
+ result: z9.array(z9.object({ feature: z9.string().min(1).max(120), cases: z9.array(ImportDraftCaseSchema) }).strict()).default([]),
2072
+ /** The assistant's word on anything it could not convert. */
2073
+ note: z9.string().max(4e3).default(""),
2074
+ createdAt: z9.string(),
2075
+ updatedAt: z9.string()
2076
+ }).strict();
2077
+ var CaseUpdateRequestSchema = z9.object({
2078
+ id: z9.string().regex(/^upd_[A-Za-z0-9]+$/),
2079
+ projectId: z9.string().min(1),
2080
+ userId: z9.string().min(1),
2081
+ instruction: z9.string().min(1).max(4e3),
2082
+ cases: z9.array(z9.object({
2083
+ id: z9.string().min(1),
2084
+ name: z9.string(),
2085
+ feature: z9.string(),
2086
+ businessSteps: z9.array(BusinessStepSchema)
2087
+ }).strict()).min(1).max(500),
2088
+ status: z9.enum(["waiting", "working", "done", "failed"]).default("waiting"),
2089
+ proposals: z9.array(z9.object({
2090
+ caseId: z9.string().min(1),
2091
+ businessSteps: z9.array(BusinessStepSchema).max(200),
2092
+ note: z9.string().max(2e3).default("")
2093
+ }).strict()).default([]),
2094
+ note: z9.string().max(4e3).default(""),
2095
+ createdAt: z9.string(),
2096
+ updatedAt: z9.string()
2097
+ }).strict();
2049
2098
 
2050
2099
  // ../engine-playwright/dist/index.js
2051
2100
  import { createHmac, randomBytes as randomBytes2 } from "crypto";
@@ -6970,8 +7019,8 @@ async function fieldNames(page) {
6970
7019
  }
6971
7020
 
6972
7021
  // ../results/dist/chunk-LYCTVHPR.js
6973
- import { z as z9 } from "zod";
6974
- var RunStatusSchema = z9.enum([
7022
+ import { z as z10 } from "zod";
7023
+ var RunStatusSchema = z10.enum([
6975
7024
  "queued",
6976
7025
  "running",
6977
7026
  "passed",
@@ -6979,7 +7028,7 @@ var RunStatusSchema = z9.enum([
6979
7028
  "cancelled",
6980
7029
  "errored"
6981
7030
  ]);
6982
- var TaskStatusSchema = z9.enum([
7031
+ var TaskStatusSchema = z10.enum([
6983
7032
  "queued",
6984
7033
  "running",
6985
7034
  "passed",
@@ -6988,7 +7037,7 @@ var TaskStatusSchema = z9.enum([
6988
7037
  "cancelled",
6989
7038
  "errored"
6990
7039
  ]);
6991
- var FailureKindSchema = z9.enum([
7040
+ var FailureKindSchema = z10.enum([
6992
7041
  "not_found",
6993
7042
  "ambiguous",
6994
7043
  "timeout",
@@ -6997,30 +7046,30 @@ var FailureKindSchema = z9.enum([
6997
7046
  "crash",
6998
7047
  "unknown"
6999
7048
  ]);
7000
- var RunCheckSchema = z9.object({
7001
- id: z9.string(),
7002
- assertionId: z9.string().nullable(),
7003
- kind: z9.string(),
7004
- expected: z9.string().nullable(),
7005
- actual: z9.string().nullable(),
7006
- ok: z9.boolean(),
7049
+ var RunCheckSchema = z10.object({
7050
+ id: z10.string(),
7051
+ assertionId: z10.string().nullable(),
7052
+ kind: z10.string(),
7053
+ expected: z10.string().nullable(),
7054
+ actual: z10.string().nullable(),
7055
+ ok: z10.boolean(),
7007
7056
  /** A failed soft check is reported but does not fail its step, so a run can
7008
7057
  * be green and still carry findings. Stored per check rather than derived,
7009
7058
  * because the flow it came from can be edited afterwards and history has to
7010
7059
  * keep saying what actually happened. */
7011
- soft: z9.boolean().default(false),
7012
- detail: z9.string().nullable()
7060
+ soft: z10.boolean().default(false),
7061
+ detail: z10.string().nullable()
7013
7062
  });
7014
- var RunStepSchema = z9.object({
7015
- id: z9.string(),
7016
- ordinal: z9.number().int().nonnegative(),
7063
+ var RunStepSchema = z10.object({
7064
+ id: z10.string(),
7065
+ ordinal: z10.number().int().nonnegative(),
7017
7066
  /** The STABLE document step id — this is what joins runs across time and
7018
7067
  * makes flake-rate a view over existing columns rather than a migration. */
7019
- stepId: z9.string(),
7020
- action: z9.string(),
7021
- targetRole: z9.string().nullable(),
7022
- targetName: z9.string().nullable(),
7023
- targetScope: z9.string().nullable(),
7068
+ stepId: z10.string(),
7069
+ action: z10.string(),
7070
+ targetRole: z10.string().nullable(),
7071
+ targetName: z10.string().nullable(),
7072
+ targetScope: z10.string().nullable(),
7024
7073
  /** What the step typed, chose or pressed.
7025
7074
  *
7026
7075
  * A report that says `fill "Password"` and nothing else cannot tell you
@@ -7029,100 +7078,100 @@ var RunStepSchema = z9.object({
7029
7078
  *
7030
7079
  * NEVER set for a secret — see `secret` below. A run report is the thing
7031
7080
  * people paste into a ticket. */
7032
- value: z9.string().nullable().default(null),
7081
+ value: z10.string().nullable().default(null),
7033
7082
  /** The step typed a secret, so `value` is deliberately absent rather than
7034
7083
  * merely unknown. Stored, because "no value" and "a value withheld" render
7035
7084
  * differently and history has to keep saying which it was. */
7036
- secret: z9.boolean().default(false),
7037
- status: z9.enum(["passed", "failed", "skipped"]),
7085
+ secret: z10.boolean().default(false),
7086
+ status: z10.enum(["passed", "failed", "skipped"]),
7038
7087
  failureKind: FailureKindSchema.nullable(),
7039
- detail: z9.string().nullable(),
7088
+ detail: z10.string().nullable(),
7040
7089
  /** WHICH WAY FOUND IT, when the first way did not.
7041
7090
  *
7042
7091
  * A step carries several routes to its element and takes the first that
7043
7092
  * matches. Passing on a later one is not a failure, but it does mean the
7044
7093
  * page has moved under the step — and a suite that repairs itself quietly
7045
7094
  * drifts away from the application it tests. Null is the ordinary case. */
7046
- foundBy: z9.string().nullable().default(null),
7047
- durationMs: z9.number().int().nonnegative().nullable(),
7095
+ foundBy: z10.string().nullable().default(null),
7096
+ durationMs: z10.number().int().nonnegative().nullable(),
7048
7097
  /** Where the browser was when this step ran. Recorded on failure, and
7049
7098
  * frequently the whole answer — the element is missing because a step
7050
7099
  * before it navigated somewhere unexpected, not because it was renamed. */
7051
- pageUrl: z9.string().nullable().default(null),
7052
- pageTitle: z9.string().nullable().default(null),
7053
- checks: z9.array(RunCheckSchema).default([])
7100
+ pageUrl: z10.string().nullable().default(null),
7101
+ pageTitle: z10.string().nullable().default(null),
7102
+ checks: z10.array(RunCheckSchema).default([])
7054
7103
  });
7055
- var RunTaskSchema = z9.object({
7056
- id: z9.string(),
7057
- ordinal: z9.number().int().nonnegative(),
7058
- caseName: z9.string(),
7059
- rowId: z9.string().nullable(),
7104
+ var RunTaskSchema = z10.object({
7105
+ id: z10.string(),
7106
+ ordinal: z10.number().int().nonnegative(),
7107
+ caseName: z10.string(),
7108
+ rowId: z10.string().nullable(),
7060
7109
  capability: CapabilitySchema,
7061
- provider: z9.string(),
7062
- attempt: z9.number().int().positive().default(1),
7063
- maxAttempts: z9.number().int().positive().default(1),
7110
+ provider: z10.string(),
7111
+ attempt: z10.number().int().positive().default(1),
7112
+ maxAttempts: z10.number().int().positive().default(1),
7064
7113
  status: TaskStatusSchema,
7065
- workerId: z9.string().nullable(),
7114
+ workerId: z10.string().nullable(),
7066
7115
  /** Cloud provider's own session, so a failure is one click from their video. */
7067
- sessionId: z9.string().nullable(),
7068
- sessionUrl: z9.string().nullable(),
7069
- detail: z9.string().nullable(),
7070
- stepsRun: z9.number().int().nonnegative().default(0),
7071
- stepsTotal: z9.number().int().nonnegative().default(0),
7072
- durationMs: z9.number().int().nonnegative().nullable(),
7073
- steps: z9.array(RunStepSchema).default([])
7116
+ sessionId: z10.string().nullable(),
7117
+ sessionUrl: z10.string().nullable(),
7118
+ detail: z10.string().nullable(),
7119
+ stepsRun: z10.number().int().nonnegative().default(0),
7120
+ stepsTotal: z10.number().int().nonnegative().default(0),
7121
+ durationMs: z10.number().int().nonnegative().nullable(),
7122
+ steps: z10.array(RunStepSchema).default([])
7074
7123
  });
7075
- var ArtifactKindSchema = z9.enum(["screenshot", "video", "trace", "console", "har"]);
7076
- var ArtifactSchema = z9.object({
7077
- id: z9.string(),
7078
- runId: z9.string(),
7079
- runStepId: z9.string().nullable(),
7124
+ var ArtifactKindSchema = z10.enum(["screenshot", "video", "trace", "console", "har"]);
7125
+ var ArtifactSchema = z10.object({
7126
+ id: z10.string(),
7127
+ runId: z10.string(),
7128
+ runStepId: z10.string().nullable(),
7080
7129
  kind: ArtifactKindSchema,
7081
- relPath: z9.string(),
7082
- bytes: z9.number().int().nonnegative().nullable(),
7083
- masked: z9.boolean().default(false),
7084
- createdAt: z9.string()
7130
+ relPath: z10.string(),
7131
+ bytes: z10.number().int().nonnegative().nullable(),
7132
+ masked: z10.boolean().default(false),
7133
+ createdAt: z10.string()
7085
7134
  });
7086
- var RunSummarySchema = z9.object({
7087
- id: z9.string(),
7088
- projectId: z9.string(),
7135
+ var RunSummarySchema = z10.object({
7136
+ id: z10.string(),
7137
+ projectId: z10.string(),
7089
7138
  /** What the run was FOR.
7090
7139
  *
7091
7140
  * `flake` is a deliberate repetition of one flow to measure how often it
7092
7141
  * passes. It is kept out of pass-rate statistics: a 98/100 flakiness check is
7093
7142
  * a useful finding, not a failing suite, and counting it as one would make
7094
7143
  * measuring reliability look like losing it. */
7095
- kind: z9.enum(["smoke", "test", "adhoc", "flake"]),
7096
- trigger: z9.enum(["ui", "cli", "ci"]),
7144
+ kind: z10.enum(["smoke", "test", "adhoc", "flake"]),
7145
+ trigger: z10.enum(["ui", "cli", "ci"]),
7097
7146
  status: RunStatusSchema,
7098
- flowId: z9.string().nullable(),
7099
- flowName: z9.string().nullable(),
7100
- gitSha: z9.string().nullable(),
7101
- gitBranch: z9.string().nullable(),
7102
- gitDirty: z9.boolean().default(false),
7103
- env: z9.string().nullable(),
7104
- concurrency: z9.number().int().positive().nullable(),
7105
- tasksTotal: z9.number().int().nonnegative().default(0),
7106
- tasksPassed: z9.number().int().nonnegative().default(0),
7107
- tasksFailed: z9.number().int().nonnegative().default(0),
7147
+ flowId: z10.string().nullable(),
7148
+ flowName: z10.string().nullable(),
7149
+ gitSha: z10.string().nullable(),
7150
+ gitBranch: z10.string().nullable(),
7151
+ gitDirty: z10.boolean().default(false),
7152
+ env: z10.string().nullable(),
7153
+ concurrency: z10.number().int().positive().nullable(),
7154
+ tasksTotal: z10.number().int().nonnegative().default(0),
7155
+ tasksPassed: z10.number().int().nonnegative().default(0),
7156
+ tasksFailed: z10.number().int().nonnegative().default(0),
7108
7157
  /** Rolled up from the run's tasks rather than stored on the run, so they
7109
7158
  * cannot drift from the step rows they describe. "9 of 12" in a list is
7110
7159
  * what tells a reader where a run died; "1 of 1 tasks" tells them nothing
7111
7160
  * until there is more than one browser in play. */
7112
- stepsRun: z9.number().int().nonnegative().default(0),
7113
- stepsTotal: z9.number().int().nonnegative().default(0),
7114
- queuedAt: z9.string(),
7115
- startedAt: z9.string().nullable(),
7116
- finishedAt: z9.string().nullable(),
7117
- durationMs: z9.number().int().nonnegative().nullable()
7161
+ stepsRun: z10.number().int().nonnegative().default(0),
7162
+ stepsTotal: z10.number().int().nonnegative().default(0),
7163
+ queuedAt: z10.string(),
7164
+ startedAt: z10.string().nullable(),
7165
+ finishedAt: z10.string().nullable(),
7166
+ durationMs: z10.number().int().nonnegative().nullable()
7118
7167
  });
7119
7168
  var RunDetailSchema = RunSummarySchema.extend({
7120
- errorMessage: z9.string().nullable(),
7121
- artifactsDir: z9.string().nullable(),
7122
- tasks: z9.array(RunTaskSchema).default([]),
7169
+ errorMessage: z10.string().nullable(),
7170
+ artifactsDir: z10.string().nullable(),
7171
+ tasks: z10.array(RunTaskSchema).default([]),
7123
7172
  /** Screenshots and the like, addressed by `runStepId`. Kept flat rather than
7124
7173
  * nested inside each step: an artifact can belong to the run as a whole. */
7125
- artifacts: z9.array(ArtifactSchema).default([]),
7174
+ artifacts: z10.array(ArtifactSchema).default([]),
7126
7175
  /** The document as it was executed — a flow, or a test case with the copies
7127
7176
  * it held that day.
7128
7177
  *
@@ -7131,7 +7180,7 @@ var RunDetailSchema = RunSummarySchema.extend({
7131
7180
  * edited, and without surfacing it the promise was only half kept: the bytes
7132
7181
  * were there and nothing could reach them. Null for runs recorded before a
7133
7182
  * snapshot was taken. */
7134
- flowSnapshot: z9.unknown().nullable().default(null)
7183
+ flowSnapshot: z10.unknown().nullable().default(null)
7135
7184
  });
7136
7185
 
7137
7186
  // ../results/dist/chunk-IW3PJWP6.js
package/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  runtimeValue,
24
24
  start,
25
25
  status
26
- } from "./chunk-ZMHE47A5.js";
26
+ } from "./chunk-JJB45ZTL.js";
27
27
 
28
28
  // src/cli.ts
29
29
  import { parseArgs } from "util";
@@ -219,6 +219,28 @@ var ServiceClient = class {
219
219
  return this.call(`/api/agent/library?${query}`);
220
220
  }
221
221
  /** Test cases written, edited or linked in one commit; duplicates skipped. */
222
+ importPart(projectId, draftId, part) {
223
+ return this.call(
224
+ `/api/agent/import-drafts/${encodeURIComponent(draftId)}?projectId=${encodeURIComponent(projectId)}&part=${part}`
225
+ );
226
+ }
227
+ saveImportCases(projectId, draftId, body) {
228
+ return this.call(
229
+ `/api/agent/import-drafts/${encodeURIComponent(draftId)}/cases?projectId=${encodeURIComponent(projectId)}`,
230
+ { method: "POST", body: JSON.stringify(body) }
231
+ );
232
+ }
233
+ updateRequest(projectId, id) {
234
+ return this.call(
235
+ `/api/agent/update-requests/${encodeURIComponent(id)}?projectId=${encodeURIComponent(projectId)}`
236
+ );
237
+ }
238
+ proposeUpdates(projectId, id, body) {
239
+ return this.call(
240
+ `/api/agent/update-requests/${encodeURIComponent(id)}/proposals?projectId=${encodeURIComponent(projectId)}`,
241
+ { method: "POST", body: JSON.stringify(body) }
242
+ );
243
+ }
222
244
  readCases(projectId, refs) {
223
245
  const ids = refs.filter((r) => /^tc_/.test(r.trim()));
224
246
  const names = refs.filter((r) => !/^tc_/.test(r.trim()));
@@ -894,6 +916,25 @@ as learned. Keep what you learn with write_knowledge (features/<name>.md,
894
916
  memory/decisions.md, a session summary), on Claude's branch for review \u2014
895
917
  never a password, key or token.
896
918
 
919
+ UPDATING TEST CASES: when asked to update test cases (upd_\u2026), read the
920
+ request with read_update_request, then propose_case_updates with each changed
921
+ case's complete new steps \u2014 keep what the change does not touch word for
922
+ word, so the person sees exactly what moved. Leave out cases that need no
923
+ change. You never change a test case yourself; the person accepts.
924
+
925
+ CONVERTING A SPREADSHEET: when asked to convert an import (imp_\u2026), read
926
+ every part with read_import_file, then save_import_cases in batches. Group
927
+ cases into features by product area (a sheet or section usually is one). Each
928
+ case is one scenario: name it after what it proves. Steps: preconditions and
929
+ setup as Given; ONE action per When / And \u2014 split steps that do several
930
+ things; each expected result as Then / And, after the action it follows.
931
+ Keep every case and every step's meaning, and its id from the file in row \u2014
932
+ that id is how a later import of the same file knows the case is already
933
+ there; never invent a step or drop one. A case found in several sheets is
934
+ converted once. Use the project's existing feature names (project_catalog)
935
+ when a case belongs in one, rather than a new look-alike. Rows that are not test cases (titles,
936
+ notes, empty) are left out. Say in note what you could not convert.
937
+
897
938
  HOW TO WORK:
898
939
  1. Call project_catalog. Reuse what exists \u2014 published, and on Claude's working
899
940
  branch \u2014 rather than writing it again.
@@ -1313,6 +1354,120 @@ ${page}`);
1313
1354
  return text(out);
1314
1355
  }
1315
1356
  },
1357
+ {
1358
+ name: "read_import_file",
1359
+ title: "Read a spreadsheet waiting to be converted",
1360
+ description: "Read one part of a spreadsheet the person is importing (its id is imp_\u2026): every sheet's rows, each as a JSON array of its cells, numbered as the spreadsheet numbers them. Part 1 says how many parts there are; read every one.",
1361
+ inputSchema: {
1362
+ type: "object",
1363
+ properties: { projectId: { type: "string" }, file: { type: "string", description: "The import's id, imp_\u2026" }, part: { type: "number", description: "Which part, from 1." } },
1364
+ required: ["file", "part"],
1365
+ additionalProperties: false
1366
+ },
1367
+ annotations: { readOnlyHint: true },
1368
+ run: async (args) => {
1369
+ const projectId = await projectFor(args["projectId"]);
1370
+ const got = await service.importPart(projectId, str(args["file"]) ?? "", Number(args["part"] ?? 1));
1371
+ return text(`${got.file} \u2014 part ${got.part} of ${got.of}${got.part < got.of ? " (read the rest too)" : " (the last)"}
1372
+
1373
+ ${got.text}`);
1374
+ }
1375
+ },
1376
+ {
1377
+ name: "save_import_cases",
1378
+ title: "Save the test cases a spreadsheet becomes",
1379
+ description: "Save test cases converted from a spreadsheet being imported (its id is imp_\u2026), in batches as you go: features, each with cases \u2014 name (the scenario it proves), steps as Given / When / Then / And lines, row (its id or row in the file), description (optional). They are shown to the person to import; nothing is written to the project until they do. done: true with the last batch; note: anything you could not convert, and why. restart: true replaces what was saved before.",
1380
+ inputSchema: {
1381
+ type: "object",
1382
+ properties: {
1383
+ projectId: { type: "string" },
1384
+ file: { type: "string", description: "The import's id, imp_\u2026" },
1385
+ features: {
1386
+ type: "array",
1387
+ items: {
1388
+ type: "object",
1389
+ properties: {
1390
+ feature: { type: "string" },
1391
+ cases: {
1392
+ type: "array",
1393
+ items: {
1394
+ type: "object",
1395
+ properties: { name: { type: "string" }, description: { type: "string" }, steps: { type: "array", items: { type: "string" } }, row: { type: "string" } },
1396
+ required: ["name", "steps"],
1397
+ additionalProperties: false
1398
+ }
1399
+ }
1400
+ },
1401
+ required: ["feature", "cases"],
1402
+ additionalProperties: false
1403
+ }
1404
+ },
1405
+ done: { type: "boolean" },
1406
+ note: { type: "string" },
1407
+ restart: { type: "boolean" }
1408
+ },
1409
+ required: ["file", "features"],
1410
+ additionalProperties: false
1411
+ },
1412
+ run: async (args) => {
1413
+ const projectId = await projectFor(args["projectId"]);
1414
+ const features = Array.isArray(args["features"]) ? args["features"] : [];
1415
+ const saved = await service.saveImportCases(projectId, str(args["file"]) ?? "", {
1416
+ features,
1417
+ ...args["done"] === true ? { done: true } : {},
1418
+ ...typeof args["note"] === "string" ? { note: args["note"] } : {},
1419
+ ...args["restart"] === true ? { restart: true } : {}
1420
+ });
1421
+ return text(`Saved ${saved.added} more \u2014 ${saved.total} test cases so far.${saved.done ? " Done: the person can now look them over and import them." : " Keep going, and pass done: true with the last batch."}`);
1422
+ }
1423
+ },
1424
+ {
1425
+ name: "read_update_request",
1426
+ title: "Read what should change in some test cases",
1427
+ description: "Read a request to update test cases (its id is upd_\u2026): what the person wants changed, and each test case as it is now \u2014 its id, feature, name and business steps.",
1428
+ inputSchema: { type: "object", properties: { projectId: { type: "string" }, request: { type: "string", description: "upd_\u2026" } }, required: ["request"], additionalProperties: false },
1429
+ annotations: { readOnlyHint: true },
1430
+ run: async (args) => {
1431
+ const projectId = await projectFor(args["projectId"]);
1432
+ const r = await service.updateRequest(projectId, str(args["request"]) ?? "");
1433
+ return text([
1434
+ `What should change: ${r.instruction}`,
1435
+ ...r.cases.map((c) => [`
1436
+ ${c.feature} \u203A ${c.name} (${c.id})`, ...c.businessSteps.length ? c.businessSteps.map((s) => ` ${s.keyword} ${s.text}`) : [" (no steps written)"]].join("\n"))
1437
+ ].join("\n"));
1438
+ }
1439
+ },
1440
+ {
1441
+ name: "propose_case_updates",
1442
+ title: "Propose new steps for test cases",
1443
+ description: "Propose the new business steps for test cases in an update request (upd_\u2026): for each case changed, its id and ALL its steps as Given / When / Then / And lines (the whole case, not only what changed). Cases that need no change are left out. The person sees each before and after and accepts the ones they want; nothing changes until they do. done: true with the last batch; note: anything you could not do.",
1444
+ inputSchema: {
1445
+ type: "object",
1446
+ properties: {
1447
+ projectId: { type: "string" },
1448
+ request: { type: "string", description: "upd_\u2026" },
1449
+ updates: {
1450
+ type: "array",
1451
+ items: {
1452
+ type: "object",
1453
+ properties: { case: { type: "string", description: "The test case's id, tc_\u2026" }, steps: { type: "array", items: { type: "string" } }, note: { type: "string", description: "Why, in a few words." } },
1454
+ required: ["case", "steps"],
1455
+ additionalProperties: false
1456
+ }
1457
+ },
1458
+ done: { type: "boolean" },
1459
+ note: { type: "string" }
1460
+ },
1461
+ required: ["request", "updates"],
1462
+ additionalProperties: false
1463
+ },
1464
+ run: async (args) => {
1465
+ const projectId = await projectFor(args["projectId"]);
1466
+ const updates = Array.isArray(args["updates"]) ? args["updates"] : [];
1467
+ const r = await service.proposeUpdates(projectId, str(args["request"]) ?? "", { updates, ...args["done"] === true ? { done: true } : {}, ...typeof args["note"] === "string" ? { note: args["note"] } : {} });
1468
+ return text(`Proposed new steps for ${r.proposed} of ${r.of} test cases.${r.done ? " Done: the person can now accept them." : " Pass done: true with the last batch."}`);
1469
+ }
1470
+ },
1316
1471
  {
1317
1472
  name: "read_test_cases",
1318
1473
  title: "Read test cases",
package/dist/engine.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolveCheckouts,
10
10
  start,
11
11
  status
12
- } from "./chunk-ZMHE47A5.js";
12
+ } from "./chunk-JJB45ZTL.js";
13
13
  export {
14
14
  AGENT_VERSION,
15
15
  browsersReady,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowriki/agent",
3
- "version": "0.1.0-beta.43",
3
+ "version": "0.1.0-beta.45",
4
4
  "description": "Run Flowriki UI tests on your own computer. Connects this machine to your Flowriki account.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",