Skip to content

Commit 40354a1

Browse files
Merge pull request #3 from leap0-dev/init-fixes
Init fixes
2 parents e0e338c + 711502f commit 40354a1

72 files changed

Lines changed: 5415 additions & 1860 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
id-token: write
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Check out repository
19+
uses: actions/checkout@v4
20+
21+
- name: Set up pnpm
22+
uses: pnpm/action-setup@v4
23+
24+
- name: Set up Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: 20.19.0
28+
cache: pnpm
29+
registry-url: https://registry.npmjs.org
30+
31+
- name: Install dependencies
32+
run: pnpm install --frozen-lockfile
33+
34+
- name: Run tests
35+
run: pnpm test
36+
37+
- name: Publish package
38+
run: npm publish --provenance --access public
39+
env:
40+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,25 @@ export LEAP0_API_KEY="your-api-key"
3030
Or pass it directly when creating a client:
3131

3232
```ts
33-
import { Leap0Client } from "leap0"
33+
import { Leap0Client } from "leap0";
3434

35-
const client = new Leap0Client({ apiKey: "your-api-key" })
35+
const client = new Leap0Client({ apiKey: "your-api-key" });
3636
```
3737

3838
## Quick Start
3939

4040
```ts
41-
import { Leap0Client } from "leap0"
41+
import { Leap0Client } from "leap0";
4242

43-
const client = new Leap0Client()
44-
const sandbox = await client.sandboxes.create()
43+
const client = new Leap0Client();
44+
const sandbox = await client.sandboxes.create();
4545

4646
try {
47-
const result = await sandbox.process.execute({ command: "echo hello from leap0" })
48-
console.log(result.result.trim())
47+
const result = await sandbox.process.execute({ command: "echo hello from leap0" });
48+
console.log(result.result.trim());
4949
} finally {
50-
await sandbox.delete()
51-
await client.close()
50+
await sandbox.delete();
51+
await client.close();
5252
}
5353
```
5454

@@ -59,88 +59,93 @@ try {
5959
Stateful code execution with streaming output.
6060

6161
```ts
62-
import { CodeLanguage, DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME } from "leap0"
63-
64-
const sandbox = await client.sandboxes.create({ templateName: DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME })
65-
const result = await sandbox.codeInterpreter.execute({ code: "x = 42", language: CodeLanguage.PYTHON })
62+
import { CodeLanguage, DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME } from "leap0";
63+
64+
const sandbox = await client.sandboxes.create({
65+
templateName: DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME,
66+
});
67+
const result = await sandbox.codeInterpreter.execute({
68+
code: "x = 42",
69+
language: CodeLanguage.PYTHON,
70+
});
6671
```
6772

6873
### Filesystem
6974

7075
Read, write, search, and inspect files inside a sandbox.
7176

7277
```ts
73-
await sandbox.filesystem.writeFile("/workspace/hello.txt", "Hello!")
74-
const content = await sandbox.filesystem.readFile("/workspace/hello.txt")
75-
const tree = await sandbox.filesystem.tree("/workspace", 2)
78+
await sandbox.filesystem.writeFile("/workspace/hello.txt", "Hello!");
79+
const content = await sandbox.filesystem.readFile("/workspace/hello.txt");
80+
const tree = await sandbox.filesystem.tree("/workspace", 2);
7681
```
7782

7883
### Git
7984

8085
Clone repositories and run Git operations inside the sandbox.
8186

8287
```ts
83-
await sandbox.git.clone("https://github.com/octocat/Hello-World.git", "/workspace/repo")
84-
const status = await sandbox.git.status("/workspace/repo")
88+
await sandbox.git.clone("https://github.com/octocat/Hello-World.git", "/workspace/repo");
89+
const status = await sandbox.git.status("/workspace/repo");
8590
```
8691

8792
### Process Execution
8893

8994
Run one-off shell commands inside a running sandbox.
9095

9196
```ts
92-
const result = await sandbox.process.execute({ command: "ls -la /workspace" })
93-
console.log(result.result)
97+
const result = await sandbox.process.execute({ command: "ls -la /workspace" });
98+
console.log(result.result);
9499
```
95100

96101
### Interactive Terminal (PTY)
97102

98103
Open persistent terminal sessions over WebSocket.
99104

100105
```ts
101-
const session = await sandbox.pty.create({ cols: 120, rows: 30, cwd: "/home/user" })
106+
const session = await sandbox.pty.create({ cols: 120, rows: 30, cwd: "/home/user" });
102107
```
103108

104109
### Language Server Protocol (LSP)
105110

106111
Use language servers for completions and editor-style workflows.
107112

108113
```ts
109-
await sandbox.lsp.start({ languageId: "python", pathToProject: "/workspace" })
114+
await sandbox.lsp.start({ languageId: "python", pathToProject: "/workspace" });
110115
```
111116

112117
### SSH Access
113118

114119
Generate temporary SSH credentials for direct sandbox access.
115120

116121
```ts
117-
const access = await sandbox.ssh.createAccess()
118-
console.log(access.hostname, access.port, access.username)
122+
const access = await sandbox.ssh.createAccess();
123+
console.log(access.hostname, access.port, access.username);
119124
```
120125

121126
### Desktop Automation
122127

123128
Control a graphical desktop inside the sandbox.
124129

125130
```ts
126-
const screenshot = await sandbox.desktop.screenshot()
131+
const screenshot = await sandbox.desktop.screenshot();
127132
```
128133

129134
### Snapshots
130135

131136
Save and restore sandbox state.
132137

133138
```ts
134-
const snapshot = await client.snapshots.create(sandbox, { name: "my-checkpoint" })
135-
const restored = await client.snapshots.resume({ snapshotName: snapshot.name ?? "my-checkpoint" })
139+
const snapshot = await client.snapshots.create(sandbox, { name: "my-checkpoint" });
140+
const restored = await client.snapshots.resume({ snapshotName: snapshot.name ?? "my-checkpoint" });
136141
```
137142

138143
## Supported Imports
139144

140145
Import clients, enums, and types from the package root:
141146

142147
```ts
143-
import { Leap0Client, SandboxState, type CreateSandboxParams } from "leap0"
148+
import { Leap0Client, SandboxState, type CreateSandboxParams } from "leap0";
144149
```
145150

146151
## Examples

examples/code_interpreter_stream.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,33 @@ import {
33
DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME,
44
Leap0Client,
55
StreamEvent,
6-
} from "../src/index.js"
6+
} from "../src/index.js";
77

