feat(exe-dev): add exe.dev VM management tools v0.2.3

Add 15 MCP tools for managing exe.dev virtual machines:
- list, create, deleteVm, restart - VM lifecycle management
- exec - execute commands on VMs via SSH
- shareShow, shareSetPublic, shareSetPrivate - visibility control
- sharePort - configure HTTP proxy port
- shareAddUser, shareRemoveUser - user access management
- shareAddLink, shareRemoveLink - shareable link management
- whoami - user account info
- shelleyInstall - install Shelley agent

Key fixes in v0.2.3:
- Properly quote SSH args to prevent local shell interpretation
- Add -- separator for commands to prevent flag parsing issues
- Support base64-encoded SSH key via EXE_DEV_SSH_KEY env var
This commit is contained in:
Ajax Davis 2026-01-15 09:49:08 +10:00
parent cae05f1504
commit c21ed5b41e
8 changed files with 1184 additions and 0 deletions

View file

@ -394,6 +394,33 @@ domain:
fields: [wasm, format, size]
description: "WebAssembly compiled artifact"
# -------------------------------------------------------------------------
# exe.dev VM management entities
# -------------------------------------------------------------------------
exe_vm:
fields: [name, image, status, createdAt, url]
description: "An exe.dev virtual machine instance"
exe_vm_list:
fields: [vms, count]
description: "List of exe.dev VMs"
exe_share_info:
fields: [vm, isPublic, port, users, links]
description: "Sharing configuration for an exe.dev VM"
exe_share_link:
fields: [token, url, createdAt]
description: "A shareable link for VM access"
exe_user_info:
fields: [email, sshKeys]
description: "exe.dev user account information"
exe_command_result:
fields: [stdout, stderr, exitCode]
description: "Result of executing a command on an exe.dev VM"
# -------------------------------------------------------------------------
# Agent & workflow entities
# -------------------------------------------------------------------------
@ -5235,6 +5262,300 @@ blocks:
description: "The cancelled job ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance, readme_documentation]
# ---------------------------------------------------------------------------
# Q) exe.dev VM Management (15 tools)
# ---------------------------------------------------------------------------
exe.list:
type: utility
description: "List all exe.dev virtual machines for the authenticated user. Returns VM names, images, status, and URLs."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev ls --json' command"
- id: json_parsing
description: "Must parse JSON output into structured VM list"
inputs: []
outputs:
- name: vms
type: exe_vm_list
description: "List of VMs with their details"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.create:
type: utility
description: "Create a new exe.dev virtual machine. Supports custom images, environment variables, and Shelley prompts."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev new' with appropriate flags"
- id: option_building
description: "Must properly format --name, --image, --env, --prompt flags"
inputs:
- name: name
type: string
optional: true
description: "VM name (auto-generated if not provided)"
- name: image
type: string
optional: true
description: "Container image (default: exeuntu)"
- name: env
type: object
optional: true
description: "Environment variables as key-value pairs"
- name: prompt
type: string
optional: true
description: "Initial prompt to send to Shelley after creation"
- name: command
type: string
optional: true
description: "Container command mode: auto, none, or custom command"
outputs:
- name: vm
type: exe_vm
description: "Created VM details including name and URL"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.delete:
type: utility
description: "Delete an exe.dev virtual machine. This permanently removes the VM and its data."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev rm <vmname> --json'"
inputs:
- name: name
type: string
description: "Name of the VM to delete"
outputs:
- name: deleted
type: boolean
description: "Whether the VM was successfully deleted"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.restart:
type: utility
description: "Restart an exe.dev virtual machine. Useful for applying changes or recovering from issues."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev restart <vmname> --json'"
inputs:
- name: name
type: string
description: "Name of the VM to restart"
outputs:
- name: restarted
type: boolean
description: "Whether the VM was successfully restarted"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.exec:
type: utility
description: "Execute a command on an exe.dev VM via SSH. Returns stdout, stderr, and exit code."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev ssh <vmname> <command>'"
- id: output_capture
description: "Must capture and return stdout, stderr, and exit code"
inputs:
- name: vm
type: string
description: "Name of the VM to execute on"
- name: command
type: string
description: "Command to execute on the VM"
outputs:
- name: result
type: exe_command_result
description: "Command execution result with stdout, stderr, exitCode"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareShow:
type: utility
description: "Show the sharing configuration for an exe.dev VM including public status, port, users, and share links."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share show <vmname> --json'"
inputs:
- name: vm
type: string
description: "Name of the VM"
outputs:
- name: share
type: exe_share_info
description: "Sharing configuration for the VM"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareSetPublic:
type: utility
description: "Make an exe.dev VM's HTTP proxy publicly accessible without authentication."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share set-public <vmname>'"
inputs:
- name: vm
type: string
description: "Name of the VM to make public"
outputs:
- name: success
type: boolean
description: "Whether the operation succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareSetPrivate:
type: utility
description: "Make an exe.dev VM's HTTP proxy private, requiring authentication to access."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share set-private <vmname>'"
inputs:
- name: vm
type: string
description: "Name of the VM to make private"
outputs:
- name: success
type: boolean
description: "Whether the operation succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.sharePort:
type: utility
description: "Configure the HTTP proxy port for an exe.dev VM. Traffic to the VM's URL will be forwarded to this port."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share port <vmname> <port>'"
inputs:
- name: vm
type: string
description: "Name of the VM"
- name: port
type: number
description: "Port number to proxy to (e.g., 8080)"
outputs:
- name: success
type: boolean
description: "Whether the port was successfully configured"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareAddUser:
type: utility
description: "Grant a user access to an exe.dev VM by email. Sends an invitation with optional custom message."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share add <vmname> <email>'"
inputs:
- name: vm
type: string
description: "Name of the VM"
- name: email
type: string
description: "Email address of user to invite"
- name: message
type: string
optional: true
description: "Custom invitation message"
outputs:
- name: success
type: boolean
description: "Whether the user was successfully added"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareRemoveUser:
type: utility
description: "Revoke a user's access to an exe.dev VM by email."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share remove <vmname> <email>'"
inputs:
- name: vm
type: string
description: "Name of the VM"
- name: email
type: string
description: "Email address of user to remove"
outputs:
- name: success
type: boolean
description: "Whether the user was successfully removed"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareAddLink:
type: utility
description: "Generate a shareable link for an exe.dev VM that can be shared with anyone."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share add-link <vmname> --json'"
inputs:
- name: vm
type: string
description: "Name of the VM"
outputs:
- name: link
type: exe_share_link
description: "Generated share link with token and URL"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shareRemoveLink:
type: utility
description: "Revoke a shareable link for an exe.dev VM."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev share remove-link <vmname> <token>'"
inputs:
- name: vm
type: string
description: "Name of the VM"
- name: token
type: string
description: "Token of the share link to remove"
outputs:
- name: success
type: boolean
description: "Whether the link was successfully removed"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.whoami:
type: utility
description: "Get the current exe.dev user's account information including email and SSH keys."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev whoami --json'"
inputs: []
outputs:
- name: user
type: exe_user_info
description: "User account information"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
exe.shelleyInstall:
type: utility
description: "Install or upgrade the Shelley agent on an exe.dev VM to the latest version."
path: "exe-dev"
domain_rules:
- id: ssh_execution
description: "Must execute 'ssh exe.dev shelley install <vmname>'"
inputs:
- name: vm
type: string
description: "Name of the VM to install Shelley on"
outputs:
- name: success
type: boolean
description: "Whether Shelley was successfully installed/upgraded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
# =============================================================================
# VALIDATORS - Which validators to run against each block
# =============================================================================

