<!--
hoody-code Subskill (sdk)
Auto-generated by Hoody Skills Generator
Generated: 2026-06-20T00:04:53.493Z
Model: mimo-v2.5-pro
Mode: sdk


Tokens: 6900

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-code Subskill

## Overview

**Service Purpose**: Hoody-code provides managed VS Code development environments accessible via unique URLs. Each instance runs in an isolated container, enabling multiple simultaneous editors per project.

**When to Use**:
- When you need a collaborative, cloud-based code editor
- For automated development workflows requiring VS Code extensions
- When building tools that interact with VS Code APIs programmatically
- For accessing development environments from any device via URL

**How It Fits Hoody Philosophy**:
Hoody-code embodies the principle of "everything as a service" by making complex development environments accessible through simple API calls. It eliminates local setup requirements while maintaining full VS Code functionality through the Hoody proxy system.

**Key Characteristics**:
- **URL-Based Access**: Each instance has a predictable domain pattern
- **Built-in Authentication**: Integrated with Hoody's session management
- **Extension Marketplace**: Install extensions remotely via API
- **Local Port Proxying**: Expose local services to the web interface
- **PWA Support**: Installable as a progressive web app

## Common Workflows

### 1. Authentication Flow

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = await HoodyClient.authenticate('https://api.hoody.com', {
  username: 'your-username',
  password: 'your-password'
})

// Step 1: Check if already authenticated
const isReady = await client.code.vscode.getVSCode()
// If successful, you're authenticated and can access VS Code

// Step 2: Manual login if needed (for password auth)
const loginPage = await client.code.auth.getLoginPage()
// Inspect loginPage for any additional required fields

// Step 3: Submit credentials
await client.code.auth.login()
// Returns success or redirects to VS Code

// Step 4: Logout when done
await client.code.auth.logout()
```

**State Verification**: After login, call `getVSCode()` - success indicates authenticated session.

### 2. VS Code Interface Access

```
// Get main VS Code web interface
const vscode = await client.code.vscode.getVSCode()

// Get PWA manifest for installation
const manifest = await client.code.vscode.getManifest()
// Contains app name, icons, and installation metadata

// Generate encryption key for web connections
const key = await client.code.vscode.mintKey()
// Returns 256-bit key stored in user data
```

**When to Use PWA Manifest**: After initial setup, use the manifest to enable "Add to Home Screen" functionality for app-like access.

### 3. Extension Management

```
// List all installed extensions
const extensions = await client.code.extensions.list()
// Returns array of extension objects with metadata

// Install extension from VSIX URL
await client.code.extensions.install({
  url: 'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-python/vsextensions/python/2024.1.0/vspackage'
})

// Verify installation
const updatedList = await client.code.extensions.list()
const pythonInstalled = updatedList.some(ext => 
  ext.identifier.id === 'ms-python.python'
)
```

**Performance Note**: Extension installations may take 10-30 seconds. Always verify success with `list()`.

### 4. Health Monitoring

```
// Check service health
const health = await client.code.health.check()
// Returns process info, uptime, and status

// Check for updates
const updates = await client.code.health.checkUpdate()
// Queries GitHub releases API (if not disabled)
```

**Important**: Health checks don't affect "heartbeat" activity counters - use freely for monitoring.

### 5. Local Service Proxying

```
// Proxy to local app with path stripping
const data = await client.code.proxy.resolve({
  port: 3000,
  path: 'api/data'
})
// Proxies to http://localhost:3000/data (path prefix removed)

// Proxy with absolute path preservation
const config = await client.code.proxy.resolveAbsolute({
  port: 8080,
  path: '/admin/settings'
})
// Proxies to http://localhost:8080/admin/settings (full path kept)
```

**Use Cases**: 
- Preview React/Angular apps running locally
- Access database admin panels (like pgAdmin)
- Test API endpoints during development

### 6. Static File Access

```
// Get security policy
const security = await client.code.static.getSecurityPolicy()
// Returns vulnerability disclosure information

// Get robots.txt
const robots = await client.code.static.getRobots()
// Controls search engine crawling

// Get static asset
const script = await client.code.static.get(
  'vs/workbench/workbench.web.main.js'
)
// Access built VS Code resources