88
async function main(): Promise<void> {
9-
const client = new Leap0Client()
9+
const client = new Leap0Client();
1010

1111
try {
12-
const sandbox = await client.sandboxes.create({ templateName: DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME })
12+
const sandbox = await client.sandboxes.create({
13+
templateName: DEFAULT_CODE_INTERPRETER_TEMPLATE_NAME,
14+
});
1315

1416
try {
15-
for await (const event of sandbox.codeInterpreter.executeStream({
16-
code: "import time\nfor i in range(3):\n print(f'step {i}')\n time.sleep(1)",
17-
language: CodeLanguage.PYTHON,
18-
}, { timeout: 10 })) {
19-
const typedEvent: StreamEvent = event
20-
console.log(typedEvent)
17+
for await (const event of sandbox.codeInterpreter.executeStream(
18+
{
19+
code: "import time\nfor i in range(3):\n print(f'step {i}')\n time.sleep(1)",
20+
language: CodeLanguage.PYTHON,
21+
},
22+
{ timeout: 10 },
23+
)) {
24+
const typedEvent: StreamEvent = event;
25+
console.log(typedEvent);
2126
}
2227
} finally {
23-
await sandbox.delete()
28+
await sandbox.delete();
2429
}
2530
} finally {
26-
await client.close()
31+
await client.close();
2732
}
2833
}
2934

30-
void main()
35+
void main();

examples/desktop.ts

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
1-
import { writeFile } from "node:fs/promises"
1+
import { writeFile } from "node:fs/promises";
22

3-
import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "../src/index.js"
4-
5-
function decodeScreenshot(value: string): Uint8Array {
6-
const encoded = value.startsWith("data:") ? value.slice(value.indexOf(",") + 1) : value
7-
return Buffer.from(encoded, "base64")
8-
}
3+
import { DEFAULT_DESKTOP_TEMPLATE_NAME, Leap0Client } from "../src/index.js";
94

105
async function main(): Promise<void> {
11-
const client = new Leap0Client()
12-
let sandbox: Awaited<ReturnType<Leap0Client["createSandbox"]>> | null = null
6+
const client = new Leap0Client();
137

148
try {
15-
sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME })
16-
await sandbox.desktop.waitUntilReady(60)
17-
console.log("Desktop:", sandbox.desktop.browserUrl())
18-
19-
const display = await sandbox.desktop.display()
20-
console.log("Display:", display)
21-
22-
await sandbox.desktop.movePointer(Math.floor(display.width / 2), Math.floor(display.height / 2))
23-
await sandbox.desktop.click(1)
24-
25-
const screenshot = await sandbox.desktop.screenshot()
26-
await writeFile("desktop-screenshot.png", decodeScreenshot(screenshot))
27-
console.log("Saved screenshot to desktop-screenshot.png")
28-
} finally {
29-
if (sandbox) {
30-
await sandbox.delete()
9+
const sandbox = await client.sandboxes.create({ templateName: DEFAULT_DESKTOP_TEMPLATE_NAME });
10+
try {
11+
await sandbox.desktop.waitUntilReady(60);
12+
console.log("Desktop:", sandbox.desktop.desktopUrl());
13+
14+
const display = await sandbox.desktop.displayInfo();
15+
console.log("Display:", display);
16+
17+
await sandbox.desktop.movePointer(
18+
Math.floor(display.width / 2),
19+
Math.floor(display.height / 2),
20+
);
21+
await sandbox.desktop.click({ button: 1 });
22+
23+
const screenshot = await sandbox.desktop.screenshot();
24+
await writeFile("desktop-screenshot.png", screenshot);
25+
console.log("Saved screenshot to desktop-screenshot.png");
26+
} finally {
27+
await sandbox.delete();
3128
}
32-
await client.close()
29+
} finally {
30+
await client.close();
3331
}
3432
}
3533

