@flrande/browserctl 0.1.0

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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README-CN.md +1155 -0
  3. package/README.md +1155 -0
  4. package/apps/browserctl/src/commands/a11y-snapshot.ts +20 -0
  5. package/apps/browserctl/src/commands/act.ts +20 -0
  6. package/apps/browserctl/src/commands/common.test.ts +87 -0
  7. package/apps/browserctl/src/commands/common.ts +191 -0
  8. package/apps/browserctl/src/commands/console-list.ts +20 -0
  9. package/apps/browserctl/src/commands/cookie-clear.ts +18 -0
  10. package/apps/browserctl/src/commands/cookie-get.ts +18 -0
  11. package/apps/browserctl/src/commands/cookie-set.ts +22 -0
  12. package/apps/browserctl/src/commands/dialog-arm.ts +20 -0
  13. package/apps/browserctl/src/commands/dom-query-all.ts +18 -0
  14. package/apps/browserctl/src/commands/dom-query.ts +18 -0
  15. package/apps/browserctl/src/commands/download-trigger.ts +22 -0
  16. package/apps/browserctl/src/commands/download-wait.test.ts +67 -0
  17. package/apps/browserctl/src/commands/download-wait.ts +27 -0
  18. package/apps/browserctl/src/commands/element-screenshot.ts +20 -0
  19. package/apps/browserctl/src/commands/frame-list.ts +16 -0
  20. package/apps/browserctl/src/commands/frame-snapshot.ts +18 -0
  21. package/apps/browserctl/src/commands/network-wait-for.ts +100 -0
  22. package/apps/browserctl/src/commands/profile-list.ts +16 -0
  23. package/apps/browserctl/src/commands/profile-use.ts +18 -0
  24. package/apps/browserctl/src/commands/response-body.ts +24 -0
  25. package/apps/browserctl/src/commands/screenshot.ts +16 -0
  26. package/apps/browserctl/src/commands/snapshot.ts +16 -0
  27. package/apps/browserctl/src/commands/status.ts +10 -0
  28. package/apps/browserctl/src/commands/storage-get.ts +20 -0
  29. package/apps/browserctl/src/commands/storage-set.ts +22 -0
  30. package/apps/browserctl/src/commands/tab-close.ts +20 -0
  31. package/apps/browserctl/src/commands/tab-focus.ts +20 -0
  32. package/apps/browserctl/src/commands/tab-open.ts +19 -0
  33. package/apps/browserctl/src/commands/tabs.ts +13 -0
  34. package/apps/browserctl/src/commands/upload-arm.ts +26 -0
  35. package/apps/browserctl/src/daemon-client.test.ts +253 -0
  36. package/apps/browserctl/src/daemon-client.ts +632 -0
  37. package/apps/browserctl/src/e2e.test.ts +99 -0
  38. package/apps/browserctl/src/main.test.ts +215 -0
  39. package/apps/browserctl/src/main.ts +372 -0
  40. package/apps/browserctl/src/smoke.test.ts +16 -0
  41. package/apps/browserctl/src/smoke.ts +5 -0
  42. package/apps/browserd/src/bootstrap.ts +432 -0
  43. package/apps/browserd/src/chrome-relay-extension-bridge.test.ts +275 -0
  44. package/apps/browserd/src/chrome-relay-extension-bridge.ts +506 -0
  45. package/apps/browserd/src/container.ts +1531 -0
  46. package/apps/browserd/src/main.test.ts +864 -0
  47. package/apps/browserd/src/main.ts +7 -0
  48. package/bin/browserctl.cjs +21 -0
  49. package/bin/browserd.cjs +21 -0
  50. package/extensions/chrome-relay/README.md +36 -0
  51. package/extensions/chrome-relay/background.js +1687 -0
  52. package/extensions/chrome-relay/manifest.json +15 -0
  53. package/extensions/chrome-relay/popup.html +369 -0
  54. package/extensions/chrome-relay/popup.js +972 -0
  55. package/package.json +51 -0
  56. package/packages/core/src/bootstrap.test.ts +10 -0
  57. package/packages/core/src/driver-registry.test.ts +45 -0
  58. package/packages/core/src/driver-registry.ts +22 -0
  59. package/packages/core/src/driver.ts +47 -0
  60. package/packages/core/src/index.ts +5 -0
  61. package/packages/core/src/ref-cache.test.ts +61 -0
  62. package/packages/core/src/ref-cache.ts +28 -0
  63. package/packages/core/src/session-store.test.ts +49 -0
  64. package/packages/core/src/session-store.ts +33 -0
  65. package/packages/core/src/types.ts +9 -0
  66. package/packages/driver-chrome-relay/src/chrome-relay-driver.test.ts +634 -0
  67. package/packages/driver-chrome-relay/src/chrome-relay-driver.ts +2206 -0
  68. package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.test.ts +264 -0
  69. package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.ts +521 -0
  70. package/packages/driver-chrome-relay/src/index.ts +26 -0
  71. package/packages/driver-managed/src/index.ts +22 -0
  72. package/packages/driver-managed/src/managed-driver.test.ts +59 -0
  73. package/packages/driver-managed/src/managed-driver.ts +125 -0
  74. package/packages/driver-managed/src/managed-local-driver.test.ts +506 -0
  75. package/packages/driver-managed/src/managed-local-driver.ts +2021 -0
  76. package/packages/driver-remote-cdp/src/index.ts +19 -0
  77. package/packages/driver-remote-cdp/src/remote-cdp-driver.test.ts +617 -0
  78. package/packages/driver-remote-cdp/src/remote-cdp-driver.ts +2042 -0
  79. package/packages/protocol/src/envelope.test.ts +25 -0
  80. package/packages/protocol/src/envelope.ts +31 -0
  81. package/packages/protocol/src/errors.test.ts +17 -0
  82. package/packages/protocol/src/errors.ts +11 -0
  83. package/packages/protocol/src/index.ts +3 -0
  84. package/packages/protocol/src/tools.ts +3 -0
  85. package/packages/transport-mcp-stdio/src/index.ts +3 -0
  86. package/packages/transport-mcp-stdio/src/sdk-server.ts +139 -0
  87. package/packages/transport-mcp-stdio/src/server.test.ts +281 -0
  88. package/packages/transport-mcp-stdio/src/server.ts +183 -0
  89. package/packages/transport-mcp-stdio/src/tool-map.ts +67 -0
  90. package/scripts/smoke.ps1 +127 -0
