@assertrx/dino 1.0.3 → 1.0.5
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/package.json +1 -1
- package/prompts/generate-bdd-from-url.md +24 -2
- package/scripts/.playwright-mcp/console-2026-08-27T20-47-33-834Z.log +9 -0
- package/scripts/.playwright-mcp/console-2026-08-27T20-56-22-679Z.log +1 -0
- package/scripts/.playwright-mcp/console-2026-08-27T20-59-22-023Z.log +3 -0
- package/scripts/.playwright-mcp/page-2026-08-27T20-47-34-065Z.yml +14 -0
- package/scripts/.playwright-mcp/page-2026-08-27T20-48-07-553Z.yml +17 -0
- package/scripts/.playwright-mcp/page-2026-08-27T20-56-22-876Z.yml +14 -0
- package/scripts/.playwright-mcp/page-2026-08-27T20-59-22-174Z.yml +14 -0
- package/scripts/.playwright-mcp/page-2026-08-27T21-00-21-032Z.yml +17 -0
- package/scripts/api-server.mjs +52 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Generate exhaustive Gherkin BDD scenarios for a single page using the bdd-gherkin skill
|
|
3
|
-
argument-hint: "<URL> [output-dir]"
|
|
3
|
+
argument-hint: "<URL> [output-dir] [auth-env-file]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Use the `bdd-gherkin` skill and `playwright-cli` commands to inspect the page at $1 and generate exhaustive Gherkin BDD scenarios for **that page only**. Fall back to the Playwright MCP bridge (`browser_*` tools) only if `playwright-cli` is unavailable or fails.
|
|
@@ -20,7 +20,7 @@ Use the `bdd-gherkin` skill and `playwright-cli` commands to inspect the page at
|
|
|
20
20
|
- Run `playwright-cli open $1` to load the page.
|
|
21
21
|
- Run `playwright-cli snapshot` to capture the accessibility tree, visible fields, buttons, links, tables, and any validation/error messages.
|
|
22
22
|
- If `playwright-cli` cannot be resolved or its commands fail, fall back to the Playwright MCP bridge: use `browser_navigate` to load $1 and `browser_snapshot` to inspect it.
|
|
23
|
-
- If the page requires authentication and an env file
|
|
23
|
+
- If the page requires authentication and an auth env file was provided (`$3`), follow the secure login flow from the `playwright-cli` skill to log in before snapshotting.
|
|
24
24
|
- Identify the primary actor(s), the business capability the page supports, and every interactive element or workflow step on the page.
|
|
25
25
|
- Do **not** navigate away from the page; generate scenarios for the page pointed to by $1 only.
|
|
26
26
|
|
|
@@ -58,8 +58,30 @@ Use the `bdd-gherkin` skill and `playwright-cli` commands to inspect the page at
|
|
|
58
58
|
- Use a clear, kebab-case file name derived from the page (e.g., `transfer-money-page.feature`, `login-page.feature`).
|
|
59
59
|
- If the page supports multiple distinct capabilities, split into multiple feature files in the output directory.
|
|
60
60
|
|
|
61
|
+
## Authentication
|
|
62
|
+
|
|
63
|
+
If the site requires login, handle credentials securely:
|
|
64
|
+
|
|
65
|
+
1. **Preferred: provide an auth env file** as the third argument (`$3`).
|
|
66
|
+
- The env file should contain variables such as:
|
|
67
|
+
```bash
|
|
68
|
+
BDD_AUTH_URL=https://example.com/login
|
|
69
|
+
BDD_USERNAME=user@example.com
|
|
70
|
+
BDD_PASSWORD=secret
|
|
71
|
+
```
|
|
72
|
+
- Load the file in a single bash command, use the values immediately to log in via `playwright-cli` (e.g., `open` the login page, then `fill` the credentials), and **do not echo, log, or persist the values anywhere**.
|
|
73
|
+
- Do not include the env file or its values in generated `.feature` files, snapshots, or test code.
|
|
74
|
+
- Mark the env file in `.gitignore` and delete it when the session is complete.
|
|
75
|
+
|
|
76
|
+
2. **Fallback: manual login**.
|
|
77
|
+
- If no env file is provided, open the login page with `playwright-cli open` and ask the user to complete login manually in the browser session.
|
|
78
|
+
- Then continue generating scenarios from the authenticated state.
|
|
79
|
+
|
|
80
|
+
3. **Never** ask the user to paste credentials into the chat, and **never** hardcode credentials into generated files.
|
|
81
|
+
|
|
61
82
|
## Output
|
|
62
83
|
|
|
63
84
|
- The saved `.feature` file path(s).
|
|
64
85
|
- A brief summary of the scenario categories covered (happy path, validation, edge cases, errors, etc.).
|
|
65
86
|
- Any clarifying assumptions made about business rules or user roles.
|
|
87
|
+
- How authentication was handled (env file or manual).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[ 296ms] [VERBOSE] [DOM] Input elements should have autocomplete attributes (suggested: "current-password"): (More info: https://goo.gl/9p2vKq) %o @ https://www.saucedemo.com/:0
|
|
2
|
+
[ 342ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/summed-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
3
|
+
[ 359ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/unique-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
4
|
+
[ 10471ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/summed-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
5
|
+
[ 10492ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/unique-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
6
|
+
[ 30601ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/summed-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
7
|
+
[ 30654ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ https://events.backtrace.io/api/unique-events/submit?universe=UNIVERSE&token=TOKEN:0
|
|
8
|
+
[ 33201ms] [ERROR] Access to fetch at 'https://submit.backtrace.io/UNIVERSE/TOKEN/json' from origin 'https://www.saucedemo.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. @ https://www.saucedemo.com/:0
|
|
9
|
+
[ 33202ms] [ERROR] Failed to load resource: net::ERR_FAILED @ https://submit.backtrace.io/UNIVERSE/TOKEN/json:0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[ 283ms] [VERBOSE] [DOM] Input elements should have autocomplete attributes (suggested: "current-password"): (More info: https://goo.gl/9p2vKq) %o @ https://www.saucedemo.com/:0
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
[ 230ms] [VERBOSE] [DOM] Input elements should have autocomplete attributes (suggested: "current-password"): (More info: https://goo.gl/9p2vKq) %o @ https://www.saucedemo.com/:0
|
|
2
|
+
[ 58486ms] [ERROR] Access to fetch at 'https://submit.backtrace.io/UNIVERSE/TOKEN/json' from origin 'https://www.saucedemo.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. @ https://www.saucedemo.com/:0
|
|
3
|
+
[ 58486ms] [ERROR] Failed to load resource: net::ERR_FAILED @ https://submit.backtrace.io/UNIVERSE/TOKEN/json:0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
- generic [ref=e3]:
|
|
2
|
+
- generic [ref=e4]: Swag Labs
|
|
3
|
+
- generic [ref=e5]:
|
|
4
|
+
- generic [ref=e9]:
|
|
5
|
+
- textbox "Username" [ref=e11]
|
|
6
|
+
- textbox "Password" [ref=e13]
|
|
7
|
+
- button "Login" [ref=e15] [cursor=pointer]
|
|
8
|
+
- generic [ref=e17]:
|
|
9
|
+
- generic [ref=e18]:
|
|
10
|
+
- heading "Accepted usernames are:" [level=4] [ref=e19]
|
|
11
|
+
- text: standard_userlocked_out_userproblem_userperformance_glitch_usererror_uservisual_user
|
|
12
|
+
- generic [ref=e20]:
|
|
13
|
+
- heading "Password for all users:" [level=4] [ref=e21]
|
|
14
|
+
- text: secret_sauce
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
- generic [ref=e3]:
|
|
2
|
+
- generic [ref=e4]: Swag Labs
|
|
3
|
+
- generic [ref=e5]:
|
|
4
|
+
- generic [ref=e9]:
|
|
5
|
+
- textbox "Username" [ref=e11]: standard_user
|
|
6
|
+
- textbox "Password" [ref=e13]: wrong_password
|
|
7
|
+
- heading [level=3] [ref=e26]:
|
|
8
|
+
- button [ref=e27] [cursor=pointer]
|
|
9
|
+
- text: "Epic sadface: Username and password do not match any user in this service"
|
|
10
|
+
- button "Login" [active] [ref=e15] [cursor=pointer]
|
|
11
|
+
- generic [ref=e17]:
|
|
12
|
+
- generic [ref=e18]:
|
|
13
|
+
- heading "Accepted usernames are:" [level=4] [ref=e19]
|
|
14
|
+
- text: standard_userlocked_out_userproblem_userperformance_glitch_usererror_uservisual_user
|
|
15
|
+
- generic [ref=e20]:
|
|
16
|
+
- heading "Password for all users:" [level=4] [ref=e21]
|
|
17
|
+
- text: secret_sauce
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
- generic [ref=e3]:
|
|
2
|
+
- generic [ref=e4]: Swag Labs
|
|
3
|
+
- generic [ref=e5]:
|
|
4
|
+
- generic [ref=e9]:
|
|
5
|
+
- textbox "Username" [ref=e11]
|
|
6
|
+
- textbox "Password" [ref=e13]
|
|
7
|
+
- button "Login" [ref=e15] [cursor=pointer]
|
|
8
|
+
- generic [ref=e17]:
|
|
9
|
+
- generic [ref=e18]:
|
|
10
|
+
- heading "Accepted usernames are:" [level=4] [ref=e19]
|
|
11
|
+
- text: standard_userlocked_out_userproblem_userperformance_glitch_usererror_uservisual_user
|
|
12
|
+
- generic [ref=e20]:
|
|
13
|
+
- heading "Password for all users:" [level=4] [ref=e21]
|
|
14
|
+
- text: secret_sauce
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
- generic [ref=e3]:
|
|
2
|
+
- generic [ref=e4]: Swag Labs
|
|
3
|
+
- generic [ref=e5]:
|
|
4
|
+
- generic [ref=e9]:
|
|
5
|
+
- textbox "Username" [ref=e11]
|
|
6
|
+
- textbox "Password" [ref=e13]
|
|
7
|
+
- button "Login" [ref=e15] [cursor=pointer]
|
|
8
|
+
- generic [ref=e17]:
|
|
9
|
+
- generic [ref=e18]:
|
|
10
|
+
- heading "Accepted usernames are:" [level=4] [ref=e19]
|
|
11
|
+
- text: standard_userlocked_out_userproblem_userperformance_glitch_usererror_uservisual_user
|
|
12
|
+
- generic [ref=e20]:
|
|
13
|
+
- heading "Password for all users:" [level=4] [ref=e21]
|
|
14
|
+
- text: secret_sauce
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
- generic [ref=e3]:
|
|
2
|
+
- generic [ref=e4]: Swag Labs
|
|
3
|
+
- generic [ref=e5]:
|
|
4
|
+
- generic [ref=e9]:
|
|
5
|
+
- textbox "Username" [ref=e11]: standard_user
|
|
6
|
+
- textbox "Password" [ref=e13]: wrong_password
|
|
7
|
+
- heading [level=3] [ref=e26]:
|
|
8
|
+
- button [ref=e27] [cursor=pointer]
|
|
9
|
+
- text: "Epic sadface: Username and password do not match any user in this service"
|
|
10
|
+
- button "Login" [active] [ref=e15] [cursor=pointer]
|
|
11
|
+
- generic [ref=e17]:
|
|
12
|
+
- generic [ref=e18]:
|
|
13
|
+
- heading "Accepted usernames are:" [level=4] [ref=e19]
|
|
14
|
+
- text: standard_userlocked_out_userproblem_userperformance_glitch_usererror_uservisual_user
|
|
15
|
+
- generic [ref=e20]:
|
|
16
|
+
- heading "Password for all users:" [level=4] [ref=e21]
|
|
17
|
+
- text: secret_sauce
|
package/scripts/api-server.mjs
CHANGED
|
@@ -54,6 +54,7 @@ const PROMPT_REGISTRY = {
|
|
|
54
54
|
params: [
|
|
55
55
|
{ name: "url", required: true, description: "Target website URL" },
|
|
56
56
|
{ name: "outputDir", required: false, description: "Output directory (default: tests/features/)" },
|
|
57
|
+
{ name: "authEnvFile", required: false, description: "Auth env file for login credentials" },
|
|
57
58
|
],
|
|
58
59
|
description: "Generate Gherkin BDD scenarios for a page by inspecting it with playwright-cli",
|
|
59
60
|
},
|
|
@@ -77,6 +78,13 @@ const PROMPT_REGISTRY = {
|
|
|
77
78
|
},
|
|
78
79
|
};
|
|
79
80
|
|
|
81
|
+
// ── Server-level agent defaults ────────────────────────────────────────
|
|
82
|
+
// Thinking level applied to every agent session created by this server.
|
|
83
|
+
// Valid: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max".
|
|
84
|
+
// Undefined → pi default (from settings, else "medium").
|
|
85
|
+
const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
86
|
+
let thinkingLevel;
|
|
87
|
+
|
|
80
88
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
81
89
|
|
|
82
90
|
/** Load a prompt template and substitute $1..$N positional arguments. */
|
|
@@ -228,6 +236,7 @@ async function createSession({ cwd, apiKey, apiKeys, provider, model: modelSelec
|
|
|
228
236
|
resourceLoader: loader,
|
|
229
237
|
sessionManager: SessionManager.inMemory(),
|
|
230
238
|
...(model ? { model } : {}),
|
|
239
|
+
...(thinkingLevel ? { thinkingLevel } : {}),
|
|
231
240
|
});
|
|
232
241
|
|
|
233
242
|
return session;
|
|
@@ -251,6 +260,26 @@ process.on("SIGTERM", shutdown);
|
|
|
251
260
|
// Health check
|
|
252
261
|
app.get("/api/health", async () => ({ status: "ok", package: "@assertrx/dino" }));
|
|
253
262
|
|
|
263
|
+
// Get the thinking level applied to agent sessions
|
|
264
|
+
app.get("/api/settings/thinking", async () => ({
|
|
265
|
+
thinkingLevel: thinkingLevel ?? null,
|
|
266
|
+
default: "medium",
|
|
267
|
+
valid: VALID_THINKING_LEVELS,
|
|
268
|
+
}));
|
|
269
|
+
|
|
270
|
+
// Set the thinking level for subsequent agent sessions
|
|
271
|
+
app.post("/api/settings/thinking", async (request, reply) => {
|
|
272
|
+
const { level } = request.body || {};
|
|
273
|
+
if (!VALID_THINKING_LEVELS.includes(level)) {
|
|
274
|
+
reply.code(400);
|
|
275
|
+
return {
|
|
276
|
+
error: `Invalid thinking level: ${JSON.stringify(level)}. Valid: ${VALID_THINKING_LEVELS.join(", ")}`,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
thinkingLevel = level;
|
|
280
|
+
return { thinkingLevel };
|
|
281
|
+
});
|
|
282
|
+
|
|
254
283
|
// List all available prompts
|
|
255
284
|
app.get("/api/prompts", async () => {
|
|
256
285
|
const prompts = Object.entries(PROMPT_REGISTRY).map(([name, entry]) => ({
|
|
@@ -433,10 +462,19 @@ app.post("/api/prompts/:name", async (request, reply) => {
|
|
|
433
462
|
|
|
434
463
|
await session.prompt(promptContent);
|
|
435
464
|
|
|
465
|
+
let stats;
|
|
466
|
+
try {
|
|
467
|
+
const s = session.getSessionStats();
|
|
468
|
+
stats = { tokens: s.tokens, cost: s.cost, toolCalls: s.toolCalls };
|
|
469
|
+
} catch {
|
|
470
|
+
/* stats unavailable */
|
|
471
|
+
}
|
|
472
|
+
|
|
436
473
|
return {
|
|
437
474
|
prompt: name,
|
|
438
475
|
response: messages.join(""),
|
|
439
476
|
toolCalls,
|
|
477
|
+
stats,
|
|
440
478
|
};
|
|
441
479
|
}
|
|
442
480
|
|
|
@@ -476,10 +514,22 @@ app.post("/api/prompts/:name", async (request, reply) => {
|
|
|
476
514
|
sendSSE("tool_end", { tool: event.toolName, error: event.isError });
|
|
477
515
|
break;
|
|
478
516
|
|
|
479
|
-
case "agent_end":
|
|
480
|
-
|
|
517
|
+
case "agent_end": {
|
|
518
|
+
let stats;
|
|
519
|
+
try {
|
|
520
|
+
const s = session.getSessionStats();
|
|
521
|
+
stats = {
|
|
522
|
+
tokens: s.tokens,
|
|
523
|
+
cost: s.cost,
|
|
524
|
+
toolCalls: s.toolCalls,
|
|
525
|
+
};
|
|
526
|
+
} catch {
|
|
527
|
+
/* stats unavailable */
|
|
528
|
+
}
|
|
529
|
+
sendSSE("done", { stats });
|
|
481
530
|
reply.raw.end();
|
|
482
531
|
break;
|
|
532
|
+
}
|
|
483
533
|
}
|
|
484
534
|
});
|
|
485
535
|
|