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

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.44";
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(),
@@ -2046,6 +2047,29 @@ var ConversationSchema = z8.object({
2046
2047
  createdAt: z8.string(),
2047
2048
  updatedAt: z8.string()
2048
2049
  }).strict();
2050
+ var IMPORT_DRAFT_TTL_MS = 24 * 60 * 60 * 1e3;
2051
+ var ImportDraftCaseSchema = z9.object({
2052
+ name: z9.string().min(1).max(120),
2053
+ description: z9.string().max(4e3).default(""),
2054
+ businessSteps: z9.array(BusinessStepSchema).max(200),
2055
+ /** Its id or row in the file. */
2056
+ row: z9.string().max(200).default("")
2057
+ }).strict();
2058
+ var ImportDraftSchema = z9.object({
2059
+ id: z9.string().regex(/^imp_[A-Za-z0-9]+$/),
2060
+ projectId: z9.string().min(1),
2061
+ userId: z9.string().min(1),
2062
+ file: z9.string().max(300),
2063
+ /** Every sheet, every cell as text. */
2064
+ sheets: z9.array(z9.object({ name: z9.string().max(200), rows: z9.array(z9.array(z9.string())) }).strict()).max(200),
2065
+ status: z9.enum(["waiting", "converting", "done", "failed"]).default("waiting"),
2066
+ /** What the assistant made of it: features, each with its cases. */
2067
+ result: z9.array(z9.object({ feature: z9.string().min(1).max(120), cases: z9.array(ImportDraftCaseSchema) }).strict()).default([]),
2068
+ /** The assistant's word on anything it could not convert. */
2069
+ note: z9.string().max(4e3).default(""),
2070
+ createdAt: z9.string(),
2071
+ updatedAt: z9.string()
2072
+ }).strict();
2049
2073
 
2050
2074
  // ../engine-playwright/dist/index.js
2051
2075
  import { createHmac, randomBytes as randomBytes2 } from "crypto";
@@ -6970,8 +6994,8 @@ async function fieldNames(page) {
6970
6994
  }
6971
6995
 
6972
6996
  // ../results/dist/chunk-LYCTVHPR.js
