testdriverai 7.8.0-test.63 → 7.8.0-test.64
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/interfaces/vitest-plugin.mjs +1 -1
- package/lib/environments.json +8 -4
- package/lib/init-project.js +1 -61
- package/lib/resolve-channel.js +39 -10
- package/lib/sentry.js +3 -1
- package/mcp-server/dist/server.mjs +24 -8
- package/mcp-server/src/server.ts +26 -8
- package/package.json +1 -1
- package/sdk.js +1 -1
- package/setup/aws/spawn-runner.sh +3 -3
- package/vitest.config.mjs +1 -1
- package/vitest.runner.config.mjs +1 -1
|
@@ -37,7 +37,7 @@ function initializeSentry() {
|
|
|
37
37
|
dsn:
|
|
38
38
|
process.env.SENTRY_DSN ||
|
|
39
39
|
"https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
|
|
40
|
-
environment:
|
|
40
|
+
environment: channelConfig.sentryEnvironment,
|
|
41
41
|
release: version,
|
|
42
42
|
sampleRate: 1.0,
|
|
43
43
|
tracesSampleRate: 1.0,
|
package/lib/environments.json
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dev": {
|
|
3
3
|
"apiRoot": "https://api-dev.testdriver.ai",
|
|
4
|
-
"consoleUrl": "https://console-dev.testdriver.ai"
|
|
4
|
+
"consoleUrl": "https://console-dev.testdriver.ai",
|
|
5
|
+
"tdEnv": "dev"
|
|
5
6
|
},
|
|
6
7
|
"test": {
|
|
7
8
|
"apiRoot": "https://api-test.testdriver.ai",
|
|
8
|
-
"consoleUrl": "https://console-test.testdriver.ai"
|
|
9
|
+
"consoleUrl": "https://console-test.testdriver.ai",
|
|
10
|
+
"tdEnv": "staging"
|
|
9
11
|
},
|
|
10
12
|
"canary": {
|
|
11
13
|
"apiRoot": "https://api-canary.testdriver.ai",
|
|
12
|
-
"consoleUrl": "https://console-canary.testdriver.ai"
|
|
14
|
+
"consoleUrl": "https://console-canary.testdriver.ai",
|
|
15
|
+
"tdEnv": "production"
|
|
13
16
|
},
|
|
14
17
|
"stable": {
|
|
15
18
|
"apiRoot": "https://api.testdriver.ai",
|
|
16
|
-
"consoleUrl": "https://console.testdriver.ai"
|
|
19
|
+
"consoleUrl": "https://console.testdriver.ai",
|
|
20
|
+
"tdEnv": "production"
|
|
17
21
|
}
|
|
18
22
|
}
|
package/lib/init-project.js
CHANGED
|
@@ -14,66 +14,11 @@ function runInstall(cmd, args, cwd, label) {
|
|
|
14
14
|
return new Promise((resolve, reject) => {
|
|
15
15
|
const child = spawn(cmd, args, {
|
|
16
16
|
cwd,
|
|
17
|
-
stdio: ["ignore", "
|
|
17
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
18
18
|
shell: process.platform === "win32",
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
22
|
-
const barWidth = 20;
|
|
23
|
-
let frame = 0;
|
|
24
|
-
let status = "resolving";
|
|
25
|
-
let filled = 0;
|
|
26
|
-
|
|
27
|
-
// Parse npm stderr for progress hints
|
|
28
|
-
const handleData = (data) => {
|
|
29
|
-
const text = data.toString();
|
|
30
|
-
if (text.includes("idealTree")) {
|
|
31
|
-
status = "resolving packages";
|
|
32
|
-
filled = Math.max(filled, 3);
|
|
33
|
-
} else if (text.includes("reify:")) {
|
|
34
|
-
status = "installing";
|
|
35
|
-
filled = Math.max(filled, 8);
|
|
36
|
-
// Try to extract package name from reify output
|
|
37
|
-
const match = text.match(/reify:([^\s:]+)/);
|
|
38
|
-
if (match) {
|
|
39
|
-
status = `installing ${match[1]}`;
|
|
40
|
-
}
|
|
41
|
-
} else if (text.includes("timing")) {
|
|
42
|
-
filled = Math.max(filled, 14);
|
|
43
|
-
status = "finalizing";
|
|
44
|
-
} else if (text.includes("added")) {
|
|
45
|
-
filled = barWidth;
|
|
46
|
-
status = "done";
|
|
47
|
-
}
|
|
48
|
-
// Slowly increment to show activity
|
|
49
|
-
if (filled < barWidth - 2) {
|
|
50
|
-
filled = Math.min(filled + 1, barWidth - 2);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
child.stdout.on("data", handleData);
|
|
55
|
-
child.stderr.on("data", handleData);
|
|
56
|
-
|
|
57
|
-
const isTTY = process.stderr.isTTY;
|
|
58
|
-
|
|
59
|
-
const interval = setInterval(() => {
|
|
60
|
-
frame = (frame + 1) % spinnerFrames.length;
|
|
61
|
-
const spinner = spinnerFrames[frame];
|
|
62
|
-
const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
|
|
63
|
-
const line = ` ${spinner} ${label} [${bar}] ${status}`;
|
|
64
|
-
if (isTTY) {
|
|
65
|
-
process.stderr.clearLine(0);
|
|
66
|
-
process.stderr.cursorTo(0);
|
|
67
|
-
process.stderr.write(line);
|
|
68
|
-
}
|
|
69
|
-
}, 80);
|
|
70
|
-
|
|
71
21
|
child.on("close", (code) => {
|
|
72
|
-
clearInterval(interval);
|
|
73
|
-
if (isTTY) {
|
|
74
|
-
process.stderr.clearLine(0);
|
|
75
|
-
process.stderr.cursorTo(0);
|
|
76
|
-
}
|
|
77
22
|
if (code === 0) {
|
|
78
23
|
resolve();
|
|
79
24
|
} else {
|
|
@@ -82,11 +27,6 @@ function runInstall(cmd, args, cwd, label) {
|
|
|
82
27
|
});
|
|
83
28
|
|
|
84
29
|
child.on("error", (err) => {
|
|
85
|
-
clearInterval(interval);
|
|
86
|
-
if (isTTY) {
|
|
87
|
-
process.stderr.clearLine(0);
|
|
88
|
-
process.stderr.cursorTo(0);
|
|
89
|
-
}
|
|
90
30
|
reject(err);
|
|
91
31
|
});
|
|
92
32
|
});
|
package/lib/resolve-channel.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolves the active release channel and API URLs.
|
|
3
3
|
*
|
|
4
|
+
* TD_CHANNEL: dev | test | canary | stable (which release channel)
|
|
5
|
+
* TD_ENV: dev | staging | production (which infrastructure tier)
|
|
6
|
+
*
|
|
4
7
|
* Channel is derived from (in priority order):
|
|
5
8
|
* 1. TD_CHANNEL env var (explicit override)
|
|
6
|
-
* 2. TD_ENV env var
|
|
9
|
+
* 2. TD_ENV env var — if it holds a legacy channel name (dev/test/canary/stable)
|
|
7
10
|
* 3. SDK package.json version prerelease tag (e.g. "7.6.0-test.5" → "test")
|
|
8
|
-
* 4. "
|
|
11
|
+
* 4. "stable" for clean semver versions
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
const semver = require("semver");
|
|
@@ -15,20 +18,20 @@ const CHANNELS = {
|
|
|
15
18
|
dev: "http://localhost:1337",
|
|
16
19
|
test: environments.test.apiRoot,
|
|
17
20
|
canary: environments.canary.apiRoot,
|
|
18
|
-
|
|
21
|
+
stable: environments.stable.apiRoot,
|
|
19
22
|
};
|
|
20
23
|
|
|
24
|
+
const VALID_ENVS = new Set(["dev", "staging", "production"]);
|
|
25
|
+
|
|
21
26
|
function resolveActiveChannel() {
|
|
22
27
|
// 1. Explicit channel override
|
|
23
28
|
if (process.env.TD_CHANNEL && CHANNELS[process.env.TD_CHANNEL]) {
|
|
24
29
|
return process.env.TD_CHANNEL;
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
// 2.
|
|
28
|
-
if (process.env.TD_ENV) {
|
|
29
|
-
|
|
30
|
-
if (CHANNELS[envName]) return envName;
|
|
31
|
-
if (envName === "stable") return "latest";
|
|
32
|
+
// 2. TD_ENV — if it holds a legacy channel name, use it as channel
|
|
33
|
+
if (process.env.TD_ENV && CHANNELS[process.env.TD_ENV]) {
|
|
34
|
+
return process.env.TD_ENV;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
// 3. Fallback: derive from package.json prerelease tag
|
|
@@ -38,9 +41,35 @@ function resolveActiveChannel() {
|
|
|
38
41
|
return pre[0];
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
return "
|
|
44
|
+
return "stable";
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
const active = resolveActiveChannel();
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Returns the infrastructure environment (dev | staging | production).
|
|
51
|
+
* Reads from environments.json tdEnv mapping.
|
|
52
|
+
*/
|
|
53
|
+
function resolveTdEnv() {
|
|
54
|
+
// If TD_ENV is already new-format, use it directly
|
|
55
|
+
if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV)) {
|
|
56
|
+
return process.env.TD_ENV;
|
|
57
|
+
}
|
|
58
|
+
// Derive from channel
|
|
59
|
+
const entry = environments[active];
|
|
60
|
+
return entry ? entry.tdEnv : "production";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const tdEnv = resolveTdEnv();
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolves the Sentry environment name.
|
|
67
|
+
* Uses the infrastructure tier (dev | staging | production).
|
|
68
|
+
*/
|
|
69
|
+
function resolveSentryEnvironment() {
|
|
70
|
+
return tdEnv;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const sentryEnvironment = resolveSentryEnvironment();
|
|
74
|
+
|
|
75
|
+
module.exports = { active, channels: CHANNELS, sentryEnvironment, tdEnv };
|
package/lib/sentry.js
CHANGED
|
@@ -14,6 +14,7 @@ const Sentry = require("@sentry/node");
|
|
|
14
14
|
const crypto = require("crypto");
|
|
15
15
|
const os = require("os");
|
|
16
16
|
const { version } = require("../package.json");
|
|
17
|
+
const { sentryEnvironment } = require("./resolve-channel");
|
|
17
18
|
const logger = require("../agent/lib/logger");
|
|
18
19
|
|
|
19
20
|
// Store trace contexts per session so concurrent tests don't overwrite each other.
|
|
@@ -41,7 +42,7 @@ if (isEnabled()) {
|
|
|
41
42
|
dsn:
|
|
42
43
|
process.env.SENTRY_DSN ||
|
|
43
44
|
"https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
|
|
44
|
-
environment:
|
|
45
|
+
environment: sentryEnvironment,
|
|
45
46
|
release: version,
|
|
46
47
|
sampleRate: 1.0,
|
|
47
48
|
tracesSampleRate: 1.0, // Sample 20% of transactions for performance
|
|
@@ -53,6 +54,7 @@ if (isEnabled()) {
|
|
|
53
54
|
platform: os.platform(),
|
|
54
55
|
arch: os.arch(),
|
|
55
56
|
nodeVersion: process.version,
|
|
57
|
+
runner: "sdk",
|
|
56
58
|
},
|
|
57
59
|
},
|
|
58
60
|
// Filter out common non-errors and expected test failures
|
|
@@ -26,18 +26,33 @@ import { sessionManager } from "./session.js";
|
|
|
26
26
|
const sdkRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
27
27
|
const packageJson = JSON.parse(fs.readFileSync(path.join(sdkRoot, "package.json"), "utf-8"));
|
|
28
28
|
const version = packageJson.version || "1.0.0";
|
|
29
|
-
// Derive release channel from package version
|
|
29
|
+
// Derive release channel and infrastructure environment from package version
|
|
30
30
|
import semver from "semver";
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const CHANNEL_TO_ENV = {
|
|
32
|
+
dev: "dev",
|
|
33
|
+
test: "staging",
|
|
34
|
+
canary: "production",
|
|
35
|
+
stable: "production",
|
|
36
|
+
};
|
|
37
|
+
const VALID_CHANNELS = new Set(Object.keys(CHANNEL_TO_ENV));
|
|
38
|
+
const VALID_ENVS = new Set(["dev", "staging", "production"]);
|
|
39
|
+
function resolveChannel(ver) {
|
|
40
|
+
if (process.env.TD_CHANNEL && VALID_CHANNELS.has(process.env.TD_CHANNEL))
|
|
34
41
|
return process.env.TD_CHANNEL;
|
|
42
|
+
if (process.env.TD_ENV && VALID_CHANNELS.has(process.env.TD_ENV))
|
|
43
|
+
return process.env.TD_ENV;
|
|
35
44
|
const pre = semver.prerelease(ver);
|
|
36
|
-
if (pre && pre.length > 0 &&
|
|
45
|
+
if (pre && pre.length > 0 && VALID_CHANNELS.has(String(pre[0])))
|
|
37
46
|
return String(pre[0]);
|
|
38
|
-
return "
|
|
47
|
+
return "stable";
|
|
48
|
+
}
|
|
49
|
+
function resolveSentryEnvironment(ver) {
|
|
50
|
+
if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV))
|
|
51
|
+
return process.env.TD_ENV;
|
|
52
|
+
return CHANNEL_TO_ENV[resolveChannel(ver)] || "production";
|
|
39
53
|
}
|
|
40
|
-
const
|
|
54
|
+
const activeChannel = resolveChannel(version);
|
|
55
|
+
const sentryEnvironment = resolveSentryEnvironment(version);
|
|
41
56
|
const isSentryEnabled = () => {
|
|
42
57
|
if (process.env.TD_TELEMETRY === "false") {
|
|
43
58
|
return false;
|
|
@@ -49,7 +64,7 @@ if (isSentryEnabled()) {
|
|
|
49
64
|
Sentry.init({
|
|
50
65
|
dsn: process.env.SENTRY_DSN ||
|
|
51
66
|
"https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
|
|
52
|
-
environment:
|
|
67
|
+
environment: sentryEnvironment,
|
|
53
68
|
release: version,
|
|
54
69
|
sampleRate: 1.0,
|
|
55
70
|
tracesSampleRate: 1.0,
|
|
@@ -57,6 +72,7 @@ if (isSentryEnabled()) {
|
|
|
57
72
|
integrations: [Sentry.httpIntegration(), Sentry.nodeContextIntegration()],
|
|
58
73
|
initialScope: {
|
|
59
74
|
tags: {
|
|
75
|
+
channel: activeChannel,
|
|
60
76
|
platform: os.platform(),
|
|
61
77
|
arch: os.arch(),
|
|
62
78
|
nodeVersion: process.version,
|
package/mcp-server/src/server.ts
CHANGED
|
@@ -34,16 +34,33 @@ const sdkRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", ".
|
|
|
34
34
|
const packageJson = JSON.parse(fs.readFileSync(path.join(sdkRoot, "package.json"), "utf-8"));
|
|
35
35
|
const version = packageJson.version || "1.0.0";
|
|
36
36
|
|
|
37
|
-
// Derive release channel from package version
|
|
37
|
+
// Derive release channel and infrastructure environment from package version
|
|
38
38
|
import semver from "semver";
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
|
|
40
|
+
const CHANNEL_TO_ENV: Record<string, string> = {
|
|
41
|
+
dev: "dev",
|
|
42
|
+
test: "staging",
|
|
43
|
+
canary: "production",
|
|
44
|
+
stable: "production",
|
|
45
|
+
};
|
|
46
|
+
const VALID_CHANNELS = new Set(Object.keys(CHANNEL_TO_ENV));
|
|
47
|
+
const VALID_ENVS = new Set(["dev", "staging", "production"]);
|
|
48
|
+
|
|
49
|
+
function resolveChannel(ver: string): string {
|
|
50
|
+
if (process.env.TD_CHANNEL && VALID_CHANNELS.has(process.env.TD_CHANNEL)) return process.env.TD_CHANNEL;
|
|
51
|
+
if (process.env.TD_ENV && VALID_CHANNELS.has(process.env.TD_ENV)) return process.env.TD_ENV;
|
|
42
52
|
const pre = semver.prerelease(ver);
|
|
43
|
-
if (pre && pre.length > 0 &&
|
|
44
|
-
return "
|
|
53
|
+
if (pre && pre.length > 0 && VALID_CHANNELS.has(String(pre[0]))) return String(pre[0]);
|
|
54
|
+
return "stable";
|
|
45
55
|
}
|
|
46
|
-
|
|
56
|
+
|
|
57
|
+
function resolveSentryEnvironment(ver: string): string {
|
|
58
|
+
if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV)) return process.env.TD_ENV;
|
|
59
|
+
return CHANNEL_TO_ENV[resolveChannel(ver)] || "production";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const activeChannel = resolveChannel(version);
|
|
63
|
+
const sentryEnvironment = resolveSentryEnvironment(version);
|
|
47
64
|
|
|
48
65
|
const isSentryEnabled = () => {
|
|
49
66
|
if (process.env.TD_TELEMETRY === "false") {
|
|
@@ -58,7 +75,7 @@ if (isSentryEnabled()) {
|
|
|
58
75
|
dsn:
|
|
59
76
|
process.env.SENTRY_DSN ||
|
|
60
77
|
"https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
|
|
61
|
-
environment:
|
|
78
|
+
environment: sentryEnvironment,
|
|
62
79
|
release: version,
|
|
63
80
|
sampleRate: 1.0,
|
|
64
81
|
tracesSampleRate: 1.0,
|
|
@@ -66,6 +83,7 @@ if (isSentryEnabled()) {
|
|
|
66
83
|
integrations: [Sentry.httpIntegration(), Sentry.nodeContextIntegration()],
|
|
67
84
|
initialScope: {
|
|
68
85
|
tags: {
|
|
86
|
+
channel: activeChannel,
|
|
69
87
|
platform: os.platform(),
|
|
70
88
|
arch: os.arch(),
|
|
71
89
|
nodeVersion: process.version,
|
package/package.json
CHANGED
package/sdk.js
CHANGED
|
@@ -3845,7 +3845,7 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3845
3845
|
const apiRoot = this.config?.TD_API_ROOT || 'unknown';
|
|
3846
3846
|
const apiKey = this.config?.TD_API_KEY || '';
|
|
3847
3847
|
const maskedKey = apiKey.length > 4 ? '***' + apiKey.slice(-4) : '(not set)';
|
|
3848
|
-
const env = process.env.TD_ENV || 'unknown';
|
|
3848
|
+
const env = process.env.TD_CHANNEL || process.env.TD_ENV || 'unknown';
|
|
3849
3849
|
const os = this.agent?.options?.os || process.env.TD_OS || 'linux';
|
|
3850
3850
|
const sdkVersion = require('./package.json').version;
|
|
3851
3851
|
|
|
@@ -145,7 +145,7 @@ done
|
|
|
145
145
|
echo "Installing runner..."
|
|
146
146
|
|
|
147
147
|
# Determine environment and version
|
|
148
|
-
|
|
148
|
+
TD_CHANNEL="${TD_CHANNEL:-stable}"
|
|
149
149
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
150
150
|
SDK_PKG_JSON="${SCRIPT_DIR}/../../../sdk/package.json"
|
|
151
151
|
RUNNER_DIR="${SCRIPT_DIR}/../../../runner"
|
|
@@ -154,11 +154,11 @@ if [ -f "$SDK_PKG_JSON" ]; then
|
|
|
154
154
|
RUNNER_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
|
|
155
155
|
echo "Runner version from SDK: $RUNNER_VERSION"
|
|
156
156
|
else
|
|
157
|
-
RUNNER_VERSION="$
|
|
157
|
+
RUNNER_VERSION="$TD_CHANNEL"
|
|
158
158
|
echo "SDK package.json not found, using env tag: $RUNNER_VERSION"
|
|
159
159
|
fi
|
|
160
160
|
|
|
161
|
-
if [ "$
|
|
161
|
+
if [ "$TD_CHANNEL" = "dev" ]; then
|
|
162
162
|
echo "Dev mode: packing and uploading local runner to S3..."
|
|
163
163
|
|
|
164
164
|
# Pack local runner
|
package/vitest.config.mjs
CHANGED
|
@@ -31,7 +31,7 @@ const sharedTestConfig = {
|
|
|
31
31
|
// Uses: environments.json (URLs) + envs/{env}.env (overlay) + fixtures (API keys)
|
|
32
32
|
// TD_PLAN selects which plan's API key to use (default: enterprise)
|
|
33
33
|
const plan = process.env.TD_PLAN || "enterprise";
|
|
34
|
-
const defaultEnv = process.env.
|
|
34
|
+
const defaultEnv = process.env.TD_CHANNEL || "dev";
|
|
35
35
|
const environments = getEnvironmentNames();
|
|
36
36
|
|
|
37
37
|
// Apply default env to the main process so the reporter/plugin picks it up
|
package/vitest.runner.config.mjs
CHANGED
|
@@ -15,7 +15,7 @@ const require = createRequire(import.meta.url);
|
|
|
15
15
|
const { resolveEnv } = require("../shared/resolve-env");
|
|
16
16
|
|
|
17
17
|
const plan = process.env.TD_PLAN || "enterprise";
|
|
18
|
-
const env = process.env.
|
|
18
|
+
const env = process.env.TD_CHANNEL || "dev";
|
|
19
19
|
const resolved = resolveEnv(env, plan);
|
|
20
20
|
|
|
21
21
|
// Apply to the main process so test code sees the vars immediately
|