@alternative-path/qa-path-mcp 1.0.8 → 1.0.10
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/__tests__/tools/project-tools.test.js +6 -2
- package/dist/__tests__/tools/project-tools.test.js.map +1 -1
- package/dist/__tests__/tools/testgroup-launch-tools.test.js +6 -2
- package/dist/__tests__/tools/testgroup-launch-tools.test.js.map +1 -1
- package/dist/__tests__/utils/time.test.d.ts +2 -0
- package/dist/__tests__/utils/time.test.d.ts.map +1 -0
- package/dist/__tests__/utils/time.test.js +58 -0
- package/dist/__tests__/utils/time.test.js.map +1 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +13 -1
- package/dist/api-client.js.map +1 -1
- package/dist/tools/module-tools.d.ts.map +1 -1
- package/dist/tools/module-tools.js +4 -2
- package/dist/tools/module-tools.js.map +1 -1
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +6 -1
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/query-tools.d.ts.map +1 -1
- package/dist/tools/query-tools.js +5 -0
- package/dist/tools/query-tools.js.map +1 -1
- package/dist/tools/testcase-tools.d.ts.map +1 -1
- package/dist/tools/testcase-tools.js +41 -44
- package/dist/tools/testcase-tools.js.map +1 -1
- package/dist/tools/testgroup-launch-tools.d.ts.map +1 -1
- package/dist/tools/testgroup-launch-tools.js +12 -4
- package/dist/tools/testgroup-launch-tools.js.map +1 -1
- package/dist/utils/time.d.ts +37 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +137 -0
- package/dist/utils/time.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timezone helpers for QA Path MCP.
|
|
3
|
+
*
|
|
4
|
+
* The backend stores and returns all timestamps in UTC. The browser UI, however,
|
|
5
|
+
* renders them in the viewer's local timezone, so the same instant can land on a
|
|
6
|
+
* different calendar day (e.g. 2026-06-16T18:45Z is "17 June 12:15 am" in IST).
|
|
7
|
+
*
|
|
8
|
+
* This MCP ships as a local stdio server: the process runs on the same machine as
|
|
9
|
+
* the browser, so the host's local timezone matches what the UI uses. We therefore
|
|
10
|
+
* detect the timezone at runtime and use it to (a) annotate returned timestamps with
|
|
11
|
+
* a local rendering and (b) compute correct UTC bounds for relative-day filters.
|
|
12
|
+
*
|
|
13
|
+
* NOTE: if this MCP is ever hosted remotely (a shared server/container), the host
|
|
14
|
+
* timezone no longer reflects any user and this default must be revisited — the
|
|
15
|
+
* timezone would then need to be supplied per-request or per-user.
|
|
16
|
+
*/
|
|
17
|
+
/** Fields that carry ISO-8601 UTC timestamps in API responses. Epoch fields (e.g.
|
|
18
|
+
* automation step `timestamp` numbers) are intentionally excluded. */
|
|
19
|
+
const TIMESTAMP_FIELDS = new Set([
|
|
20
|
+
"created_at",
|
|
21
|
+
"updated_at",
|
|
22
|
+
"last_executed_date",
|
|
23
|
+
"next_scheduled_run",
|
|
24
|
+
]);
|
|
25
|
+
/** Detect the host's local IANA timezone, falling back to UTC. */
|
|
26
|
+
export function getLocalTimeZone() {
|
|
27
|
+
try {
|
|
28
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return "UTC";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Offset (in minutes) of `tz` from UTC at the given UTC instant. East of UTC is positive. */
|
|
35
|
+
function offsetMinutesAt(tz, utcMs) {
|
|
36
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
37
|
+
timeZone: tz,
|
|
38
|
+
hour12: false,
|
|
39
|
+
year: "numeric",
|
|
40
|
+
month: "2-digit",
|
|
41
|
+
day: "2-digit",
|
|
42
|
+
hour: "2-digit",
|
|
43
|
+
minute: "2-digit",
|
|
44
|
+
second: "2-digit",
|
|
45
|
+
});
|
|
46
|
+
const parts = dtf.formatToParts(new Date(utcMs));
|
|
47
|
+
const map = {};
|
|
48
|
+
for (const p of parts)
|
|
49
|
+
map[p.type] = p.value;
|
|
50
|
+
// Hour can come back as "24" at midnight in some engines; normalize to 0.
|
|
51
|
+
const hour = map.hour === "24" ? 0 : Number(map.hour);
|
|
52
|
+
const asUtc = Date.UTC(Number(map.year), Number(map.month) - 1, Number(map.day), hour, Number(map.minute), Number(map.second));
|
|
53
|
+
// formatToParts only resolves to seconds, so the source instant's milliseconds
|
|
54
|
+
// leak in as a fractional minute. Real IANA offsets are whole minutes — round.
|
|
55
|
+
return Math.round((asUtc - utcMs) / 60000);
|
|
56
|
+
}
|
|
57
|
+
/** Format an offset in minutes as "+05:30" / "-08:00" / "+00:00". */
|
|
58
|
+
function formatOffset(offsetMinutes) {
|
|
59
|
+
const sign = offsetMinutes < 0 ? "-" : "+";
|
|
60
|
+
const abs = Math.abs(offsetMinutes);
|
|
61
|
+
const hh = String(Math.floor(abs / 60)).padStart(2, "0");
|
|
62
|
+
const mm = String(abs % 60).padStart(2, "0");
|
|
63
|
+
return `${sign}${hh}:${mm}`;
|
|
64
|
+
}
|
|
65
|
+
/** The local calendar Y/M/D in `tz` for a given UTC instant. */
|
|
66
|
+
function localYmd(tz, utcMs) {
|
|
67
|
+
const dtf = new Intl.DateTimeFormat("en-CA", {
|
|
68
|
+
timeZone: tz,
|
|
69
|
+
year: "numeric",
|
|
70
|
+
month: "2-digit",
|
|
71
|
+
day: "2-digit",
|
|
72
|
+
});
|
|
73
|
+
const map = {};
|
|
74
|
+
for (const p of dtf.formatToParts(new Date(utcMs)))
|
|
75
|
+
map[p.type] = p.value;
|
|
76
|
+
return { year: Number(map.year), month1: Number(map.month), day: Number(map.day) };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Render a UTC timestamp string as an ISO-8601 string in `tz` carrying the offset,
|
|
80
|
+
* e.g. "2026-06-17T00:15:00+05:30". Returns null for unparseable input.
|
|
81
|
+
*/
|
|
82
|
+
export function formatInTimeZone(isoUtc, tz) {
|
|
83
|
+
const ms = Date.parse(isoUtc);
|
|
84
|
+
if (Number.isNaN(ms))
|
|
85
|
+
return null;
|
|
86
|
+
const { year, month1, day } = localYmd(tz, ms);
|
|
87
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
88
|
+
timeZone: tz,
|
|
89
|
+
hour12: false,
|
|
90
|
+
hour: "2-digit",
|
|
91
|
+
minute: "2-digit",
|
|
92
|
+
second: "2-digit",
|
|
93
|
+
});
|
|
94
|
+
const map = {};
|
|
95
|
+
for (const p of dtf.formatToParts(new Date(ms)))
|
|
96
|
+
map[p.type] = p.value;
|
|
97
|
+
const hour = map.hour === "24" ? "00" : map.hour;
|
|
98
|
+
const offset = formatOffset(offsetMinutesAt(tz, ms));
|
|
99
|
+
const yyyy = String(year).padStart(4, "0");
|
|
100
|
+
const mo = String(month1).padStart(2, "0");
|
|
101
|
+
const dd = String(day).padStart(2, "0");
|
|
102
|
+
return `${yyyy}-${mo}-${dd}T${hour}:${map.minute}:${map.second}${offset}`;
|
|
103
|
+
}
|
|
104
|
+
/** A compact timezone descriptor for `_meta`. Date filtering is resolved server-side
|
|
105
|
+
* from the `timezone` sent on the request, so no client-computed ranges are needed. */
|
|
106
|
+
export function timezoneMeta(tz = getLocalTimeZone(), nowMs = Date.now()) {
|
|
107
|
+
return {
|
|
108
|
+
name: tz,
|
|
109
|
+
offset: formatOffset(offsetMinutesAt(tz, nowMs)),
|
|
110
|
+
note: "All timestamps from the API are UTC. `*_local` fields render them in this timezone. " +
|
|
111
|
+
"Date filters use bare calendar dates and are interpreted in this timezone server-side.",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Recursively clone `value`, adding a `<field>_local` sibling for every known UTC
|
|
116
|
+
* timestamp field (see TIMESTAMP_FIELDS). Non-timestamp data is passed through
|
|
117
|
+
* unchanged. Safe on arrays, plain objects, and primitives.
|
|
118
|
+
*/
|
|
119
|
+
export function enrichTimestamps(value, tz = getLocalTimeZone()) {
|
|
120
|
+
if (Array.isArray(value)) {
|
|
121
|
+
return value.map((v) => enrichTimestamps(v, tz));
|
|
122
|
+
}
|
|
123
|
+
if (value && typeof value === "object") {
|
|
124
|
+
const out = {};
|
|
125
|
+
for (const [key, val] of Object.entries(value)) {
|
|
126
|
+
out[key] = enrichTimestamps(val, tz);
|
|
127
|
+
if (TIMESTAMP_FIELDS.has(key) && typeof val === "string" && val.length > 0) {
|
|
128
|
+
const local = formatInTimeZone(val, tz);
|
|
129
|
+
if (local)
|
|
130
|
+
out[`${key}_local`] = local;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alternative-path/qa-path-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "MCP server for QA-Path Test Management System - Manage test cases, modules, components, and subcomponents via Cursor, Claude and VS Code",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|