36-
void main()
34+
void main();

examples/filesystem_and_git.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,43 @@
1-
import { Leap0Client } from "../src/index.js"
1+
import { Leap0Client } from "../src/index.js";
22

33
async function main(): Promise<void> {
4-
const client = new Leap0Client()
5-
const repoPath = "/workspace/hello-world"
4+
const client = new Leap0Client();
5+
const repoPath = "/workspace/hello-world";
66

77
try {
8-
const sandbox = await client.sandboxes.create()
8+
const sandbox = await client.sandboxes.create();
99

1010
try {
11-
const clone = await sandbox.git.clone("https://github.com/octocat/Hello-World.git", repoPath)
12-
console.log("clone exit:", clone.exitCode)
13-
14-
const status = await sandbox.git.status(repoPath)
15-
console.log("git status:\n", status.output)
16-
17-
await sandbox.filesystem.writeFile(`${repoPath}/sdk-demo.txt`, "Hello from the Leap0 JS SDK\n")
18-
const exists = await sandbox.filesystem.exists(`${repoPath}/sdk-demo.txt`)
19-
console.log("file exists:", exists.exists)
20-
21-
const fileInfo = await sandbox.filesystem.stat(`${repoPath}/README`)
22-
console.log("readme size:", fileInfo.size)
23-
24-
const tree = await sandbox.filesystem.tree(repoPath, 2)
25-
console.log("tree items:", tree.entries.map((entry) => entry.name))
11+
const clone = await sandbox.git.clone({
12+
url: "https://github.com/octocat/Hello-World.git",
13+
path: repoPath,
14+
});
15+
console.log("clone exit:", clone.exitCode);
16+
17+
const status = await sandbox.git.status(repoPath);
18+
console.log("git status:\n", status.output);
19+
20+
await sandbox.filesystem.writeFile(
21+
`${repoPath}/sdk-demo.txt`,
22+
"Hello from the Leap0 JS SDK\n",
23+
);
24+
const exists = await sandbox.filesystem.exists(`${repoPath}/sdk-demo.txt`);
25+
console.log("file exists:", exists);
26+
27+
const fileInfo = await sandbox.filesystem.stat(`${repoPath}/README`);
28+
console.log("readme size:", fileInfo.size);
29+
30+
const tree = await sandbox.filesystem.tree(repoPath, { maxDepth: 2 });
31+
console.log(
32+
"tree items:",
33+
tree.items.map((entry: { name: string }) => entry.name),
34+
);
2635
} finally {
27-
await sandbox.delete()
36+
await sandbox.delete();
2837
}
2938
} finally {
30-
await client.close()
39+
await client.close();
3140
}
3241
}
3342

34-
void main()
43+
void main();

0 commit comments

Comments
 (0)