View file

@ -0,0 +1,45 @@
/**
* Block metadata for exe.dev tools
* This file provides metadata for the blocks validator
*/
import {
create,
deleteVm,
exec,
list,
restart,
shareAddLink,
shareAddUser,
sharePort,
shareRemoveLink,
shareRemoveUser,
shareSetPrivate,
shareSetPublic,
shareShow,
shelleyInstall,
whoami,
} from './src/index.js';
export const block = {
name: 'exe-dev',
description: 'Manage exe.dev virtual machines via SSH',
tools: {
list,
create,
deleteVm,
restart,
exec,
shareShow,
shareSetPublic,
shareSetPrivate,
sharePort,
shareAddUser,
shareRemoveUser,
shareAddLink,
shareRemoveLink,
whoami,
shelleyInstall,
},
};
export default block;

View file

@ -0,0 +1,6 @@
/**
* exe.dev VM Management Tools
* Re-exports from src/index.ts for blocks validator compatibility
*/
export * from './src/index.js';
export { default } from './src/index.js';

View file

@ -0,0 +1,123 @@
{
"name": "@tpmjs/tools-exe-dev",
"version": "0.2.3",
"description": "Manage exe.dev virtual machines. Create, list, delete, restart VMs, manage sharing, and execute commands via SSH.",
"type": "module",
"keywords": [
"tpmjs",
"exe.dev",
"vm",
"virtual-machine",
"ssh",
"cloud",
"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"
},
"dependencies": {
"ai": "6.0.23"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/tpmjs/tpmjs.git",
"directory": "packages/tools/official/exe-dev"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "ops",
"frameworks": [
"vercel-ai"
],
"env": [
{
"name": "EXE_DEV_SSH_KEY",
"description": "Base64-encoded SSH private key for exe.dev authentication. Generate with: cat ~/.ssh/id_ed25519 | base64",
"required": false
}
],
"tools": [
{
"name": "list",
"description": "List all exe.dev virtual machines for the authenticated user."
},
{
"name": "create",
"description": "Create a new exe.dev virtual machine with optional image, env vars, and Shelley prompt."
},
{
"name": "deleteVm",
"description": "Delete an exe.dev virtual machine permanently."
},
{
"name": "restart",
"description": "Restart an exe.dev virtual machine."
},
{
"name": "exec",
"description": "Execute a command on an exe.dev VM via SSH."
},
{
"name": "shareShow",
"description": "Show the sharing configuration for an exe.dev VM."
},
{
"name": "shareSetPublic",
"description": "Make an exe.dev VM's HTTP proxy publicly accessible."
},
{
"name": "shareSetPrivate",
"description": "Make an exe.dev VM's HTTP proxy private."
},
{
"name": "sharePort",
"description": "Configure the HTTP proxy port for an exe.dev VM."
},
{
"name": "shareAddUser",
"description": "Grant a user access to an exe.dev VM by email."
},
{
"name": "shareRemoveUser",
"description": "Revoke a user's access to an exe.dev VM."
},
{
"name": "shareAddLink",
"description": "Generate a shareable link for an exe.dev VM."
},
{
"name": "shareRemoveLink",
"description": "Revoke a shareable link for an exe.dev VM."
},
{
"name": "whoami",
"description": "Get the current exe.dev user's account information."
},
{
"name": "shelleyInstall",
"description": "Install or upgrade Shelley agent on an exe.dev VM."
}
]
}
}

