use-computer 0.0.20__tar.gz → 0.0.22__tar.gz

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 (60) hide show
  1. {use_computer-0.0.20 → use_computer-0.0.22}/PKG-INFO +1 -1
  2. use_computer-0.0.22/examples/go/hello_windows.go +35 -0
  3. use_computer-0.0.22/examples/javascript/hello_windows.ts +14 -0
  4. use_computer-0.0.22/go/README.md +46 -0
  5. use_computer-0.0.22/go/client.go +192 -0
  6. use_computer-0.0.22/go/go.mod +3 -0
  7. use_computer-0.0.22/go/sandbox.go +156 -0
  8. use_computer-0.0.22/javascript/.gitignore +3 -0
  9. use_computer-0.0.22/javascript/README.md +48 -0
  10. use_computer-0.0.22/javascript/package-lock.json +51 -0
  11. use_computer-0.0.22/javascript/package.json +27 -0
  12. use_computer-0.0.22/javascript/src/client.ts +82 -0
  13. use_computer-0.0.22/javascript/src/http.ts +96 -0
  14. use_computer-0.0.22/javascript/src/index.ts +11 -0
  15. use_computer-0.0.22/javascript/src/sandbox.ts +208 -0
  16. use_computer-0.0.22/javascript/tsconfig.json +16 -0
  17. {use_computer-0.0.20 → use_computer-0.0.22}/pyproject.toml +1 -1
  18. {use_computer-0.0.20 → use_computer-0.0.22}/.env.example +0 -0
  19. {use_computer-0.0.20 → use_computer-0.0.22}/.gitignore +0 -0
  20. {use_computer-0.0.20 → use_computer-0.0.22}/.pre-commit-config.yaml +0 -0
  21. {use_computer-0.0.20 → use_computer-0.0.22}/README.md +0 -0
  22. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_1_hello_macos.py +0 -0
  23. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_2_hello_ios.py +0 -0
  24. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_3_recording.py +0 -0
  25. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_4_file_transfer.py +0 -0
  26. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_5_keepalive.py +0 -0
  27. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_6_hello_tvos.py +0 -0
  28. {use_computer-0.0.20 → use_computer-0.0.22}/examples/_7_hello_windows.py +0 -0
  29. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/__init__.py +0 -0
  30. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/accessibility.py +0 -0
  31. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/ax_transpile.py +0 -0
  32. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/client.py +0 -0
  33. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/display.py +0 -0
  34. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/errors.py +0 -0
  35. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/ios/__init__.py +0 -0
  36. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/ios/apps.py +0 -0
  37. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/ios/environment.py +0 -0
  38. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/ios/input.py +0 -0
  39. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/macos/__init__.py +0 -0
  40. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/macos/keyboard.py +0 -0
  41. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/macos/mouse.py +0 -0
  42. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/models.py +0 -0
  43. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/parsers.py +0 -0
  44. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/py.typed +0 -0
  45. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/recording.py +0 -0
  46. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/retry.py +0 -0
  47. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/sandbox.py +0 -0
  48. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/screenshot.py +0 -0
  49. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/simulators.py +0 -0
  50. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/__init__.py +0 -0
  51. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/pre_command.sh +0 -0
  52. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/task.toml +0 -0
  53. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/test_ios.sh +0 -0
  54. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/test_ios_nograder.sh +0 -0
  55. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/test_macos.sh +0 -0
  56. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/test_macos_check.sh +0 -0
  57. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/tasks/templates/test_macos_nograder.sh +0 -0
  58. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/windows/__init__.py +0 -0
  59. {use_computer-0.0.20 → use_computer-0.0.22}/use_computer/windows/shell.py +0 -0
  60. {use_computer-0.0.20 → use_computer-0.0.22}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: use-computer
3
- Version: 0.0.20
3
+ Version: 0.0.22
4
4
  Summary: Python SDK for the use.computer macOS and iOS Computer Use API
5
5
  Project-URL: Homepage, https://use.computer
6
6
  Project-URL: Documentation, https://api.use.computer/docs
