testdriverai 7.2.9 → 7.2.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/.github/workflows/testdriver.yml +127 -0
- package/.testdriver/last-sandbox +7 -0
- package/agent/events.js +1 -0
- package/agent/index.js +71 -54
- package/agent/lib/sandbox.js +11 -1
- package/agents.md +393 -0
- package/debug/01-table-initial.png +0 -0
- package/debug/02-after-ai-explore.png +0 -0
- package/debug/02-after-scroll.png +0 -0
- package/docs/docs.json +93 -125
- package/docs/v7/_drafts/caching.mdx +2 -2
- package/docs/v7/{getting-started → _drafts}/installation.mdx +0 -66
- package/docs/v7/{features/coverage.mdx → _drafts/powerful.mdx} +1 -90
- package/docs/v7/{features → _drafts}/scalable.mdx +126 -4
- package/docs/v7/_drafts/screenshot.mdx +155 -0
- package/docs/v7/_drafts/writing-tests.mdx +25 -0
- package/docs/v7/{api/act.mdx → ai.mdx} +27 -27
- package/docs/v7/{api/assert.mdx → assert.mdx} +3 -3
- package/docs/v7/aws-setup.mdx +338 -0
- package/docs/v7/caching.mdx +128 -0
- package/docs/v7/ci-cd.mdx +605 -0
- package/docs/v7/{api/click.mdx → click.mdx} +4 -4
- package/docs/v7/cloud.mdx +120 -0
- package/docs/v7/customizing-devices.mdx +129 -0
- package/docs/v7/{api/doubleClick.mdx → double-click.mdx} +5 -5
- package/docs/v7/enterprise.mdx +135 -0
- package/docs/v7/examples.mdx +5 -0
- package/docs/v7/{api/exec.mdx → exec.mdx} +3 -3
- package/docs/v7/{api/find.mdx → find.mdx} +17 -21
- package/docs/v7/{api/focusApplication.mdx → focus-application.mdx} +3 -3
- package/docs/v7/generating-tests.mdx +32 -0
- package/docs/v7/{api/hover.mdx → hover.mdx} +3 -3
- package/docs/v7/locating-elements.mdx +71 -0
- package/docs/v7/making-assertions.mdx +32 -0
- package/docs/v7/{api/mouseDown.mdx → mouse-down.mdx} +7 -7
- package/docs/v7/{api/mouseUp.mdx → mouse-up.mdx} +8 -8
- package/docs/v7/performing-actions.mdx +51 -0
- package/docs/v7/{api/pressKeys.mdx → press-keys.mdx} +3 -3
- package/docs/v7/quickstart.mdx +162 -0
- package/docs/v7/reusable-code.mdx +240 -0
- package/docs/v7/{api/rightClick.mdx → right-click.mdx} +5 -5
- package/docs/v7/running-tests.mdx +181 -0
- package/docs/v7/{api/scroll.mdx → scroll.mdx} +3 -3
- package/docs/v7/secrets.mdx +115 -0
- package/docs/v7/self-hosted.mdx +66 -0
- package/docs/v7/{api/type.mdx → type.mdx} +3 -3
- package/docs/v7/variables.mdx +111 -0
- package/docs/v7/waiting-for-elements.mdx +66 -0
- package/docs/v7/what-is-testdriver.mdx +54 -0
- package/lib/vitest/hooks.mjs +80 -68
- package/package.json +1 -1
- package/sdk.d.ts +22 -9
- package/sdk.js +177 -44
- package/test/manual/reconnect-provision.test.mjs +49 -0
- package/test/manual/reconnect-signin.test.mjs +41 -0
- package/test/testdriver/ai.test.mjs +30 -0
- package/test/testdriver/setup/testHelpers.mjs +0 -1
- package/test/testdriver/windows-installer.test.mjs +61 -0
- package/tests/table-sort-enrollments.test.mjs +72 -0
- package/tests/table-sort-experiment.test.mjs +42 -0
- package/tests/table-sort-setup.test.mjs +59 -0
- package/vitest.config.mjs +1 -0
- package/docs/v7/api/assertions.mdx +0 -403
- package/docs/v7/features/ai-native.mdx +0 -413
- package/docs/v7/features/application-logs.mdx +0 -353
- package/docs/v7/features/browser-logs.mdx +0 -414
- package/docs/v7/features/cache-management.mdx +0 -402
- package/docs/v7/features/continuous-testing.mdx +0 -346
- package/docs/v7/features/data-driven-testing.mdx +0 -441
- package/docs/v7/features/easy-to-write.mdx +0 -280
- package/docs/v7/features/enterprise.mdx +0 -656
- package/docs/v7/features/fast.mdx +0 -406
- package/docs/v7/features/managed-sandboxes.mdx +0 -384
- package/docs/v7/features/network-monitoring.mdx +0 -568
- package/docs/v7/features/parallel-execution.mdx +0 -381
- package/docs/v7/features/powerful.mdx +0 -531
- package/docs/v7/features/sandbox-customization.mdx +0 -229
- package/docs/v7/features/stable.mdx +0 -473
- package/docs/v7/features/system-performance.mdx +0 -616
- package/docs/v7/features/test-analytics.mdx +0 -373
- package/docs/v7/features/test-cases.mdx +0 -393
- package/docs/v7/features/test-replays.mdx +0 -408
- package/docs/v7/features/test-reports.mdx +0 -308
- package/docs/v7/getting-started/debugging-tests.mdx +0 -382
- package/docs/v7/getting-started/quickstart.mdx +0 -90
- package/docs/v7/getting-started/running-tests.mdx +0 -173
- package/docs/v7/getting-started/setting-up-in-ci.mdx +0 -612
- package/docs/v7/getting-started/writing-tests.mdx +0 -534
- package/docs/v7/overview/what-is-testdriver.mdx +0 -386
- package/docs/v7/presets/chrome-extension.mdx +0 -248
- package/docs/v7/presets/chrome.mdx +0 -300
- package/docs/v7/presets/electron.mdx +0 -460
- package/docs/v7/presets/vscode.mdx +0 -417
- package/docs/v7/presets/webapp.mdx +0 -393
- package/vitest.config.js +0 -18
- /package/docs/v7/{commands → _drafts/commands}/assert.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/exec.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/focus-application.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/if.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/match-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/press-keys.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/remember.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/run.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/type.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait.mdx +0 -0
- /package/docs/v7/{getting-started → _drafts}/configuration.mdx +0 -0
- /package/docs/v7/{features → _drafts}/observable.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/linux.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/macos.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/windows.mdx +0 -0
- /package/docs/v7/{playwright.mdx → _drafts/playwright.mdx} +0 -0
- /package/docs/v7/{overview → _drafts}/readme.mdx +0 -0
- /package/docs/v7/{features → _drafts}/reports.mdx +0 -0
- /package/docs/v7/{api/client.mdx → client.mdx} +0 -0
- /package/docs/v7/{api/dashcam.mdx → dashcam.mdx} +0 -0
- /package/docs/v7/{api/elements.mdx → elements.mdx} +0 -0
- /package/docs/v7/{api/sandbox.mdx → sandbox.mdx} +0 -0
|
@@ -34,3 +34,130 @@ jobs:
|
|
|
34
34
|
name: test-results
|
|
35
35
|
path: test-results/
|
|
36
36
|
retention-days: 30
|
|
37
|
+
|
|
38
|
+
# Init command test - only runs on PRs, not on main/master
|
|
39
|
+
- name: Create test directory for init
|
|
40
|
+
if: github.event_name == 'pull_request'
|
|
41
|
+
run: |
|
|
42
|
+
mkdir -p /tmp/test-init-project
|
|
43
|
+
cd /tmp/test-init-project
|
|
44
|
+
|
|
45
|
+
- name: Run init command (skip prompts)
|
|
46
|
+
if: github.event_name == 'pull_request'
|
|
47
|
+
working-directory: /tmp/test-init-project
|
|
48
|
+
run: |
|
|
49
|
+
# Create .env with API key first to skip the prompt
|
|
50
|
+
echo "TD_API_KEY=${{ secrets.TD_API_KEY }}" > .env
|
|
51
|
+
|
|
52
|
+
# Run init command using the CLI from the repo
|
|
53
|
+
node ${{ github.workspace }}/bin/testdriverai.js init
|
|
54
|
+
env:
|
|
55
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
56
|
+
|
|
57
|
+
- name: Verify project structure
|
|
58
|
+
if: github.event_name == 'pull_request'
|
|
59
|
+
working-directory: /tmp/test-init-project
|
|
60
|
+
run: |
|
|
61
|
+
echo "Checking generated files..."
|
|
62
|
+
|
|
63
|
+
# Check for package.json
|
|
64
|
+
if [ ! -f "package.json" ]; then
|
|
65
|
+
echo "❌ package.json not found"
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
echo "✓ package.json exists"
|
|
69
|
+
|
|
70
|
+
# Check for vitest config
|
|
71
|
+
if [ ! -f "vitest.config.js" ]; then
|
|
72
|
+
echo "❌ vitest.config.js not found"
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
echo "✓ vitest.config.js exists"
|
|
76
|
+
|
|
77
|
+
# Check for test file
|
|
78
|
+
if [ ! -f "tests/example.test.js" ]; then
|
|
79
|
+
echo "❌ tests/example.test.js not found"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
echo "✓ tests/example.test.js exists"
|
|
83
|
+
|
|
84
|
+
# Check for .env file
|
|
85
|
+
if [ ! -f ".env" ]; then
|
|
86
|
+
echo "❌ .env not found"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
echo "✓ .env exists"
|
|
90
|
+
|
|
91
|
+
# Check for .gitignore
|
|
92
|
+
if [ ! -f ".gitignore" ]; then
|
|
93
|
+
echo "❌ .gitignore not found"
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
echo "✓ .gitignore exists"
|
|
97
|
+
|
|
98
|
+
# Check for GitHub workflow
|
|
99
|
+
if [ ! -f ".github/workflows/testdriver.yml" ]; then
|
|
100
|
+
echo "❌ .github/workflows/testdriver.yml not found"
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
echo "✓ .github/workflows/testdriver.yml exists"
|
|
104
|
+
|
|
105
|
+
- name: Verify vitest config contents
|
|
106
|
+
if: github.event_name == 'pull_request'
|
|
107
|
+
working-directory: /tmp/test-init-project
|
|
108
|
+
run: |
|
|
109
|
+
echo "Checking vitest.config.js contents..."
|
|
110
|
+
|
|
111
|
+
# Check for TestDriver reporter
|
|
112
|
+
if ! grep -q "TestDriver()" vitest.config.js; then
|
|
113
|
+
echo "❌ TestDriver reporter not found in vitest.config.js"
|
|
114
|
+
cat vitest.config.js
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
echo "✓ TestDriver reporter is configured"
|
|
118
|
+
|
|
119
|
+
# Check for setupFiles
|
|
120
|
+
if ! grep -q "setupFiles.*testdriverai/vitest/setup" vitest.config.js; then
|
|
121
|
+
echo "❌ setupFiles not configured correctly"
|
|
122
|
+
cat vitest.config.js
|
|
123
|
+
exit 1
|
|
124
|
+
fi
|
|
125
|
+
echo "✓ setupFiles is configured"
|
|
126
|
+
|
|
127
|
+
- name: Verify test file contents
|
|
128
|
+
if: github.event_name == 'pull_request'
|
|
129
|
+
working-directory: /tmp/test-init-project
|
|
130
|
+
run: |
|
|
131
|
+
echo "Checking test file contents..."
|
|
132
|
+
|
|
133
|
+
# Check for .provision usage
|
|
134
|
+
if ! grep -q "\.provision\.chrome" tests/example.test.js; then
|
|
135
|
+
echo "❌ Test does not use .provision.chrome"
|
|
136
|
+
cat tests/example.test.js
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
echo "✓ Test uses .provision.chrome"
|
|
140
|
+
|
|
141
|
+
# Check for TestDriver import
|
|
142
|
+
if ! grep -q "from 'testdriverai/vitest/hooks'" tests/example.test.js; then
|
|
143
|
+
echo "❌ Test does not import from testdriverai/vitest/hooks"
|
|
144
|
+
cat tests/example.test.js
|
|
145
|
+
exit 1
|
|
146
|
+
fi
|
|
147
|
+
echo "✓ Test imports TestDriver from vitest/hooks"
|
|
148
|
+
|
|
149
|
+
- name: Run the generated test
|
|
150
|
+
if: github.event_name == 'pull_request'
|
|
151
|
+
working-directory: /tmp/test-init-project
|
|
152
|
+
run: npm test
|
|
153
|
+
env:
|
|
154
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
155
|
+
|
|
156
|
+
- name: Upload init test results
|
|
157
|
+
if: always() && github.event_name == 'pull_request'
|
|
158
|
+
uses: actions/upload-artifact@v4
|
|
159
|
+
with:
|
|
160
|
+
name: test-init-results
|
|
161
|
+
path: /tmp/test-init-project/test-results/
|
|
162
|
+
retention-days: 7
|
|
163
|
+
if-no-files-found: warn
|
package/agent/events.js
CHANGED
package/agent/index.js
CHANGED
|
@@ -1619,49 +1619,35 @@ ${regression}
|
|
|
1619
1619
|
this.emitter.emit(events.log.log, `${inputFile} (end)`);
|
|
1620
1620
|
}
|
|
1621
1621
|
|
|
1622
|
-
// Returns
|
|
1623
|
-
|
|
1624
|
-
const
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1622
|
+
// Returns the path to the last sandbox file
|
|
1623
|
+
getLastSandboxFilePath() {
|
|
1624
|
+
const testdriverDir = path.join(process.cwd(), '.testdriver');
|
|
1625
|
+
return path.join(testdriverDir, 'last-sandbox');
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// Returns full sandbox info from last-sandbox file (no timeout - let API validate)
|
|
1629
|
+
getLastSandboxId() {
|
|
1630
|
+
const lastSandboxFile = this.getLastSandboxFilePath();
|
|
1628
1631
|
|
|
1629
1632
|
if (fs.existsSync(lastSandboxFile)) {
|
|
1630
1633
|
try {
|
|
1631
|
-
const
|
|
1632
|
-
const mtime = new Date(stats.mtime);
|
|
1633
|
-
const now = new Date();
|
|
1634
|
-
const diffMinutes = (now - mtime) / (1000 * 60);
|
|
1635
|
-
if (diffMinutes < 10) {
|
|
1636
|
-
const fileContent = fs.readFileSync(lastSandboxFile, "utf-8").trim();
|
|
1637
|
-
|
|
1638
|
-
// Parse sandbox info (supports both old format and new format)
|
|
1639
|
-
let sandboxInfo;
|
|
1640
|
-
try {
|
|
1641
|
-
sandboxInfo = JSON.parse(fileContent);
|
|
1642
|
-
} catch {
|
|
1643
|
-
return fileContent || null;
|
|
1644
|
-
}
|
|
1634
|
+
const fileContent = fs.readFileSync(lastSandboxFile, "utf-8").trim();
|
|
1645
1635
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
if (currentAmi === storedAmi && currentInstance === storedInstance) {
|
|
1653
|
-
// Return sandboxId (new format) or instanceId (old format for backwards compatibility)
|
|
1654
|
-
return sandboxInfo.sandboxId || sandboxInfo.instanceId;
|
|
1655
|
-
} else {
|
|
1656
|
-
this.emitter.emit(
|
|
1657
|
-
events.log.log,
|
|
1658
|
-
theme.dim(
|
|
1659
|
-
"Recent sandbox found but AMI/instance type doesn't match current requirements",
|
|
1660
|
-
),
|
|
1661
|
-
);
|
|
1662
|
-
return null;
|
|
1663
|
-
}
|
|
1636
|
+
// Parse sandbox info (supports both old format and new format)
|
|
1637
|
+
let sandboxInfo;
|
|
1638
|
+
try {
|
|
1639
|
+
sandboxInfo = JSON.parse(fileContent);
|
|
1640
|
+
} catch {
|
|
1641
|
+
return { sandboxId: fileContent || null };
|
|
1664
1642
|
}
|
|
1643
|
+
|
|
1644
|
+
return {
|
|
1645
|
+
sandboxId: sandboxInfo.sandboxId || sandboxInfo.instanceId || null,
|
|
1646
|
+
os: sandboxInfo.os || 'linux',
|
|
1647
|
+
ami: sandboxInfo.ami || null,
|
|
1648
|
+
instanceType: sandboxInfo.instanceType || null,
|
|
1649
|
+
timestamp: sandboxInfo.timestamp || null,
|
|
1650
|
+
};
|
|
1665
1651
|
} catch {
|
|
1666
1652
|
// ignore errors
|
|
1667
1653
|
}
|
|
@@ -1669,12 +1655,43 @@ ${regression}
|
|
|
1669
1655
|
return null;
|
|
1670
1656
|
}
|
|
1671
1657
|
|
|
1658
|
+
// Returns sandboxId to use if AMI/instance type match current requirements
|
|
1659
|
+
getRecentSandboxId() {
|
|
1660
|
+
const sandboxInfo = this.getLastSandboxId();
|
|
1661
|
+
|
|
1662
|
+
if (!sandboxInfo || !sandboxInfo.sandboxId) {
|
|
1663
|
+
return null;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
// Check if AMI and instance type match current requirements
|
|
1667
|
+
const currentAmi = this.sandboxAmi || null;
|
|
1668
|
+
const currentInstance = this.sandboxInstance || null;
|
|
1669
|
+
const storedAmi = sandboxInfo.ami || null;
|
|
1670
|
+
const storedInstance = sandboxInfo.instanceType || null;
|
|
1671
|
+
|
|
1672
|
+
if (currentAmi === storedAmi && currentInstance === storedInstance) {
|
|
1673
|
+
return sandboxInfo.sandboxId;
|
|
1674
|
+
} else {
|
|
1675
|
+
this.emitter.emit(
|
|
1676
|
+
events.log.log,
|
|
1677
|
+
theme.dim(
|
|
1678
|
+
"Recent sandbox found but AMI/instance type doesn't match current requirements",
|
|
1679
|
+
),
|
|
1680
|
+
);
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1672
1685
|
saveLastSandboxId(sandboxId, osType = "linux") {
|
|
1673
|
-
const lastSandboxFile =
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
);
|
|
1686
|
+
const lastSandboxFile = this.getLastSandboxFilePath();
|
|
1687
|
+
const testdriverDir = path.dirname(lastSandboxFile);
|
|
1688
|
+
|
|
1677
1689
|
try {
|
|
1690
|
+
// Ensure .testdriver directory exists
|
|
1691
|
+
if (!fs.existsSync(testdriverDir)) {
|
|
1692
|
+
fs.mkdirSync(testdriverDir, { recursive: true });
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1678
1695
|
const sandboxInfo = {
|
|
1679
1696
|
sandboxId: sandboxId,
|
|
1680
1697
|
os: osType,
|
|
@@ -1682,7 +1699,7 @@ ${regression}
|
|
|
1682
1699
|
instanceType: this.sandboxInstance || null,
|
|
1683
1700
|
timestamp: new Date().toISOString(),
|
|
1684
1701
|
};
|
|
1685
|
-
fs.writeFileSync(lastSandboxFile, JSON.stringify(sandboxInfo), {
|
|
1702
|
+
fs.writeFileSync(lastSandboxFile, JSON.stringify(sandboxInfo, null, 2), {
|
|
1686
1703
|
encoding: "utf-8",
|
|
1687
1704
|
});
|
|
1688
1705
|
} catch {
|
|
@@ -1691,10 +1708,7 @@ ${regression}
|
|
|
1691
1708
|
}
|
|
1692
1709
|
|
|
1693
1710
|
clearRecentSandboxId() {
|
|
1694
|
-
const lastSandboxFile =
|
|
1695
|
-
os.homedir(),
|
|
1696
|
-
".testdriverai-last-sandbox",
|
|
1697
|
-
);
|
|
1711
|
+
const lastSandboxFile = this.getLastSandboxFilePath();
|
|
1698
1712
|
try {
|
|
1699
1713
|
if (fs.existsSync(lastSandboxFile)) {
|
|
1700
1714
|
fs.unlinkSync(lastSandboxFile);
|
|
@@ -1703,6 +1717,7 @@ ${regression}
|
|
|
1703
1717
|
// ignore errors
|
|
1704
1718
|
}
|
|
1705
1719
|
}
|
|
1720
|
+
|
|
1706
1721
|
async buildEnv(options = {}) {
|
|
1707
1722
|
// If instance already exists, do not build environment again
|
|
1708
1723
|
if (this.instance) {
|
|
@@ -1785,6 +1800,7 @@ ${regression}
|
|
|
1785
1800
|
let instance = await this.connectToSandboxDirect(
|
|
1786
1801
|
this.sandboxId,
|
|
1787
1802
|
true, // always persist by default
|
|
1803
|
+
this.keepAlive, // pass keepAlive TTL
|
|
1788
1804
|
);
|
|
1789
1805
|
|
|
1790
1806
|
this.instance = instance;
|
|
@@ -1799,11 +1815,6 @@ ${regression}
|
|
|
1799
1815
|
);
|
|
1800
1816
|
console.error("Failed to reconnect to sandbox:", error);
|
|
1801
1817
|
}
|
|
1802
|
-
} else if (!createNew && !recentId) {
|
|
1803
|
-
this.emitter.emit(
|
|
1804
|
-
events.log.narration,
|
|
1805
|
-
theme.dim(`no recent sandbox found, creating a new one.`),
|
|
1806
|
-
);
|
|
1807
1818
|
} else if (!createNew && this.sandboxId && !this.config.CI) {
|
|
1808
1819
|
// Only attempt to connect to existing sandbox if not in CI mode and not creating new
|
|
1809
1820
|
// Attempt to connect to known instance
|
|
@@ -1816,6 +1827,7 @@ ${regression}
|
|
|
1816
1827
|
let instance = await this.connectToSandboxDirect(
|
|
1817
1828
|
this.sandboxId,
|
|
1818
1829
|
true, // always persist by default
|
|
1830
|
+
this.keepAlive, // pass keepAlive TTL
|
|
1819
1831
|
);
|
|
1820
1832
|
|
|
1821
1833
|
this.instance = instance;
|
|
@@ -1858,6 +1870,7 @@ ${regression}
|
|
|
1858
1870
|
let instance = await this.connectToSandboxDirect(
|
|
1859
1871
|
this.sandboxId,
|
|
1860
1872
|
true, // always persist by default
|
|
1873
|
+
this.keepAlive, // pass keepAlive TTL
|
|
1861
1874
|
);
|
|
1862
1875
|
this.instance = instance;
|
|
1863
1876
|
await this.renderSandbox(instance, headless);
|
|
@@ -2047,10 +2060,10 @@ Please check your network connection, TD_API_KEY, or the service status.`,
|
|
|
2047
2060
|
}
|
|
2048
2061
|
}
|
|
2049
2062
|
|
|
2050
|
-
async connectToSandboxDirect(sandboxId, persist = false) {
|
|
2063
|
+
async connectToSandboxDirect(sandboxId, persist = false, keepAlive = null) {
|
|
2051
2064
|
const { formatter } = require("../sdk-log-formatter.js");
|
|
2052
2065
|
this.emitter.emit(events.log.narration, formatter.getPrefix("connect") + " " + theme.green.bold("Connecting") + " " + theme.cyan(`to sandbox...`));
|
|
2053
|
-
let reply = await this.sandbox.connect(sandboxId, persist);
|
|
2066
|
+
let reply = await this.sandbox.connect(sandboxId, persist, keepAlive);
|
|
2054
2067
|
|
|
2055
2068
|
// reply includes { success, url, sandbox: {...} }
|
|
2056
2069
|
// For renderSandbox, we need the sandbox object with url merged in
|
|
@@ -2079,6 +2092,10 @@ Please check your network connection, TD_API_KEY, or the service status.`,
|
|
|
2079
2092
|
if (this.sandboxInstance) {
|
|
2080
2093
|
sandboxConfig.instanceType = this.sandboxInstance;
|
|
2081
2094
|
}
|
|
2095
|
+
// Add keepAlive TTL if specified
|
|
2096
|
+
if (this.keepAlive !== undefined && this.keepAlive !== null) {
|
|
2097
|
+
sandboxConfig.keepAlive = this.keepAlive;
|
|
2098
|
+
}
|
|
2082
2099
|
|
|
2083
2100
|
let instance = await this.sandbox.send(sandboxConfig, 60000 * 8);
|
|
2084
2101
|
|
package/agent/lib/sandbox.js
CHANGED
|
@@ -155,11 +155,12 @@ const createSandbox = (emitter, analytics, sessionInstance) => {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
async connect(sandboxId, persist = false) {
|
|
158
|
+
async connect(sandboxId, persist = false, keepAlive = null) {
|
|
159
159
|
let reply = await this.send({
|
|
160
160
|
type: "connect",
|
|
161
161
|
persist,
|
|
162
162
|
sandboxId,
|
|
163
|
+
keepAlive,
|
|
163
164
|
});
|
|
164
165
|
|
|
165
166
|
if (reply.success) {
|
|
@@ -227,6 +228,15 @@ const createSandbox = (emitter, analytics, sessionInstance) => {
|
|
|
227
228
|
this.socket.on("message", async (raw) => {
|
|
228
229
|
let message = JSON.parse(raw);
|
|
229
230
|
|
|
231
|
+
// Handle progress messages (no requestId needed)
|
|
232
|
+
if (message.type === 'sandbox.progress') {
|
|
233
|
+
emitter.emit(events.sandbox.progress, {
|
|
234
|
+
step: message.step,
|
|
235
|
+
message: message.message,
|
|
236
|
+
});
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
230
240
|
if (!this.ps[message.requestId]) {
|
|
231
241
|
console.warn(
|
|
232
242
|
"No pending promise found for requestId:",
|