View file

@ -0,0 +1,652 @@
/**
* exe.dev VM Management Tools for TPMJS
* Manage virtual machines on exe.dev via SSH commands.
*
* Authentication: Set EXE_DEV_SSH_KEY env var with your base64-encoded SSH private key.
* To encode your key: cat ~/.ssh/id_ed25519 | base64
*
* Alternatively, if running locally with SSH already configured, the tools will
* fall back to your default SSH config.
*/
import { exec as nodeExec } from 'node:child_process';
import { chmodSync, existsSync, unlinkSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { promisify } from 'node:util';
import { jsonSchema, tool } from 'ai';
const execAsync = promisify(nodeExec);
// Temp key file path (unique per process to avoid conflicts)
const KEY_FILE_PATH = join(tmpdir(), `exe-dev-key-${process.pid}`);
// ============================================================================
// Types
// ============================================================================
export interface ExeVM {
name: string;
image?: string;
status?: string;
createdAt?: string;
url?: string;
}
export interface ExeVMList {
vms: ExeVM[];
count: number;
}
export interface ExeShareInfo {
vm: string;
isPublic: boolean;
port?: number;
users: string[];
links: ExeShareLink[];
}
export interface ExeShareLink {
token: string;
url: string;
createdAt?: string;
}
export interface ExeUserInfo {
email: string;
sshKeys: string[];
}
export interface ExeCommandResult {
stdout: string;
stderr: string;
exitCode: number;
}
// Input types
interface CreateInput {
name?: string;
image?: string;
env?: Record<string, string>;
prompt?: string;
command?: string;
}
interface VmNameInput {
name: string;
}
interface ExecInput {
vm: string;
command: string;
}
interface VmInput {
vm: string;
}
interface SharePortInput {
vm: string;
port: number;
}
interface ShareUserInput {
vm: string;
email: string;
message?: string;
}
interface ShareRemoveUserInput {
vm: string;
email: string;
}
interface ShareRemoveLinkInput {
vm: string;
token: string;
}
// ============================================================================
// Helper Functions
// ============================================================================
/**
* Setup SSH key from environment variable if available.
* Returns the SSH command options to use the key, or empty string for default SSH config.
*/
function setupSshKey(): string {
const base64Key = process.env.EXE_DEV_SSH_KEY;
if (!base64Key) {
// No env var set, fall back to default SSH config
return '';
}
try {
// Decode base64 key
const keyContent = Buffer.from(base64Key, 'base64').toString('utf-8');
// Write to temp file with secure permissions
writeFileSync(KEY_FILE_PATH, keyContent, { mode: 0o600 });
// Double-check permissions (some systems may ignore mode in writeFileSync)
chmodSync(KEY_FILE_PATH, 0o600);
// Return SSH options to use this key
return `-i ${KEY_FILE_PATH} -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null`;
} catch (error) {
throw new Error(
`Failed to setup SSH key from EXE_DEV_SSH_KEY: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Cleanup the temporary SSH key file if it exists.
*/
function cleanupSshKey(): void {
try {
if (existsSync(KEY_FILE_PATH)) {
unlinkSync(KEY_FILE_PATH);
}
} catch {
// Ignore cleanup errors
}
}
/**
* Build the SSH command with appropriate options.
*/
function buildSshCommand(args: string): string {
const sshOptions = setupSshKey();
// Quote the entire args to prevent local shell interpretation
const escapedArgs = args.replace(/'/g, "'\\''");
if (sshOptions) {
return `ssh ${sshOptions} exe.dev '${escapedArgs}'`;
}
return `ssh exe.dev '${escapedArgs}'`;
}
async function runExeCommand(args: string): Promise<string> {
try {
const command = buildSshCommand(args);
const { stdout, stderr } = await execAsync(command, {
timeout: 60000, // 60 second timeout
});
if (stderr && !stdout) {
throw new Error(stderr);
}
return stdout.trim();
} catch (error) {
if (error instanceof Error) {
const message = error.message || 'Command failed';
throw new Error(`exe.dev command failed: ${message}`);
}
throw error;
} finally {
cleanupSshKey();
}
}
async function runExeCommandWithExit(
args: string
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
try {
const command = buildSshCommand(args);
const { stdout, stderr } = await execAsync(command, {
timeout: 60000,
});
return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode: 0 };
} catch (error: unknown) {
const execError = error as { stdout?: string; stderr?: string; code?: number };
return {
stdout: execError.stdout?.trim() || '',
stderr:
execError.stderr?.trim() || (error instanceof Error ? error.message : 'Unknown error'),
exitCode: execError.code || 1,
};
} finally {
cleanupSshKey();
}
}
function parseJsonOutput<T>(output: string): T {
try {
return JSON.parse(output) as T;
} catch {
throw new Error(`Failed to parse exe.dev output as JSON: ${output}`);
}
}
// ============================================================================
// Tools
// ============================================================================
/**
* List all exe.dev VMs
*/
export const list = tool({
description:
'List all exe.dev virtual machines for the authenticated user. Returns VM names, images, status, and URLs. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<Record<string, never>>({
type: 'object',
properties: {},
required: [],
additionalProperties: false,
}),
async execute(_input: Record<string, never>): Promise<ExeVMList> {
const output = await runExeCommand('ls --json');
const vms = parseJsonOutput<ExeVM[]>(output);
return {
vms,
count: vms.length,
};
},
});
/**
* Create a new exe.dev VM
*/
export const create = tool({
description:
'Create a new exe.dev virtual machine. Supports custom images, environment variables, and Shelley prompts. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<CreateInput>({
type: 'object',
properties: {
name: {
type: 'string',
description: 'VM name (auto-generated if not provided)',
},
image: {
type: 'string',
description: 'Container image (default: exeuntu)',
},
env: {
type: 'object',
description: 'Environment variables as key-value pairs',
additionalProperties: { type: 'string' },
},
prompt: {
type: 'string',
description: 'Initial prompt to send to Shelley after creation',
},
command: {
type: 'string',
description: 'Container command mode: auto, none, or custom command',
},
},
required: [],
additionalProperties: false,
}),
async execute(input: CreateInput): Promise<ExeVM> {
const args: string[] = ['new', '--json'];
if (input.name) {
args.push(`--name=${input.name}`);
}
if (input.image) {
args.push(`--image=${input.image}`);
}
if (input.command) {
args.push(`--command=${input.command}`);
}
if (input.prompt) {
args.push(`--prompt="${input.prompt.replace(/"/g, '\\"')}"`);
}
if (input.env) {
for (const [key, value] of Object.entries(input.env)) {
args.push(`--env ${key}=${value}`);
}
}
const output = await runExeCommand(args.join(' '));
return parseJsonOutput<ExeVM>(output);
},
});
/**
* Delete an exe.dev VM
*/
export const deleteVm = tool({
description:
'Delete an exe.dev virtual machine. This permanently removes the VM and its data. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<VmNameInput>({
type: 'object',
properties: {
name: {
type: 'string',
description: 'Name of the VM to delete',
},
},
required: ['name'],
additionalProperties: false,
}),
async execute(input: VmNameInput): Promise<{ deleted: boolean; name: string }> {
await runExeCommand(`rm ${input.name} --json`);
return { deleted: true, name: input.name };
},
});
/**
* Restart an exe.dev VM
*/
export const restart = tool({
description:
'Restart an exe.dev virtual machine. Useful for applying changes or recovering from issues. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<VmNameInput>({
type: 'object',
properties: {
name: {
type: 'string',
description: 'Name of the VM to restart',
},
},
required: ['name'],
additionalProperties: false,
}),
async execute(input: VmNameInput): Promise<{ restarted: boolean; name: string }> {
await runExeCommand(`restart ${input.name} --json`);
return { restarted: true, name: input.name };
},
});
/**
* Execute a command on an exe.dev VM
*/
export const exec = tool({
description:
'Execute a command on an exe.dev VM via SSH. Returns stdout, stderr, and exit code. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<ExecInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM to execute on',
},
command: {
type: 'string',
description: 'Command to execute on the VM',
},
},
required: ['vm', 'command'],
additionalProperties: false,
}),
async execute(input: ExecInput): Promise<ExeCommandResult> {
// The command is passed directly - buildSshCommand handles the quoting
const result = await runExeCommandWithExit(`ssh ${input.vm} -- ${input.command}`);
return result;
},
});
/**
* Show share configuration for a VM
*/
export const shareShow = tool({
description:
'Show the sharing configuration for an exe.dev VM including public status, port, users, and share links. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<VmInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
},
required: ['vm'],
additionalProperties: false,
}),
async execute(input: VmInput): Promise<ExeShareInfo> {
const output = await runExeCommand(`share show ${input.vm} --json`);
return parseJsonOutput<ExeShareInfo>(output);
},
});
/**
* Make a VM public
*/
export const shareSetPublic = tool({
description:
"Make an exe.dev VM's HTTP proxy publicly accessible without authentication. Requires SSH access to exe.dev.",
inputSchema: jsonSchema<VmInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM to make public',
},
},
required: ['vm'],
additionalProperties: false,
}),
async execute(input: VmInput): Promise<{ success: boolean; vm: string }> {
await runExeCommand(`share set-public ${input.vm}`);
return { success: true, vm: input.vm };
},
});
/**
* Make a VM private
*/
export const shareSetPrivate = tool({
description:
"Make an exe.dev VM's HTTP proxy private, requiring authentication to access. Requires SSH access to exe.dev.",
inputSchema: jsonSchema<VmInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM to make private',
},
},
required: ['vm'],
additionalProperties: false,
}),
async execute(input: VmInput): Promise<{ success: boolean; vm: string }> {
await runExeCommand(`share set-private ${input.vm}`);
return { success: true, vm: input.vm };
},
});
/**
* Set proxy port for a VM
*/
export const sharePort = tool({
description:
"Configure the HTTP proxy port for an exe.dev VM. Traffic to the VM's URL will be forwarded to this port. Requires SSH access to exe.dev.",
inputSchema: jsonSchema<SharePortInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
port: {
type: 'number',
description: 'Port number to proxy to (e.g., 8080)',
},
},
required: ['vm', 'port'],
additionalProperties: false,
}),
async execute(input: SharePortInput): Promise<{ success: boolean; vm: string; port: number }> {
await runExeCommand(`share port ${input.vm} ${input.port}`);
return { success: true, vm: input.vm, port: input.port };
},
});
/**
* Add a user to a VM
*/
export const shareAddUser = tool({
description:
'Grant a user access to an exe.dev VM by email. Sends an invitation with optional custom message. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<ShareUserInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
email: {
type: 'string',
description: 'Email address of user to invite',
},
message: {
type: 'string',
description: 'Custom invitation message',
},
},
required: ['vm', 'email'],
additionalProperties: false,
}),
async execute(input: ShareUserInput): Promise<{ success: boolean; vm: string; email: string }> {
let cmd = `share add ${input.vm} ${input.email}`;
if (input.message) {
cmd += ` --message="${input.message.replace(/"/g, '\\"')}"`;
}
await runExeCommand(cmd);
return { success: true, vm: input.vm, email: input.email };
},
});
/**
* Remove a user from a VM
*/
export const shareRemoveUser = tool({
description: "Revoke a user's access to an exe.dev VM by email. Requires SSH access to exe.dev.",
inputSchema: jsonSchema<ShareRemoveUserInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
email: {
type: 'string',
description: 'Email address of user to remove',
},
},
required: ['vm', 'email'],
additionalProperties: false,
}),
async execute(
input: ShareRemoveUserInput
): Promise<{ success: boolean; vm: string; email: string }> {
await runExeCommand(`share remove ${input.vm} ${input.email}`);
return { success: true, vm: input.vm, email: input.email };
},
});
/**
* Create a share link for a VM
*/
export const shareAddLink = tool({
description:
'Generate a shareable link for an exe.dev VM that can be shared with anyone. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<VmInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
},
required: ['vm'],
additionalProperties: false,
}),
async execute(input: VmInput): Promise<ExeShareLink> {
const output = await runExeCommand(`share add-link ${input.vm} --json`);
return parseJsonOutput<ExeShareLink>(output);
},
});
/**
* Remove a share link from a VM
*/
export const shareRemoveLink = tool({
description: 'Revoke a shareable link for an exe.dev VM. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<ShareRemoveLinkInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM',
},
token: {
type: 'string',
description: 'Token of the share link to remove',
},
},
required: ['vm', 'token'],
additionalProperties: false,
}),
async execute(
input: ShareRemoveLinkInput
): Promise<{ success: boolean; vm: string; token: string }> {
await runExeCommand(`share remove-link ${input.vm} ${input.token}`);
return { success: true, vm: input.vm, token: input.token };
},
});
/**
* Get current user info
*/
export const whoami = tool({
description:
"Get the current exe.dev user's account information including email and SSH keys. Requires SSH access to exe.dev.",
inputSchema: jsonSchema<Record<string, never>>({
type: 'object',
properties: {},
required: [],
additionalProperties: false,
}),
async execute(_input: Record<string, never>): Promise<ExeUserInfo> {
const output = await runExeCommand('whoami --json');
return parseJsonOutput<ExeUserInfo>(output);
},
});
/**
* Install Shelley on a VM
*/
export const shelleyInstall = tool({
description:
'Install or upgrade the Shelley agent on an exe.dev VM to the latest version. Requires SSH access to exe.dev.',
inputSchema: jsonSchema<VmInput>({
type: 'object',
properties: {
vm: {
type: 'string',
description: 'Name of the VM to install Shelley on',
},
},
required: ['vm'],
additionalProperties: false,
}),
async execute(input: VmInput): Promise<{ success: boolean; vm: string }> {
await runExeCommand(`shelley install ${input.vm}`);
return { success: true, vm: input.vm };
},
});
// ============================================================================
// Default Export
// ============================================================================
export default {
list,
create,
deleteVm,
restart,
exec,
shareShow,
shareSetPublic,
shareSetPrivate,
sharePort,
shareAddUser,
shareRemoveUser,
shareAddLink,
shareRemoveLink,
whoami,
shelleyInstall,
};

View file

@ -0,0 +1,11 @@
{
"extends": "@tpmjs/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"incremental": false,
"composite": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
sourcemap: true,
target: 'es2022',
});

16
pnpm-lock.yaml generated
View file

@ -1529,6 +1529,22 @@ importers:
specifier: ^5.9.3
version: 5.9.3
packages/tools/official/exe-dev:
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/executive-brief:
dependencies:
ai: