testdriverai 7.7.0-canary.2 → 7.8.0-test.2
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/CHANGELOG.md +21 -17
- package/agent/lib/config.js +1 -1
- package/agent/lib/sandbox.js +2 -2
- package/interfaces/cli/commands/init.js +1 -1
- package/interfaces/vitest-plugin.mjs +8 -10
- package/lib/core/Dashcam.js +11 -33
- package/lib/init-project.js +1 -0
- package/lib/resolve-channel.js +45 -0
- package/lib/vitest/hooks.mjs +1 -1
- package/mcp-server/dist/server.mjs +12 -2
- package/mcp-server/package-lock.json +12 -3
- package/mcp-server/package.json +2 -0
- package/mcp-server/src/server.ts +11 -2
- package/package.json +3 -2
- package/sdk.js +25 -8
- package/channel.json +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
|
-
## 7.
|
|
1
|
+
## 7.8.0-test.2 (2026-03-13)
|
|
2
|
+
|
|
3
|
+
## ✨ Features
|
|
4
|
+
|
|
5
|
+
- Implement automatic cleanup of unused Ably channels to improve resource management [API] (df6181de)
|
|
2
6
|
|
|
3
7
|
## 🔧 Maintenance
|
|
4
8
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
- Enhance render.yaml configuration for improved deployment [Infrastructure] (c21f708d)
|
|
9
|
+
- Streamline CI/CD workflows with improved test organization and environment configuration [SDK] (df6181de)
|
|
10
|
+
- Enhance development environment setup with better environment variable management (df6181de)
|
|
11
|
+
- Improve connection handling and URL resolution for better reliability [SDK] (df6181de)
|
|
9
12
|
|
|
10
|
-
##
|
|
13
|
+
## 7.6.0-test.8 (2026-03-13)
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- Improve
|
|
15
|
+
🔧 Maintenance
|
|
16
|
+
|
|
17
|
+
- Improve release workflow automation for more reliable package promotions (358bb702)
|
|
15
18
|
|
|
16
|
-
## 7.
|
|
19
|
+
## 7.6.0-test.7 (2026-03-13)
|
|
17
20
|
|
|
18
21
|
## 🔧 Maintenance
|
|
19
22
|
|
|
20
|
-
-
|
|
21
|
-
- Improve
|
|
22
|
-
-
|
|
23
|
-
-
|
|
23
|
+
- Eliminate CI race conditions in promotion pipeline and streamline release workflows [CI] (9d83f886)
|
|
24
|
+
- Improve VNC URL display in CI environments [API] (9d83f886)
|
|
25
|
+
- Add dynamic channel resolution system for SDK configuration [SDK] (9d83f886)
|
|
26
|
+
- Update MCP server dependencies and enhance error handling [SDK] (9d83f886)
|
|
24
27
|
|
|
25
|
-
## 7.
|
|
28
|
+
## 7.6.0-test.6 (2026-03-13)
|
|
26
29
|
|
|
27
|
-
🔧 Maintenance
|
|
30
|
+
## 🔧 Maintenance
|
|
28
31
|
|
|
29
|
-
- Improve
|
|
32
|
+
- Improve CI/CD pipeline reliability by eliminating race conditions in release promotion workflows [c21f708d]
|
|
33
|
+
- Fix VNC URL display in continuous integration environment [API] [c21f708d]
|
|
30
34
|
|
|
31
35
|
## 7.6.0-test.5 (2026-03-12)
|
|
32
36
|
|
package/agent/lib/config.js
CHANGED
|
@@ -16,7 +16,7 @@ function parseValue(value) {
|
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const channelConfig = require("../../channel.
|
|
19
|
+
const channelConfig = require("../../lib/resolve-channel.js");
|
|
20
20
|
|
|
21
21
|
// Factory function that creates a config instance
|
|
22
22
|
const createConfig = (environment = {}) => {
|
package/agent/lib/sandbox.js
CHANGED
|
@@ -511,7 +511,7 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
|
|
|
511
511
|
url = runnerVncUrl;
|
|
512
512
|
logger.log(`Using runner-provided vncUrl: ${url}`);
|
|
513
513
|
} else if (runnerIp && noVncPort) {
|
|
514
|
-
url = `http://${runnerIp}:${noVncPort}/vnc_lite.html`;
|
|
514
|
+
url = `http://${runnerIp}:${noVncPort}/vnc_lite.html?token=V3b8wG9`;
|
|
515
515
|
logger.log(`noVNC URL constructed from runner ip+port: ${url}`);
|
|
516
516
|
} else if (runnerIp) {
|
|
517
517
|
url = "http://" + runnerIp;
|
|
@@ -619,7 +619,7 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
|
|
|
619
619
|
}
|
|
620
620
|
|
|
621
621
|
// Construct VNC URL — use port 8080 (nginx noVNC proxy) for Windows instances
|
|
622
|
-
var directUrl = message.ip ? "http://" + message.ip + ":8080/vnc_lite.html" : undefined;
|
|
622
|
+
var directUrl = message.ip ? "http://" + message.ip + ":8080/vnc_lite.html?token=V3b8wG9" : undefined;
|
|
623
623
|
|
|
624
624
|
return {
|
|
625
625
|
success: true,
|
|
@@ -12,7 +12,7 @@ const { execSync } = require("child_process");
|
|
|
12
12
|
require("dotenv").config();
|
|
13
13
|
|
|
14
14
|
// API configuration
|
|
15
|
-
const channelConfig = require("../../../channel.
|
|
15
|
+
const channelConfig = require("../../../lib/resolve-channel.js");
|
|
16
16
|
const API_BASE_URL = process.env.TD_API_ROOT || channelConfig.channels[channelConfig.active];
|
|
17
17
|
const POLL_INTERVAL = 5000; // 5 seconds
|
|
18
18
|
const POLL_TIMEOUT = 900000; // 15 minutes
|
|
@@ -9,7 +9,7 @@ import { setTestRunInfo } from "./shared-test-state.mjs";
|
|
|
9
9
|
|
|
10
10
|
// Use createRequire to import CommonJS modules without esbuild processing
|
|
11
11
|
const require = createRequire(import.meta.url);
|
|
12
|
-
const channelConfig = require("../channel.
|
|
12
|
+
const channelConfig = require("../lib/resolve-channel.js");
|
|
13
13
|
|
|
14
14
|
// Import Sentry for error reporting
|
|
15
15
|
const Sentry = require("@sentry/node");
|
|
@@ -1249,12 +1249,15 @@ function getConsoleUrl(apiRoot) {
|
|
|
1249
1249
|
|
|
1250
1250
|
if (!apiRoot) return "https://console.testdriver.ai";
|
|
1251
1251
|
|
|
1252
|
-
//
|
|
1253
|
-
|
|
1254
|
-
|
|
1252
|
+
// Map known channel API URLs to their console equivalents
|
|
1253
|
+
// e.g. https://api.canary.testdriver.ai -> https://console.canary.testdriver.ai
|
|
1254
|
+
for (const url of Object.values(channelConfig.channels)) {
|
|
1255
|
+
if (url === apiRoot) {
|
|
1256
|
+
return url.replace("api", "console").replace("1337", "3001");
|
|
1257
|
+
}
|
|
1255
1258
|
}
|
|
1256
1259
|
|
|
1257
|
-
// Local development:
|
|
1260
|
+
// Local development: ngrok/cloudflare tunnels -> localhost:3001
|
|
1258
1261
|
if (apiRoot.includes("ngrok.io") || apiRoot.includes("trycloudflare.com") || apiRoot.includes("localhost")) {
|
|
1259
1262
|
return `http://localhost:3001`;
|
|
1260
1263
|
}
|
|
@@ -1265,15 +1268,10 @@ function getConsoleUrl(apiRoot) {
|
|
|
1265
1268
|
const renderPrMatch = apiRoot.match(/https:\/\/([\w-]+)-api(-[\w]+)?(-pr-\d+)?\.onrender\.com/);
|
|
1266
1269
|
if (renderPrMatch) {
|
|
1267
1270
|
const [, prefix, suffix, prSuffix] = renderPrMatch;
|
|
1268
|
-
// Map API naming to Web naming:
|
|
1269
|
-
// canary-api -> canary-web
|
|
1270
|
-
// testdriver-api-i4m4 -> web-i4m4
|
|
1271
1271
|
let webPrefix;
|
|
1272
1272
|
if (prefix === 'testdriver' && suffix) {
|
|
1273
|
-
// testdriver-api-i4m4 -> web-i4m4
|
|
1274
1273
|
webPrefix = 'web' + suffix;
|
|
1275
1274
|
} else {
|
|
1276
|
-
// canary-api -> canary-web
|
|
1277
1275
|
webPrefix = prefix + '-web';
|
|
1278
1276
|
}
|
|
1279
1277
|
return `https://${webPrefix}${prSuffix || ''}.onrender.com`;
|
package/lib/core/Dashcam.js
CHANGED
|
@@ -80,7 +80,7 @@ class Dashcam {
|
|
|
80
80
|
* @private
|
|
81
81
|
*/
|
|
82
82
|
_getApiRoot() {
|
|
83
|
-
const channelConfig = require("../../channel.
|
|
83
|
+
const channelConfig = require("../../lib/resolve-channel.js");
|
|
84
84
|
return (
|
|
85
85
|
this.client.config?.TD_API_ROOT || channelConfig.channels[channelConfig.active]
|
|
86
86
|
);
|
|
@@ -92,7 +92,7 @@ class Dashcam {
|
|
|
92
92
|
* @param {string} apiRoot - The API root URL
|
|
93
93
|
* @returns {string} The corresponding console URL
|
|
94
94
|
*/
|
|
95
|
-
static getConsoleUrl(apiRoot = (() => { const c = require("../../channel.
|
|
95
|
+
static getConsoleUrl(apiRoot = (() => { const c = require("../../lib/resolve-channel.js"); return c.channels[c.active]; })()) {
|
|
96
96
|
// Allow explicit override via env (e.g. VITE_DOMAIN from .env)
|
|
97
97
|
if (process.env.VITE_DOMAIN) return process.env.VITE_DOMAIN;
|
|
98
98
|
|
|
@@ -448,41 +448,19 @@ class Dashcam {
|
|
|
448
448
|
|
|
449
449
|
this.recording = false;
|
|
450
450
|
|
|
451
|
-
// Extract
|
|
451
|
+
// Extract the /replay/... path from CLI output and reconstruct the URL
|
|
452
|
+
// using getConsoleUrl(). The CLI may return a wrong domain (e.g. canary-web.onrender.com)
|
|
453
|
+
// so we always rewrite the base URL to match the current environment.
|
|
452
454
|
if (output) {
|
|
453
|
-
//
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
/https?:\/\/[^\s"',}]+\/replay\/[^\s"',}]+/,
|
|
455
|
+
// Match /replay/{id} with optional query params from any URL or broken prefix
|
|
456
|
+
const replayPathMatch = output.match(
|
|
457
|
+
/(?:https?:\/\/[^\s"',}]+|undefined|null)?(\/replay\/[^\s"',}]+)/,
|
|
457
458
|
);
|
|
458
|
-
if (
|
|
459
|
-
|
|
460
|
-
// Remove trailing punctuation but keep query params
|
|
461
|
-
url = url.replace(/[.,;:!\)\]]+$/, "").trim();
|
|
462
|
-
return url;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Fallback: any dashcam.io or testdriver.ai URL
|
|
466
|
-
const dashcamUrlMatch = output.match(
|
|
467
|
-
/https?:\/\/(?:app\.)?(?:dashcam\.io|testdriver\.ai)[^\s"',}]+/,
|
|
468
|
-
);
|
|
469
|
-
if (dashcamUrlMatch) {
|
|
470
|
-
let url = dashcamUrlMatch[0];
|
|
471
|
-
url = url.replace(/[.,;:!\?\)\]]+$/, "").trim();
|
|
472
|
-
return url;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Fallback: dashcam CLI may output "undefined/replay/{id}?share={key}"
|
|
476
|
-
// when it doesn't know the console URL. Extract the path and reconstruct
|
|
477
|
-
// a proper URL using our console URL mapping.
|
|
478
|
-
const brokenUrlMatch = output.match(
|
|
479
|
-
/(?:undefined|null)?(\/replay\/[^\s"',}]+)/,
|
|
480
|
-
);
|
|
481
|
-
if (brokenUrlMatch) {
|
|
482
|
-
const replayPath = brokenUrlMatch[1].replace(/[.,;:!\)\]]+$/, "").trim();
|
|
459
|
+
if (replayPathMatch) {
|
|
460
|
+
const replayPath = replayPathMatch[1].replace(/[.,;:!\)\]]+$/, "").trim();
|
|
483
461
|
const consoleUrl = Dashcam.getConsoleUrl(this._getApiRoot());
|
|
484
462
|
const url = consoleUrl + replayPath;
|
|
485
|
-
this._log("debug", "
|
|
463
|
+
this._log("debug", "Replay URL:", url);
|
|
486
464
|
return url;
|
|
487
465
|
}
|
|
488
466
|
|
package/lib/init-project.js
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the active release channel and API URLs.
|
|
3
|
+
*
|
|
4
|
+
* Channel is derived from (in priority order):
|
|
5
|
+
* 1. TD_CHANNEL env var (explicit override)
|
|
6
|
+
* 2. TD_ENV env var (set by envs/<name>.env)
|
|
7
|
+
* 3. SDK package.json version prerelease tag (e.g. "7.6.0-test.5" → "test")
|
|
8
|
+
* 4. "latest" for clean semver versions (stable releases)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const semver = require("semver");
|
|
12
|
+
|
|
13
|
+
const CHANNELS = {
|
|
14
|
+
dev: "http://localhost:1337",
|
|
15
|
+
test: "https://api.test.testdriver.ai",
|
|
16
|
+
canary: "https://api.canary.testdriver.ai",
|
|
17
|
+
latest: "https://api.testdriver.ai",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function resolveActiveChannel() {
|
|
21
|
+
// 1. Explicit channel override
|
|
22
|
+
if (process.env.TD_CHANNEL && CHANNELS[process.env.TD_CHANNEL]) {
|
|
23
|
+
return process.env.TD_CHANNEL;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 2. Environment name from env file (mapped: stable → latest)
|
|
27
|
+
if (process.env.TD_ENV) {
|
|
28
|
+
const envName = process.env.TD_ENV;
|
|
29
|
+
if (CHANNELS[envName]) return envName;
|
|
30
|
+
if (envName === "stable") return "latest";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 3. Fallback: derive from package.json prerelease tag
|
|
34
|
+
const version = require("../package.json").version;
|
|
35
|
+
const pre = semver.prerelease(version);
|
|
36
|
+
if (pre && pre.length > 0 && CHANNELS[pre[0]]) {
|
|
37
|
+
return pre[0];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return "latest";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const active = resolveActiveChannel();
|
|
44
|
+
|
|
45
|
+
module.exports = { active, channels: CHANNELS };
|
package/lib/vitest/hooks.mjs
CHANGED
|
@@ -22,7 +22,7 @@ import TestDriverSDK from "../../sdk.js";
|
|
|
22
22
|
|
|
23
23
|
// Use createRequire to import CommonJS modules
|
|
24
24
|
const require = createRequire(import.meta.url);
|
|
25
|
-
const channelConfig = require("../../channel.
|
|
25
|
+
const channelConfig = require("../../lib/resolve-channel.js");
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Minimum required Vitest major version
|
|
@@ -26,8 +26,18 @@ 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
|
-
|
|
30
|
-
|
|
29
|
+
// Derive release channel from package version prerelease tag (e.g. "7.6.0-test.5" → "test")
|
|
30
|
+
import semver from "semver";
|
|
31
|
+
const KNOWN_CHANNELS = new Set(["dev", "test", "canary", "latest"]);
|
|
32
|
+
function resolveReleaseChannel(ver) {
|
|
33
|
+
if (process.env.TD_CHANNEL && KNOWN_CHANNELS.has(process.env.TD_CHANNEL))
|
|
34
|
+
return process.env.TD_CHANNEL;
|
|
35
|
+
const pre = semver.prerelease(ver);
|
|
36
|
+
if (pre && pre.length > 0 && KNOWN_CHANNELS.has(String(pre[0])))
|
|
37
|
+
return String(pre[0]);
|
|
38
|
+
return "latest";
|
|
39
|
+
}
|
|
40
|
+
const releaseChannel = resolveReleaseChannel(version);
|
|
31
41
|
const isSentryEnabled = () => {
|
|
32
42
|
if (process.env.TD_TELEMETRY === "false") {
|
|
33
43
|
return false;
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
"@modelcontextprotocol/ext-apps": "^1.0.0",
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
13
13
|
"@sentry/node": "^9.0.0",
|
|
14
|
+
"semver": "^7.7.4",
|
|
14
15
|
"zod": "^3.24.0"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/node": "^22.0.0",
|
|
19
|
+
"@types/semver": "^7.7.1",
|
|
18
20
|
"cross-env": "^7.0.3",
|
|
19
21
|
"tsx": "^4.19.0",
|
|
20
22
|
"typescript": "^5.6.0",
|
|
@@ -1745,6 +1747,13 @@
|
|
|
1745
1747
|
"@types/pg": "*"
|
|
1746
1748
|
}
|
|
1747
1749
|
},
|
|
1750
|
+
"node_modules/@types/semver": {
|
|
1751
|
+
"version": "7.7.1",
|
|
1752
|
+
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
|
|
1753
|
+
"integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
|
|
1754
|
+
"dev": true,
|
|
1755
|
+
"license": "MIT"
|
|
1756
|
+
},
|
|
1748
1757
|
"node_modules/@types/shimmer": {
|
|
1749
1758
|
"version": "1.2.0",
|
|
1750
1759
|
"resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz",
|
|
@@ -3087,9 +3096,9 @@
|
|
|
3087
3096
|
"license": "MIT"
|
|
3088
3097
|
},
|
|
3089
3098
|
"node_modules/semver": {
|
|
3090
|
-
"version": "7.7.
|
|
3091
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.
|
|
3092
|
-
"integrity": "sha512-
|
|
3099
|
+
"version": "7.7.4",
|
|
3100
|
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
|
3101
|
+
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
|
3093
3102
|
"license": "ISC",
|
|
3094
3103
|
"bin": {
|
|
3095
3104
|
"semver": "bin/semver.js"
|
package/mcp-server/package.json
CHANGED
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
"@modelcontextprotocol/ext-apps": "^1.0.0",
|
|
17
17
|
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
18
18
|
"@sentry/node": "^9.0.0",
|
|
19
|
+
"semver": "^7.7.4",
|
|
19
20
|
"zod": "^3.24.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
23
|
"@types/node": "^22.0.0",
|
|
24
|
+
"@types/semver": "^7.7.1",
|
|
23
25
|
"cross-env": "^7.0.3",
|
|
24
26
|
"tsx": "^4.19.0",
|
|
25
27
|
"typescript": "^5.6.0",
|
package/mcp-server/src/server.ts
CHANGED
|
@@ -33,8 +33,17 @@ import { sessionManager, type SessionState } from "./session.js";
|
|
|
33
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
|
-
|
|
37
|
-
|
|
36
|
+
|
|
37
|
+
// Derive release channel from package version prerelease tag (e.g. "7.6.0-test.5" → "test")
|
|
38
|
+
import semver from "semver";
|
|
39
|
+
const KNOWN_CHANNELS = new Set(["dev", "test", "canary", "latest"]);
|
|
40
|
+
function resolveReleaseChannel(ver: string): string {
|
|
41
|
+
if (process.env.TD_CHANNEL && KNOWN_CHANNELS.has(process.env.TD_CHANNEL)) return process.env.TD_CHANNEL;
|
|
42
|
+
const pre = semver.prerelease(ver);
|
|
43
|
+
if (pre && pre.length > 0 && KNOWN_CHANNELS.has(String(pre[0]))) return String(pre[0]);
|
|
44
|
+
return "latest";
|
|
45
|
+
}
|
|
46
|
+
const releaseChannel = resolveReleaseChannel(version);
|
|
38
47
|
|
|
39
48
|
const isSentryEnabled = () => {
|
|
40
49
|
if (process.env.TD_TELEMETRY === "false") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testdriverai",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.8.0-test.2",
|
|
4
4
|
"description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
|
|
5
5
|
"main": "sdk.js",
|
|
6
6
|
"types": "sdk.d.ts",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"@octokit/rest": "^20.1.1",
|
|
86
86
|
"@sentry/node": "^9.47.1",
|
|
87
87
|
"@stoplight/yaml-ast-parser": "^0.0.50",
|
|
88
|
-
"ajv": "^8.17.1",
|
|
89
88
|
"ably": "^2.6.0",
|
|
89
|
+
"ajv": "^8.17.1",
|
|
90
90
|
"arktype": "^2.1.19",
|
|
91
91
|
"axios": "^1.7.7",
|
|
92
92
|
"chalk": "^4.1.2",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"pixelmatch": "^7.1.0",
|
|
106
106
|
"remark-parse": "^11.0.0",
|
|
107
107
|
"sanitize-filename": "^1.6.3",
|
|
108
|
+
"semver": "^7.7.4",
|
|
108
109
|
"strip-ansi": "^6.0.1",
|
|
109
110
|
"terminal-image": "^4.1.0",
|
|
110
111
|
"tmp": "^0.2.3",
|
package/sdk.js
CHANGED
|
@@ -1438,7 +1438,7 @@ class TestDriverSDK {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
|
|
1440
1440
|
// Set up environment with API key
|
|
1441
|
-
const channelConfig = require("./channel.
|
|
1441
|
+
const channelConfig = require("./lib/resolve-channel.js");
|
|
1442
1442
|
const environment = {
|
|
1443
1443
|
TD_API_KEY: resolvedApiKey,
|
|
1444
1444
|
TD_API_ROOT: options.apiRoot || process.env.TD_API_ROOT || channelConfig.channels[channelConfig.active],
|
|
@@ -3815,9 +3815,27 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3815
3815
|
*/
|
|
3816
3816
|
_logEnvironmentInfo() {
|
|
3817
3817
|
const apiRoot = this.config?.TD_API_ROOT || 'unknown';
|
|
3818
|
+
const apiKey = this.config?.TD_API_KEY || '';
|
|
3819
|
+
const maskedKey = apiKey.length > 4 ? '***' + apiKey.slice(-4) : '(not set)';
|
|
3820
|
+
const env = process.env.TD_ENV || 'unknown';
|
|
3821
|
+
const os = this.agent?.options?.os || process.env.TD_OS || 'linux';
|
|
3818
3822
|
const sdkVersion = require('./package.json').version;
|
|
3819
|
-
const http = apiRoot.startsWith('https') ? require('https') : require('http');
|
|
3820
3823
|
|
|
3824
|
+
// Always print local config immediately
|
|
3825
|
+
const localLines = [
|
|
3826
|
+
'',
|
|
3827
|
+
` ┌─ TestDriver SDK v${sdkVersion}`,
|
|
3828
|
+
` │ Environment: ${env}`,
|
|
3829
|
+
` │ API: ${apiRoot}`,
|
|
3830
|
+
` │ Key: ${maskedKey}`,
|
|
3831
|
+
` │ OS: ${os}`,
|
|
3832
|
+
` └─`,
|
|
3833
|
+
'',
|
|
3834
|
+
];
|
|
3835
|
+
console.log(localLines.join('\n'));
|
|
3836
|
+
|
|
3837
|
+
// Fetch API version info asynchronously (non-blocking, best-effort)
|
|
3838
|
+
const http = apiRoot.startsWith('https') ? require('https') : require('http');
|
|
3821
3839
|
const url = apiRoot + '/api/entrance/version';
|
|
3822
3840
|
const req = http.get(url, { timeout: 5000 }, (res) => {
|
|
3823
3841
|
let data = '';
|
|
@@ -3825,19 +3843,18 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3825
3843
|
res.on('end', () => {
|
|
3826
3844
|
try {
|
|
3827
3845
|
const info = JSON.parse(data);
|
|
3828
|
-
if (info.channel === 'stable') return; // don't show on stable
|
|
3829
3846
|
const commit = info.commit || 'unknown';
|
|
3830
3847
|
const shortCommit = commit.substring(0, 7);
|
|
3831
3848
|
const commitUrl = commit !== 'unknown'
|
|
3832
3849
|
? `https://github.com/testdriverai/mono/commit/${commit}`
|
|
3833
3850
|
: null;
|
|
3834
3851
|
const lines = [
|
|
3835
|
-
|
|
3836
|
-
`
|
|
3837
|
-
` API: ${apiRoot} (${info.channel || 'unknown'} v${info.version || '?'})`,
|
|
3852
|
+
` ┌─ API Server`,
|
|
3853
|
+
` │ Channel: ${info.channel || 'unknown'} v${info.version || '?'}`,
|
|
3838
3854
|
commitUrl
|
|
3839
|
-
? ` Commit: ${shortCommit} → ${commitUrl}`
|
|
3840
|
-
: ` Commit: ${shortCommit}`,
|
|
3855
|
+
? ` │ Commit: ${shortCommit} → ${commitUrl}`
|
|
3856
|
+
: ` │ Commit: ${shortCommit}`,
|
|
3857
|
+
` └─`,
|
|
3841
3858
|
'',
|
|
3842
3859
|
];
|
|
3843
3860
|
console.log(lines.join('\n'));
|