@@ -0,0 +1,35 @@
1
+ // Windows (Beta). Run:
2
+ // export USE_COMPUTER_API_KEY=...
3
+ // go run hello_windows.go
4
+ package main
5
+
6
+ import (
7
+ "context"
8
+ "fmt"
9
+ "os"
10
+
11
+ uc "github.com/josancamon19/use-computer-sdk/go"
12
+ )
13
+
14
+ func main() {
15
+ ctx := context.Background()
16
+ c := uc.New()
17
+
18
+ win, err := c.Create(ctx, uc.CreateOptions{Type: uc.Windows, Version: "windows-11"})
19
+ if err != nil {
20
+ panic(err)
21
+ }
22
+ defer win.Close(ctx)
23
+
24
+ name, _ := win.RunShell(ctx, "$env:COMPUTERNAME", "powershell")
25
+ fmt.Println("computer name:", name.Stdout)
26
+ win.RunShell(ctx, "Start-Process notepad", "powershell")
27
+ win.TypeText(ctx, "hello from use.computer")
28
+
29
+ png, err := win.Screenshot(ctx)
30
+ if err != nil {
31
+ panic(err)
32
+ }
33
+ os.WriteFile("hello_windows.png", png, 0o644)
34
+ fmt.Printf("saved hello_windows.png (%d bytes)\n", len(png))
35
+ }
@@ -0,0 +1,14 @@
1
+ // Windows (Beta) — run: USE_COMPUTER_API_KEY=... npx tsx hello_windows.ts
2
+ import { Computer } from "use-computer";
3
+
4
+ const computer = new Computer();
5
+ await using win = await computer.create({ type: "windows", version: "windows-11" });
6
+
7
+ console.log("computer name:", (await win.run("$env:COMPUTERNAME")).stdout.trim());
8
+ await win.run("Start-Process notepad");
9
+ await win.keyboard.type("hello from use.computer");
10
+
11
+ const png = await win.screenshot.takeFullScreen();
12
+ const { writeFile } = await import("node:fs/promises");
13
+ await writeFile("hello_windows.png", png);
14
+ console.log(`saved hello_windows.png (${png.length} bytes)`);
@@ -0,0 +1,46 @@
1
+ # use-computer — Go SDK
2
+
3
+ Go client for [use.computer](https://use.computer) — rent dedicated VMs (macOS, iOS/visionOS/tvOS simulators, **Windows**, **Ubuntu**) built for computer-use agents. Parity with the [Python](../python) and [TypeScript](../javascript) SDKs.
4
+
5
+ ```bash
6
+ go get github.com/josancamon19/use-computer-sdk/go@latest
7
+ export USE_COMPUTER_API_KEY=mk_live_...
8
+ ```
9
+
10
+ ```go
11
+ package main
12
+
13
+ import (
14
+ "context"
15
+ "fmt"
16
+
17
+ uc "github.com/josancamon19/use-computer-sdk/go"
18
+ )
19
+
20
+ func main() {
21
+ ctx := context.Background()
22
+ c := uc.New() // base URL + key from env, or uc.WithBaseURL/WithAPIKey
23
+
24
+ // Windows (Beta) — no SSH; runs in-guest via PowerShell/cmd
25
+ win, err := c.Create(ctx, uc.CreateOptions{Type: uc.Windows, Version: "windows-11"})
26
+ if err != nil {
27
+ panic(err)
28
+ }
29
+ defer win.Close(ctx)
30
+
31
+ r, _ := win.RunShell(ctx, "$env:COMPUTERNAME", "powershell")
32
+ fmt.Println(r.Stdout)
33
+ win.Click(ctx, 400, 300)
34
+ win.TypeText(ctx, "hello from use.computer")
35
+ png, _ := win.Screenshot(ctx)
36
+ fmt.Printf("screenshot %d bytes\n", len(png))
37
+ }
38
+ ```
39
+
40
+ ## Surface
41
+
42
+ - `New(opts...)` → `*Computer`; `WithBaseURL`, `WithAPIKey`, `WithHTTPClient`.
43
+ - `Create(ctx, CreateOptions{Type, Version, Host, Family, DeviceType, Runtime})` → `*Sandbox`.
44
+ - `Sandbox`: `Exec` (SSH on macOS / in-guest on Ubuntu / PowerShell on Windows), `RunShell(cmd, "powershell"|"cmd")`, `Screenshot`, `Click`, `Move`, `Scroll`, `TypeText`, `PressKey`, `Hotkey`, `UITree`, `Upload`, `Download`, `StartRecording`/`StopRecording`, `Keepalive`, `Close`.
45
+
46
+ Every call takes a `context.Context`. Docs: [docs.use.computer](https://docs.use.computer). Windows is **Beta** (admin-only).
@@ -0,0 +1,192 @@
1
+ // Package usecomputer is the Go SDK for use.computer — rent dedicated VMs
2
+ // (macOS, iOS/visionOS/tvOS simulators, Windows, Ubuntu) for computer-use agents.
3
+ // Parity with the Python and TypeScript SDKs.
4
+ package usecomputer
5
+
6
+ import (
7
+ "bytes"
8
+ "context"
9
+ "encoding/json"
10
+ "fmt"
11
+ "io"
12
+ "net/http"
13
+ "net/url"
14
+ "os"
15
+ "strings"
16
+ "time"
17
+ )
18
+
19
+ // SandboxType is the OS family of a sandbox.
20
+ type SandboxType string
21
+
22
+ const (
23
+ MacOS SandboxType = "macos"
24
+ IOS SandboxType = "ios"
25
+ Windows SandboxType = "windows"
26
+ Ubuntu SandboxType = "ubuntu"
27
+ )
28
+
29
+ // Computer is a client for a use.computer gateway.
30
+ type Computer struct {
31
+ baseURL string
32
+ apiKey string
33
+ http *http.Client
34
+ }
35
+
36
+ // Option configures a Computer.
37
+ type Option func(*Computer)
38
+
39
+ // WithBaseURL sets the gateway base URL (default $USE_COMPUTER_BASE_URL or https://api.use.computer).
40
+ func WithBaseURL(u string) Option { return func(c *Computer) { c.baseURL = strings.TrimRight(u, "/") } }
41
+
42
+ // WithAPIKey sets the API key (default $USE_COMPUTER_API_KEY).
43
+ func WithAPIKey(k string) Option { return func(c *Computer) { c.apiKey = k } }
44
+
45
+ // WithHTTPClient overrides the underlying *http.Client.
46
+ func WithHTTPClient(h *http.Client) Option { return func(c *Computer) { c.http = h } }
47
+
48
+ // New creates a Computer client.
49
+ func New(opts ...Option) *Computer {
50
+ c := &Computer{
51
+ baseURL: envOr("USE_COMPUTER_BASE_URL", "https://api.use.computer"),
52
+ apiKey: os.Getenv("USE_COMPUTER_API_KEY"),
53
+ http: &http.Client{Timeout: 200 * time.Second},
54
+ }
55
+ for _, o := range opts {
56
+ o(c)
57
+ }
58
+ c.baseURL = strings.TrimRight(c.baseURL, "/")
59
+ return c
60
+ }
61
+
62
+ // CreateOptions selects the sandbox to create.
63
+ type CreateOptions struct {
64
+ Type SandboxType // default MacOS
65
+ Host string // pin to a host (e.g. "mm001")
66
+ Version string // windows image version: "windows-11" (default), "windows-10"
67
+ Family string // ios simulator family
68
+ DeviceType string // ios exact device type
69
+ Runtime string // ios exact runtime
70
+ }
71
+
72
+ type createResponse struct {
73
+ SandboxID string `json:"sandbox_id"`
74
+ Type string `json:"type"`
75
+ VNCURL string `json:"vnc_url"`
76
+ SSHURL string `json:"ssh_url"`
77
+ VMIP string `json:"vm_ip"`
78
+ Host string `json:"host"`
79
+ }
80
+
81
+ // Create provisions a new sandbox and returns it once ready.
82
+ func (c *Computer) Create(ctx context.Context, opts CreateOptions) (*Sandbox, error) {
83
+ t := opts.Type
84
+ if t == "" {
85
+ t = MacOS
86
+ }
87
+ body := map[string]any{"type": string(t)}
88
+ if opts.Host != "" {
89
+ body["host"] = opts.Host
90
+ }
91
+ if t == Windows && opts.Version != "" {
92
+ body["version"] = opts.Version
93
+ }
94
+ if t == IOS {
95
+ if opts.Family != "" {
96
+ body["family"] = opts.Family
97
+ }
98
+ if opts.DeviceType != "" {
99
+ body["device_type"] = opts.DeviceType
100
+ }
101
+ if opts.Runtime != "" {
102
+ body["runtime"] = opts.Runtime
103
+ }
104
+ }
105
+ var resp createResponse
106
+ if err := c.doJSON(ctx, http.MethodPost, "/v1/sandboxes", body, &resp); err != nil {
107
+ return nil, err
108
+ }
109
+ return &Sandbox{
110
+ ID: resp.SandboxID, Type: t, VNCURL: resp.VNCURL, SSHURL: resp.SSHURL, VMIP: resp.VMIP,
111
+ c: c, prefix: "/v1/sandboxes/" + resp.SandboxID,
112
+ }, nil
113
+ }
114
+
115
+ // Platforms discovers available platforms, images, runtimes, and device types.
116
+ func (c *Computer) Platforms(ctx context.Context) (map[string]any, error) {
117
+ var out map[string]any
118
+ return out, c.doJSON(ctx, http.MethodGet, "/v1/platforms", nil, &out)
119
+ }
120
+
121
+ // --- internal HTTP helpers ---
122
+
123
+ func (c *Computer) newReq(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
124
+ req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, body)
125
+ if err != nil {
126
+ return nil, err
127
+ }
128
+ if c.apiKey != "" {
129
+ req.Header.Set("Authorization", "Bearer "+c.apiKey)
130
+ }
131
+ return req, nil
132
+ }
133
+
134
+ func (c *Computer) doJSON(ctx context.Context, method, path string, body, out any) error {
135
+ var rdr io.Reader
136
+ if body != nil {
137
+ b, err := json.Marshal(body)
138
+ if err != nil {
139
+ return err
140
+ }
141
+ rdr = bytes.NewReader(b)
142
+ } else if method == http.MethodPost {
143
+ rdr = strings.NewReader("{}")
144
+ }
145
+ req, err := c.newReq(ctx, method, path, rdr)
146
+ if err != nil {
147
+ return err
148
+ }
149
+ if rdr != nil {
150
+ req.Header.Set("Content-Type", "application/json")
151
+ }
152
+ resp, err := c.http.Do(req)
153
+ if err != nil {
154
+ return err
155
+ }
156
+ defer resp.Body.Close()
157
+ if resp.StatusCode >= 400 {
158
+ b, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
159
+ return fmt.Errorf("%s %s: %d: %s", method, path, resp.StatusCode, strings.TrimSpace(string(b)))
160
+ }
161
+ if out == nil {
162
+ return nil
163
+ }
164
+ return json.NewDecoder(resp.Body).Decode(out)
165
+ }
166
+
167
+ func (c *Computer) getBytes(ctx context.Context, path string, q url.Values) ([]byte, error) {
168
+ if q != nil {
169
+ path += "?" + q.Encode()
170
+ }
171
+ req, err := c.newReq(ctx, http.MethodGet, path, nil)
172
+ if err != nil {
173
+ return nil, err
174
+ }
175
+ resp, err := c.http.Do(req)
176
+ if err != nil {
177
+ return nil, err
178
+ }
179
+ defer resp.Body.Close()
180
+ if resp.StatusCode >= 400 {
181
+ b, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
182
+ return nil, fmt.Errorf("GET %s: %d: %s", path, resp.StatusCode, strings.TrimSpace(string(b)))
183
+ }
184
+ return io.ReadAll(resp.Body)
185
+ }
186
+
187
+ func envOr(k, def string) string {
188
+ if v := os.Getenv(k); v != "" {
189
+ return v
190
+ }
191
+ return def
192
+ }
@@ -0,0 +1,3 @@
1
+ module github.com/josancamon19/use-computer-sdk/go
2
+
3
+ go 1.22
@@ -0,0 +1,156 @@
1
+ package usecomputer
2
+
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "fmt"
7
+ "net/http"
8
+ "net/url"
9
+ )
10
+
11
+ // Sandbox is a running VM. Action methods map 1:1 to the gateway HTTP surface.
12
+ type Sandbox struct {
13
+ ID string
14
+ Type SandboxType
15
+ VNCURL string
16
+ SSHURL string // macOS only
17
+ VMIP string // macOS only
18
+
19
+ c *Computer
20
+ prefix string
21
+ }
22
+
23
+ // ExecResult is the outcome of a shell command.
24
+ type ExecResult struct {
25
+ Stdout string `json:"stdout"`
26
+ Stderr string `json:"stderr"`
27
+ ExitCode int `json:"-"`
28
+ }
29
+
30
+ type execWire struct {
31
+ Stdout string `json:"stdout"`
32
+ Stderr string `json:"stderr"`
33
+ ExitCode *int `json:"exit_code"`
34
+ ReturnCode *int `json:"return_code"`
35
+ }
36
+
37
+ func (e execWire) result() ExecResult {
38
+ code := 0
39
+ if e.ExitCode != nil {
40
+ code = *e.ExitCode
41
+ } else if e.ReturnCode != nil {
42
+ code = *e.ReturnCode
43
+ }
44
+ return ExecResult{Stdout: e.Stdout, Stderr: e.Stderr, ExitCode: code}
45
+ }
46
+
47
+ // Exec runs a command: SSH on macOS, in-guest on Ubuntu, PowerShell on Windows.
48
+ // On Windows pass shell ("powershell" or "cmd") via RunShell for cmd.
49
+ func (s *Sandbox) Exec(ctx context.Context, command string) (ExecResult, error) {
50
+ var w execWire
51
+ err := s.c.doJSON(ctx, http.MethodPost, s.prefix+"/exec", map[string]any{"command": command}, &w)
52
+ return w.result(), err
53
+ }
54
+
55
+ // RunShell runs a command on Windows in the given shell ("powershell" | "cmd").
56
+ func (s *Sandbox) RunShell(ctx context.Context, command, shell string) (ExecResult, error) {
57
+ var w execWire
58
+ err := s.c.doJSON(ctx, http.MethodPost, s.prefix+"/exec", map[string]any{"command": command, "shell": shell}, &w)
59
+ return w.result(), err
60
+ }
61
+
62
+ // Screenshot returns a full-screen PNG/JPEG.
63
+ func (s *Sandbox) Screenshot(ctx context.Context) ([]byte, error) {
64
+ return s.c.getBytes(ctx, s.prefix+"/screenshot", nil)
65
+ }
66
+
67
+ // Click left-clicks at (x, y).
68
+ func (s *Sandbox) Click(ctx context.Context, x, y int) error {
69
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/act",
70
+ map[string]any{"action": map[string]any{"type": "click", "x": x, "y": y, "button": "left"}}, nil)
71
+ }
72
+
73
+ // Move moves the cursor to (x, y).
74
+ func (s *Sandbox) Move(ctx context.Context, x, y int) error {
75
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/mouse/move", map[string]any{"x": x, "y": y}, nil)
76
+ }
77
+
78
+ // Scroll scrolls by (dx, dy) at (x, y).
79
+ func (s *Sandbox) Scroll(ctx context.Context, x, y, dx, dy int) error {
80
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/act",
81
+ map[string]any{"action": map[string]any{"type": "scroll", "x": x, "y": y, "scroll_x": dx, "scroll_y": dy}}, nil)
82
+ }
83
+
84
+ // TypeText types a string.
85
+ func (s *Sandbox) TypeText(ctx context.Context, text string) error {
86
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/keyboard/type", map[string]any{"text": text}, nil)
87
+ }
88
+
89
+ // PressKey presses a single key.
90
+ func (s *Sandbox) PressKey(ctx context.Context, key string) error {
91
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/keyboard/press", map[string]any{"key": key}, nil)
92
+ }
93
+
94
+ // Hotkey presses a combo, e.g. "ctrl+c" (macOS "cmd+c", Windows "win+d").
95
+ func (s *Sandbox) Hotkey(ctx context.Context, combo string) error {
96
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/keyboard/hotkey", map[string]any{"keys": combo}, nil)
97
+ }
98
+
99
+ // UITree returns the native UI tree (macOS axe schema / Windows UIAutomation).
100
+ func (s *Sandbox) UITree(ctx context.Context) (map[string]any, error) {
101
+ var out map[string]any
102
+ return out, s.c.doJSON(ctx, http.MethodGet, s.prefix+"/display/windows", nil, &out)
103
+ }
104
+
105
+ // Upload writes bytes to remotePath in the VM.
106
+ func (s *Sandbox) Upload(ctx context.Context, data []byte, remotePath string) error {
107
+ req, err := s.c.newReq(ctx, http.MethodPut, s.prefix+"/files?"+url.Values{"path": {remotePath}}.Encode(), bytes.NewReader(data))
108
+ if err != nil {
109
+ return err
110
+ }
111
+ req.Header.Set("Content-Type", "application/octet-stream")
112
+ resp, err := s.c.http.Do(req)
113
+ if err != nil {
114
+ return err
115
+ }
116
+ defer resp.Body.Close()
117
+ if resp.StatusCode >= 400 {
118
+ return fmt.Errorf("upload %s: %d", remotePath, resp.StatusCode)
119
+ }
120
+ return nil
121
+ }
122
+
123
+ // Download reads remotePath from the VM.
124
+ func (s *Sandbox) Download(ctx context.Context, remotePath string) ([]byte, error) {
125
+ return s.c.getBytes(ctx, s.prefix+"/files", url.Values{"path": {remotePath}})
126
+ }
127
+
128
+ // StartRecording starts a screen recording, returning its id.
129
+ func (s *Sandbox) StartRecording(ctx context.Context) (string, error) {
130
+ var out struct {
131
+ RecordingID string `json:"recording_id"`
132
+ ID string `json:"id"`
133
+ }
134
+ if err := s.c.doJSON(ctx, http.MethodPost, s.prefix+"/recording/start", nil, &out); err != nil {
135
+ return "", err
136
+ }
137
+ if out.RecordingID != "" {
138
+ return out.RecordingID, nil
139
+ }
140
+ return out.ID, nil
141
+ }
142
+
143
+ // StopRecording stops a recording by id.
144
+ func (s *Sandbox) StopRecording(ctx context.Context, recordingID string) error {
145
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/recording/stop", map[string]any{"recording_id": recordingID}, nil)
146
+ }
147
+
148
+ // Keepalive resets the idle timer.
149
+ func (s *Sandbox) Keepalive(ctx context.Context) error {
150
+ return s.c.doJSON(ctx, http.MethodPost, s.prefix+"/keepalive", nil, nil)
151
+ }
152
+
153
+ // Close destroys the sandbox.
154
+ func (s *Sandbox) Close(ctx context.Context) error {
155
+ return s.c.doJSON(ctx, http.MethodDelete, s.prefix, nil, nil)
156
+ }
@@ -0,0 +1,3 @@
1
+ node_modules/
2
+ dist/
3
+ *.tsbuildinfo
@@ -0,0 +1,48 @@
1
+ # use-computer — TypeScript SDK
2
+
3
+ TypeScript/JavaScript client for [use.computer](https://use.computer) — rent dedicated VMs (macOS, iOS/visionOS/tvOS simulators, **Windows**, **Ubuntu**) built for computer-use agents. Parity with the [Python SDK](../python); async-native.
4
+
5
+ ```bash
6
+ npm install use-computer
7
+ export USE_COMPUTER_API_KEY=mk_live_...
8
+ ```
9
+
10
+ ```ts
11
+ import { Computer } from "use-computer";
12
+
13
+ const computer = new Computer(); // baseUrl + apiKey from env, or pass {baseUrl, apiKey}
14
+
15
+ // macOS (default)
16
+ const mac = await computer.create({ type: "macos" });
17
+ await mac.execSsh("open -a TextEdit");
18
+ await mac.keyboard.type("hello");
19
+ const png = await mac.screenshot.takeFullScreen();
20
+ await mac.close();
21
+
22
+ // Windows (Beta) — no SSH; exec runs in-guest via PowerShell/cmd
23
+ await using win = await computer.create({ type: "windows", version: "windows-11" });
24
+ console.log((await win.run("$env:COMPUTERNAME")).stdout);
25
+ await win.mouse.click(400, 300);
26
+ await win.keyboard.type("hello from use.computer");
27
+ const tree = await win.uiTree(); // native Windows UIAutomation tree
28
+
29
+ // iOS simulator
30
+ const ios = await computer.create({ type: "ios", family: "iphone" });
31
+ await ios.tap(120, 300);
32
+
33
+ // Ubuntu
34
+ const ubuntu = await computer.create({ type: "ubuntu" });
35
+ console.log((await ubuntu.exec("uname -a")).stdout);
36
+ ```
37
+
38
+ ## Surface
39
+
40
+ - `Computer.create({ type, version?, host?, family?, deviceType?, runtime? })` → typed sandbox.
41
+ - All sandboxes: `screenshot.takeFullScreen()/takeCompressed()`, `recording.start()/stop()/listAll()/download()`, `uiTree()`, `displayInfo()`, `upload(bytes, path)`, `download(path)`, `keepalive()`, `close()`.
42
+ - macOS / Windows / Ubuntu: `mouse.move/click/doubleClick/scroll/drag/position`, `keyboard.type/press/hotkey`.
43
+ - macOS: `execSsh(cmd)`. Windows: `run(cmd, "powershell"|"cmd")` (no SSH). Ubuntu: `exec(cmd)`.
44
+ - iOS: `tap`, `pressButton`, `pressRemote`, `launch` (no axe-schema `uiTree`).
45
+
46
+ `await using` (TS 5.2+) auto-closes the sandbox at scope exit.
47
+
48
+ Docs: [docs.use.computer](https://docs.use.computer). Windows is **Beta** (admin-only).
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "use-computer",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "use-computer",
9
+ "version": "0.1.0",
10
+ "license": "MIT",
11
+ "devDependencies": {
12
+ "@types/node": "^20.0.0",
13
+ "typescript": "^5.6.0"
14
+ },
15
+ "engines": {
16
+ "node": ">=18"
17
+ }
18
+ },
19
+ "node_modules/@types/node": {
20
+ "version": "20.19.41",
21
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz",
22
+ "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==",
23
+ "dev": true,
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "undici-types": "~6.21.0"
27
+ }
28
+ },
29
+ "node_modules/typescript": {
30
+ "version": "5.9.3",
31
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
32
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
33
+ "dev": true,
34
+ "license": "Apache-2.0",
35
+ "bin": {
36
+ "tsc": "bin/tsc",
37
+ "tsserver": "bin/tsserver"
38
+ },
39
+ "engines": {
40
+ "node": ">=14.17"
41
+ }
42
+ },
43
+ "node_modules/undici-types": {
44
+ "version": "6.21.0",
45
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
46
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
47
+ "dev": true,
48
+ "license": "MIT"
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "use-computer",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for use.computer — rent dedicated VMs (macOS, iOS/visionOS/tvOS simulators, Windows, Ubuntu) built for computer-use agents.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": ["dist", "README.md"],
17
+ "engines": { "node": ">=18" },
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.json",
20
+ "typecheck": "tsc -p tsconfig.json --noEmit",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "keywords": ["use.computer", "computer-use", "agents", "macos", "windows", "ios", "ubuntu", "sandbox", "vnc"],
24
+ "repository": { "type": "git", "url": "https://github.com/josancamon19/use-computer-sdk.git", "directory": "javascript" },
25
+ "homepage": "https://docs.use.computer",
26
+ "devDependencies": { "typescript": "^5.6.0", "@types/node": "^20.0.0" }
27
+ }
@@ -0,0 +1,82 @@
1
+ import { HttpClient } from "./http.js";
2
+ import {
3
+ IOSSandbox,
4
+ MacOSSandbox,
5
+ type SandboxType,
6
+ UbuntuSandbox,
7
+ WindowsSandbox,
8
+ type AnySandbox,
9
+ } from "./sandbox.js";
10
+
11
+ export interface ComputerOptions {
12
+ /** Gateway base URL. Default: $USE_COMPUTER_BASE_URL or https://api.use.computer */
13
+ baseUrl?: string;
14
+ /** API key. Default: $USE_COMPUTER_API_KEY */
15
+ apiKey?: string;
16
+ }
17
+
18
+ export interface CreateOptions {
19
+ type?: SandboxType;
20
+ /** Pin to a specific host machine (e.g. "mm001"). */
21
+ host?: string;
22
+ /** iOS: simulator family ("iphone" | "ipad" | "tv" | "watch" | "vision"). */
23
+ family?: string;
24
+ /** iOS: exact CoreSimulator device type / runtime identifiers. */
25
+ deviceType?: string;
26
+ runtime?: string;
27
+ /** Windows: image version — "windows-11" (default), "windows-10". */
28
+ version?: string;
29
+ }
30
+
31
+ interface CreateResponse {
32
+ sandbox_id: string;
33
+ type?: string;
34
+ vnc_url?: string;
35
+ ssh_url?: string;
36
+ vm_ip?: string;
37
+ host?: string;
38
+ }
39
+
40
+ export class Computer {
41
+ private readonly http: HttpClient;
42
+
43
+ constructor(opts: ComputerOptions = {}) {
44
+ const baseUrl = opts.baseUrl ?? process.env.USE_COMPUTER_BASE_URL ?? "https://api.use.computer";
45
+ const apiKey = opts.apiKey ?? process.env.USE_COMPUTER_API_KEY ?? "";
46
+ this.http = new HttpClient(baseUrl, apiKey);
47
+ }
48
+
49
+ /** Discover available platforms, images, runtimes, and device types. */
50
+ platforms(): Promise<unknown> {
51
+ return this.http.getJSON("/v1/platforms");
52
+ }
53
+
54
+ async create(opts: { type?: "macos"; host?: string }): Promise<MacOSSandbox>;
55
+ async create(opts: { type: "ios"; family?: string; deviceType?: string; runtime?: string }): Promise<IOSSandbox>;
56
+ async create(opts: { type: "windows"; version?: string; host?: string }): Promise<WindowsSandbox>;
57
+ async create(opts: { type: "ubuntu"; host?: string }): Promise<UbuntuSandbox>;
58
+ async create(opts: CreateOptions = {}): Promise<AnySandbox> {
59
+ const type = (opts.type ?? "macos") as SandboxType;
60
+ const body: Record<string, unknown> = { type };
61
+ if (opts.host) body.host = opts.host;
62
+ if (type === "windows" && opts.version) body.version = opts.version;
63
+ if (type === "ios") {
64
+ if (opts.family) body.family = opts.family;
65
+ if (opts.deviceType) body.device_type = opts.deviceType;
66
+ if (opts.runtime) body.runtime = opts.runtime;
67
+ }
68
+ const d = await this.http.postJSON<CreateResponse>("/v1/sandboxes", body);
69
+ const id = d.sandbox_id;
70
+ const vnc = d.vnc_url ?? "";
71
+ switch (type) {
72
+ case "windows":
73
+ return new WindowsSandbox(id, this.http, vnc);
74
+ case "ubuntu":
75
+ return new UbuntuSandbox(id, this.http, vnc);
76
+ case "ios":
77
+ return new IOSSandbox(id, this.http, vnc);
78
+ default:
79
+ return new MacOSSandbox(id, this.http, vnc, d.ssh_url ?? "", d.vm_ip ?? "");
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,96 @@
1
+ // Thin fetch wrapper: base URL + bearer auth, JSON/binary helpers, typed errors.
2
+
3
+ export class UseComputerError extends Error {}
4
+
5
+ export class PlatformNotSupportedError extends UseComputerError {
6
+ constructor(
7
+ public action: string,
8
+ public sandboxType: string,
9
+ public hint: string,
10
+ ) {
11
+ super(`${action} not supported on ${sandboxType} sandbox: ${hint}`);
12
+ }
13
+ }
14
+
15
+ export class HttpClient {
16
+ readonly baseUrl: string;
17
+ private readonly apiKey: string;
18
+
19
+ constructor(baseUrl: string, apiKey: string) {
20
+ this.baseUrl = baseUrl.replace(/\/$/, "");
21
+ this.apiKey = apiKey;
22
+ }
23
+
24
+ private headers(extra?: Record<string, string>): Record<string, string> {
25
+ const h: Record<string, string> = { ...extra };
26
+ if (this.apiKey) h["Authorization"] = `Bearer ${this.apiKey}`;
27
+ return h;
28
+ }
29
+
30
+ private async check(resp: Response, path: string): Promise<Response> {
31
+ if (resp.ok) return resp;
32
+ const body = await resp.text().catch(() => "");
33
+ throw new UseComputerError(`${resp.status} ${path}: ${body.slice(0, 500)}`);
34
+ }
35
+
36
+ async getJSON<T = unknown>(path: string, params?: Record<string, string>): Promise<T> {
37
+ const url = new URL(this.baseUrl + path);
38
+ if (params) for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
39
+ const resp = await this.check(await fetch(url, { headers: this.headers() }), path);
40
+ return (await resp.json()) as T;
41
+ }
42
+
43
+ async getBytes(path: string, params?: Record<string, string>): Promise<Uint8Array> {
44
+ const url = new URL(this.baseUrl + path);
45
+ if (params) for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
46
+ const resp = await this.check(await fetch(url, { headers: this.headers() }), path);
47
+ return new Uint8Array(await resp.arrayBuffer());
48
+ }
49
+
50
+ async postJSON<T = unknown>(path: string, body?: unknown, timeoutMs = 180_000): Promise<T> {
51
+ const resp = await this.check(
52
+ await fetch(this.baseUrl + path, {
53
+ method: "POST",
54
+ headers: this.headers({ "Content-Type": "application/json" }),
55
+ body: body === undefined ? "{}" : JSON.stringify(body),
56
+ signal: AbortSignal.timeout(timeoutMs),
57
+ }),
58
+ path,
59
+ );
60
+ const ct = resp.headers.get("content-type") ?? "";
61
+ if (ct.startsWith("application/json")) return (await resp.json()) as T;
62
+ return undefined as T;
63
+ }
64
+
65
+ /** POST returning either an image (screenshot) or JSON — used by /act. */
66
+ async postActionRaw(path: string, body: unknown): Promise<{ image?: Uint8Array; data?: unknown }> {
67
+ const resp = await this.check(
68
+ await fetch(this.baseUrl + path, {
69
+ method: "POST",
70
+ headers: this.headers({ "Content-Type": "application/json" }),
71
+ body: JSON.stringify(body),
72
+ }),
73
+ path,
74
+ );
75
+ const ct = resp.headers.get("content-type") ?? "";
76
+ if (ct.startsWith("image/")) return { image: new Uint8Array(await resp.arrayBuffer()) };
77
+ return { data: await resp.json() };
78
+ }
79
+
80
+ async putBytes(path: string, data: Uint8Array, params?: Record<string, string>): Promise<void> {
81
+ const url = new URL(this.baseUrl + path);
82
+ if (params) for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
83
+ await this.check(
84
+ await fetch(url, {
85
+ method: "PUT",
86
+ headers: this.headers({ "Content-Type": "application/octet-stream" }),
87
+ body: data as unknown as BodyInit,
88
+ }),
89
+ path,
90
+ );
91
+ }
92
+
93
+ async delete(path: string): Promise<void> {
94
+ await this.check(await fetch(this.baseUrl + path, { method: "DELETE", headers: this.headers() }), path);
95
+ }
96
+ }
@@ -0,0 +1,11 @@
1
+ export { Computer } from "./client.js";
2
+ export type { ComputerOptions, CreateOptions } from "./client.js";
3
+ export {
4
+ Sandbox,
5
+ MacOSSandbox,
6
+ WindowsSandbox,
7
+ UbuntuSandbox,
8
+ IOSSandbox,
9
+ } from "./sandbox.js";
10
+ export type { SandboxType, ExecResult, RecordingInfo, AnySandbox, WindowsShellKind } from "./sandbox.js";
11
+ export { UseComputerError, PlatformNotSupportedError } from "./http.js";
@@ -0,0 +1,208 @@
1
+ import { HttpClient, PlatformNotSupportedError } from "./http.js";
2
+
3
+ export type SandboxType = "macos" | "ios" | "windows" | "ubuntu";
4
+
5
+ export interface ExecResult {
6
+ stdout: string;
7
+ stderr: string;
8
+ exitCode: number;
9
+ }
10
+
11
+ export interface RecordingInfo {
12
+ recordingId: string;
13
+ fileSize?: number;
14
+ }
15
+
16
+ function execFromJSON(d: Record<string, unknown>): ExecResult {
17
+ return {
18
+ stdout: String(d.stdout ?? ""),
19
+ stderr: String(d.stderr ?? ""),
20
+ exitCode: Number(d.exit_code ?? d.return_code ?? d.returncode ?? 0),
21
+ };
22
+ }
23
+
24
+ // --- action sub-objects (each bound to a sandbox's HTTP prefix) ---
25
+
26
+ class Screenshot {
27
+ constructor(private http: HttpClient, private prefix: string) {}
28
+ takeFullScreen(): Promise<Uint8Array> {
29
+ return this.http.getBytes(`${this.prefix}/screenshot`);
30
+ }
31
+ takeCompressed(): Promise<Uint8Array> {
32
+ return this.http.getBytes(`${this.prefix}/screenshot/compressed`);
33
+ }
34
+ }
35
+
36
+ class Mouse {
37
+ constructor(private http: HttpClient, private prefix: string) {}
38
+ move(x: number, y: number): Promise<void> {
39
+ return this.http.postJSON(`${this.prefix}/mouse/move`, { x, y });
40
+ }
41
+ async click(x: number, y: number, button = "left"): Promise<void> {
42
+ await this.http.postActionRaw(`${this.prefix}/act`, { action: { type: "click", x, y, button } });
43
+ }
44
+ async doubleClick(x: number, y: number): Promise<void> {
45
+ await this.http.postActionRaw(`${this.prefix}/act`, { action: { type: "double_click", x, y } });
46
+ }
47
+ async scroll(x: number, y: number, dx: number, dy: number): Promise<void> {
48
+ await this.http.postActionRaw(`${this.prefix}/act`, { action: { type: "scroll", x, y, scroll_x: dx, scroll_y: dy } });
49
+ }
50
+ async drag(path: Array<[number, number]>): Promise<void> {
51
+ await this.http.postActionRaw(`${this.prefix}/act`, { action: { type: "drag", path } });
52
+ }
53
+ position(): Promise<{ x: number; y: number }> {
54
+ return this.http.getJSON(`${this.prefix}/mouse/position`);
55
+ }
56
+ }
57
+
58
+ class Keyboard {
59
+ constructor(private http: HttpClient, private prefix: string) {}
60
+ type(text: string): Promise<void> {
61
+ return this.http.postJSON(`${this.prefix}/keyboard/type`, { text });
62
+ }
63
+ press(key: string): Promise<void> {
64
+ return this.http.postJSON(`${this.prefix}/keyboard/press`, { key });
65
+ }
66
+ /** e.g. "ctrl+c" (macOS: "cmd+c", windows: "ctrl+c", "win+d"). */
67
+ hotkey(combo: string): Promise<void> {
68
+ return this.http.postJSON(`${this.prefix}/keyboard/hotkey`, { keys: combo });
69
+ }
70
+ }
71
+
72
+ class Recording {
73
+ constructor(private http: HttpClient, private prefix: string) {}
74
+ async start(): Promise<string> {
75
+ const d = await this.http.postJSON<Record<string, unknown>>(`${this.prefix}/recording/start`);
76
+ return String(d.recording_id ?? d.id ?? "");
77
+ }
78
+ async stop(recordingId: string): Promise<RecordingInfo> {
79
+ const d = await this.http.postJSON<Record<string, unknown>>(`${this.prefix}/recording/stop`, { recording_id: recordingId });
80
+ return { recordingId: String(d.recording_id ?? recordingId), fileSize: Number(d.file_size ?? 0) };
81
+ }
82
+ async listAll(): Promise<RecordingInfo[]> {
83
+ const d = await this.http.getJSON<unknown>(`${this.prefix}/recordings`);
84
+ const items = Array.isArray(d) ? d : ((d as Record<string, unknown>).recordings as unknown[]) ?? [];
85
+ return items.map((r) => {
86
+ const o = r as Record<string, unknown>;
87
+ return { recordingId: String(o.recording_id ?? o.id ?? ""), fileSize: Number(o.file_size ?? 0) };
88
+ });
89
+ }
90
+ download(recordingId: string): Promise<Uint8Array> {
91
+ return this.http.getBytes(`${this.prefix}/recordings/${recordingId}/download`);
92
+ }
93
+ }
94
+
95
+ // --- sandboxes ---
96
+
97
+ export class Sandbox {
98
+ readonly screenshot: Screenshot;
99
+ readonly recording: Recording;
100
+ protected readonly http: HttpClient;
101
+ protected readonly prefix: string;
102
+
103
+ constructor(
104
+ readonly sandboxId: string,
105
+ readonly type: SandboxType,
106
+ http: HttpClient,
107
+ readonly vncUrl = "",
108
+ ) {
109
+ this.http = http;
110
+ this.prefix = `/v1/sandboxes/${sandboxId}`;
111
+ this.screenshot = new Screenshot(http, this.prefix);
112
+ this.recording = new Recording(http, this.prefix);
113
+ }
114
+
115
+ /** Native UI tree (macOS axe schema / Windows UIAutomation). */
116
+ uiTree(): Promise<unknown> {
117
+ return this.http.getJSON(`${this.prefix}/display/windows`);
118
+ }
119
+
120
+ displayInfo(): Promise<{ width: number; height: number }> {
121
+ return this.http.getJSON(`${this.prefix}/display/info`);
122
+ }
123
+
124
+ async upload(data: Uint8Array, remotePath: string): Promise<void> {
125
+ await this.http.putBytes(`${this.prefix}/files`, data, { path: remotePath });
126
+ }
127
+
128
+ download(remotePath: string): Promise<Uint8Array> {
129
+ return this.http.getBytes(`${this.prefix}/files`, { path: remotePath });
130
+ }
131
+
132
+ async keepalive(): Promise<void> {
133
+ await this.http.postJSON(`${this.prefix}/keepalive`);
134
+ }
135
+
136
+ async close(): Promise<void> {
137
+ await this.http.delete(this.prefix);
138
+ }
139
+ }
140
+
141
+ export class MacOSSandbox extends Sandbox {
142
+ readonly mouse: Mouse;
143
+ readonly keyboard: Keyboard;
144
+ constructor(sandboxId: string, http: HttpClient, vncUrl = "", readonly sshUrl = "", readonly vmIp = "") {
145
+ super(sandboxId, "macos", http, vncUrl);
146
+ this.mouse = new Mouse(http, this.prefix);
147
+ this.keyboard = new Keyboard(http, this.prefix);
148
+ }
149
+ async execSsh(command: string, timeoutMs = 120_000): Promise<ExecResult> {
150
+ const d = await this.http.postJSON<Record<string, unknown>>(`${this.prefix}/exec`, { command }, timeoutMs);
151
+ return execFromJSON(d);
152
+ }
153
+ }
154
+
155
+ export type WindowsShellKind = "powershell" | "cmd";
156
+
157
+ export class WindowsSandbox extends Sandbox {
158
+ readonly mouse: Mouse;
159
+ readonly keyboard: Keyboard;
160
+ constructor(sandboxId: string, http: HttpClient, vncUrl = "") {
161
+ super(sandboxId, "windows", http, vncUrl);
162
+ this.mouse = new Mouse(http, this.prefix);
163
+ this.keyboard = new Keyboard(http, this.prefix);
164
+ }
165
+ /** Run a command in-guest (no SSH). PowerShell by default. */
166
+ async run(command: string, shell: WindowsShellKind = "powershell", timeoutMs = 120_000): Promise<ExecResult> {
167
+ const d = await this.http.postJSON<Record<string, unknown>>(`${this.prefix}/exec`, { command, shell }, timeoutMs);
168
+ return execFromJSON(d);
169
+ }
170
+ }
171
+
172
+ export class UbuntuSandbox extends Sandbox {
173
+ readonly mouse: Mouse;
174
+ readonly keyboard: Keyboard;
175
+ constructor(sandboxId: string, http: HttpClient, vncUrl = "") {
176
+ super(sandboxId, "ubuntu", http, vncUrl);
177
+ this.mouse = new Mouse(http, this.prefix);
178
+ this.keyboard = new Keyboard(http, this.prefix);
179
+ }
180
+ async exec(command: string, timeoutMs = 120_000): Promise<ExecResult> {
181
+ const d = await this.http.postJSON<Record<string, unknown>>(`${this.prefix}/exec`, { command }, timeoutMs);
182
+ return execFromJSON(d);
183
+ }
184
+ }
185
+
186
+ export class IOSSandbox extends Sandbox {
187
+ constructor(sandboxId: string, http: HttpClient, vncUrl = "") {
188
+ super(sandboxId, "ios", http, vncUrl);
189
+ }
190
+ tap(x: number, y: number): Promise<void> {
191
+ return this.http.postJSON(`${this.prefix}/tap`, { x, y });
192
+ }
193
+ pressButton(button: string): Promise<void> {
194
+ return this.http.postJSON(`${this.prefix}/button`, { button });
195
+ }
196
+ pressRemote(button: string): Promise<void> {
197
+ return this.http.postJSON(`${this.prefix}/remote`, { button });
198
+ }
199
+ launch(bundleId: string): Promise<void> {
200
+ return this.http.postJSON(`${this.prefix}/launch`, { bundle_id: bundleId });
201
+ }
202
+ // axe-schema accessibility is macOS-only.
203
+ uiTree(): Promise<unknown> {
204
+ return Promise.reject(new PlatformNotSupportedError("ui_tree", "ios", "use screenshots + tap coordinates"));
205
+ }
206
+ }
207
+
208
+ export type AnySandbox = MacOSSandbox | WindowsSandbox | UbuntuSandbox | IOSSandbox;
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022", "DOM"],
7
+ "declaration": true,
8
+ "outDir": "dist",
9
+ "rootDir": "src",
10
+ "strict": true,
11
+ "esModuleInterop": true,
12
+ "skipLibCheck": true,
13
+ "forceConsistentCasingInFileNames": true
14
+ },
15
+ "include": ["src/**/*.ts"]
16
+ }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "use-computer"
7
- version = "0.0.20"
7
+ version = "0.0.22"
8
8
  description = "Python SDK for the use.computer macOS and iOS Computer Use API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes