skills/1wos/sdkhackthon/moru-javascript

moru-javascript

Originally frommoru-ai/skills
SKILL.md

Moru JavaScript/TypeScript SDK

npm install @moru-ai/core

TypeScript types included.

Quick Start

import Sandbox from '@moru-ai/core'

const sbx = await Sandbox.create()
try {
  await sbx.files.write("/app/script.py", "print('Hello from Moru!')")
  const result = await sbx.commands.run("python3 /app/script.py")
  console.log(result.stdout)
} finally {
  await sbx.kill()
}

Quick Reference

Task Code
Create sandbox await Sandbox.create() or await Sandbox.create("template")
Run command await sbx.commands.run("cmd")
Read file await sbx.files.read("/path")
Write file await sbx.files.write("/path", "content")
Background process await sbx.commands.run("cmd", { background: true })
Set timeout Sandbox.create({ timeoutMs: 600000 }) or sbx.setTimeout(600000)
Use volume Sandbox.create({ volumeId, volumeMountPath: "/workspace" })

Sandbox Lifecycle

Create

import Sandbox from '@moru-ai/core'

// Default template
const sbx = await Sandbox.create()

// Specific template
const sbx = await Sandbox.create("python")

// With options
const sbx = await Sandbox.create("python", {
  timeoutMs: 600000,                // milliseconds (default: 300000)
  metadata: { project: "myapp" },
  envs: { API_KEY: "secret" },
  volumeId: "vol_xxx",
  volumeMountPath: "/workspace",
  allowInternetAccess: true,
})

Connect to Existing

const sbx = await Sandbox.connect("sbx_abc123")
if (await sbx.isRunning()) {
  const result = await sbx.commands.run("echo still alive")
}

Kill

await sbx.kill()
// or
await Sandbox.kill("sbx_abc123")

List All

for await (const info of Sandbox.list()) {
  console.log(`${info.sandboxId}: ${info.state}`)
}

Running Commands

Basic

const result = await sbx.commands.run("echo hello")
console.log(result.stdout)      // "hello\n"
console.log(result.stderr)      // ""
console.log(result.exitCode)    // 0

With Options

const result = await sbx.commands.run("python3 script.py", {
  cwd: "/app",                              // Working directory
  user: "root",                             // Run as root
  envs: { DEBUG: "1" },                    // Environment variables
  timeoutMs: 120000,                        // Command timeout (ms)
  onStdout: (data) => process.stdout.write(data),  // Stream stdout
  onStderr: (data) => process.stderr.write(data),  // Stream stderr
})

Background Process

const handle = await sbx.commands.run("python3 server.py", { background: true })

// Get public URL
const url = sbx.getHost(8080)
console.log(`Server at: ${url}`)

// Send input
await handle.sendStdin("quit\n")

// Wait for completion
const result = await handle.wait()

// Or kill it
await handle.kill()

Process Management

// List running processes
for (const proc of await sbx.commands.list()) {
  console.log(`PID ${proc.pid}: ${proc.command}`)
}

// Kill by PID
await sbx.commands.kill(1234)

Working with Files

Read/Write

// Write
await sbx.files.write("/app/config.json", '{"key": "value"}')

// Read
const content = await sbx.files.read("/app/config.json")

// Binary
const bytes = await sbx.files.read("/app/image.png", { format: 'bytes' })
const blob = await sbx.files.read("/app/image.png", { format: 'blob' })
await sbx.files.write("/app/output.bin", binaryData)

// Stream large files
const stream = await sbx.files.read("/app/large.bin", { format: 'stream' })

Multiple Files

await sbx.files.write([
  { path: "/app/file1.txt", data: "content1" },
  { path: "/app/file2.txt", data: "content2" },
])

Directory Operations

// Check existence
if (await sbx.files.exists("/app/config.json")) {
  const config = await sbx.files.read("/app/config.json")
}

// List directory
for (const entry of await sbx.files.list("/app")) {
  console.log(`${entry.type}: ${entry.name} (${entry.size} bytes)`)
}

// Recursive list
const entries = await sbx.files.list("/app", { depth: 5 })

// Get info
const info = await sbx.files.getInfo("/app/file.txt")
console.log(`Size: ${info.size}, Modified: ${info.modifiedTime}`)

// Create directory
await sbx.files.makeDir("/app/data")

// Delete
await sbx.files.remove("/app/old_file.txt")

// Rename/Move
await sbx.files.rename("/app/old.txt", "/app/new.txt")

Watch for Changes

const handle = await sbx.files.watchDir("/app", (event) => {
  console.log(`${event.type}: ${event.name}`)
})
await handle.stop()