// Get Hoody-injected scripts
const injected = await client.code.static.getInjectedScript(
  'hoody-integration.js'
)
// Scripts loaded when --hoody-code flag is enabled
```

## Advanced Operations

### Automated Development Environment Setup

```
async function setupDevEnvironment(projectUrl: string) {
  try {
    // 1. Ensure clean session
    try {
      await client.code.auth.logout()
    } catch (e) {
      // Already logged out
    }
    
    // 2. Authenticate fresh
    await client.code.auth.login()
    
    // 3. Install essential extensions
    const essentials = [
      'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-python/vsextensions/python/2024.1.0/vspackage',
      'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/bradlc/vscode-tailwindcss/0.12.0/vspackage'
    ]
    
    for (const url of essentials) {
      await client.code.extensions.install({ url })
    }
    
    // 4. Verify setup
    const extensions = await client.code.extensions.list()
    const required = ['ms-python.python', 'bradlc.vscode-tailwindcss']
    
    const missing = required.filter(id => 
      !extensions.some(ext => ext.identifier.id === id)
    )
    
    if (missing.length > 0) {
      throw new Error(`Missing extensions: ${missing.join(', ')}`)
    }
    
    // 5. Generate encryption key
    await client.code.vscode.mintKey()
    
    // 6. Return success with access URL
    return {
      success: true,
      url: `https://{project}-{container}-code-{service}.{node}.containers.hoody.com`,
      extensions: extensions.length
    }
    
  } catch (error) {
    console.error('Setup failed:', error)
    throw error
  }
}
```

### Error Recovery Patterns

```
async function resilientExtensionInstall(url: string, maxRetries = 3) {
  let attempt = 0
  
  while (attempt < maxRetries) {
    try {
      await client.code.extensions.install({ url })
      
      // Verify installation succeeded
      const list = await client.code.extensions.list()
      const extensionId = url.split('/').pop()?.split('-')[0]
      
      if (list.some(ext => ext.identifier.id.includes(extensionId!))) {
        return true
      }
      
      throw new Error('Extension not found after installation')
      
    } catch (error) {
      attempt++
      
      if (attempt === maxRetries) {
        throw new Error(`Failed to install ${url} after ${maxRetries} attempts: ${error}`)
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000
      await new Promise(resolve => setTimeout(resolve, delay))
    }
  }
  
  return false
}
```

### Performance Optimization

```
// Parallel extension installation
async function installExtensionsParallel(urls: string[]) {
  const results = await Promise.allSettled(
    urls.map(url => 
      client.code.extensions.install({ url })
        .then(() => ({ url, success: true }))
        .catch(error => ({ url, success: false, error: error.message }))
    )
  )
  
  return {
    successful: results.filter(r => r.status === 'fulfilled' && r.value.success).length,
    failed: results.filter(r => r.status === 'rejected' || !r.value?.success).length,
    results: results.map(r => r.status === 'fulfilled' ? r.value : r.reason)
  }
}

// Cache health check results
let lastHealthCheck: any = null
let lastCheckTime = 0

async function getCachedHealth() {
  const now = Date.now()
  if (now - lastCheckTime < 60000 && lastHealthCheck) {
    return lastHealthCheck
  }
  
  lastHealthCheck = await client.code.health.check()
  lastCheckTime = now
  return lastHealthCheck
}
```

## Quick Reference

### Most Common Endpoints

| Endpoint | Method | SDK Method | Required Parameters |
|----------|--------|------------|---------------------|
| `/api/v1/code` | GET | `getVSCode()` | - |
| `/api/v1/code/extensions/install` | POST | `install({ url })` | `url: string` |
| `/api/v1/code/extensions/list` | GET | `list()` | - |
| `/api/v1/code/health` | GET | `health.check()` | - |
| `/api/v1/code/proxy/{port}/{path}` | GET | `proxy.resolve({ port, path })` | `port: string` |
| `/api/v1/code/login` | POST | `auth.login()` | - |

### Essential Parameters

**Proxy Endpoints**:
- `port`: Local port number (1024-65535)
- `path`: Path to proxy (optional)

**Extension Installation**:
- `url`: HTTPS URL to VSIX file

### Typical Response Formats

**Health Check**:
```
{
  "status": "healthy",
  "version": "1.0.0",
  "uptime": 12345,
  "processes": {
    "main": {
      "pid": 1234,
      "memory": 50000000
    }
  }
}
```

**Extension List**:
```
[
  {
    "identifier": {
      "id": "ms-python.python",
      "uuid": "12345678-1234-1234-1234-123456789abc"
    },
    "version": "2024.1.0",
    "name": "Python",
    "publisher": "ms-python"
  }
]
```

**Base URL Pattern**:
```
https://{projectId}-{containerId}-code-{serviceId}.{node}.containers.hoody.com
```

### Important Notes

1. **Authentication**: Sessions are cookie-based; use `auth.login()`/`auth.logout()`
2. **Rate Limiting**: Login has 2 attempts/minute, 12 attempts/hour
3. **Update Checks**: Occur every 6 hours, notifications weekly
4. **Proxy Ports**: Must be between 1024-65535
5. **Extension URLs**: Must be HTTPS VSIX files from valid sources