@@ -0,0 +1,67 @@
1
+ import { ErrorCode, createErr, createOk, type ToolResponse } from "../../protocol/src/index";
2
+
3
+ export type ToolCallArgs = {
4
+ sessionId: string;
5
+ profile?: string;
6
+ targetId?: string;
7
+ timeoutMs?: number;
8
+ [key: string]: unknown;
9
+ };
10
+
11
+ export type ToolHandler<TData = Record<string, unknown>> = (
12
+ args: ToolCallArgs
13
+ ) => Promise<ToolResponse<TData>> | ToolResponse<TData>;
14
+
15
+ export type ToolMap = Map<string, ToolHandler>;
16
+
17
+ export const V1_TOOL_NAMES = [
18
+ "browser.status",
19
+ "browser.profile.list",
20
+ "browser.profile.use",
21
+ "browser.tab.list",
22
+ "browser.tab.open",
23
+ "browser.tab.focus",
24
+ "browser.tab.close",
25
+ "browser.snapshot",
26
+ "browser.screenshot",
27
+ "browser.dom.query",
28
+ "browser.dom.queryAll",
29
+ "browser.element.screenshot",
30
+ "browser.a11y.snapshot",
31
+ "browser.act",
32
+ "browser.upload.arm",
33
+ "browser.dialog.arm",
34
+ "browser.download.wait",
35
+ "browser.download.trigger",
36
+ "browser.network.waitFor",
37
+ "browser.cookie.get",
38
+ "browser.cookie.set",
39
+ "browser.cookie.clear",
40
+ "browser.storage.get",
41
+ "browser.storage.set",
42
+ "browser.frame.list",
43
+ "browser.frame.snapshot",
44
+ "browser.console.list",
45
+ "browser.network.responseBody"
46
+ ] as const;
47
+
48
+ const browserStatusHandler: ToolHandler<{ kind: "stdio"; ready: true }> = async () =>
49
+ createOk({
50
+ kind: "stdio",
51
+ ready: true
52
+ });
53
+
54
+ function createNotImplementedHandler(toolName: string): ToolHandler {
55
+ return async () => createErr(ErrorCode.E_DRIVER_UNAVAILABLE, `Tool is not implemented: ${toolName}`);
56
+ }
57
+
58
+ export function buildToolMap(): ToolMap {
59
+ const map: ToolMap = new Map();
60
+
61
+ for (const toolName of V1_TOOL_NAMES) {
62
+ map.set(toolName, createNotImplementedHandler(toolName));
63
+ }
64
+
65
+ map.set("browser.status", browserStatusHandler);
66
+ return map;
67
+ }
@@ -0,0 +1,127 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version Latest
3
+
4
+ $scriptDir = Split-Path -Parent $PSCommandPath
5
+ $repoRoot = Resolve-Path -LiteralPath (Join-Path $scriptDir '..')
6
+ $browserdEntry = Join-Path $repoRoot 'apps/browserd/src/main.ts'
7
+ $browserctlEntry = Join-Path $repoRoot 'apps/browserctl/src/main.ts'
8
+
9
+ $daemonProcess = $null
10
+ $daemonPort = 41337
11
+ $timeoutMs = 10000
12
+ $pollIntervalMs = 250
13
+ $pnpmExecutable = if ($IsWindows) { 'pnpm.cmd' } else { 'pnpm' }
14
+
15
+ function Invoke-SmokeStatus {
16
+ param(
17
+ [Parameter(Mandatory = $true)]
18
+ [string]$BrowserctlEntry
19
+ )
20
+
21
+ $previousPort = $env:BROWSERCTL_DAEMON_PORT
22
+ $env:BROWSERCTL_DAEMON_PORT = "$daemonPort"
23
+
24
+ $statusOutput = & pnpm exec tsx $BrowserctlEntry status --json 2>&1
25
+ $exitCode = $LASTEXITCODE
26
+ $statusText = [string]::Join([Environment]::NewLine, @($statusOutput))
27
+
28
+ if ($null -eq $previousPort) {
29
+ Remove-Item Env:\BROWSERCTL_DAEMON_PORT -ErrorAction SilentlyContinue
30
+ } else {
31
+ $env:BROWSERCTL_DAEMON_PORT = $previousPort
32
+ }
33
+
34
+ if ($exitCode -ne 0) {
35
+ return @{
36
+ Ok = $false
37
+ Reason = "browserctl status exited with code $exitCode. Output: $statusText"
38
+ }
39
+ }
40
+
41
+ $statusPayload = $null
42
+ try {
43
+ $statusPayload = $statusText | ConvertFrom-Json -ErrorAction Stop
44
+ } catch {
45
+ return @{
46
+ Ok = $false
47
+ Reason = "browserctl status returned invalid JSON. Output: $statusText"
48
+ }
49
+ }
50
+
51
+ if (-not $statusPayload.ok) {
52
+ return @{
53
+ Ok = $false
54
+ Reason = 'browserctl status returned ok=false.'
55
+ }
56
+ }
57
+
58
+ $errorProperty = $statusPayload.PSObject.Properties['error']
59
+ if ($null -ne $errorProperty -and $null -ne $errorProperty.Value) {
60
+ $errorJson = $errorProperty.Value | ConvertTo-Json -Compress
61
+ return @{
62
+ Ok = $false
63
+ Reason = "browserctl status returned error payload: $errorJson"
64
+ }
65
+ }
66
+
67
+ return @{
68
+ Ok = $true
69
+ Payload = $statusPayload
70
+ }
71
+ }
72
+
73
+ try {
74
+ $previousPort = $env:BROWSERCTL_DAEMON_PORT
75
+ $env:BROWSERCTL_DAEMON_PORT = "$daemonPort"
76
+ & pnpm exec tsx $browserctlEntry daemon-stop --json *> $null
77
+ if ($null -eq $previousPort) {
78
+ Remove-Item Env:\BROWSERCTL_DAEMON_PORT -ErrorAction SilentlyContinue
79
+ } else {
80
+ $env:BROWSERCTL_DAEMON_PORT = $previousPort
81
+ }
82
+
83
+ $daemonEnv = @{
84
+ BROWSERD_TRANSPORT = 'tcp'
85
+ BROWSERD_PORT = "$daemonPort"
86
+ }
87
+
88
+ $daemonProcess = Start-Process -FilePath $pnpmExecutable `
89
+ -ArgumentList @('exec', 'tsx', $browserdEntry) `
90
+ -WorkingDirectory $repoRoot `
91
+ -Environment $daemonEnv `
92
+ -PassThru
93
+
94
+ $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
95
+ $lastFailure = 'status probe did not run'
96
+ $statusResult = $null
97
+
98
+ while ($stopwatch.ElapsedMilliseconds -lt $timeoutMs) {
99
+ $statusResult = Invoke-SmokeStatus -BrowserctlEntry $browserctlEntry
100
+ if ($statusResult.Ok) {
101
+ break
102
+ }
103
+
104
+ $lastFailure = [string]$statusResult.Reason
105
+ Start-Sleep -Milliseconds $pollIntervalMs
106
+ }
107
+
108
+ if ($null -eq $statusResult -or -not $statusResult.Ok) {
109
+ $elapsedMs = [int]$stopwatch.ElapsedMilliseconds
110
+ throw "Smoke failed: browserctl status --json was not ready within ${timeoutMs}ms (elapsed ${elapsedMs}ms). Last failure: $lastFailure"
111
+ }
112
+
113
+ Write-Host 'Smoke passed: daemon started and browserctl status --json returned success.'
114
+ } finally {
115
+ if ($null -ne $daemonProcess -and -not $daemonProcess.HasExited) {
116
+ Stop-Process -Id $daemonProcess.Id -ErrorAction SilentlyContinue
117
+ }
118
+
119
+ $previousPort = $env:BROWSERCTL_DAEMON_PORT
120
+ $env:BROWSERCTL_DAEMON_PORT = "$daemonPort"
121
+ & pnpm exec tsx $browserctlEntry daemon-stop --json *> $null
122
+ if ($null -eq $previousPort) {
123
+ Remove-Item Env:\BROWSERCTL_DAEMON_PORT -ErrorAction SilentlyContinue
124
+ } else {
125
+ $env:BROWSERCTL_DAEMON_PORT = $previousPort
126
+ }
127
+ }