Volumes (Persistent Storage)

import Sandbox, { Volume } from '@moru-ai/core'

// Create volume (idempotent)
const vol = await Volume.create({ name: "my-workspace" })

// Attach to sandbox
const sbx = await Sandbox.create("base", {
  volumeId: vol.volumeId,
  volumeMountPath: "/workspace"  // Must be /workspace, /data, /mnt, or /volumes
})

// Data in /workspace persists after kill
await sbx.commands.run("echo 'persistent' > /workspace/data.txt")
await sbx.kill()

// Later - data still there
const sbx2 = await Sandbox.create("base", {
  volumeId: vol.volumeId,
  volumeMountPath: "/workspace"
})
const result = await sbx2.commands.run("cat /workspace/data.txt")
console.log(result.stdout)  // "persistent"

Volume Operations (No Sandbox Needed)

const vol = await Volume.get("my-workspace")

// List files
for (const f of await vol.listFiles("/")) {
  console.log(`${f.type}: ${f.name}`)
}

// Download/Upload
const content = await vol.download("/data.txt")
await vol.upload("/config.json", Buffer.from('{"key": "value"}'))

// Delete file
await vol.delete("/old_file.txt")

// Delete volume (WARNING: permanent)
await vol.delete()

Templates

import { Template, waitForPort } from '@moru-ai/core'

// Define template
const template = Template()
  .fromPythonImage("3.11")
  .aptInstall(["curl", "git"])
  .pipInstall(["flask", "pandas", "requests"])
  .copy("./app", "/app")
  .setWorkdir("/app")
  .setEnvs({ FLASK_ENV: "production" })
  .setStartCmd("python app.py", waitForPort(5000))

// Build
const info = await Template.build(template, { alias: "my-flask-app" })

// Use
const sbx = await Sandbox.create("my-flask-app")

From Dockerfile

const template = Template().fromDockerfile("./Dockerfile")
await Template.build(template, { alias: "my-app" })

Build Options

await Template.build(template, {
  alias: "my-app",
  cpuCount: 4,
  memoryMB: 2048,
  onBuildLogs: (entry) => console.log(entry.message),
})

// Background build
const info = await Template.buildInBackground(template, { alias: "my-app" })
const status = await Template.getBuildStatus(info)  // building, success, failed

Error Handling

import Sandbox, {
  SandboxError,              // Base
  TimeoutError,              // Operation timed out
  NotFoundError,             // Resource not found
  AuthenticationError,       // Invalid API key
  NotEnoughSpaceError,       // Disk full
  CommandExitError,          // Non-zero exit (has exitCode, stdout, stderr)
} from '@moru-ai/core'

try {
  const sbx = await Sandbox.create()
  try {
    const result = await sbx.commands.run("python3 script.py", { timeoutMs: 30000 })
  } finally {
    await sbx.kill()
  }
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log("Command timed out")
  } else if (error instanceof CommandExitError) {
    console.log(`Failed with exit code ${error.exitCode}: ${error.stderr}`)
  } else if (error instanceof AuthenticationError) {
    console.log("Invalid API key - check MORU_API_KEY")
  }
}

TypeScript Types

import type {
  SandboxOpts,
  SandboxInfo,
  CommandResult,
  CommandStartOpts,
  EntryInfo,
  VolumeInfo,
} from '@moru-ai/core'

Common Pitfalls

Always cleanup sandboxes

// ❌ WRONG
const sbx = await Sandbox.create()
await sbx.commands.run("echo hello")
// Forgot to kill - sandbox keeps running!

// ✅ CORRECT
const sbx = await Sandbox.create()
try {
  await sbx.commands.run("echo hello")
} finally {
  await sbx.kill()
}

Don't assume packages exist

// ❌ WRONG
await sbx.commands.run("python3 -c 'import pandas'")  // ImportError!

// ✅ CORRECT
await sbx.commands.run("pip install pandas", { timeoutMs: 120000 })
await sbx.commands.run("python3 -c 'import pandas'")

Write to volume path for persistence

// ❌ WRONG - lost on kill
await sbx.files.write("/home/user/data.txt", "important")

// ✅ CORRECT - persisted
await sbx.files.write("/workspace/data.txt", "important")

Handle command failures

const result = await sbx.commands.run("python3 script.py")
if (result.exitCode !== 0) {
  console.log(`Error: ${result.stderr}`)
}
Weekly Installs
3
First Seen
12 days ago
Installed on
cursor3
opencode2
antigravity2
claude-code2
github-copilot2
codex2