From 4461bf70c86eec7503c058c7b9b26693f06889c3 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Thu, 15 Jan 2026 06:38:45 +1000 Subject: [PATCH] feat(unsandbox): add code execution tools for unsandbox API - Add 4 new tools: executeCodeAsync, getJob, execute, run - Support 42+ programming languages - Features: network isolation modes, input files, compiled artifacts, WASM - Add entity definitions for code execution results - All tools pass schema and shape validation --- packages/tools/official/blocks.yml | 215 ++++++++ packages/tools/official/unsandbox/block.ts | 18 + packages/tools/official/unsandbox/index.ts | 6 + .../tools/official/unsandbox/package.json | 110 ++++ .../tools/official/unsandbox/src/index.ts | 503 ++++++++++++++++++ .../tools/official/unsandbox/tsconfig.json | 11 + .../tools/official/unsandbox/tsup.config.ts | 10 + pnpm-lock.yaml | 16 + 8 files changed, 889 insertions(+) create mode 100644 packages/tools/official/unsandbox/block.ts create mode 100644 packages/tools/official/unsandbox/index.ts create mode 100644 packages/tools/official/unsandbox/package.json create mode 100644 packages/tools/official/unsandbox/src/index.ts create mode 100644 packages/tools/official/unsandbox/tsconfig.json create mode 100644 packages/tools/official/unsandbox/tsup.config.ts diff --git a/packages/tools/official/blocks.yml b/packages/tools/official/blocks.yml index ff95006..160383d 100644 --- a/packages/tools/official/blocks.yml +++ b/packages/tools/official/blocks.yml @@ -367,6 +367,33 @@ domain: fields: [mode, allowedDomains, rules] description: "DNS-based network filtering configuration" + # ------------------------------------------------------------------------- + # Code execution entities (unsandbox) + # ------------------------------------------------------------------------- + code_execution_result: + fields: [stdout, stderr, exitCode, duration, language] + description: "Result of executing code in a sandbox" + + code_execution_job: + fields: [jobId, status, createdAt, language] + description: "Async code execution job reference" + + code_job_result: + fields: [jobId, status, stdout, stderr, exitCode, duration, error] + description: "Completed job result with output" + + input_file: + fields: [filename, content] + description: "File to make available in sandbox /tmp/input/" + + compiled_artifact: + fields: [binary, format, size] + description: "Compiled binary artifact from code execution" + + wasm_artifact: + fields: [wasm, format, size] + description: "WebAssembly compiled artifact" + # ------------------------------------------------------------------------- # Agent & workflow entities # ------------------------------------------------------------------------- @@ -4951,6 +4978,194 @@ blocks: description: "Whether the policy was successfully applied" measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation] + # --------------------------------------------------------------------------- + # M) Code Execution - Unsandbox (4 tools) + # --------------------------------------------------------------------------- + unsandbox.executeCodeAsync: + type: utility + description: "Execute code asynchronously in a secure sandbox. Returns a job_id immediately. Use getJob to check status and retrieve results. Supports 42+ languages including Python, JavaScript, TypeScript, Go, Rust, C, C++, Java, Ruby, and more." + path: "unsandbox" + domain_rules: + - id: api_integration + description: "Must call Unsandbox API POST /execute/async endpoint" + - id: language_support + description: | + Must support these languages: python, javascript, typescript, ruby, perl, php, lua, bash, r, + elixir, erlang, tcl, scheme, powershell, clojure, commonlisp, crystal, groovy, deno, awk, raku, + c, cpp, go, rust, java, kotlin, cobol, fortran, d, zig, nim, v, objc, dart, julia, haskell, + ocaml, fsharp, csharp, prolog, forth + - id: network_modes + description: "Must support 'zerotrust' (default, blocks all network) and 'semitrusted' (allows outbound)" + - id: input_files + description: "Must support optional input_files array with filename and base64 content" + inputs: + - name: language + type: string + description: "Programming language to execute (e.g., 'python', 'javascript', 'go', 'rust')" + - name: code + type: string + description: "The source code to execute" + - name: input_files + type: InputFile[] + optional: true + description: "Optional array of input files to make available in /tmp/input/" + - name: network_mode + type: "'zerotrust' | 'semitrusted'" + optional: true + description: "Network isolation mode. 'zerotrust' (default) blocks all network. 'semitrusted' allows outbound." + - name: ttl + type: number + optional: true + description: "Execution timeout in seconds (1-900). Default: 60." + - name: return_artifact + type: boolean + optional: true + description: "For compiled languages, return the compiled binary" + - name: return_wasm_artifact + type: boolean + optional: true + description: "Compile to WebAssembly. Supported for C, C++, Rust, Zig, Go." + outputs: + - name: job_id + type: string + description: "Job ID to use with getJob to retrieve results" + - name: status + type: string + description: "Initial job status (typically 'queued' or 'running')" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation] + + unsandbox.getJob: + type: utility + description: "Get the status and results of an async code execution job. Poll this endpoint until status is 'completed' or 'failed'." + path: "unsandbox" + domain_rules: + - id: api_integration + description: "Must call Unsandbox API GET /jobs/{job_id} endpoint" + - id: status_handling + description: "Must handle all status values: queued, running, completed, failed" + inputs: + - name: job_id + type: string + description: "The job ID returned from executeCodeAsync" + outputs: + - name: job_id + type: string + description: "The job ID" + - name: status + type: string + description: "Job status: 'queued', 'running', 'completed', or 'failed'" + - name: stdout + type: string + optional: true + description: "Standard output from execution (when completed)" + - name: stderr + type: string + optional: true + description: "Standard error from execution (when completed)" + - name: exit_code + type: number + optional: true + description: "Exit code from execution (when completed)" + - name: duration_ms + type: number + optional: true + description: "Execution duration in milliseconds (when completed)" + - name: error + type: string + optional: true + description: "Error message (when failed)" + - name: artifact + type: string + optional: true + description: "Base64-encoded compiled binary (if return_artifact was true)" + - name: wasm_artifact + type: string + optional: true + description: "Base64-encoded WebAssembly binary (if return_wasm_artifact was true)" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation] + + unsandbox.execute: + type: utility + description: "Execute code synchronously in a secure sandbox. Blocks until execution completes and returns results directly. Best for quick scripts under 60 seconds." + path: "unsandbox" + domain_rules: + - id: api_integration + description: "Must call Unsandbox API POST /execute endpoint (sync)" + - id: timeout_handling + description: "Must handle execution timeout gracefully" + inputs: + - name: language + type: string + description: "Programming language to execute" + - name: code + type: string + description: "The source code to execute" + - name: input_files + type: InputFile[] + optional: true + description: "Optional array of input files to make available in /tmp/input/" + - name: network_mode + type: "'zerotrust' | 'semitrusted'" + optional: true + description: "Network isolation mode. Default: 'zerotrust'" + - name: ttl + type: number + optional: true + description: "Execution timeout in seconds (1-900). Default: 60." + outputs: + - name: stdout + type: string + description: "Standard output from execution" + - name: stderr + type: string + description: "Standard error from execution" + - name: exit_code + type: number + description: "Exit code from execution" + - name: duration_ms + type: number + description: "Execution duration in milliseconds" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation] + + unsandbox.run: + type: utility + description: "Execute code with automatic language detection from shebang. Send raw code with a shebang line (e.g., #!/usr/bin/env python) and the language is auto-detected." + path: "unsandbox" + domain_rules: + - id: api_integration + description: "Must call Unsandbox API POST /run endpoint with text/plain content type" + - id: shebang_detection + description: "Language is auto-detected from shebang line in code" + inputs: + - name: code + type: string + description: "The source code with shebang line (e.g., #!/usr/bin/env python)" + - name: network_mode + type: "'zerotrust' | 'semitrusted'" + optional: true + description: "Network isolation mode. Default: 'zerotrust'" + - name: ttl + type: number + optional: true + description: "Execution timeout in seconds (1-900). Default: 60." + outputs: + - name: stdout + type: string + description: "Standard output from execution" + - name: stderr + type: string + description: "Standard error from execution" + - name: exit_code + type: number + description: "Exit code from execution" + - name: detected_language + type: string + description: "Language detected from shebang" + - name: duration_ms + type: number + description: "Execution duration in milliseconds" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation] + # ============================================================================= # VALIDATORS - Which validators to run against each block # ============================================================================= diff --git a/packages/tools/official/unsandbox/block.ts b/packages/tools/official/unsandbox/block.ts new file mode 100644 index 0000000..1589101 --- /dev/null +++ b/packages/tools/official/unsandbox/block.ts @@ -0,0 +1,18 @@ +/** + * Block metadata for unsandbox tools + * This file provides metadata for the blocks validator + */ +import { execute, executeCodeAsync, getJob, run } from './src/index.js'; + +export const block = { + name: 'unsandbox', + description: 'Execute code in a secure sandbox environment supporting 42+ languages', + tools: { + executeCodeAsync, + getJob, + execute, + run, + }, +}; + +export default block; diff --git a/packages/tools/official/unsandbox/index.ts b/packages/tools/official/unsandbox/index.ts new file mode 100644 index 0000000..71ed0d7 --- /dev/null +++ b/packages/tools/official/unsandbox/index.ts @@ -0,0 +1,6 @@ +/** + * Unsandbox Code Execution Tools + * Re-exports from src/index.ts for blocks validator compatibility + */ +export * from './src/index.js'; +export { default } from './src/index.js'; diff --git a/packages/tools/official/unsandbox/package.json b/packages/tools/official/unsandbox/package.json new file mode 100644 index 0000000..655cef5 --- /dev/null +++ b/packages/tools/official/unsandbox/package.json @@ -0,0 +1,110 @@ +{ + "name": "@tpmjs/tools-unsandbox", + "version": "0.1.0", + "description": "Execute code in a secure sandbox environment. Supports 42+ programming languages with async execution, input files, and compiled artifacts.", + "type": "module", + "keywords": [ + "tpmjs", + "code-execution", + "sandbox", + "unsandbox", + "ai" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist .turbo" + }, + "devDependencies": { + "@tpmjs/tsconfig": "workspace:*", + "tsup": "^8.5.1", + "typescript": "^5.9.3" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/tpmjs/tpmjs.git", + "directory": "packages/tools/official/unsandbox" + }, + "homepage": "https://tpmjs.com", + "license": "MIT", + "tpmjs": { + "category": "code-execution", + "frameworks": [ + "vercel-ai" + ], + "tools": [ + { + "name": "executeCodeAsync", + "description": "Execute code asynchronously in a secure sandbox. Returns a job_id immediately. Use getJob to check status and retrieve results.", + "parameters": [ + { + "name": "language", + "type": "string", + "description": "Programming language to execute", + "required": true + }, + { + "name": "code", + "type": "string", + "description": "The source code to execute", + "required": true + }, + { + "name": "input_files", + "type": "array", + "description": "Optional array of input files", + "required": false + }, + { + "name": "network_mode", + "type": "string", + "description": "Network isolation mode: zerotrust or semitrusted", + "required": false + }, + { + "name": "ttl", + "type": "number", + "description": "Execution timeout in seconds (1-900)", + "required": false + } + ], + "returns": { + "type": "object", + "description": "Job ID and initial status" + } + }, + { + "name": "getJob", + "description": "Get the status and results of an async code execution job", + "parameters": [ + { + "name": "job_id", + "type": "string", + "description": "The job ID returned from executeCodeAsync", + "required": true + } + ], + "returns": { + "type": "object", + "description": "Job status and results" + } + } + ] + }, + "dependencies": { + "ai": "6.0.23" + } +} diff --git a/packages/tools/official/unsandbox/src/index.ts b/packages/tools/official/unsandbox/src/index.ts new file mode 100644 index 0000000..57d8bde --- /dev/null +++ b/packages/tools/official/unsandbox/src/index.ts @@ -0,0 +1,503 @@ +/** + * Unsandbox Code Execution Tools for TPMJS + * Execute code in a secure sandbox environment supporting 42+ languages. + * + * @requires UNSANDBOX_API_KEY environment variable + */ + +import { jsonSchema, tool } from 'ai'; + +const UNSANDBOX_API_BASE = 'https://api.unsandbox.com'; + +/** + * Supported programming languages + */ +export const SUPPORTED_LANGUAGES = [ + 'python', + 'javascript', + 'typescript', + 'ruby', + 'perl', + 'php', + 'lua', + 'bash', + 'r', + 'elixir', + 'erlang', + 'tcl', + 'scheme', + 'powershell', + 'clojure', + 'commonlisp', + 'crystal', + 'groovy', + 'deno', + 'awk', + 'raku', + 'c', + 'cpp', + 'go', + 'rust', + 'java', + 'kotlin', + 'cobol', + 'fortran', + 'd', + 'zig', + 'nim', + 'v', + 'objc', + 'dart', + 'julia', + 'haskell', + 'ocaml', + 'fsharp', + 'csharp', + 'prolog', + 'forth', +] as const; + +export type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number]; + +export type NetworkMode = 'zerotrust' | 'semitrusted'; + +export interface InputFile { + filename: string; + content: string; // Base64 encoded +} + +export interface ExecuteAsyncInput { + language: string; + code: string; + input_files?: InputFile[]; + network_mode?: NetworkMode; + ttl?: number; + return_artifact?: boolean; + return_wasm_artifact?: boolean; +} + +export interface ExecuteAsyncResult { + job_id: string; + status: string; +} + +export interface GetJobInput { + job_id: string; +} + +export interface GetJobResult { + job_id: string; + status: 'queued' | 'running' | 'completed' | 'failed'; + stdout?: string; + stderr?: string; + exit_code?: number; + duration_ms?: number; + error?: string; + artifact?: string; + wasm_artifact?: string; +} + +function getApiKey(): string { + const key = process.env.UNSANDBOX_API_KEY; + if (!key) { + throw new Error( + 'UNSANDBOX_API_KEY environment variable is required. Get your API key from https://unsandbox.com' + ); + } + return key; +} + +/** + * Execute code asynchronously in a secure sandbox. + * Returns a job_id immediately. Use getJob to check status and retrieve results. + * Supports 42+ languages including Python, JavaScript, TypeScript, Go, Rust, C, C++, Java, Ruby, and more. + */ +export const executeCodeAsync = tool({ + description: + 'Execute code asynchronously in a secure sandbox. Returns a job_id immediately. Use getJob to check status and retrieve results. Supports 42+ languages including Python, JavaScript, TypeScript, Go, Rust, C, C++, Java, Ruby, and more.', + inputSchema: jsonSchema({ + type: 'object', + properties: { + language: { + type: 'string', + description: + 'Programming language to execute. Supported: python, javascript, typescript, ruby, perl, php, lua, bash, r, elixir, erlang, tcl, scheme, powershell, clojure, commonlisp, crystal, groovy, deno, awk, raku, c, cpp, go, rust, java, kotlin, cobol, fortran, d, zig, nim, v, objc, dart, julia, haskell, ocaml, fsharp, csharp, prolog, forth.', + }, + code: { + type: 'string', + description: 'The source code to execute.', + }, + input_files: { + type: 'array', + description: 'Optional array of input files to make available in /tmp/input/.', + items: { + type: 'object', + properties: { + filename: { + type: 'string', + description: 'Name of the file.', + }, + content: { + type: 'string', + description: 'Base64-encoded file content.', + }, + }, + required: ['filename', 'content'], + }, + }, + network_mode: { + type: 'string', + enum: ['zerotrust', 'semitrusted'], + description: + 'Network isolation mode. "zerotrust" (default) blocks all network. "semitrusted" allows outbound.', + }, + ttl: { + type: 'number', + description: 'Execution timeout in seconds (1-900). Default: 60.', + }, + return_artifact: { + type: 'boolean', + description: 'For compiled languages, return the compiled binary.', + }, + return_wasm_artifact: { + type: 'boolean', + description: 'Compile to WebAssembly. Supported for C, C++, Rust, Zig, Go.', + }, + }, + required: ['language', 'code'], + additionalProperties: false, + }), + async execute(input: ExecuteAsyncInput): Promise { + const apiKey = getApiKey(); + + // Validate language + if (!input.language || typeof input.language !== 'string') { + throw new Error('Language is required and must be a string'); + } + + if (!input.code || typeof input.code !== 'string') { + throw new Error('Code is required and must be a string'); + } + + // Validate TTL if provided + if (input.ttl !== undefined && (input.ttl < 1 || input.ttl > 900)) { + throw new Error('TTL must be between 1 and 900 seconds'); + } + + const requestBody: Record = { + language: input.language.toLowerCase(), + code: input.code, + }; + + if (input.input_files) { + requestBody.input_files = input.input_files; + } + + if (input.network_mode) { + requestBody.network_mode = input.network_mode; + } + + if (input.ttl) { + requestBody.ttl = input.ttl; + } + + if (input.return_artifact) { + requestBody.return_artifact = input.return_artifact; + } + + if (input.return_wasm_artifact) { + requestBody.return_wasm_artifact = input.return_wasm_artifact; + } + + const response = await fetch(`${UNSANDBOX_API_BASE}/execute/async`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`Unsandbox API error: HTTP ${response.status} - ${errorText}`); + } + + const result = (await response.json()) as { job_id: string; status?: string }; + + return { + job_id: result.job_id, + status: result.status || 'queued', + }; + }, +}); + +/** + * Get the status and results of an async code execution job. + * Poll this endpoint until status is 'completed' or 'failed'. + */ +export const getJob = tool({ + description: + "Get the status and results of an async code execution job. Poll this endpoint until status is 'completed' or 'failed'.", + inputSchema: jsonSchema({ + type: 'object', + properties: { + job_id: { + type: 'string', + description: 'The job ID returned from executeCodeAsync', + }, + }, + required: ['job_id'], + additionalProperties: false, + }), + async execute(input: GetJobInput): Promise { + const apiKey = getApiKey(); + + if (!input.job_id || typeof input.job_id !== 'string') { + throw new Error('job_id is required and must be a string'); + } + + const response = await fetch(`${UNSANDBOX_API_BASE}/jobs/${encodeURIComponent(input.job_id)}`, { + method: 'GET', + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }); + + if (!response.ok) { + if (response.status === 404) { + throw new Error(`Job not found: ${input.job_id}`); + } + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`Unsandbox API error: HTTP ${response.status} - ${errorText}`); + } + + const result = (await response.json()) as GetJobResult; + + return { + job_id: result.job_id || input.job_id, + status: result.status, + stdout: result.stdout, + stderr: result.stderr, + exit_code: result.exit_code, + duration_ms: result.duration_ms, + error: result.error, + artifact: result.artifact, + wasm_artifact: result.wasm_artifact, + }; + }, +}); + +/** + * Sync execution interfaces + */ +export interface ExecuteSyncInput { + language: string; + code: string; + input_files?: InputFile[]; + network_mode?: NetworkMode; + ttl?: number; +} + +export interface ExecuteSyncResult { + stdout: string; + stderr: string; + exit_code: number; + duration_ms: number; +} + +export interface RunInput { + code: string; + network_mode?: NetworkMode; + ttl?: number; +} + +export interface RunResult { + stdout: string; + stderr: string; + exit_code: number; + detected_language: string; + duration_ms: number; +} + +/** + * Execute code synchronously in a secure sandbox. + * Blocks until execution completes and returns results directly. + * Best for quick scripts under 60 seconds. + */ +export const execute = tool({ + description: + 'Execute code synchronously in a secure sandbox. Blocks until execution completes and returns results directly. Best for quick scripts under 60 seconds.', + inputSchema: jsonSchema({ + type: 'object', + properties: { + language: { + type: 'string', + description: 'Programming language to execute', + }, + code: { + type: 'string', + description: 'The source code to execute', + }, + input_files: { + type: 'array', + description: 'Optional array of input files to make available in /tmp/input/', + items: { + type: 'object', + properties: { + filename: { type: 'string' }, + content: { type: 'string' }, + }, + required: ['filename', 'content'], + }, + }, + network_mode: { + type: 'string', + enum: ['zerotrust', 'semitrusted'], + description: "Network isolation mode. Default: 'zerotrust'", + }, + ttl: { + type: 'number', + description: 'Execution timeout in seconds (1-900). Default: 60.', + }, + }, + required: ['language', 'code'], + additionalProperties: false, + }), + async execute(input: ExecuteSyncInput): Promise { + const apiKey = getApiKey(); + + if (!input.language || typeof input.language !== 'string') { + throw new Error('Language is required and must be a string'); + } + + if (!input.code || typeof input.code !== 'string') { + throw new Error('Code is required and must be a string'); + } + + if (input.ttl !== undefined && (input.ttl < 1 || input.ttl > 900)) { + throw new Error('TTL must be between 1 and 900 seconds'); + } + + const requestBody: Record = { + language: input.language.toLowerCase(), + code: input.code, + }; + + if (input.input_files) { + requestBody.input_files = input.input_files; + } + + if (input.network_mode) { + requestBody.network_mode = input.network_mode; + } + + if (input.ttl) { + requestBody.ttl = input.ttl; + } + + const response = await fetch(`${UNSANDBOX_API_BASE}/execute`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`Unsandbox API error: HTTP ${response.status} - ${errorText}`); + } + + const result = (await response.json()) as ExecuteSyncResult; + + return { + stdout: result.stdout || '', + stderr: result.stderr || '', + exit_code: result.exit_code ?? 0, + duration_ms: result.duration_ms || 0, + }; + }, +}); + +/** + * Execute code with automatic language detection from shebang. + * Send raw code with a shebang line (e.g., #!/usr/bin/env python) and the language is auto-detected. + */ +export const run = tool({ + description: + 'Execute code with automatic language detection from shebang. Send raw code with a shebang line (e.g., #!/usr/bin/env python) and the language is auto-detected.', + inputSchema: jsonSchema({ + type: 'object', + properties: { + code: { + type: 'string', + description: 'The source code with shebang line (e.g., #!/usr/bin/env python)', + }, + network_mode: { + type: 'string', + enum: ['zerotrust', 'semitrusted'], + description: "Network isolation mode. Default: 'zerotrust'", + }, + ttl: { + type: 'number', + description: 'Execution timeout in seconds (1-900). Default: 60.', + }, + }, + required: ['code'], + additionalProperties: false, + }), + async execute(input: RunInput): Promise { + const apiKey = getApiKey(); + + if (!input.code || typeof input.code !== 'string') { + throw new Error('Code is required and must be a string'); + } + + if (input.ttl !== undefined && (input.ttl < 1 || input.ttl > 900)) { + throw new Error('TTL must be between 1 and 900 seconds'); + } + + // Build query params for network_mode and ttl + const url = new URL(`${UNSANDBOX_API_BASE}/run`); + if (input.network_mode) { + url.searchParams.set('network_mode', input.network_mode); + } + if (input.ttl) { + url.searchParams.set('ttl', input.ttl.toString()); + } + + const response = await fetch(url.toString(), { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + Authorization: `Bearer ${apiKey}`, + }, + body: input.code, + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`Unsandbox API error: HTTP ${response.status} - ${errorText}`); + } + + const result = (await response.json()) as RunResult; + + return { + stdout: result.stdout || '', + stderr: result.stderr || '', + exit_code: result.exit_code ?? 0, + detected_language: result.detected_language || 'unknown', + duration_ms: result.duration_ms || 0, + }; + }, +}); + +// Default export for convenience +export default { + executeCodeAsync, + getJob, + execute, + run, +}; diff --git a/packages/tools/official/unsandbox/tsconfig.json b/packages/tools/official/unsandbox/tsconfig.json new file mode 100644 index 0000000..6521d56 --- /dev/null +++ b/packages/tools/official/unsandbox/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@tpmjs/tsconfig/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "incremental": false, + "composite": false + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/tools/official/unsandbox/tsup.config.ts b/packages/tools/official/unsandbox/tsup.config.ts new file mode 100644 index 0000000..a242871 --- /dev/null +++ b/packages/tools/official/unsandbox/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + clean: true, + treeshake: true, + splitting: false, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f81e7e..5718eac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3540,6 +3540,22 @@ importers: specifier: ^5.9.3 version: 5.9.3 + packages/tools/official/unsandbox: + dependencies: + ai: + specifier: 6.0.23 + version: 6.0.23(zod@4.3.5) + devDependencies: + '@tpmjs/tsconfig': + specifier: workspace:* + version: link:../../../config/tsconfig + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + packages/tools/official/url-normalize: dependencies: ai: