@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.
- package/dist/{chunk-ZMHE47A5.js → chunk-JJB45ZTL.js} +131 -82
- package/dist/cli.js +156 -1
- package/dist/engine.js +1 -1
- package/package.json +1 -1
|
@@ -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.
|
|
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
|
|
6974
|
-
var RunStatusSchema =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
7001
|
-
id:
|
|
7002
|
-
assertionId:
|
|
7003
|
-
kind:
|
|
7004
|
-
expected:
|
|
7005
|
-
actual:
|
|
7006
|
-
ok:
|
|
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:
|
|
7012
|
-
detail:
|
|
7060
|
+
soft: z10.boolean().default(false),
|
|
7061
|
+
detail: z10.string().nullable()
|
|
7013
7062
|
});
|
|
7014
|
-
var RunStepSchema =
|
|
7015
|
-
id:
|
|
7016
|
-
ordinal:
|
|
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:
|
|
7020
|
-
action:
|
|
7021
|
-
targetRole:
|
|
7022
|
-
targetName:
|
|
7023
|
-
targetScope:
|
|
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:
|
|
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:
|
|
7037
|
-
status:
|
|
7085
|
+
secret: z10.boolean().default(false),
|
|
7086
|
+
status: z10.enum(["passed", "failed", "skipped"]),
|
|
7038
7087
|
failureKind: FailureKindSchema.nullable(),
|
|
7039
|
-
detail:
|
|
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:
|
|
7047
|
-
durationMs:
|
|
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:
|
|
7052
|
-
pageTitle:
|
|
7053
|
-
checks:
|
|
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 =
|
|
7056
|
-
id:
|
|
7057
|
-
ordinal:
|
|
7058
|
-
caseName:
|
|
7059
|
-
rowId:
|
|
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:
|
|
7062
|
-
attempt:
|
|
7063
|
-
maxAttempts:
|
|
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:
|
|
7114
|
+
workerId: z10.string().nullable(),
|
|
7066
7115
|
/** Cloud provider's own session, so a failure is one click from their video. */
|
|
7067
|
-
sessionId:
|
|
7068
|
-
sessionUrl:
|
|
7069
|
-
detail:
|
|
7070
|
-
stepsRun:
|
|
7071
|
-
stepsTotal:
|
|
7072
|
-
durationMs:
|
|
7073
|
-
steps:
|
|
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 =
|
|
7076
|
-
var ArtifactSchema =
|
|
7077
|
-
id:
|
|
7078
|
-
runId:
|
|
7079
|
-
runStepId:
|
|
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:
|
|
7082
|
-
bytes:
|
|
7083
|
-
masked:
|
|
7084
|
-
createdAt:
|
|
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 =
|
|
7087
|
-
id:
|
|
7088
|
-
projectId:
|
|
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:
|
|
7096
|
-
trigger:
|
|
7144
|
+
kind: z10.enum(["smoke", "test", "adhoc", "flake"]),
|
|
7145
|
+
trigger: z10.enum(["ui", "cli", "ci"]),
|
|
7097
7146
|
status: RunStatusSchema,
|
|
7098
|
-
flowId:
|
|
7099
|
-
flowName:
|
|
7100
|
-
gitSha:
|
|
7101
|
-
gitBranch:
|
|
7102
|
-
gitDirty:
|
|
7103
|
-
env:
|
|
7104
|
-
concurrency:
|
|
7105
|
-
tasksTotal:
|
|
7106
|
-
tasksPassed:
|
|
7107
|
-
tasksFailed:
|
|
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:
|
|
7113
|
-
stepsTotal:
|
|
7114
|
-
queuedAt:
|
|
7115
|
-
startedAt:
|
|
7116
|
-
finishedAt:
|
|
7117
|
-
durationMs:
|
|
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:
|
|
7121
|
-
artifactsDir:
|
|
7122
|
-
tasks:
|
|
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:
|
|
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:
|
|
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-
|
|
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
package/package.json
CHANGED