6973
- import { z as z9 } from "zod";
6974
- var RunStatusSchema = z9.enum([
6997
+ import { z as z10 } from "zod";
6998
+ var RunStatusSchema = z10.enum([
6975
6999
  "queued",
6976
7000
  "running",
6977
7001
  "passed",
@@ -6979,7 +7003,7 @@ var RunStatusSchema = z9.enum([
6979
7003
  "cancelled",
6980
7004
  "errored"
6981
7005
  ]);
6982
- var TaskStatusSchema = z9.enum([
7006
+ var TaskStatusSchema = z10.enum([
6983
7007
  "queued",
6984
7008
  "running",
6985
7009
  "passed",
@@ -6988,7 +7012,7 @@ var TaskStatusSchema = z9.enum([
6988
7012
  "cancelled",
6989
7013
  "errored"
6990
7014
  ]);
6991
- var FailureKindSchema = z9.enum([
7015
+ var FailureKindSchema = z10.enum([
6992
7016
  "not_found",
6993
7017
  "ambiguous",
6994
7018
  "timeout",
@@ -6997,30 +7021,30 @@ var FailureKindSchema = z9.enum([
6997
7021
  "crash",
6998
7022
  "unknown"
6999
7023
  ]);
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(),
7024
+ var RunCheckSchema = z10.object({
7025
+ id: z10.string(),
7026
+ assertionId: z10.string().nullable(),
7027
+ kind: z10.string(),
7028
+ expected: z10.string().nullable(),
7029
+ actual: z10.string().nullable(),
7030
+ ok: z10.boolean(),
7007
7031
  /** A failed soft check is reported but does not fail its step, so a run can
7008
7032
  * be green and still carry findings. Stored per check rather than derived,
7009
7033
  * because the flow it came from can be edited afterwards and history has to
7010
7034
  * keep saying what actually happened. */
7011
- soft: z9.boolean().default(false),
7012
- detail: z9.string().nullable()
7035
+ soft: z10.boolean().default(false),
7036
+ detail: z10.string().nullable()
7013
7037
  });
7014
- var RunStepSchema = z9.object({
7015
- id: z9.string(),
7016
- ordinal: z9.number().int().nonnegative(),
7038
+ var RunStepSchema = z10.object({
7039
+ id: z10.string(),
7040
+ ordinal: z10.number().int().nonnegative(),
7017
7041
  /** The STABLE document step id — this is what joins runs across time and
7018
7042
  * 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(),
7043
+ stepId: z10.string(),
7044
+ action: z10.string(),
7045
+ targetRole: z10.string().nullable(),
7046
+ targetName: z10.string().nullable(),
7047
+ targetScope: z10.string().nullable(),
7024
7048
  /** What the step typed, chose or pressed.
7025
7049
  *
7026
7050
  * A report that says `fill "Password"` and nothing else cannot tell you
@@ -7029,100 +7053,100 @@ var RunStepSchema = z9.object({
7029
7053
  *
7030
7054
  * NEVER set for a secret — see `secret` below. A run report is the thing
7031
7055
  * people paste into a ticket. */
7032
- value: z9.string().nullable().default(null),
7056
+ value: z10.string().nullable().default(null),
7033
7057
  /** The step typed a secret, so `value` is deliberately absent rather than
7034
7058
  * merely unknown. Stored, because "no value" and "a value withheld" render
7035
7059
  * differently and history has to keep saying which it was. */
7036
- secret: z9.boolean().default(false),
7037
- status: z9.enum(["passed", "failed", "skipped"]),
7060
+ secret: z10.boolean().default(false),
7061
+ status: z10.enum(["passed", "failed", "skipped"]),
7038
7062
  failureKind: FailureKindSchema.nullable(),
7039
- detail: z9.string().nullable(),
7063
+ detail: z10.string().nullable(),
7040
7064
  /** WHICH WAY FOUND IT, when the first way did not.
7041
7065
  *
7042
7066
  * A step carries several routes to its element and takes the first that
7043
7067
  * matches. Passing on a later one is not a failure, but it does mean the
7044
7068
  * page has moved under the step — and a suite that repairs itself quietly
7045
7069
  * 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(),
7070
+ foundBy: z10.string().nullable().default(null),
7071
+ durationMs: z10.number().int().nonnegative().nullable(),
7048
7072
  /** Where the browser was when this step ran. Recorded on failure, and
7049
7073
  * frequently the whole answer — the element is missing because a step
7050
7074
  * 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([])
7075
+ pageUrl: z10.string().nullable().default(null),
7076
+ pageTitle: z10.string().nullable().default(null),
7077
+ checks: z10.array(RunCheckSchema).default([])
7054
7078
  });
7055
- var RunTaskSchema = z9.object({
7056
- id: z9.string(),
7057
- ordinal: z9.number().int().nonnegative(),
7058
- caseName: z9.string(),
7059
- rowId: z9.string().nullable(),
7079
+ var RunTaskSchema = z10.object({
7080
+ id: z10.string(),
7081
+ ordinal: z10.number().int().nonnegative(),
7082
+ caseName: z10.string(),
7083
+ rowId: z10.string().nullable(),
7060
7084
  capability: CapabilitySchema,
7061
- provider: z9.string(),
7062
- attempt: z9.number().int().positive().default(1),
7063
- maxAttempts: z9.number().int().positive().default(1),
7085
+ provider: z10.string(),
7086
+ attempt: z10.number().int().positive().default(1),
7087
+ maxAttempts: z10.number().int().positive().default(1),
7064
7088
  status: TaskStatusSchema,
7065
- workerId: z9.string().nullable(),
7089
+ workerId: z10.string().nullable(),
7066
7090
  /** 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([])
7091
+ sessionId: z10.string().nullable(),
7092
+ sessionUrl: z10.string().nullable(),
7093
+ detail: z10.string().nullable(),
7094
+ stepsRun: z10.number().int().nonnegative().default(0),
7095
+ stepsTotal: z10.number().int().nonnegative().default(0),
7096
+ durationMs: z10.number().int().nonnegative().nullable(),
7097
+ steps: z10.array(RunStepSchema).default([])
7074
7098
  });
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(),
7099
+ var ArtifactKindSchema = z10.enum(["screenshot", "video", "trace", "console", "har"]);
7100
+ var ArtifactSchema = z10.object({
7101
+ id: z10.string(),
7102
+ runId: z10.string(),
7103
+ runStepId: z10.string().nullable(),
7080
7104
  kind: ArtifactKindSchema,
7081
- relPath: z9.string(),
7082
- bytes: z9.number().int().nonnegative().nullable(),
7083
- masked: z9.boolean().default(false),
7084
- createdAt: z9.string()
7105
+ relPath: z10.string(),
7106
+ bytes: z10.number().int().nonnegative().nullable(),
7107
+ masked: z10.boolean().default(false),
7108
+ createdAt: z10.string()
7085
7109
  });
7086
- var RunSummarySchema = z9.object({
7087
- id: z9.string(),
7088
- projectId: z9.string(),
7110
+ var RunSummarySchema = z10.object({
7111
+ id: z10.string(),
7112
+ projectId: z10.string(),
7089
7113
  /** What the run was FOR.
7090
7114
  *
7091
7115
  * `flake` is a deliberate repetition of one flow to measure how often it
7092
7116
  * passes. It is kept out of pass-rate statistics: a 98/100 flakiness check is
7093
7117
  * a useful finding, not a failing suite, and counting it as one would make
7094
7118
  * measuring reliability look like losing it. */
7095
- kind: z9.enum(["smoke", "test", "adhoc", "flake"]),
7096
- trigger: z9.enum(["ui", "cli", "ci"]),
7119
+ kind: z10.enum(["smoke", "test", "adhoc", "flake"]),
7120
+ trigger: z10.enum(["ui", "cli", "ci"]),
7097
7121
  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),
7122
+ flowId: z10.string().nullable(),
7123
+ flowName: z10.string().nullable(),
7124
+ gitSha: z10.string().nullable(),
7125
+ gitBranch: z10.string().nullable(),
7126
+ gitDirty: z10.boolean().default(false),
7127
+ env: z10.string().nullable(),
7128
+ concurrency: z10.number().int().positive().nullable(),
7129
+ tasksTotal: z10.number().int().nonnegative().default(0),
7130
+ tasksPassed: z10.number().int().nonnegative().default(0),
7131
+ tasksFailed: z10.number().int().nonnegative().default(0),
7108
7132
  /** Rolled up from the run's tasks rather than stored on the run, so they
7109
7133
  * cannot drift from the step rows they describe. "9 of 12" in a list is
7110
7134
  * what tells a reader where a run died; "1 of 1 tasks" tells them nothing
7111
7135
  * 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()
7136
+ stepsRun: z10.number().int().nonnegative().default(0),
7137
+ stepsTotal: z10.number().int().nonnegative().default(0),
7138
+ queuedAt: z10.string(),
7139
+ startedAt: z10.string().nullable(),
7140
+ finishedAt: z10.string().nullable(),
7141
+ durationMs: z10.number().int().nonnegative().nullable()
7118
7142
  });
7119
7143
  var RunDetailSchema = RunSummarySchema.extend({
7120
- errorMessage: z9.string().nullable(),
7121
- artifactsDir: z9.string().nullable(),
7122
- tasks: z9.array(RunTaskSchema).default([]),
7144
+ errorMessage: z10.string().nullable(),
7145
+ artifactsDir: z10.string().nullable(),
7146
+ tasks: z10.array(RunTaskSchema).default([]),
7123
7147
  /** Screenshots and the like, addressed by `runStepId`. Kept flat rather than
7124
7148
  * nested inside each step: an artifact can belong to the run as a whole. */
7125
- artifacts: z9.array(ArtifactSchema).default([]),
7149
+ artifacts: z10.array(ArtifactSchema).default([]),
7126
7150
  /** The document as it was executed — a flow, or a test case with the copies
7127
7151
  * it held that day.
7128
7152
  *
@@ -7131,7 +7155,7 @@ var RunDetailSchema = RunSummarySchema.extend({
7131
7155
  * edited, and without surfacing it the promise was only half kept: the bytes
7132
7156
  * were there and nothing could reach them. Null for runs recorded before a
7133
7157
  * snapshot was taken. */
7134
- flowSnapshot: z9.unknown().nullable().default(null)
7158
+ flowSnapshot: z10.unknown().nullable().default(null)
7135
7159
  });
7136
7160
 
7137
7161
  // ../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-E24RRF2Q.js";
27
27
 
28
28
  // src/cli.ts
29
29
  import { parseArgs } from "util";
@@ -219,6 +219,17 @@ 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
+ }
222
233
  readCases(projectId, refs) {
223
234
  const ids = refs.filter((r) => /^tc_/.test(r.trim()));
224
235
  const names = refs.filter((r) => !/^tc_/.test(r.trim()));
@@ -894,6 +905,16 @@ as learned. Keep what you learn with write_knowledge (features/<name>.md,
894
905
  memory/decisions.md, a session summary), on Claude's branch for review \u2014
895
906
  never a password, key or token.
896
907
 
908
+ CONVERTING A SPREADSHEET: when asked to convert an import (imp_\u2026), read
909
+ every part with read_import_file, then save_import_cases in batches. Group
910
+ cases into features by product area (a sheet or section usually is one). Each
911
+ case is one scenario: name it after what it proves. Steps: preconditions and
912
+ setup as Given; ONE action per When / And \u2014 split steps that do several
913
+ things; each expected result as Then / And, after the action it follows.
914
+ Keep every case and every step's meaning, and its id from the file in row;
915
+ never invent a step or drop one. Rows that are not test cases (titles,
916
+ notes, empty) are left out. Say in note what you could not convert.
917
+
897
918
  HOW TO WORK:
898
919
  1. Call project_catalog. Reuse what exists \u2014 published, and on Claude's working
899
920
  branch \u2014 rather than writing it again.
@@ -1313,6 +1334,73 @@ ${page}`);
1313
1334
  return text(out);
1314
1335
  }
1315
1336
  },
1337
+ {
1338
+ name: "read_import_file",
1339
+ title: "Read a spreadsheet waiting to be converted",
1340
+ 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.",
1341
+ inputSchema: {
1342
+ type: "object",
1343
+ properties: { projectId: { type: "string" }, file: { type: "string", description: "The import's id, imp_\u2026" }, part: { type: "number", description: "Which part, from 1." } },
1344
+ required: ["file", "part"],
1345
+ additionalProperties: false
1346
+ },
1347
+ annotations: { readOnlyHint: true },
1348
+ run: async (args) => {
1349
+ const projectId = await projectFor(args["projectId"]);
1350
+ const got = await service.importPart(projectId, str(args["file"]) ?? "", Number(args["part"] ?? 1));
1351
+ return text(`${got.file} \u2014 part ${got.part} of ${got.of}${got.part < got.of ? " (read the rest too)" : " (the last)"}
1352
+
1353
+ ${got.text}`);
1354
+ }
1355
+ },
1356
+ {
1357
+ name: "save_import_cases",
1358
+ title: "Save the test cases a spreadsheet becomes",
1359
+ 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.",
1360
+ inputSchema: {
1361
+ type: "object",
1362
+ properties: {
1363
+ projectId: { type: "string" },
1364
+ file: { type: "string", description: "The import's id, imp_\u2026" },
1365
+ features: {
1366
+ type: "array",
1367
+ items: {
1368
+ type: "object",
1369
+ properties: {
1370
+ feature: { type: "string" },
1371
+ cases: {
1372
+ type: "array",
1373
+ items: {
1374
+ type: "object",
1375
+ properties: { name: { type: "string" }, description: { type: "string" }, steps: { type: "array", items: { type: "string" } }, row: { type: "string" } },
1376
+ required: ["name", "steps"],
1377
+ additionalProperties: false
1378
+ }
1379
+ }
1380
+ },
1381
+ required: ["feature", "cases"],
1382
+ additionalProperties: false
1383
+ }
1384
+ },
1385
+ done: { type: "boolean" },
1386
+ note: { type: "string" },
1387
+ restart: { type: "boolean" }
1388
+ },
1389
+ required: ["file", "features"],
1390
+ additionalProperties: false
1391
+ },
1392
+ run: async (args) => {
1393
+ const projectId = await projectFor(args["projectId"]);
1394
+ const features = Array.isArray(args["features"]) ? args["features"] : [];
1395
+ const saved = await service.saveImportCases(projectId, str(args["file"]) ?? "", {
1396
+ features,
1397
+ ...args["done"] === true ? { done: true } : {},
1398
+ ...typeof args["note"] === "string" ? { note: args["note"] } : {},
1399
+ ...args["restart"] === true ? { restart: true } : {}
1400
+ });
1401
+ 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."}`);
1402
+ }
1403
+ },
1316
1404
  {
1317
1405
  name: "read_test_cases",
1318
1406
  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-E24RRF2Q.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.44",
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",