@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assertrx/dino",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A friendly purple dinosaur pi package with a custom TUI header, theme, and Playwright skills.",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -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 is provided, follow the secure login flow from the `playwright-cli` skill.
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
@@ -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
- sendSSE("done", {});
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