testeiya 0.8.1 β 0.10.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/PIPELINES.md +153 -19
- package/README.md +29 -14
- package/dist/prompt/pipeline-report.js +23 -0
- package/dist/prompt/pipeline-report.js.map +1 -0
- package/dist/prompt/report.js +1 -1
- package/dist/prompt/testomat.io.js +2 -2
- package/dist/prompt/testomat.io.js.map +1 -1
- package/dist/src/args.js +19 -1
- package/dist/src/args.js.map +1 -1
- package/dist/src/cli.js +4 -2
- package/dist/src/cli.js.map +1 -1
- package/dist/src/doctor.js +8 -10
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/langfuse-extension.js +2 -0
- package/dist/src/langfuse-extension.js.map +1 -1
- package/dist/src/mcp.js +20 -90
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/pipeline/command-stage.js +2 -2
- package/dist/src/pipeline/command-stage.js.map +1 -1
- package/dist/src/pipeline/log.js +5 -0
- package/dist/src/pipeline/log.js.map +1 -1
- package/dist/src/pipeline/overlay.js +217 -0
- package/dist/src/pipeline/overlay.js.map +1 -0
- package/dist/src/pipeline/pipeline-file.js +67 -5
- package/dist/src/pipeline/pipeline-file.js.map +1 -1
- package/dist/src/pipeline/pipeline.js +48 -29
- package/dist/src/pipeline/pipeline.js.map +1 -1
- package/dist/src/pipeline/stage.js +49 -13
- package/dist/src/pipeline/stage.js.map +1 -1
- package/dist/src/pipeline/state.js +3 -1
- package/dist/src/pipeline/state.js.map +1 -1
- package/dist/src/pipeline/summary-stage.js +99 -0
- package/dist/src/pipeline/summary-stage.js.map +1 -0
- package/dist/src/pipeline/task-stage.js +25 -10
- package/dist/src/pipeline/task-stage.js.map +1 -1
- package/dist/src/pipeline/variables.js +34 -2
- package/dist/src/pipeline/variables.js.map +1 -1
- package/dist/src/session.js +19 -14
- package/dist/src/session.js.map +1 -1
- package/package.json +6 -9
- package/pipelines/api-testing.yml +9 -6
- package/pipelines/issue-test-cases.yml +14 -13
- package/pipelines/pr-review.yml +13 -9
- package/pipelines/regression.yml +6 -3
- package/pipelines/web-testing.yml +13 -12
- package/prompt/pipeline-report.ts +23 -0
- package/prompt/report.ts +1 -1
- package/prompt/testomat.io.ts +4 -4
- package/skills/codeceptjs/lint-codeceptjs-tests/SKILL.md +104 -0
- package/skills/skills.lock.json +5 -2
- package/skills/testomatio/qa-process/testing-workflow/SKILL.md +12 -7
- package/skills/testomatio/requirements/catalog-features/SKILL.md +132 -0
- package/skills/testomatio/requirements/catalog-features/references/layout.md +43 -0
- package/skills/testomatio/requirements/detect-product-mismatches/SKILL.md +146 -0
- package/skills/testomatio/requirements/detect-product-mismatches/references/features.md +84 -0
- package/skills/testomatio/requirements/detect-product-mismatches/references/layout.md +93 -0
- package/skills/testomatio/requirements/wiki-from-code/SKILL.md +58 -71
- package/skills/testomatio/requirements/wiki-from-code/references/behaviors.md +42 -0
- package/skills/testomatio/requirements/wiki-from-code/references/layout.md +70 -71
- package/dist/src/mcp-extension.js +0 -9
- package/dist/src/mcp-extension.js.map +0 -1
- package/dist/vendor/mcp.js +0 -14801
- package/mcp-tools.json +0 -1949
|
@@ -2,11 +2,11 @@ import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { log } from "./log.js";
|
|
4
4
|
import { Stage } from "./stage.js";
|
|
5
|
-
import { SESSIONS_DIR } from "./state.js";
|
|
6
|
-
const RETRY_NOTE = "This stage stopped before it finished. Go on from where you stopped. Files you already wrote are in the
|
|
5
|
+
import { CHANGES_FILE, LAST_DIR, SESSIONS_DIR } from "./state.js";
|
|
6
|
+
const RETRY_NOTE = "This stage stopped before it finished. Go on from where you stopped. Files you already wrote are in the stage folder.";
|
|
7
7
|
/**
|
|
8
8
|
* An agent stage: a `testeiya task` run. It writes its report to `<id>.md`
|
|
9
|
-
* and its verdict to `<id>.json
|
|
9
|
+
* and its verdict to `<id>.json`, in its folder.
|
|
10
10
|
*/
|
|
11
11
|
export class TaskStage extends Stage {
|
|
12
12
|
result = { field: "report", extension: "md" };
|
|
@@ -15,8 +15,8 @@ export class TaskStage extends Stage {
|
|
|
15
15
|
}
|
|
16
16
|
async runItem(context, item, vars) {
|
|
17
17
|
const { dir } = context;
|
|
18
|
-
const report = `${this.id}${item.suffix}.md`;
|
|
19
|
-
const envelope = `${this.id}${item.suffix}.json`;
|
|
18
|
+
const report = `${this.folder}/${this.id}${item.suffix}.md`;
|
|
19
|
+
const envelope = `${this.folder}/${this.id}${item.suffix}.json`;
|
|
20
20
|
rmSync(join(dir, report), { force: true });
|
|
21
21
|
rmSync(join(dir, envelope), { force: true });
|
|
22
22
|
const task = this.task(context, vars);
|
|
@@ -38,8 +38,9 @@ export class TaskStage extends Stage {
|
|
|
38
38
|
const { session } = this.spec;
|
|
39
39
|
const args = [];
|
|
40
40
|
// Only the reporting stage posts. Every other stage keeps out of the comment thread.
|
|
41
|
+
// Their reports land in the summary, which is signed once.
|
|
41
42
|
if (!context.report)
|
|
42
|
-
args.push("--no-thread");
|
|
43
|
+
args.push("--no-thread", "--no-default-footer");
|
|
43
44
|
for (const output of outputs)
|
|
44
45
|
args.push("-o", output);
|
|
45
46
|
if (context.report)
|
|
@@ -56,20 +57,34 @@ export class TaskStage extends Stage {
|
|
|
56
57
|
}
|
|
57
58
|
/** The task, then where its files are, so the model never guesses a path. */
|
|
58
59
|
task(context, vars) {
|
|
59
|
-
const
|
|
60
|
-
const lines = [`
|
|
60
|
+
const dir = this.dir(context);
|
|
61
|
+
const lines = [`Stage folder: ${dir}`];
|
|
61
62
|
const wanted = this.inputs();
|
|
62
63
|
const present = wanted.filter((input) => existsSync(join(dir, input)));
|
|
63
64
|
const absent = wanted.filter((input) => !present.includes(input));
|
|
64
65
|
if (present.length > 0)
|
|
65
|
-
lines.push(`Read these first: ${present.join(", ")}`);
|
|
66
|
-
const outputs = this.spec.outputs.map((output) => vars.expand(output));
|
|
66
|
+
lines.push(`Read these first: ${present.map((input) => join(dir, input)).join(", ")}`);
|
|
67
|
+
const outputs = this.spec.outputs.map((output) => join(dir, vars.expand(output)));
|
|
67
68
|
if (outputs.length > 0)
|
|
68
69
|
lines.push(`Write these files: ${outputs.join(", ")}`);
|
|
69
70
|
for (const input of absent)
|
|
70
71
|
lines.push(`Not available: ${input} (${context.missing(input)})`);
|
|
72
|
+
const last = this.lastRound(context);
|
|
73
|
+
if (last)
|
|
74
|
+
lines.push(last);
|
|
71
75
|
return `${vars.expand(this.spec.task ?? "").trim()}\n\n${lines.join("\n")}`;
|
|
72
76
|
}
|
|
77
|
+
/** A new round updates the last one's result instead of starting over. */
|
|
78
|
+
lastRound(context) {
|
|
79
|
+
const last = join(context.dir, LAST_DIR, this.folder);
|
|
80
|
+
if (!existsSync(last))
|
|
81
|
+
return null;
|
|
82
|
+
let line = `Last round: ${last}. Update its result: keep what still holds, redo what the changes touch.`;
|
|
83
|
+
const changes = join(context.dir, CHANGES_FILE);
|
|
84
|
+
if (existsSync(changes))
|
|
85
|
+
line += ` Changed files: ${changes}`;
|
|
86
|
+
return line;
|
|
87
|
+
}
|
|
73
88
|
readEnvelope(path) {
|
|
74
89
|
if (!existsSync(path))
|
|
75
90
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-stage.js","sourceRoot":"","sources":["../../../src/pipeline/task-stage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAgC,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,YAAY,EAAoB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"task-stage.js","sourceRoot":"","sources":["../../../src/pipeline/task-stage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,42 @@
|
|
|
1
|
+
import { Liquid } from "liquidjs";
|
|
2
|
+
/** `${NAME}`, `${NAME:-default}` or `${NAME | filter | filter: arg}`. */
|
|
3
|
+
const REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*)|(\s*\|[^}]*))?\}/g;
|
|
4
|
+
/** Liquid's filters, and ours for URLs. Only expressions: Liquid's tags never run. */
|
|
5
|
+
const liquid = new Liquid({ strictFilters: true });
|
|
6
|
+
liquid.registerFilter("host", (value) => url(value)?.host ?? "");
|
|
7
|
+
liquid.registerFilter("path", (value) => url(value)?.pathname ?? "");
|
|
1
8
|
/** The environment a pipeline runs in, and `${NAME}` expansion over it. */
|
|
2
9
|
export class Variables {
|
|
3
10
|
values;
|
|
4
11
|
constructor(values) {
|
|
5
12
|
this.values = values;
|
|
6
13
|
}
|
|
14
|
+
/** Why the filters in `text` cannot run, or null. */
|
|
15
|
+
static problem(text) {
|
|
16
|
+
for (const [, name, , filters] of text.matchAll(REFERENCE)) {
|
|
17
|
+
if (!filters)
|
|
18
|
+
continue;
|
|
19
|
+
try {
|
|
20
|
+
liquid.evalValueSync(`${name}${filters}`, {});
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return `\${${name}${filters}}: ${err.message.split("\n")[0]}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/** Whether `text` uses a filter. */
|
|
29
|
+
static filtered(text) {
|
|
30
|
+
return [...text.matchAll(REFERENCE)].some((match) => match[3]);
|
|
31
|
+
}
|
|
7
32
|
get(name) {
|
|
8
33
|
return this.values[name];
|
|
9
34
|
}
|
|
10
|
-
/** `${NAME}` and `${NAME:-default}`, the shell's rule: unset is empty. */
|
|
35
|
+
/** `${NAME}` and `${NAME:-default}`, the shell's rule: unset is empty. A `|` runs Liquid filters. */
|
|
11
36
|
expand(text) {
|
|
12
|
-
return text.replace(
|
|
37
|
+
return text.replace(REFERENCE, (_, name, fallback, filters) => {
|
|
38
|
+
if (filters)
|
|
39
|
+
return String(liquid.evalValueSync(`${name}${filters}`, this.values) ?? "");
|
|
13
40
|
const value = this.values[name];
|
|
14
41
|
if (value)
|
|
15
42
|
return value;
|
|
@@ -38,4 +65,9 @@ export class Variables {
|
|
|
38
65
|
return { ...this.values };
|
|
39
66
|
}
|
|
40
67
|
}
|
|
68
|
+
function url(value) {
|
|
69
|
+
if (typeof value !== "string" || !URL.canParse(value))
|
|
70
|
+
return null;
|
|
71
|
+
return new URL(value);
|
|
72
|
+
}
|
|
41
73
|
//# sourceMappingURL=variables.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variables.js","sourceRoot":"","sources":["../../../src/pipeline/variables.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,OAAO,SAAS;IACS;IAA7B,YAA6B,MAAW;QAAX,WAAM,GAAN,MAAM,CAAK;IAAG,CAAC;IAE5C,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"variables.js","sourceRoot":"","sources":["../../../src/pipeline/variables.ts"],"names":[],"mappings":"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"}
|
package/dist/src/session.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { createAgentSession, createCodemodeExtension, createMcpExtension, DefaultResourceLoader, ModelRuntime, SettingsManager, } from "@earendil-works/pi-coding-agent";
|
|
4
5
|
import { buildSystemPrompt } from "../prompt/system-prompt.js";
|
|
5
6
|
import { pathClis } from "../prompt/clis.js";
|
|
6
7
|
import { PACKAGE_ROOT, PI_STATE_DIR, TESTEIYA_HOME } from "./env.js";
|
|
7
8
|
import { langfuseConfig } from "./langfuse.js";
|
|
8
|
-
import { hasMcp, tmsAccess } from "./mcp.js";
|
|
9
|
+
import { hasMcp, mcpConfig, tmsAccess } from "./mcp.js";
|
|
9
10
|
import { applyEnvKeys, resolveModel } from "./model.js";
|
|
10
11
|
import { createSetResultTool } from "./result.js";
|
|
11
12
|
import { sessionModel } from "./sessions.js";
|
|
12
13
|
// From the package root, never this file's own directory: `../skills` would
|
|
13
14
|
// resolve to dist/skills, and the filter below would silently drop everything.
|
|
14
15
|
export const BUNDLED_SKILLS_DIR = join(PACKAGE_ROOT, "skills");
|
|
15
|
-
const MCP_EXTENSION = extensionPath("mcp-extension");
|
|
16
16
|
const ATTRIBUTION_EXTENSION = extensionPath("attribution-extension");
|
|
17
17
|
const LANGFUSE_EXTENSION = extensionPath("langfuse-extension");
|
|
18
|
+
// The package root: pi loads it through its `pi.extensions` manifest.
|
|
19
|
+
const SUBAGENTS_EXTENSION = dirname(createRequire(import.meta.url).resolve("pi-subagents"));
|
|
18
20
|
/** The one runtime factory, so every command reads the same auth. */
|
|
19
21
|
export async function createRuntime() {
|
|
20
22
|
const runtime = await ModelRuntime.create({
|
|
@@ -37,6 +39,7 @@ export function createLoader(options) {
|
|
|
37
39
|
settingsManager: options.settingsManager,
|
|
38
40
|
additionalSkillPaths: [BUNDLED_SKILLS_DIR],
|
|
39
41
|
additionalExtensionPaths: options.extensionPaths,
|
|
42
|
+
extensionFactories: options.extensionFactories,
|
|
40
43
|
systemPromptOverride: options.systemPrompt,
|
|
41
44
|
skillsOverride: (current) => ({
|
|
42
45
|
skills: current.skills.filter((s) => s.baseDir.startsWith(BUNDLED_SKILLS_DIR)),
|
|
@@ -47,19 +50,26 @@ export function createLoader(options) {
|
|
|
47
50
|
export async function createTesteiyaSession(options) {
|
|
48
51
|
const runtime = await createRuntime();
|
|
49
52
|
const model = resolveModel(runtime, options.model, sessionModel(options.sessionManager));
|
|
50
|
-
const settingsManager = SettingsManager.inMemory(
|
|
51
|
-
|
|
53
|
+
const settingsManager = SettingsManager.inMemory({
|
|
54
|
+
defaultTools: ["+codemode"],
|
|
55
|
+
// A checkout never gets to add agents, settings or MCP servers of its own.
|
|
56
|
+
defaultProjectTrust: "never",
|
|
57
|
+
});
|
|
58
|
+
const extensionPaths = [ATTRIBUTION_EXTENSION, SUBAGENTS_EXTENSION];
|
|
52
59
|
if (langfuseConfig())
|
|
53
60
|
extensionPaths.push(LANGFUSE_EXTENSION);
|
|
61
|
+
// pi's CLI loads these as built-ins; SDK sessions only get what is listed here.
|
|
62
|
+
const extensionFactories = [createCodemodeExtension({ models: false })];
|
|
54
63
|
const connectedMcps = [];
|
|
55
64
|
if (hasMcp()) {
|
|
56
|
-
|
|
65
|
+
extensionFactories.push(createMcpExtension({ loadConfig: mcpConfig, openUrl: () => { } }));
|
|
57
66
|
connectedMcps.push("Testomat.io");
|
|
58
67
|
}
|
|
59
68
|
const loader = createLoader({
|
|
60
69
|
cwd: options.cwd,
|
|
61
70
|
settingsManager,
|
|
62
71
|
extensionPaths,
|
|
72
|
+
extensionFactories,
|
|
63
73
|
systemPrompt: () => buildSystemPrompt({
|
|
64
74
|
cwd: options.cwd,
|
|
65
75
|
tms: tmsAccess(),
|
|
@@ -83,15 +93,10 @@ export async function createTesteiyaSession(options) {
|
|
|
83
93
|
settingsManager,
|
|
84
94
|
sessionManager: options.sessionManager,
|
|
85
95
|
customTools: [createSetResultTool(options.result)],
|
|
86
|
-
// Extensions start their runtime on this event. Without it the MCP adapter
|
|
87
|
-
// registers its tools but never connects, and every call answers
|
|
88
|
-
// "MCP not initialized".
|
|
89
96
|
sessionStartEvent: { type: "session_start", reason: "startup" },
|
|
90
97
|
});
|
|
91
|
-
// Starts the extension runtime and fires session_start.
|
|
92
|
-
// does not do this
|
|
93
|
-
// constructed but never initialized: the MCP adapter registers its tools and
|
|
94
|
-
// then answers "MCP not initialized" for every call.
|
|
98
|
+
// Starts the extension runtime and fires session_start, where MCP connects.
|
|
99
|
+
// createAgentSession does not do this; pi's own modes do.
|
|
95
100
|
await session.bindExtensions({
|
|
96
101
|
mode: "print",
|
|
97
102
|
onError: (err) => {
|
package/dist/src/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testeiya",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "AI testing agent β QA-focused coding agent for manual and automated tests",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"pipelines",
|
|
19
19
|
"PIPELINES.md",
|
|
20
20
|
"skills",
|
|
21
|
-
"mcp-tools.json",
|
|
22
21
|
"README.md",
|
|
23
22
|
"LICENSE"
|
|
24
23
|
],
|
|
@@ -31,8 +30,7 @@
|
|
|
31
30
|
"scripts": {
|
|
32
31
|
"start": "npm run build && node dist/src/cli.js",
|
|
33
32
|
"dev": "./testeiya",
|
|
34
|
-
"build": "tsc -p tsconfig.json
|
|
35
|
-
"build:vendor": "esbuild scripts/vendor-entry.ts --bundle --format=esm --platform=node --packages=external --outfile=dist/vendor/mcp.js",
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
36
34
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
35
|
"prepublishOnly": "npm run build",
|
|
38
36
|
"test": "npm run build && node --test test/*.test.js"
|
|
@@ -46,19 +44,18 @@
|
|
|
46
44
|
"pi"
|
|
47
45
|
],
|
|
48
46
|
"dependencies": {
|
|
49
|
-
"@earendil-works/pi-ai": "^
|
|
50
|
-
"@earendil-works/pi-coding-agent": "^
|
|
51
|
-
"@earendil-works/pi-tui": "^0.84.3",
|
|
47
|
+
"@earendil-works/pi-ai": "^1.4.0",
|
|
48
|
+
"@earendil-works/pi-coding-agent": "^1.4.0",
|
|
52
49
|
"@testomatio/mcp": "^3.1.0",
|
|
53
50
|
"chalk": "^5.6.2",
|
|
54
51
|
"dedent": "^1.7.2",
|
|
55
|
-
"
|
|
52
|
+
"liquidjs": "^10.30.0",
|
|
53
|
+
"pi-subagents": "^0.81.0",
|
|
56
54
|
"typebox": "1.3.7",
|
|
57
55
|
"yaml": "^2.9.0"
|
|
58
56
|
},
|
|
59
57
|
"devDependencies": {
|
|
60
58
|
"@types/node": "^22.19.19",
|
|
61
|
-
"esbuild": "^0.28.1",
|
|
62
59
|
"tsx": "^4.23.12",
|
|
63
60
|
"typescript": "^5.9.3"
|
|
64
61
|
}
|
|
@@ -10,30 +10,33 @@ gates:
|
|
|
10
10
|
message: Explorbot has no AI provider. Set EXPLORBOT_AI_PROVIDER and its key.
|
|
11
11
|
|
|
12
12
|
env:
|
|
13
|
-
EXPLORBOT_OUTPUT: ${PIPELINE_DIR}/explorbot
|
|
14
13
|
EXPLORBOT_NO_BANNER: "1"
|
|
15
14
|
|
|
16
15
|
stages:
|
|
17
16
|
- id: review
|
|
17
|
+
title: Pull request review
|
|
18
|
+
emoji: π
|
|
18
19
|
session: qa
|
|
19
20
|
task: |
|
|
20
21
|
Review this pull request as a QA engineer. /qa-review-pr
|
|
21
|
-
List
|
|
22
|
-
Leave the file empty when no endpoint changed.
|
|
22
|
+
List the API endpoints it adds or changes in endpoints.txt, one path per line like /users/{id}, empty if none.
|
|
23
23
|
outputs: [endpoints.txt]
|
|
24
24
|
|
|
25
25
|
- id: explore
|
|
26
|
+
title: API exploration
|
|
27
|
+
emoji: π€
|
|
26
28
|
when: [api, explorbot-ai]
|
|
27
29
|
each_line: endpoints.txt
|
|
28
|
-
run: npx -y explorbot api explore "$ITEM" --style psycho
|
|
30
|
+
run: EXPLORBOT_OUTPUT="$STAGE_DIR/explorbot" npx -y explorbot api explore "$ITEM" --style psycho
|
|
29
31
|
outputs: [explorbot/]
|
|
30
32
|
timeout: 10m
|
|
31
33
|
|
|
32
34
|
- id: results
|
|
35
|
+
title: Results
|
|
36
|
+
emoji: π
|
|
33
37
|
session: qa
|
|
34
38
|
when: [api, explorbot-ai]
|
|
35
39
|
task: |
|
|
36
|
-
Explorbot results
|
|
37
|
-
Say which failures are real defects in this change: a broken contract, missing validation, a wrong status.
|
|
40
|
+
Read the Explorbot results in explorbot/ and say which failures are real defects in this change. /explorbot-fundamentals
|
|
38
41
|
Fail the run if any is a real defect.
|
|
39
42
|
inputs: [endpoints.txt, explorbot/]
|
|
@@ -11,29 +11,30 @@ gates:
|
|
|
11
11
|
|
|
12
12
|
when: [issue]
|
|
13
13
|
|
|
14
|
+
env:
|
|
15
|
+
# https://github.com/org/repo/issues/42 β org-repo-issues-42
|
|
16
|
+
TESTOMATIO_BRANCH: ${ISSUE_URL | path | slugify}
|
|
17
|
+
|
|
14
18
|
stages:
|
|
15
19
|
- id: requirements
|
|
20
|
+
title: Requirements
|
|
21
|
+
emoji: π
|
|
16
22
|
session: analyst
|
|
17
|
-
task:
|
|
18
|
-
Read the issue at ${ISSUE_URL}: its body, its comments, and every linked issue.
|
|
19
|
-
An epic has sub-issues. Read each one. On GitHub, `gh issue view <url> --comments`
|
|
20
|
-
reads an issue and `gh api repos/<owner>/<repo>/issues/<number>/sub_issues` lists sub-issues.
|
|
21
|
-
Review the requirements as a QA engineer. /qa-requirement-reviewer
|
|
22
|
-
Write the acceptance criteria to criteria.md, one section per sub-issue or feature area.
|
|
23
|
-
End it with the open questions and gaps you found.
|
|
24
|
-
The code here may not implement the issue yet. Read it only to use the real names of screens and terms.
|
|
25
|
-
outputs: [criteria.md]
|
|
23
|
+
task: Review the requirements in ${ISSUE_URL}. /qa-requirement-reviewer
|
|
26
24
|
|
|
27
25
|
- id: test-cases
|
|
26
|
+
title: Test cases
|
|
27
|
+
emoji: π
|
|
28
28
|
session: writer
|
|
29
29
|
task: |
|
|
30
|
-
Write test cases from
|
|
31
|
-
Put them in test-cases/, one markdown file per suite
|
|
32
|
-
|
|
33
|
-
inputs: [criteria.md]
|
|
30
|
+
Write test cases from requirements.md. /qa-write-test-cases
|
|
31
|
+
Put them in test-cases/, one markdown file per suite.
|
|
32
|
+
inputs: [requirements.md]
|
|
34
33
|
outputs: [test-cases/]
|
|
35
34
|
|
|
36
35
|
- id: sync
|
|
36
|
+
title: Sync to Testomat.io
|
|
37
|
+
emoji: π
|
|
37
38
|
when: [testomatio]
|
|
38
39
|
each_file: test-cases/*.md
|
|
39
40
|
task: |
|
package/pipelines/pr-review.yml
CHANGED
|
@@ -15,27 +15,31 @@ when: [code-changed]
|
|
|
15
15
|
|
|
16
16
|
stages:
|
|
17
17
|
- id: requirements
|
|
18
|
+
title: Requirements
|
|
19
|
+
emoji: π
|
|
18
20
|
session: reviewer
|
|
19
|
-
task:
|
|
20
|
-
Work out what this pull request is meant to do. /qa-pr-requirements-analyzer
|
|
21
|
-
Write the acceptance criteria to criteria.md.
|
|
22
|
-
outputs: [criteria.md]
|
|
21
|
+
task: Work out what this pull request is meant to do. /qa-pr-requirements-analyzer
|
|
23
22
|
|
|
24
23
|
- id: review
|
|
24
|
+
title: Review
|
|
25
|
+
emoji: π
|
|
25
26
|
session: reviewer
|
|
26
|
-
task:
|
|
27
|
-
|
|
28
|
-
inputs: [criteria.md]
|
|
27
|
+
task: Review this pull request as a QA engineer against requirements.md. /qa-review-pr
|
|
28
|
+
inputs: [requirements.md]
|
|
29
29
|
|
|
30
30
|
- id: test-cases
|
|
31
|
+
title: Test cases
|
|
32
|
+
emoji: π
|
|
31
33
|
session: writer
|
|
32
34
|
task: |
|
|
33
|
-
Write test cases for this pull request from
|
|
35
|
+
Write test cases for this pull request from requirements.md and review.md. /qa-write-test-cases
|
|
34
36
|
Put them in test-cases/, one markdown file per suite.
|
|
35
|
-
inputs: [
|
|
37
|
+
inputs: [requirements.md, review.md]
|
|
36
38
|
outputs: [test-cases/]
|
|
37
39
|
|
|
38
40
|
- id: sync
|
|
41
|
+
title: Sync to Testomat.io
|
|
42
|
+
emoji: π
|
|
39
43
|
when: [testomatio]
|
|
40
44
|
each_file: test-cases/*.md
|
|
41
45
|
task: |
|
package/pipelines/regression.yml
CHANGED
|
@@ -22,6 +22,8 @@ env:
|
|
|
22
22
|
|
|
23
23
|
stages:
|
|
24
24
|
- id: tests
|
|
25
|
+
title: Tests
|
|
26
|
+
emoji: π§ͺ
|
|
25
27
|
when: [testomatio]
|
|
26
28
|
run: |
|
|
27
29
|
npx -y @testomatio/reporter run --kind detect --warn \
|
|
@@ -30,10 +32,11 @@ stages:
|
|
|
30
32
|
timeout: 30m
|
|
31
33
|
|
|
32
34
|
- id: failures
|
|
35
|
+
title: Failures
|
|
36
|
+
emoji: π
|
|
33
37
|
when: [local, test-command]
|
|
34
38
|
session: triage
|
|
35
39
|
task: |
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Do not edit any file. Fail the run if this change caused a failure.
|
|
40
|
+
Triage the failures in tests.log without editing files. /debug-fix-failed-flaky-autotests
|
|
41
|
+
Fail the run if this change caused a failure.
|
|
39
42
|
inputs: [tests.log]
|
|
@@ -13,38 +13,39 @@ gates:
|
|
|
13
13
|
message: Explorbot has no AI provider. Set EXPLORBOT_AI_PROVIDER and its key.
|
|
14
14
|
|
|
15
15
|
env:
|
|
16
|
-
EXPLORBOT_OUTPUT: ${PIPELINE_DIR}/explorbot
|
|
17
16
|
EXPLORBOT_NO_BANNER: "1"
|
|
18
17
|
|
|
19
18
|
stages:
|
|
20
19
|
- id: review
|
|
20
|
+
title: Review
|
|
21
|
+
emoji: π
|
|
21
22
|
session: qa
|
|
22
|
-
task:
|
|
23
|
-
Review this pull request as a QA engineer. /qa-review-pr
|
|
24
|
-
Write the user-facing scenarios worth checking in a browser to scenarios.md.
|
|
25
|
-
outputs: [scenarios.md]
|
|
23
|
+
task: Review this pull request as a QA engineer. List the scenarios worth checking in a browser. /qa-review-pr
|
|
26
24
|
|
|
27
25
|
- id: write-plan
|
|
26
|
+
title: Test plan
|
|
27
|
+
emoji: πΊοΈ
|
|
28
28
|
session: qa
|
|
29
29
|
when: [staging]
|
|
30
|
-
task:
|
|
31
|
-
|
|
32
|
-
Write the plan to plan.md. Keep only scenarios a browser can check.
|
|
33
|
-
inputs: [scenarios.md]
|
|
30
|
+
task: Turn the browser scenarios in review.md into an Explorbot test plan for ${EXPLORBOT_URL} in plan.md. /explorbot-plan
|
|
31
|
+
inputs: [review.md]
|
|
34
32
|
outputs: [plan.md]
|
|
35
33
|
|
|
36
34
|
- id: explore
|
|
35
|
+
title: Browser testing
|
|
36
|
+
emoji: π
|
|
37
37
|
when: [staging, browser, explorbot-ai]
|
|
38
|
-
run: npx -y explorbot test "$
|
|
38
|
+
run: EXPLORBOT_OUTPUT="$STAGE_DIR/explorbot" npx -y explorbot test "$STAGE_DIR/plan.md" '*'
|
|
39
39
|
inputs: [plan.md]
|
|
40
40
|
outputs: [explorbot/]
|
|
41
41
|
timeout: 30m
|
|
42
42
|
|
|
43
43
|
- id: results
|
|
44
|
+
title: Results
|
|
45
|
+
emoji: π
|
|
44
46
|
session: qa
|
|
45
47
|
when: [staging, browser, explorbot-ai]
|
|
46
48
|
task: |
|
|
47
|
-
Explorbot
|
|
48
|
-
Say which failed scenarios are real defects in this change and which are test noise.
|
|
49
|
+
Read the Explorbot report in explorbot/ and say which failed scenarios are real defects and which are noise. /explorbot-fundamentals
|
|
49
50
|
Fail the run if any is a real defect.
|
|
50
51
|
inputs: [plan.md, explorbot/]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import dedent from "dedent";
|
|
2
|
+
|
|
3
|
+
export const pipelineReport = dedent`
|
|
4
|
+
<pipeline-report>
|
|
5
|
+
The draft is the report: every stage's report, word for word, under its own \`### <emoji> <title>\` heading. Your job is to trim it, never to write it. This format overrides <final-report>, its title included.
|
|
6
|
+
|
|
7
|
+
1. Copy the draft to the report file with the \`write\` tool, word for word.
|
|
8
|
+
2. Trim it with the \`edit\` tool:
|
|
9
|
+
* Drop a line that repeats what an earlier section already said.
|
|
10
|
+
* When a section is too long, shorten its lines or drop its least important bullets.
|
|
11
|
+
3. Nothing repeats and nothing is too long: leave the copy as it is.
|
|
12
|
+
|
|
13
|
+
Never:
|
|
14
|
+
* Add, rename, merge, reorder or drop a heading.
|
|
15
|
+
* Add a sentence, a title, an intro, a conclusion or a closing summary.
|
|
16
|
+
* Change a fact, a number, an id or a link. Reword only to shorten.
|
|
17
|
+
* Cut a numbered list, or replace a list with a count like "10 items, see the file".
|
|
18
|
+
* Add findings, assumptions or advice of your own.
|
|
19
|
+
|
|
20
|
+
* A command stage's section links its log. You may add up to three bullets quoting its failures from the log.
|
|
21
|
+
* The verdict is given. Do not call a result tool to set one.
|
|
22
|
+
</pipeline-report>
|
|
23
|
+
`;
|
package/prompt/report.ts
CHANGED
|
@@ -18,7 +18,7 @@ export function finalReport(path: string): string {
|
|
|
18
18
|
<final-report>
|
|
19
19
|
* Write your complete final report to \`${path}\` with the \`write\` tool. Writing it is required before you finish.
|
|
20
20
|
* That file is your answer. It is the run's deliverable; nothing else you say is kept.
|
|
21
|
-
* A skill's output format overrides every rule in this block, including the title. Follow it strictly.
|
|
21
|
+
* A skill's or the task's output format overrides every rule in this block, including the title. Follow it strictly.
|
|
22
22
|
* Decide the **severity of your report**. Low severity: a few short bullets, nothing more.
|
|
23
23
|
* Do not make the reader go through a long report for a minor issue with no effect.
|
|
24
24
|
* Severity decides how many items you report, not how long each one is. Even a critical finding is: what breaks, for whom, when.
|
package/prompt/testomat.io.ts
CHANGED
|
@@ -38,8 +38,8 @@ export function testomatio(options: TestomatioOptions): string {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function dynamicData(tms: TmsAccess): string {
|
|
41
|
-
if (tms === "mcp-
|
|
42
|
-
return "Get them through the
|
|
41
|
+
if (tms === "mcp-tools") {
|
|
42
|
+
return "Get them through the `mcp__testomatio__*` tools, one per entity (`tests`, `runs`, `testruns`, `issues`, β¦); pick the operation with its `command` param.";
|
|
43
43
|
}
|
|
44
44
|
if (tms === "cli-only") {
|
|
45
45
|
return "There are no Testomat.io tools in this session. Get them from the REST API: `curl` with the `TESTOMATIO` token as the Authorization header against `$TESTOMATIO_URL/api/v2`. Keep to documented endpoints; never invent paths or parameters.";
|
|
@@ -48,11 +48,11 @@ function dynamicData(tms: TmsAccess): string {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* `mcp-
|
|
51
|
+
* `mcp-tools`: one tool per entity, named `mcp__testomatio__<tool>`. `cli-only`: no
|
|
52
52
|
* tools at all; `check-tests` and REST through the shell. `mcp-direct`: one tool
|
|
53
53
|
* per entity, prefixed `testomatio-<slug>`; the desktop app's one-shot mode.
|
|
54
54
|
*/
|
|
55
|
-
export type TmsAccess = "mcp-direct" | "mcp-
|
|
55
|
+
export type TmsAccess = "mcp-direct" | "mcp-tools" | "cli-only";
|
|
56
56
|
|
|
57
57
|
export interface TestomatioOptions {
|
|
58
58
|
/** How the agent reaches Testomat.io in this run. */
|