@qa-gentic/stlc-agents 1.0.23 → 1.0.25
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/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/server.py +8 -7
- package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/server.py +7 -6
- package/src/stlc_agents/agent_jira_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/server.py +9 -8
- package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/server.py +9 -8
- package/src/stlc_agents/shared/__pycache__/cost_tracker.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/pricing.cpython-310.pyc +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qa-gentic/stlc-agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"description": "QA STLC Agents — five MCP servers + skills for AI-powered test case, Gherkin, Playwright generation, and Helix-QA file writing against Azure DevOps and Jira Cloud. Full pipeline for both: fetch → test cases → Gherkin → Playwright → Helix-QA. Works with Claude Code, GitHub Copilot, Cursor, Windsurf.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|
|
Binary file
|
|
@@ -17,6 +17,7 @@ Skills: see skills/generate-gherkin.md
|
|
|
17
17
|
import asyncio
|
|
18
18
|
import json
|
|
19
19
|
import sys
|
|
20
|
+
import time
|
|
20
21
|
|
|
21
22
|
from dotenv import load_dotenv
|
|
22
23
|
from mcp.server import Server
|
|
@@ -31,6 +32,7 @@ from stlc_agents.agent_gherkin_generator.tools.ado_gherkin import (
|
|
|
31
32
|
attach_work_item_file as _attach_wi_file,
|
|
32
33
|
validate_gherkin_content as _validate_gherkin,
|
|
33
34
|
)
|
|
35
|
+
from stlc_agents.shared.cost_tracker import track
|
|
34
36
|
|
|
35
37
|
load_dotenv()
|
|
36
38
|
|
|
@@ -377,6 +379,7 @@ async def list_tools() -> list[types.Tool]:
|
|
|
377
379
|
|
|
378
380
|
@app.call_tool()
|
|
379
381
|
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
382
|
+
t0 = time.monotonic()
|
|
380
383
|
try:
|
|
381
384
|
if name == "fetch_feature_hierarchy":
|
|
382
385
|
result = await asyncio.to_thread(
|
|
@@ -415,7 +418,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
415
418
|
"Fix the errors below before attaching to ADO."
|
|
416
419
|
),
|
|
417
420
|
}
|
|
418
|
-
return
|
|
421
|
+
return track(result, tool_name=name, server="qa-gherkin-generator", t0=t0)
|
|
419
422
|
|
|
420
423
|
result = await asyncio.to_thread(
|
|
421
424
|
_attach_feature,
|
|
@@ -445,7 +448,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
445
448
|
"Fix the errors below before attaching to ADO."
|
|
446
449
|
),
|
|
447
450
|
}
|
|
448
|
-
return
|
|
451
|
+
return track(result, tool_name=name, server="qa-gherkin-generator", t0=t0)
|
|
449
452
|
|
|
450
453
|
result = await asyncio.to_thread(
|
|
451
454
|
_attach_wi_file,
|
|
@@ -506,13 +509,11 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
506
509
|
else:
|
|
507
510
|
result = {"error": f"Unknown tool: {name}"}
|
|
508
511
|
|
|
509
|
-
return
|
|
512
|
+
return track(result, tool_name=name, server="qa-gherkin-generator", t0=t0)
|
|
510
513
|
|
|
511
514
|
except Exception as exc:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
text=json.dumps({"error": str(exc), "tool": name}, indent=2),
|
|
515
|
-
)]
|
|
515
|
+
err_result = {"error": str(exc), "tool": name}
|
|
516
|
+
return track(err_result, tool_name=name, server="qa-gherkin-generator", t0=t0)
|
|
516
517
|
|
|
517
518
|
|
|
518
519
|
async def _run():
|
|
@@ -23,6 +23,7 @@ import asyncio
|
|
|
23
23
|
import json
|
|
24
24
|
import re
|
|
25
25
|
import sys
|
|
26
|
+
import time
|
|
26
27
|
|
|
27
28
|
from dotenv import load_dotenv
|
|
28
29
|
from mcp.server import Server
|
|
@@ -36,6 +37,7 @@ from stlc_agents.agent_helix_writer.tools.helix_write import (
|
|
|
36
37
|
list_helix_tree as _list_tree,
|
|
37
38
|
update_helix_file as _update_file,
|
|
38
39
|
)
|
|
40
|
+
from stlc_agents.shared.cost_tracker import track
|
|
39
41
|
|
|
40
42
|
load_dotenv()
|
|
41
43
|
|
|
@@ -448,6 +450,7 @@ async def list_tools() -> list[types.Tool]:
|
|
|
448
450
|
|
|
449
451
|
@app.call_tool()
|
|
450
452
|
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
453
|
+
t0 = time.monotonic()
|
|
451
454
|
try:
|
|
452
455
|
if name == "inspect_helix_project":
|
|
453
456
|
result = await asyncio.to_thread(_inspect, arguments["helix_root"])
|
|
@@ -467,7 +470,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
467
470
|
"below and retry. No files were written to disk."
|
|
468
471
|
),
|
|
469
472
|
}
|
|
470
|
-
return
|
|
473
|
+
return track(result, tool_name=name, server="qa-helix-writer", t0=t0)
|
|
471
474
|
|
|
472
475
|
result = await asyncio.to_thread(
|
|
473
476
|
_write_files,
|
|
@@ -507,13 +510,11 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
507
510
|
else:
|
|
508
511
|
result = {"error": f"Unknown tool: {name}"}
|
|
509
512
|
|
|
510
|
-
return
|
|
513
|
+
return track(result, tool_name=name, server="qa-helix-writer", t0=t0)
|
|
511
514
|
|
|
512
515
|
except Exception as exc:
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
text=json.dumps({"error": str(exc), "tool": name}, indent=2),
|
|
516
|
-
)]
|
|
516
|
+
err_result = {"error": str(exc), "tool": name}
|
|
517
|
+
return track(err_result, tool_name=name, server="qa-helix-writer", t0=t0)
|
|
517
518
|
|
|
518
519
|
|
|
519
520
|
async def _run():
|
|
@@ -22,6 +22,7 @@ Skills: see skills/qa-jira-manager.md
|
|
|
22
22
|
import asyncio
|
|
23
23
|
import json
|
|
24
24
|
import sys
|
|
25
|
+
import time
|
|
25
26
|
|
|
26
27
|
from dotenv import load_dotenv
|
|
27
28
|
from mcp.server import Server
|
|
@@ -36,6 +37,7 @@ from stlc_agents.agent_jira_manager.tools.jira_workitem import (
|
|
|
36
37
|
get_linked_test_cases as _get_linked_test_cases,
|
|
37
38
|
attach_gherkin_to_issue as _attach_gherkin,
|
|
38
39
|
)
|
|
40
|
+
from stlc_agents.shared.cost_tracker import track
|
|
39
41
|
|
|
40
42
|
load_dotenv()
|
|
41
43
|
|
|
@@ -411,6 +413,7 @@ async def list_tools() -> list[types.Tool]:
|
|
|
411
413
|
|
|
412
414
|
@app.call_tool()
|
|
413
415
|
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
416
|
+
t0 = time.monotonic()
|
|
414
417
|
try:
|
|
415
418
|
cloud_id = (arguments.get("cloud_id") or "").strip() or get_cloud_id()
|
|
416
419
|
|
|
@@ -442,7 +445,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
442
445
|
"below and retry. No test cases were created in Jira."
|
|
443
446
|
),
|
|
444
447
|
}
|
|
445
|
-
return
|
|
448
|
+
return track(result, tool_name=name, server="qa-jira-manager", t0=t0)
|
|
446
449
|
|
|
447
450
|
# ── Peek at the issue to get type and project_key ─────────────
|
|
448
451
|
issue_data: dict = {}
|
|
@@ -484,7 +487,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
484
487
|
"Reply 'yes' or 'confirm' to proceed, or 'no' / 'cancel' to abort."
|
|
485
488
|
),
|
|
486
489
|
}
|
|
487
|
-
return
|
|
490
|
+
return track(result, tool_name=name, server="qa-jira-manager", t0=t0)
|
|
488
491
|
|
|
489
492
|
if not project_key:
|
|
490
493
|
result = {
|
|
@@ -494,7 +497,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
494
497
|
"Pass project_key explicitly, e.g. 'PROJ'."
|
|
495
498
|
),
|
|
496
499
|
}
|
|
497
|
-
return
|
|
500
|
+
return track(result, tool_name=name, server="qa-jira-manager", t0=t0)
|
|
498
501
|
|
|
499
502
|
# ── Create test cases ─────────────────────────────────────────
|
|
500
503
|
created = []
|
|
@@ -638,13 +641,11 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
638
641
|
else:
|
|
639
642
|
result = {"error": f"Unknown tool: {name}"}
|
|
640
643
|
|
|
641
|
-
return
|
|
644
|
+
return track(result, tool_name=name, server="qa-jira-manager", t0=t0)
|
|
642
645
|
|
|
643
646
|
except Exception as exc:
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
text=json.dumps({"error": str(exc), "tool": name}, indent=2),
|
|
647
|
-
)]
|
|
647
|
+
err_result = {"error": str(exc), "tool": name}
|
|
648
|
+
return track(err_result, tool_name=name, server="qa-jira-manager", t0=t0)
|
|
648
649
|
|
|
649
650
|
|
|
650
651
|
# ---------------------------------------------------------------------------
|
|
Binary file
|
|
@@ -17,6 +17,7 @@ import asyncio
|
|
|
17
17
|
import json
|
|
18
18
|
import os
|
|
19
19
|
import sys
|
|
20
|
+
import time
|
|
20
21
|
|
|
21
22
|
from dotenv import load_dotenv
|
|
22
23
|
from mcp.server import Server
|
|
@@ -30,6 +31,7 @@ from stlc_agents.agent_test_case_manager.tools.ado_workitem import (
|
|
|
30
31
|
link_test_cases_to_work_item as _link_test_cases,
|
|
31
32
|
get_linked_test_cases as _get_linked_test_cases,
|
|
32
33
|
)
|
|
34
|
+
from stlc_agents.shared.cost_tracker import track
|
|
33
35
|
|
|
34
36
|
load_dotenv()
|
|
35
37
|
|
|
@@ -351,6 +353,7 @@ async def list_tools() -> list[types.Tool]:
|
|
|
351
353
|
|
|
352
354
|
@app.call_tool()
|
|
353
355
|
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
356
|
+
t0 = time.monotonic()
|
|
354
357
|
try:
|
|
355
358
|
if name == "fetch_work_item":
|
|
356
359
|
result = await asyncio.to_thread(
|
|
@@ -380,7 +383,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
380
383
|
"below and retry. No test cases were created in ADO."
|
|
381
384
|
),
|
|
382
385
|
}
|
|
383
|
-
return
|
|
386
|
+
return track(result, tool_name=name, server="qa-test-case-manager", t0=t0)
|
|
384
387
|
|
|
385
388
|
# ── Epic guard — always check work item type before creating TCs ─
|
|
386
389
|
try:
|
|
@@ -399,7 +402,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
399
402
|
"Feature or PBI/Bug ID instead."
|
|
400
403
|
),
|
|
401
404
|
}
|
|
402
|
-
return
|
|
405
|
+
return track(result, tool_name=name, server="qa-test-case-manager", t0=t0)
|
|
403
406
|
except Exception:
|
|
404
407
|
pass # if the peek fails, continue and let the real call surface the error
|
|
405
408
|
|
|
@@ -448,7 +451,7 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
448
451
|
"Reply 'yes' or 'confirm' to proceed, or 'no' / 'cancel' to abort."
|
|
449
452
|
),
|
|
450
453
|
}
|
|
451
|
-
return
|
|
454
|
+
return track(result, tool_name=name, server="qa-test-case-manager", t0=t0)
|
|
452
455
|
except Exception:
|
|
453
456
|
pass # wi_data may not be set if the earlier peek failed; continue normally
|
|
454
457
|
|
|
@@ -565,13 +568,11 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
565
568
|
else:
|
|
566
569
|
result = {"error": f"Unknown tool: {name}"}
|
|
567
570
|
|
|
568
|
-
return
|
|
571
|
+
return track(result, tool_name=name, server="qa-test-case-manager", t0=t0)
|
|
569
572
|
|
|
570
573
|
except Exception as exc:
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
text=json.dumps({"error": str(exc), "tool": name}, indent=2),
|
|
574
|
-
)]
|
|
574
|
+
err_result = {"error": str(exc), "tool": name}
|
|
575
|
+
return track(err_result, tool_name=name, server="qa-test-case-manager", t0=t0)
|
|
575
576
|
|
|
576
577
|
|
|
577
578
|
# ---------------------------------------------------------------------------
|
|
Binary file
|
|
Binary file
|